11 unsigned long rgb; /* on screen */
12 char c; /* canonical */
15 static int height, width;
18 static void debug_flush(void) {
19 eassert(!fflush(debug));
20 eassert(!ferror(debug));
27 typedef struct { /* both inclusive */
32 static inline char get(int x, int y) { return image[y * width + x]; }
33 static inline char get_p(Point p) { return get(p.x,p.y); }
36 static const CanonColourInfo canoncolourinfos[]= {
37 { 0x475A5E, '*' }, /* edge */
38 { 0x2C5F7A, '*' }, /* edge just under box heading shadow */
39 { 0x7D9094, '+' }, /* interbox */
40 { 0xBDC5BF, ' ' }, /* background - pale */
41 { 0xADB5AF, ' ' }, /* background - dark */
42 { 0x000000, 'o' }, /* foreground */
43 { 0xD4B356, ' ' }, /* background (cursor) */
44 { 0xFFFFFF, 'o' }, /* foreground (cursor) */
48 #define START_MAIN {200,200}
50 static void require_rectangle(int tlx, int tly, int brx, int bry, char c) {
52 for (x=tlx; x<=brx; x++)
53 for (y=tly; y<=bry; y++)
54 eassert(get(x,y) == c);
56 static void require_rectangle_r(Rect rr, char c) {
57 require_rectangle(rr.tl.x,rr.tl.y, rr.br.x,rr.br.y, c);
60 static void debug_rect(const char *what, int whati, Rect rr) {
62 fprintf(debug, "%s %d: %d,%d..%d,%d:\n", what, whati,
63 rr.tl.x,rr.tl.y, rr.br.x,rr.br.y);
64 w= rr.br.x - rr.tl.x + 1;
65 for (y=rr.tl.y; y<=rr.br.y; y++) {
66 fprintf(debug, "%4d %4d ",y,y-rr.tl.y);
67 r= fwrite(image + y*width + rr.tl.x, 1, w, debug);
75 static void find_main_rectangle(void) {
76 Rect whole = { {0,0}, {width-1,height-1} };
77 Rect mainr = { START_MAIN,START_MAIN };
79 #define WALK_UNTIL(point,coord,increm,stop,edge) \
81 if (get_p((point)) == (edge)) { (point).coord -= (increm); break; } \
82 eassert((point).coord != (stop)); \
83 (point).coord += (increm); \
86 WALK_UNTIL(mainr.tl, x,-1, whole.tl.x, '*');
87 WALK_UNTIL(mainr.tl, y,-1, whole.tl.y, '*');
88 WALK_UNTIL(mainr.br, x,+1, whole.br.x, '*');
89 WALK_UNTIL(mainr.br, y,+1, whole.br.y, '*');
91 require_rectangle(mainr.tl.x-1, mainr.tl.y, mainr.tl.x-1, mainr.br.y, '*');
92 require_rectangle(mainr.br.x+1, mainr.tl.y, mainr.br.x+1, mainr.br.y, '*');
93 require_rectangle(mainr.tl.x, mainr.tl.y-1, mainr.br.x, mainr.tl.y-1, '*');
94 require_rectangle(mainr.tl.x, mainr.br.y+1, mainr.br.x, mainr.br.y+1, '*');
96 #define CHECK_STRIP_BORDER(tlbr,xy,increm) \
101 csb_p.xy= mainr.tlbr.xy; \
102 if (get_p(csb_p)=='+') { \
104 csb_r.tl.xy= csb_p.xy; \
105 csb_r.br.xy= csb_p.xy; \
106 require_rectangle_r(csb_r, '+'); \
107 mainr.tlbr.xy += increm; \
111 debug_rect("mainr",0, mainr);
113 CHECK_STRIP_BORDER(tl,x,+1);
114 CHECK_STRIP_BORDER(tl,y,+1);
115 CHECK_STRIP_BORDER(br,x,-1);
116 CHECK_STRIP_BORDER(br,y,-1);
118 debug_rect("mainr",1, mainr);
121 static void load_image_and_canonify(void) {
123 unsigned char rgb[3];
125 const CanonColourInfo *cci;
127 pnm_readpaminit(stdin, &inpam, sizeof(inpam));
128 height= inpam.height;
130 eassert(inpam.maxval == 255);
131 eassert(inpam.bytes_per_sample == 1);
133 image= malloc(width*height);
135 memset(image,'?',width*height);
137 for (y=0; y<height; y++) {
138 for (x=0; x<width; x++) {
139 r= fread(&rgb,1,3,stdin); eassert(r==3);
141 ((unsigned long)rgb[0]<<16) |
142 ((unsigned long)rgb[1]<<8) |
144 for (cci=canoncolourinfos; cci->c; cci++)
145 if (cci->rgb == rgb_l) {
146 image[y*width + x]= cci->c;
150 fprintf(debug, "%4d ",y);
151 r= fwrite(image + y*width, 1,width, debug); eassert(r==width);
158 load_image_and_canonify();
159 find_main_rectangle();
161 repeatedly_find_top_thing();