chiark / gitweb /
Can find each commodity
[ypp-sc-tools.main.git] / pctb / convert.c
1 #include <pam.h>
2 #include <stdint.h>
3 #include <inttypes.h>
4 #include <assert.h>
5 #include <string.h>
6
7 #define eassert assert
8 #define debug stdout
9
10 typedef struct {
11   unsigned long rgb; /* on screen */
12   char c; /* canonical */
13 } CanonColourInfo;
14
15 static int height, width;
16 static char *image;
17
18 static void debug_flush(void) {
19   eassert(!fflush(debug));
20   eassert(!ferror(debug));
21 }
22
23 typedef struct {
24   int x, y;
25 } Point;
26
27 typedef struct { /* both inclusive */
28   Point tl;
29   Point br;
30 } Rect;
31
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); }
34
35
36 #define START_MAIN {200,200}
37 #define INTERESTING_COLUMNS 6
38 #define MAX_COLUMNS 7
39
40 static Rect mainr = { START_MAIN,START_MAIN };
41 static int commbasey, comminty;
42 static int colrightx[INTERESTING_COLUMNS];
43
44
45 static const CanonColourInfo canoncolourinfos[]= {
46   { 0x475A5E, '*' }, /* edge */
47   { 0x2C5F7A, '*' }, /* edge just under box heading shadow */
48   { 0x7D9094, '+' }, /* interbox */
49   { 0xBDC5BF, ' ' }, /* background - pale */
50   { 0xADB5AF, ' ' }, /* background - dark */
51   { 0x000000, 'o' }, /* foreground */
52   { 0xD4B356, ' ' }, /* background (cursor) */
53   { 0xFFFFFF, 'o' }, /* foreground (cursor) */
54   { 0,0 }
55 };
56
57 static void require_rectangle(int tlx, int tly, int brx, int bry,
58                               const char *ok) {
59   int x,y;
60   for (x=tlx; x<=brx; x++)
61     for (y=tly; y<=bry; y++) {
62       int c= get(x,y);
63       assert(strchr(ok,c));
64     }
65 }
66 static void require_rectangle_r(Rect rr, const char *ok) {
67   require_rectangle(rr.tl.x,rr.tl.y, rr.br.x,rr.br.y, ok);
68 }
69
70 static void debug_rect(const char *what, int whati, Rect rr) {
71   int y,r,w;
72   fprintf(debug, "%s %d: %d,%d..%d,%d:\n", what, whati,
73           rr.tl.x,rr.tl.y, rr.br.x,rr.br.y);
74   w= rr.br.x - rr.tl.x + 1;
75   for (y=rr.tl.y; y<=rr.br.y; y++) {
76     fprintf(debug, "%4d%*s|", y, rr.tl.x,"");
77     r= fwrite(image + y*width + rr.tl.x, 1, w, debug);
78     eassert(r==w);
79     fputc('|',debug);
80     fputc('\n',debug);
81   }
82   debug_flush();
83 }
84
85 #define WALK_UNTIL(point,coord,increm,last,edge)                        \
86   for (;;) {                                                            \
87     if ((point).coord == (last)+(increm)) break;                        \
88     if (get_p((point)) == (edge)) { (point).coord -= (increm); break; } \
89     (point).coord += (increm);                                          \
90   }
91
92 #define WALK_UNTIL_MUST(point,coord,increm,last,edge)   \
93   do {                                                  \
94     WALK_UNTIL(point,coord,increm,last,edge);           \
95     eassert((point).coord != (last)+(increm));          \
96   } while(0)
97
98 static void find_structure(void) {
99   Rect whole = { {0,0}, {width-1,height-1} };
100
101   WALK_UNTIL_MUST(mainr.tl, x,-1, whole.tl.x, '*');
102   WALK_UNTIL_MUST(mainr.tl, y,-1, whole.tl.y, '*');
103   WALK_UNTIL_MUST(mainr.br, x,+1, whole.br.x, '*');
104   WALK_UNTIL_MUST(mainr.br, y,+1, whole.br.y, '*');
105
106   require_rectangle(mainr.tl.x-1, mainr.tl.y, mainr.tl.x-1, mainr.br.y, "*");
107   require_rectangle(mainr.br.x+1, mainr.tl.y, mainr.br.x+1, mainr.br.y, "*");
108   require_rectangle(mainr.tl.x, mainr.tl.y-1, mainr.br.x, mainr.tl.y-1, "*");
109   require_rectangle(mainr.tl.x, mainr.br.y+1, mainr.br.x, mainr.br.y+1, "*");
110
111 #define CHECK_STRIP_BORDER(tlbr,xy,increm)      \
112   do {                                          \
113     Point csb_p;                                \
114     Rect csb_r;                                 \
115     csb_p= mainr.tl;                            \
116     csb_p.xy= mainr.tlbr.xy;                    \
117     if (get_p(csb_p)=='+') {                    \
118       csb_r= mainr;                             \
119       csb_r.tl.xy= csb_p.xy;                    \
120       csb_r.br.xy= csb_p.xy;                    \
121       require_rectangle_r(csb_r, "+");          \
122       mainr.tlbr.xy += increm;                  \
123     }                                           \
124   } while(0)
125
126   debug_rect("mainr",0, mainr);
127
128   CHECK_STRIP_BORDER(tl,x,+1);
129   CHECK_STRIP_BORDER(tl,y,+1);
130   CHECK_STRIP_BORDER(br,x,-1);
131   CHECK_STRIP_BORDER(br,y,-1);
132
133   debug_rect("mainr",1, mainr);
134
135   Point up = START_MAIN;
136   WALK_UNTIL_MUST(up, y,-1, mainr.tl.y, '+');
137
138   Point down = START_MAIN;
139   down.y++;
140   WALK_UNTIL_MUST(down, y,+1, mainr.br.y, '+');
141
142   int xscaleunit, y,x;
143   for (y=0, xscaleunit=1; y<4; y++, xscaleunit*=10) {
144     fprintf(debug,"     ");
145     for (x=0; x<=width; x++) {
146       if (x % xscaleunit) fputc(' ',debug);
147       else fprintf(debug,"%d",(x / xscaleunit)%10);
148     }
149     fputc('\n',debug);
150   }
151
152   commbasey= up.y;
153   comminty= down.y - up.y + 2;
154   fprintf(debug, "up.y=%d down.y=%d commbasey=%d comminty=%d\n",
155           up.y,down.y, commbasey,comminty);
156
157   Point across= { mainr.tl.x, commbasey };
158   int colno=0;
159   for (;;) {
160     eassert(get_p(across) != '+');
161     WALK_UNTIL(across, x,+1, mainr.br.x, '+');
162     eassert(colno < MAX_COLUMNS);
163     int colrx= across.x;
164     if (colrx > mainr.br.x) colrx= mainr.br.x;
165     if (colno < INTERESTING_COLUMNS) {
166       colrightx[colno]= colrx;
167       fprintf(debug,"colrightx[%d]= %d\n",colno,colrx);
168     } else {
169       fprintf(debug,"extra colr %d  %d\n",colno,colrx);
170     }
171       
172     colno++;
173     
174     if (across.x >= mainr.br.x-1)
175       break;
176
177     across.x++;
178     require_rectangle(across.x,mainr.tl.y, across.x,mainr.br.y, "+");
179     across.x++;
180   }
181   
182 }                   
183
184 static void find_commodity(int offset, Rect *rr) {
185   /* rr->tl.x==-1 if offset out of range */
186   rr->tl.y= commbasey - offset*comminty;
187   rr->br.y= rr->tl.y + comminty-2;
188   if (rr->tl.y < mainr.tl.y || rr->br.y > mainr.br.y) { rr->tl.x=-1; return; }
189   if (rr->tl.y > mainr.tl.y)
190     require_rectangle(rr->tl.x,rr->tl.y-1, rr->br.x,rr->tl.y-1, "+");
191   if (rr->br.y < mainr.tl.y)
192     require_rectangle(rr->tl.x,rr->br.y+1, rr->br.x,rr->br.y+1, "+");
193   
194   rr->tl.x= mainr.tl.x;
195   rr->br.x= mainr.br.x;
196 }
197
198 static void load_image_and_canonify(void) {
199   struct pam inpam;
200   unsigned char rgb[3];
201   int x,y,r;
202   const CanonColourInfo *cci;
203
204   pnm_readpaminit(stdin, &inpam, sizeof(inpam));
205   height= inpam.height;
206   width= inpam.width;
207   eassert(inpam.maxval == 255);
208   eassert(inpam.bytes_per_sample == 1);
209
210   image= malloc(width*height);
211   eassert(image);
212   memset(image,'?',width*height);
213
214   for (y=0; y<height; y++) {
215     for (x=0; x<width; x++) {
216       r= fread(&rgb,1,3,stdin);  eassert(r==3);
217       unsigned long rgb_l=
218         ((unsigned long)rgb[0]<<16) |
219         ((unsigned long)rgb[1]<<8) |
220                        (rgb[2]);
221       for (cci=canoncolourinfos; cci->c; cci++)
222         if (cci->rgb == rgb_l) {
223           image[y*width + x]= cci->c;
224           break;
225         }
226     }
227     fprintf(debug, "%4d ",y);
228     r= fwrite(image + y*width, 1,width, debug);  eassert(r==width);
229     fputc('\n',debug);
230   }
231   debug_flush();
232 }
233
234 int main(void) {
235   load_image_and_canonify();
236   find_structure();
237
238   Rect thisr;
239   int tryrect;
240   for (tryrect= +height; tryrect >= -height; tryrect--) {
241     find_commodity(tryrect, &thisr);
242     if (thisr.tl.x >= 0)
243       debug_rect("commod",tryrect, thisr);
244   }
245   return 0;
246 }