+static void compute_shift_mask(ShMask *sm, int targshift,
+ unsigned long ximage_mask) {
+ unsigned long below;
+
+ sm->lshift= 0;
+ sm->rshift= 0;
+ sm->mask= 0xfful << targshift;
+ below= ~0ul << targshift;
+
+ for (;;) {
+ if (ximage_mask < sm->mask) {
+ sm->lshift++; ximage_mask <<= 1;
+ } else if ((ximage_mask & ~below) > sm->mask) {
+ sm->rshift++; ximage_mask >>= 1;
+ } else {
+ break;
+ }
+ assert(!(sm->lshift && sm->rshift));
+ }
+ assert(sm->lshift < LONG_BIT);
+ assert(sm->rshift < LONG_BIT);
+}
+
+static CanonImage *convert_page(Snapshot *sn) {
+ ShMask shiftmasks[3];
+ CanonImage *im;
+
+#define COMPUTE_SHIFT_MASK(ix, targshift, rgb) \
+ compute_shift_mask(&shiftmasks[ix], targshift, sn->rgb##_mask)
+ COMPUTE_SHIFT_MASK(0, 16, red);
+ COMPUTE_SHIFT_MASK(1, 8, green);
+ COMPUTE_SHIFT_MASK(2, 0, blue);
+
+ CANONICALISE_IMAGE(im, sn->width, sn->height, {
+ long xrgb= XGetPixel(sn, x, y);
+ int i;
+ rgb= 0;
+ for (i=0; i<3; i++)
+ rgb |= ((xrgb << shiftmasks[i].lshift)
+ >> shiftmasks[i].rshift) & shiftmasks[i].mask;
+ });
+
+ return im;
+}