chiark / gitweb /
Reverse order of samples in Rgb and other optimisations
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 19 Jul 2009 14:31:07 +0000 (15:31 +0100)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 19 Jul 2009 14:31:07 +0000 (15:31 +0100)
pctb/convert.h
pctb/pages.c
pctb/rgbimage.c
pctb/structure.c
pctb/structure.h

index 1dcb8a2..11f534b 100644 (file)
 
 #define MAXIMGIDENT 100
 
+typedef uint32_t Rgb; /* red<<0 | green<<8 | blue<<16 */
+
 typedef struct RgbImage {
   int w, h;
-  unsigned char data[];
-  /* red   = data[ y*w*3 + x*3 + 0 ] = RI_PIXEL(ri,x,y)[0]
-   * green = data[ y*w*3 + x*3 + 1 ] = RI_PIXEL(ri,x,y)[1]
-   * blue  = data[ y*w*3 + x*3 + 2 ] = RI_PIXEL(ri,x,y)[2]
-   */
+  Rgb data[]; /* data[ y*w + x ] */
 } RgbImage;
 
-typedef unsigned long Rgb;
-
 void identify_rgbimage(const RgbImage *base, Rect portion,
                       char result[MAXIMGIDENT], const char *what);
 RgbImage *alloc_rgb_image(int w, int h);
 void fwrite_ppmraw(FILE *f, const RgbImage *ri);
 
-#define RI_PIXEL(ri,x,y) ((ri)->data + ((y)*(ri)->w + (x)) * 3)
+#define RI_PIXEL32(ri,x,y) ((ri)->data + ((y)*(ri)->w + (x)))
 
 static inline Rgb ri_rgb(const RgbImage *ri, int x, int y) {
-  const unsigned char *rip= RI_PIXEL(ri,x,y);
-  return (rip[0] << 16) |
-         (rip[1] <<  8) |
-         (rip[2]      );
+  return *RI_PIXEL32(ri,x,y);
 }
 
 /*----- from structure.c -----*/
index 95a1c46..e7d3ec9 100644 (file)
@@ -264,9 +264,9 @@ static void snapshot(Snapshot **output) {
 
 #define COMPUTE_SHIFT_MASK(ix, rgb) \
   compute_shift_mask(&shiftmasks[ix], im_use->rgb##_mask)
-  COMPUTE_SHIFT_MASK(0, red);
+  COMPUTE_SHIFT_MASK(0, blue);
   COMPUTE_SHIFT_MASK(1, green);
-  COMPUTE_SHIFT_MASK(2, blue);
+  COMPUTE_SHIFT_MASK(2, red);
   
   if (!*output)
     *output= alloc_rgb_image(wwidth, wheight);
@@ -274,7 +274,7 @@ static void snapshot(Snapshot **output) {
   rtimestamp(&begin, "compute_shift_masks+alloc_rgb_image");
 
   int x,y,i;
-  unsigned char *op= (*output)->data;
+  uint32_t *op32= (*output)->data;
   for (y=0; y<wheight; y++) {
     if (im_use->xoffset == 0 &&
        im_use->format == ZPixmap &&
@@ -286,21 +286,19 @@ static void snapshot(Snapshot **output) {
        im_use->blue_mask  == 0xff0000U) {
       const char *p= im_use->data + y * im_use->bytes_per_line;
 //      debugf("optimised copy y=%d",y);
-      for (x=0; x<wwidth; x++) {
-       *op++ = *p++;
-       *op++ = *p++;
-       *op++ = *p++;
-       p++;
-      }
+      memcpy(op32, p, wwidth*sizeof(*op32));
+      op32 += wwidth;
     } else {
       for (x=0; x<wwidth; x++) {
        long xrgb= XGetPixel(im_use,x,y);
+       Rgb sample= 0;
        for (i=0; i<3; i++) {
-         unsigned long sample=
+         sample <<= 8;
+         sample |=
            ((xrgb << shiftmasks[i].lshift) >> shiftmasks[i].rshift)
            & SAMPLEMASK;
-         *op++= sample;
        }
+       *op32++= sample;
       }
     }
   }
@@ -519,22 +517,20 @@ static void set_focus_commodity(void) {
 
 static CanonImage *convert_page(const Snapshot *sn, RgbImage **rgb_r) {
   CanonImage *im;
-  RgbImage *rgb;
+  RgbImage *ri;
 
   fwrite_ppmraw(screenshot_file, sn);
 
-  const unsigned char *pixel= sn->data;
-  CANONICALISE_IMAGE(im, sn->w, sn->h, rgb, {
-    r= *pixel++;
-    g= *pixel++;
-    b= *pixel++;
+  const Rgb *pixel= sn->data;
+  CANONICALISE_IMAGE(im, sn->w, sn->h, ri, {
+    rgb= *pixel++;
   });
 
   sysassert(!ferror(screenshot_file));
   sysassert(!fflush(screenshot_file));
 
-  if (rgb_r) *rgb_r= rgb;
-  else free(rgb);
+  if (rgb_r) *rgb_r= ri;
+  else free(ri);
 
   return im;
 }
@@ -583,8 +579,12 @@ static void convert_store_page(Snapshot *current) {
   CanonImage *ci;
   PageStruct *pstruct;
   
+  progress("page %d prescanning   ...",npages);
   ci= convert_page(current,&rgb);
+
+  progress("page %d overview      ...",npages);
   find_structure(ci,&pstruct, 0,0,0,0);
+
   store_current_page(ci,pstruct,rgb);
 }
 
@@ -612,7 +612,7 @@ void take_screenshots(void) {
     debugf("PAGING page %d converted\n",npages);
 
     wait_for_stability(&current,last, 0,
-                      "page %d collecting...",
+                      "page %d collecting    ...",
                       npages+1);
 
     if (npages &&  /* first pagedown doesn't do much */
index 81eddf9..dc9fa68 100644 (file)
@@ -85,14 +85,16 @@ static int identify1(const RgbImage *base, Rect portion,
     int x,y,i;
     for (y=0; y<h; y++) {
       for (x=0; x<w; x++) {
+       uint32_t rgb=0;
        for (i=0; i<3; i++) {
          int c;
          dbassert( dbfile_scanf("%d",&c) == 1);
          dbassert(c>=0 && c<=255);
-         int px= portion.tl.x + x, py= portion.tl.y + y;
-         diff |= px > portion.br.x || py > portion.br.y ||
-                 (c != RI_PIXEL(base,px,py)[i]);
+         rgb |= (Rgb)c << (i*8);
        }
+       int px= portion.tl.x + x, py= portion.tl.y + y;
+       diff |= px > portion.br.x || py > portion.br.y ||
+               rgb != ri_rgb(base,px,py);
       }
     }
     if (!diff) {
@@ -116,12 +118,17 @@ static int identify(const RgbImage *base, Rect portion,
 }
 
 void fwrite_ppmraw(FILE *f, const RgbImage *ri) {
+  int i;
   fprintf(f,
          "P6\n"
          "%d %d\n"
          "255\n", ri->w, ri->h);
-  int count= ri->w * ri->h * 3;
-  sysassert( fwrite(ri->data, 1, count, f) == count );
+  for (i=0; i < ri->w * ri->h; i++) {
+    Rgb rgb= ri->data[i];
+    fputc_unlocked(rgb >> 0,  f);
+    fputc_unlocked(rgb >> 8,  f);
+    fputc_unlocked(rgb >> 16, f);
+  }
   sysassert(!ferror(f));
   sysassert(!fflush(f));
 }
@@ -132,8 +139,9 @@ static void fwrite_ppm(FILE *f, const RgbImage *base, Rect portion) {
   for (y=portion.tl.y; y<=portion.br.y; y++) {
     for (x=portion.tl.x; x<=portion.br.x; x++) {
       putc(' ',f);
+      Rgb rgb= ri_rgb(base,x,y);
       for (i=0; i<3; i++)
-       fprintf(f," %3d", RI_PIXEL(base,x,y)[i]);
+       fprintf(f," %3d", (rgb>>(i*8)) & 0xff);
     }
     putc('\n',f);
   }
@@ -173,7 +181,7 @@ void identify_rgbimage(const RgbImage *base, Rect portion,
 
 RgbImage *alloc_rgb_image(int w, int h) {
   RgbImage *ri;
-  ri= mmalloc(sizeof(*ri) + w*h*3);
+  ri= mmalloc(sizeof(*ri) + w*h*sizeof(ri->data[0]));
   ri->w= w;
   ri->h= h;
   return ri;
index 8ab74ee..21bb169 100644 (file)
@@ -67,7 +67,7 @@ void select_page(int page) {
 
 
 typedef struct {
-  Rgb rgb; /* on screen */
+  Rgb rgbx; /* on screen, REVERSED BYTES ie r||g||b */
   char c; /* canonical */
 } CanonColourInfo;
 
@@ -114,9 +114,9 @@ CanonColourInfoReds canoncolourinfo_tree;
 void canon_colour_prepare(void) {
   const CanonColourInfo *cci;
   for (cci=canoncolourinfo_table; cci->c; cci++) {
-    unsigned char r= cci->rgb >> 16;
-    unsigned char g= cci->rgb >>  8;
-    unsigned char b= cci->rgb;
+    unsigned char r= cci->rgbx >> 16;
+    unsigned char g= cci->rgbx >>  8;
+    unsigned char b= cci->rgbx;
 
     CanonColourInfoGreens *greens= canoncolourinfo_tree.red2[r];
     if (!greens) {
@@ -170,7 +170,7 @@ static void mustfail2(void) {
 #define MP(v) fprintf(stderr," %s=%d,%d",#v,(v).x,(v).y)
 #define MI(v) fprintf(stderr," %s=%d",   #v,(v))
 #define MIL(v) fprintf(stderr," %s=%ld", #v,(v))
-#define MRGB(v) fprintf(stderr," %s=%06lx", #v,(v))
+#define MRGB(v) fprintf(stderr," %s=%06"PRIx32, #v,(v))
 #define MC(v) fprintf(stderr," %s='%c'", #v,(v))
 #define MS(v) fprintf(stderr," %s=\"%s\"", #v,(v))
 #define MF(v) fprintf(stderr," %s=%f", #v,(v))
@@ -491,10 +491,10 @@ static void file_read_image_ppm(FILE *f) {
   struct pam inpam;
   unsigned char rgb_buf[3];
   CanonImage *im;
-  RgbImage *rgb;
+  RgbImage *ri;
   PageStruct *pstruct;
 
-  progress("page %d reading...",npages);
+  progress("page %d reading       ...",npages);
 
   pnm_readpaminit(f, &inpam, sizeof(inpam));
   if (!(inpam.maxval == 255 &&
@@ -502,14 +502,12 @@ static void file_read_image_ppm(FILE *f) {
        inpam.format == RPPM_FORMAT))
     fatal("PNM screenshot(s) file must be 8bpp 1 byte-per-sample RGB raw");
 
-  CANONICALISE_IMAGE(im, inpam.width, inpam.height, rgb, {
-    int rr= fread(&rgb_buf,1,3,f);
-    sysassert(!ferror(f));
+  CANONICALISE_IMAGE(im, inpam.width, inpam.height, ri, {
+    errno=0; int rr= fread_unlocked(&rgb_buf,1,3,f);
+    sysassert(rr==3);
     if (rr!=3) fatal("PNM screenshot(s) file ends unexpectedly");
 
-    r= rgb_buf[0];
-    g= rgb_buf[1];
-    b= rgb_buf[2];
+    rgb= rgb_buf[0] | (rgb_buf[1] << 8) | (rgb_buf[2] << 16);
   });
 
   sysassert(!ferror(screenshot_file));
@@ -518,15 +516,15 @@ static void file_read_image_ppm(FILE *f) {
     fatal("Too many images in screenshots file; max is %d.\n", MAX_PAGES);
 
   find_structure(im,&pstruct, 0,0,0,0);
-  store_current_page(im,pstruct,rgb);
+  store_current_page(im,pstruct,ri);
   npages++;
 }
 
 void store_current_page(CanonImage *ci, PageStruct *pstruct, RgbImage *rgb) {
   assert(ci==cim);
-  progress("page %d condensing...",npages);
+  progress("page %d unantialiasing...",npages);
   adjust_colours(ci, rgb);
-  progress("page %d storing...",npages);
+  progress("page %d storing       ...",npages);
   if (!npages) page0_rgbimage= rgb;
   else free(rgb);
   page_images[npages]= cim;
@@ -536,6 +534,7 @@ void store_current_page(CanonImage *ci, PageStruct *pstruct, RgbImage *rgb) {
 
 void read_one_screenshot(void) {
   progress("reading screenshot...");
+  file_read_image_ppm(screenshot_file);
   progress_log("read screenshot.");
 }
 
@@ -559,40 +558,54 @@ void read_screenshots(void) {
   progress_log("read %d screenshots.",npages);
 }
 
-static inline double find_aa_density(const RgbImage *ri,
-                                    Point p, long background,
-                                    long foreground, int fg_extra) {
+static double aa_bg_chan[3], aa_scale_chan[3], aa_alpha_mean_max;
+static Rgb aa_background, aa_foreground;
+
+static void find_aa_density_prep(Rgb bg, Rgb fg, int fg_extra) {
+  int i;
+  unsigned char fg_chan[3];
+
+  aa_background= bg;
+  aa_foreground= fg;
+  aa_alpha_mean_max= fg_extra ? 0.999 : 1.0;
+
+  for (i=0; i<3; i++) {
+    aa_bg_chan[i]=             (aa_background >> (i*8)) & 0xff;
+    fg_chan[i]=                 aa_foreground >> (i*8);
+    aa_scale_chan[i]= 1.0 / (fg_chan[i] + fg_extra - aa_bg_chan[i]);
+  }
+}
+
+static inline double find_aa_density(const RgbImage *ri, Point p) {
   Rgb here= ri_rgb(ri, p.x, p.y);
 
-  double alpha[3], alpha_mean=0;
+  double alpha[3], alpha_total=0;
   int i;
   for (i=0; i<3; i++) {
-    unsigned char here_chan= here       >> (i*8);
-    unsigned char bg_chan=   background >> (i*8);
-    unsigned char fg_chan=   foreground >> (i*8);
-    double alpha_chan=
-      ((double)here_chan    - (double)bg_chan) /
-      ((fg_chan + fg_extra) - (double)bg_chan);
+    unsigned char here_chan= here >> (i*8);
+
+    double alpha_chan= (here_chan - aa_bg_chan[i]) * aa_scale_chan[i];
     alpha[i]= alpha_chan;
-    alpha_mean += alpha_chan * (1/3.0);
+    alpha_total += alpha_chan;
   }
 
+  double alpha_mean= round(alpha_total * (1e5/3.0)) * 1e-5;
+  
   double thresh= 1.5/AAMAXVAL;
   double alpha_min= alpha_mean - thresh;
   double alpha_max= alpha_mean + thresh;
+
   for (i=0; i<3; i++)
     MUST( alpha_min <= alpha[i] && alpha[i] <= alpha_max,
          MP(p);
-         MRGB(here);MRGB(background);MRGB(foreground);MI(fg_extra);
+         MRGB(here);MRGB(aa_background);MRGB(aa_foreground);
+         MF(aa_alpha_mean_max);
          MF(alpha_min); MI(i);MF(alpha[i]);MF(alpha_max) );
 
-  if (   -1e-5 <  alpha_mean && alpha_mean <= 0.0     ) alpha_mean= 0.0;
-  if (1.0      <= alpha_mean && alpha_mean <= 1.0+1e-5) alpha_mean= 1.0;
-
-  MUST( 0 <= alpha_mean &&
-       (fg_extra ? (alpha_mean < 0.999) : (alpha_mean <= 1.0)),
+  MUST( 0 <= alpha_mean && alpha_mean <= aa_alpha_mean_max,
        MP(p);
-       MRGB(here);MRGB(background);MRGB(foreground);MI(fg_extra);
+       MRGB(here);MRGB(aa_background);MRGB(aa_foreground);
+       MF(aa_alpha_mean_max);
        MF(alpha_mean); MF(alpha[0]);MF(alpha[1]);MF(alpha[2]); );
 
   return alpha_mean;
@@ -672,19 +685,24 @@ static void adjust_colours_cell(CanonImage *ci, const RgbImage *ri,
   Rgb background;
   unsigned char chanbg[3];
   long bg_count=0, light_count=0, dark_count=0;
+  int i;
   Point p;
 
   background= ri_rgb(ri, cell.br.x, cell.br.y);
-  memcpy(chanbg, RI_PIXEL(ri, cell.br.x, cell.br.y), 3);
+  for (i=0; i<3; i++)
+    chanbg[i]= background >> (i*8);
 
   FOR_P_RECT(p,cell) {
-    const unsigned char *here_pixel= RI_PIXEL(ri, p.x, p.y);
-    int i;
-    for (i=0; i<3; i++) {
-      unsigned here= here_pixel[i];
-      if (here == chanbg[i]) bg_count++;
-      else if (here < chanbg[i]) dark_count  += (chanbg[i] - here)/4 + 1;
-      else if (here > chanbg[i]) light_count += (here - chanbg[i])/4 + 1;
+    Rgb herergb= ri_rgb(ri, p.x, p.y);
+    if (herergb==background) {
+      bg_count+=3;
+    } else {
+      for (i=0; i<3; i++) {
+       unsigned char here= herergb >> (i*8);
+       if (here == chanbg[i]) bg_count++;
+       else if (here < chanbg[i]) dark_count  += (chanbg[i] - here)/4 + 1;
+       else if (here > chanbg[i]) light_count += (here - chanbg[i])/4 + 1;
+      }
     }
   }
   long total_count= RECT_W(cell) * RECT_H(cell) * 3;
@@ -717,8 +735,10 @@ static void adjust_colours_cell(CanonImage *ci, const RgbImage *ri,
 
   int monochrome= 1;
 
+  find_aa_density_prep(background, foreground, fg_extra);
+
   FOR_P_RECT(p,cell) {
-    double alpha= find_aa_density(ri,p,background,foreground,fg_extra);
+    double alpha= find_aa_density(ri,p);
 
     int here_int= floor((AAMAXVAL+1)*alpha);
     assert(here_int <= AAMAXVAL);
@@ -754,7 +774,7 @@ void analyse(FILE *tsv_output) {
     if (!rd)
       rd= ocr_init(text_h);
 
-    progress("Scanning page %d...",page);
+    progress("Processing page %d...",page);
 
     const char *tab= "";
     
@@ -812,14 +832,14 @@ void find_islandname(void) {
   Rect sunshiner= find_sunshine_widget();
   char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
 
-  const unsigned char *srcp;
-  unsigned char *destp, *endp;
+  const Rgb *srcp;
+  Rgb *destp, *endp;
   for (srcp= rgbsrc->data, destp=ri->data,
-        endp= ri->data + 3 * ri->w * ri->h;
+        endp= ri->data + ri->w * ri->h;
        destp < endp;
        srcp++, destp++) {
-    unsigned char c= *srcp & 0xf0;
-    *destp= c | (c>>4);
+    Rgb new= *srcp & 0xf0f0f0;
+    *destp= new | (new>>4);
   }
 
   identify_rgbimage(ri, sunshiner, sunshine, "sunshine widget");
@@ -845,13 +865,11 @@ void find_islandname(void) {
 //    islandnamer.br.y = larger_islandnamebry;
     debug_rect("islandnamer",1, islandnamer);
 
-    int x,y,i;
+    int x,y;
     for (x=islandnamer.tl.x; x<=islandnamer.br.x; x++)
       for (y=islandnamer.tl.y; y<=islandnamer.br.y; y++) {
-       if (RI_PIXEL(ri,x,y)[0] < 0x40) {
-         for (i=0; i<3; i++) {
-           RI_PIXEL(ri,x,y)[i]= 0;
-         }
+       if ((ri_rgb(ri,x,y) & 0xff) < 0x40) {
+         *RI_PIXEL32(ri,x,y)= 0;
        }
       }
 
@@ -904,10 +922,12 @@ void find_islandname(void) {
       uint32_t pattern=0;
       int runs[32], nruns=0;
       runs[0]=0; runs[1]=0;
+
+      find_aa_density_prep(0xCCCCAA,0x002255,0);
       
       for (p.y=islandnamer.tl.y; p.y<=islandnamer.br.y; p.y++) {
        pattern <<= 1;
-       double alpha= find_aa_density(ri,p, 0xCCCCAA,0x002255,0);
+       double alpha= find_aa_density(ri,p);
        if (alpha >= 0.49) {
           runs[nruns]++;
           pattern |= 1u;
index 73f6571..263a26a 100644 (file)
@@ -50,43 +50,41 @@ static inline char canon_lookup_colour(unsigned char r,
   return blues->blue2[b];
 }
 
-#define CANONICALISE_IMAGE(im,w,h,rgb_save, COMPUTE_RGB) do{   \
-    /* compute_rgb should be a number of statements, or                \
-     * a block, which assigns to                               \
-     *   Rgb rgb;                                              \
-     * given the values of                                     \
-     *   int x,y;                                              \
-     * all of which are anamorphic.  Result is stored in im.   \
-     * The COMPUTE_RGB is executed exactly once for            \
-     * each pixel in reading order.                            \
-     */                                                                \
-    (im)= alloc_canon_image((w), (h));                         \
-    (rgb_save)= alloc_rgb_image((w), (h));                     \
-                                                               \
-    int x,y;                                                   \
-    for (y=0; y<(h); y++) {                                    \
-      for (x=0; x<(w); x++) {                                  \
-        unsigned char r,g,b;                                   \
-       COMPUTE_RGB;                                            \
-        CANONIMG_ALSO_STORERGB((rgb_save));                    \
-       (im)->d[y*(w) + x]= canon_lookup_colour(r,g,b);         \
-      }                                                                \
-      if (DEBUGP(rect)) {                                      \
-       fprintf(debug, "%4d ",y);                               \
-       fwrite(im->d + y*(w), 1,(w), debug);                    \
-       fputc('\n',debug);                                      \
-      }                                                                \
-    }                                                          \
-    debug_flush();                                             \
+#define CANONICALISE_IMAGE(im,w,h,rgb_save, COMPUTE_RGB) do{           \
+    /* compute_rgb should be a number of statements, or                        \
+     * a block, which assigns to                                       \
+     *   Rgb rgb;                                                      \
+     * given the values of                                             \
+     *   int x,y;                                                      \
+     * all of which are anamorphic.  Result is stored in im.           \
+     * The COMPUTE_RGB is executed exactly once for                    \
+     * each pixel in reading order.                                    \
+     */                                                                        \
+    (im)= alloc_canon_image((w), (h));                                 \
+    (rgb_save)= alloc_rgb_image((w), (h));                             \
+                                                                       \
+    int x,y;                                                           \
+    for (y=0; y<(h); y++) {                                            \
+      for (x=0; x<(w); x++) {                                          \
+        Rgb rgb;                                                       \
+       COMPUTE_RGB;                                                    \
+        CANONIMG_ALSO_STORERGB((rgb_save));                            \
+       (im)->d[y*(w) + x]= canon_lookup_colour(rgb, rgb>>8, rgb>>16);  \
+      }                                                                        \
+      if (DEBUGP(rect)) {                                              \
+       fprintf(debug, "%4d ",y);                                       \
+       fwrite(im->d + y*(w), 1,(w), debug);                            \
+       fputc('\n',debug);                                              \
+      }                                                                        \
+    }                                                                  \
+    debug_flush();                                                     \
   }while(0)
 
 
 #define CANONIMG_ALSO_STORERGB(ri)             \
   do{                                          \
-    unsigned char *rip= RI_PIXEL((ri),x,y);    \
-    rip[0]= r;                                 \
-    rip[1]= g;                                 \
-    rip[2]= b;                                 \
+    Rgb *rip= RI_PIXEL32((ri),x,y);            \
+    *rip= rgb;                                 \
   }while(0)