chiark / gitweb /
antialiasing text conversion: canonimage has 0..AAMAXVAL
[ypp-sc-tools.web-live.git] / pctb / structure.c
index d053b448bf458b9f1c4f5d45559ccd8482f3b92a..5a593887350025f8ce39c5e5d2a90e9c72df61e9 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "structure.h"
 
-static const CanonImage *cim;
+static CanonImage *cim;
 
 static inline char get(int x, int y) { return cim->d[y * cim->w + x]; }
 static inline char get_p(Point p) { return get(p.x,p.y); }
@@ -92,10 +92,16 @@ const CanonColourInfo canoncolourinfos[]= {
 
 static void mustfail1(const char *file, int line, const char *what) {
   fprintf(stderr,
-         "\n\n"
-         "Unable to figure out contents of YPP client display.\n"
-         " Check that your client is logged in has the correct display.\n"
-         " If that isn't the problem, please report this as a fault.\n\n"
+ "\n\n"
+ "Unable to figure out contents of YPP client display.\n"
+ "Please check the following:\n"
+ "   * YPP client is showing commodity listing screen\n"
+ "   * YPP client has antialiased text turned off (Ye / Options / General)\n"
+ "   * YPP client window is on top (we try to raise it but your window\n"
+ "      manager might have prevented that from succeeding)\n"
+ "   * Your X display is 24bpp (NB some VNC servers use 16bpp by default)\n"
+ "\n"
+ "If all of these are true, please report this as a fault.\n\n"
          "Technical details:"
          " %s:%d: requirement failed:\n"
          " %s\n",
@@ -117,8 +123,11 @@ 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 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))
 #define MSB(v) fprintf(stderr," %s", (v))
 #define MR(v) fprintf(stderr," %s=%d,%d..%d,%d",\
                       #v,(v).tl.x,(v).tl.y,(v).br.x,(v).br.y)
@@ -127,20 +136,23 @@ static void mustfail2(void) {
 #define REQUIRE_RECTANGLE(tlx,tly,brx,bry,ok) \
  require_rectangle(tlx, tly, brx, bry, ok, __LINE__);
 
-static void require_rectangle(int tlx, int tly, int brx, int bry,
-                             const char *ok, int lineno) {
+#define FOR_P_RECT(p,rr)                               \
+  for ((p).x=(rr).tl.x; (p).x<=(rr).br.x; (p).x++)     \
+    for ((p).y=(rr).tl.y; (p).y<=(rr).br.y; (p).y++)
+
+static void require_rectangle_r(Rect rr, const char *ok, int lineno) {
   Point p;
-  for (p.x=tlx; p.x<=brx; p.x++)
-    for (p.y=tly; p.y<=bry; p.y++) {
-      int c= get_p(p);
-      MUST( strchr(ok,c), ({
-            Rect rm={{tlx,tly},{brx,bry}};
-            MI(lineno),MR(rm);MP(p);MS(ok);
-      }));
-    }
+  FOR_P_RECT(p,rr) {
+    int c= get_p(p);
+    MUST( strchr(ok,c), ({
+      MI(lineno),MR(rr);MP(p);MS(ok);
+    }));
+  }
 }
-static void require_rectangle_r(Rect rr, const char *ok, int lineno) {
-  require_rectangle(rr.tl.x,rr.tl.y, rr.br.x,rr.br.y, ok, lineno);
+static void require_rectangle(int tlx, int tly, int brx, int bry,
+                             const char *ok, int lineno) {
+  Rect rr= {{tlx,tly},{brx,bry}};
+  require_rectangle_r(rr, ok, lineno);
 }
 
 static void debug_rect(const char *what, int whati, Rect rr) {
@@ -215,7 +227,7 @@ static int commod_selector_matches(Rect search, const char *const *all,
     (search).TLBR.XY += increm;                                                   \
   }
 
-void find_structure(const CanonImage *im, int *max_relevant_y_r) {
+void find_structure(CanonImage *im, int *max_relevant_y_r) {
   cim= im;
   
   Rect whole = { {0,0}, {cim->w-1,cim->h-1} };
@@ -369,7 +381,6 @@ static void file_read_image_ppm(FILE *f) {
   struct pam inpam;
   unsigned char rgb_buf[3];
   CanonImage *im;
-  RgbImage *ri=0;
 
   pnm_readpaminit(f, &inpam, sizeof(inpam));
   if (!(inpam.maxval == 255 &&
@@ -377,9 +388,6 @@ 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");
 
-  if (!npages)
-    page0_rgbimage= ri= alloc_rgb_image(inpam.width, inpam.height);
-
   CANONICALISE_IMAGE(im, inpam.width, inpam.height, {
     int r= fread(&rgb_buf,1,3,f);
     sysassert(!ferror(f));
@@ -390,8 +398,6 @@ static void file_read_image_ppm(FILE *f) {
        ((unsigned long)rgb_buf[1]<<8) |
                       (rgb_buf[2]);
 
-    if (ri)
-      CANONIMG_ALSO_STORERGB(ri);
   });
 
   sysassert(!ferror(screenshot_file));
@@ -444,13 +450,74 @@ static void find_commodity(int offset, Rect *rr) {
     REQUIRE_RECTANGLE(rr->tl.x,rr->br.y+1, rr->br.x,rr->br.y+1, "+");
 }
 
-static void find_table_entry(Rect commod, int colno, Rect *cellr) {
-  cellr->tl.y= commod.tl.y;
-  cellr->br.y= commod.br.y;
-  cellr->tl.x= !colno ? commod.tl.x : colrightx[colno-1]+2;
-  cellr->br.x=                        colrightx[colno];
-  debug_rect("cell", colno, *cellr);
-  require_rectangle_r(*cellr, " o", __LINE__);
+static void find_table_entry(Rect commod, int colno, Rect *cell) {
+  cell->tl.y= commod.tl.y;
+  cell->br.y= commod.br.y;
+  cell->tl.x= !colno ? commod.tl.x : colrightx[colno-1]+2;
+  cell->br.x=                        colrightx[colno];
+  debug_rect("cell", colno, *cell);
+
+  const RgbImage *ri= cim->rgb;
+  
+  Rgb background= ri_rgb(ri, cell->br.x, cell->br.y);
+  long bg_count=0, white_count=0, black_count=0;
+  Point p;
+  FOR_P_RECT(p,*cell) {
+    Rgb here= ri_rgb(ri, p.x, p.y);
+    if (here == background) bg_count++;
+    else if (here == 0) black_count++;
+    else if (here == 0xffffffU) white_count++;
+  }
+  long total_count= RECT_W(*cell) * RECT_H(*cell);
+  MUST( bg_count > 8*total_count / 10,
+       MR(*cell);MIL(bg_count);MIL(white_count);MIL(black_count) );
+  if (bg_count == total_count)
+    return;
+
+  MUST( !!black_count != !!white_count,
+       MR(*cell);MIL(bg_count);MIL(white_count);MIL(black_count) );
+
+  debugf("TABLEENTRY col=%d %d,%d..%d,%d bg=%ld white=%ld black=%ld\n",
+        colno, cell->tl.x,cell->tl.y, cell->br.x,cell->br.y,
+        bg_count, white_count, black_count);
+  
+  Rgb foreground= white_count ? 0xffffffU : 0;
+  int monochrome= 1;
+
+  FOR_P_RECT(p,*cell) {
+    Rgb here= ri_rgb(ri, p.x, p.y);
+    double alpha[3], alpha_mean=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) /
+       ((double)fg_chan   - (double)bg_chan);
+      alpha[i]= alpha_chan;
+      alpha_mean += alpha_chan * (1/3.0);
+    }
+
+    double thresh= 1.0/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,
+           MI(i);MRGB(here);MRGB(background);MRGB(foreground);
+           MF(alpha_min);MF(alpha[i]);MF(alpha_max) );
+
+    MUST( 0 <= alpha_mean && alpha_mean <= 1,
+         MRGB(here);MRGB(background);MRGB(foreground);
+         MF(alpha_mean) );
+    int here_int= AAMAXVAL*alpha_mean;
+    if (!(here_int==0 || here_int==AAMAXVAL)) monochrome=0;
+    cim->d[p.y * cim->w + p.x]= '0' + here_int;
+  }
+
+  debug_rect("cell0M", colno, *cell);
+
+  require_rectangle_r(*cell, "0123456789", __LINE__);
 }
 
 static void ocr_rectangle(Rect r, const OcrCellType ct, FILE *tsv_output) {
@@ -465,8 +532,9 @@ static void ocr_rectangle(Rect r, const OcrCellType ct, FILE *tsv_output) {
       Point here= { x+r.tl.x, y+r.tl.y };
       int pixel= get_p(here);
       switch (pixel) {
-      case ' ':           break;
-      case 'o': cx |= rv; break;
+      case ' ':                      break;
+      case '0':                      break;
+      case '0'+AAMAXVAL:  cx |= rv;  break;
       default:
        MUST(!"wrong pixel",
             MC(pixel);MP(here);MSB(ocr_celltype_name(ct));MR(r); );
@@ -547,12 +615,14 @@ Rect find_sunshine_widget(void) {
 }
 
 void find_islandname(RgbImage *ri) {
+  find_structure(page_images[0], 0);
+
   Rect sunshiner= find_sunshine_widget();
   char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
 
   const unsigned char *srcp;
   unsigned char *destp, *endp;
-  for (srcp=page0_rgbimage->data, destp=ri->data,
+  for (srcp=page_images[0]->rgb->data, destp=ri->data,
         endp= ri->data + 3 * ri->w * ri->h;
        destp < endp;
        srcp++, destp++) {
@@ -680,14 +750,11 @@ void find_islandname(RgbImage *ri) {
     islandnamer.br.x= p.x;
 
     identify_rgbimage(ri, islandnamer, archisland, "island");
-
-    assert(!"not vessel");
   }
 
   char *delim= strstr(archisland," - ");
   assert(delim);
-  archipelago= masprintf("%.*s", delim-archisland, archisland);
+  archipelago= masprintf("%.*s", (int)(delim-archisland), archisland);
   island= masprintf("%s", delim+3);
 
-  free(ri);
 }