2 rule based OCR engine, partly rewritten for edges (old=pixel)
5 This is a Optical-Character-Recognition program
6 Copyright (C) 2000-2007 Joerg Schulenburg
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 see README for email address
24 >>> DO NOT EDIT THIS FILE IF YOU NOT REALLY KNOW WHAT YOU ARE DOING! <<<
26 I have invested lot of time, to write this part of the program.
27 This engine should recognize chars allways right or return UNKNOWN.
28 If you change something, test all other example files too,
29 to be sure that all things work better. (JoergS)
31 This engine was pixelbased until 0.40 which was not successfull enough.
32 Also code changes always hade side effects. The vectorisation of the code
33 starts from version 0.41 with the chars XNz and seems to be much better
34 to handle. Vectorization means we frame each character by a chain of
35 vectors and dont care about pixels anymore. Unfortunatly I have to
36 replace all the pixel codes, which is a long process. Old code will be lost.
41 - if box1->p and b differ, reduce probability
42 - probability makes life much easier here
43 - use only one box!?, may be bits have usefull infos
44 - divide this file, suggestion: classify chars:
45 high=ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhklt, low=acegijmnopqrsuvwxyz
47 often_used=etianmsurwdkgo rarely_used=hvjcflpqxyz.,:
49 every char (large overhead)
50 - two-pass version (first pass without tolerance)
51 2nd pass with tolerance (ex: one tiny more in sdata->holes)
53 general feature extraction:
54 - white holes at middle, upper, lower position (cost much time)
55 - test lines and triangles insteat of rectangles
57 char is removed, wchar_t is used (better code)
59 making a static global variable-set x.x0,x.x1, and call test_a,
60 test_b ... (faster compilation, but not reentrant!)
62 - adding slant-angle (if detected) to distinguish between l and / ?
63 - ac (alternate chars) as string add_ac(box1,"/") => box1->ac="Il/";
64 for better context correction or output: "Ha[lI][lI]o!"
70 // #include "pgm2asc.h"
76 #define IFV if(JOB->cfg.verbose&4)
77 #define MM {IFV fprintf(stderr,"\nDBG %c L%04d (%d,%d): ",(char)c_ask,__LINE__,box1->x0,box1->y0);}
79 // the old debug mode (0.40) was only for a special char, for another char
80 // code must be recompiled with C_ASK='char'
81 // new debug mode (0.41) explains why char is declined or accepted as ABC...
82 // the output can be filtered by external scripts
83 // ToDo: we could reduce output to filter string
84 #ifndef DO_DEBUG /* can be defined outside */
85 #define DO_DEBUG 0 /* 0 is the default */
88 /* this macro is for debugging output: "if char is declined, why?" */
89 #if DO_DEBUG /* 0=Work mode, 1=debugging mode */
90 // Setac: output, that char is choosen with a probability
91 // Break: output, why the char is not choosen
92 // MSG: debugging functions for char C_ASK, mostly messages
93 // DBG: definitions usefull only for debugging
94 #define Setac(box1,ac,ad) { MM;IFV fprintf(stderr,"setac %d",ad);setac(box1,ac,ad); }
95 #define Break { MM;IFV fprintf(stderr,"break"); break; }
96 #define MSG(x) { MM;IFV x }
99 #define Setac(box1,ac,ad) setac(box1,ac,ad)
107 // static inline int sq(int x) { return x*x; } /* square */
110 * go from vector j1 to vector j2 and measure maximum deviation of
111 * the steps from the line connecting j1 and j2
112 * return the squared maximum distance
113 * in units of the box size times 1024
114 * ToDo: 1) better give back max-dx and max-dy ???
115 * errors if j1 and j2 are in different frames or belong to
116 * more then one frame?
117 * 2) Better get deviation from a complete vector graphic?
118 * The vectorgraphic is the ideal test char adapted to the
119 * extrem vertices of the real char.
121 int line_deviation( struct box *box1, int j1, int j2 ) {
122 int r1x, r1y, r2x, r2y, r3x, r3y, i, x, y, d, dist, maxdist=0, frame, l2;
123 r1x=box1->frame_vector[j1][0];
124 r1y=box1->frame_vector[j1][1];
125 r2x=box1->frame_vector[j2][0];
126 r2y=box1->frame_vector[j2][1];
127 if (!box1->num_frames) return(-1);
128 if (j1<0 || j1>box1->num_frame_vectors[box1->num_frames-1] ||
129 j2<0 || j2>box1->num_frame_vectors[box1->num_frames-1]) {
130 fprintf(stderr,"Error in "__FILE__" L%d: idx out of range",__LINE__);
133 /* get the frame the endvector belongs to */
134 for (i=0;i<box1->num_frames;i++)
135 if (j2<box1->num_frame_vectors[i]) break;
137 /* frame(j1)<=frame(j2) possible */
138 for (i=j1;;i++) { // do it for each vector between j1 and j2
139 if (i >= box1->num_frame_vectors[frame])
140 i=((frame)?box1->num_frame_vectors[frame-1]:0); /* go around */
142 // for (i=j1;i!=j2;i=(i+1)%box1->num_frame_vectors[0]) {~}
143 r3x=box1->frame_vector[i][0];
144 r3y=box1->frame_vector[i][1];
146 // german: Abstand Punkt von Strecke, Laenge Lotrechte
147 // germ.Strecke : l1=(r1+r2)/2+d*(r2-r1)/2 for d=-1..1
148 // germ.Lotrechte: l2=r3+b*[-(r2-r1).y,(r2-r1).x]
149 // Schnittpunkt : l1=l2,
150 // eq1x: (r1x+r2x)/2-r3x+d*(r2x-r1x)/2+b*(r2y-r1y)=0
151 // eq1y: (r1y+r2y)/2-r3y+d*(r2y-r1y)/2-b*(r2x-r1x)=0
152 // eq2x: b*(r2x-r1x)*(r2y-r1y)=-((r1x+r2x)/2-r3x+d*(r2x-r1x)/2)*(r2x-r1x)
153 // eq2y: b*(r2x-r1x)*(r2y-r1y)= ((r1y+r2y)/2-r3y+d*(r2y-r1y)/2)*(r2y-r1y)
154 // eq2y-eq2x: ... in units of 1024 (fast integer rounded correctly)
155 l2=sq(r2x-r1x)+sq(r2y-r1y); // square of distance r2-r1
157 // fprintf(stderr,"ocr0 L%d: r1==r2 r1= %d %d",__LINE__, r1x, r1y); // debugging
160 d=-( ((r1x+r2x)-2*r3x)*(r2x-r1x)
161 +((r1y+r2y)-2*r3y)*(r2y-r1y))*1024/l2; // ..-1024..+1024..
162 if (d<=-1024) { x=r1x; y=r1y; } // starting point
164 if (d>=1024) { x=r2x; y=r2y; } // end point
166 x=((r1x+r2x)+1)/2+(d*(r2x-r1x))/2048;
167 y=((r1y+r2y)+1)/2+(d*(r2y-r1y))/2048;
168 /* we have the crossing point x,y now */
171 dist=sq((x-r3x)*1024/(box1->x1-box1->x0+1))
172 +sq((y-r3y)*1024/(box1->y1-box1->y0+1)); // 0..2*sq(1024)
173 if (dist>maxdist) maxdist=dist;
175 // fprintf(stderr,"\nDBG dev: %d-%d-%d dist=%5d max=%5d d=%d %d,%d-%d,%d"
176 // " vector= %d %d crosspoint= %d %d ",
177 // j1,i,j2,dist,maxdist,d,r1x,r1y,r2x,r2y,r3x,r3y,x,y);
183 * search vectors between j1 and j2 for nearest point a to point r
186 * r-> $$...$$ $ - mark vectors
187 * @@$..@@ @ - black pixels
188 * @@$..@@ . - white pixels
194 * j1 --> $$...$$ <-- j2
196 * ToDo: vector aa[5] = {rx,ry,x,y,d^2,idx} statt rx,ry?
197 * j1 and j2 must be in the same frame
200 int nearest_frame_vector( struct box *box1, int j1, int j2, int rx, int ry) {
201 int x,y,d,i,aa[4]; /* x,y,normalized_distance^2,vector_index */
202 int frame=0, x0=box1->x0, y0=box1->y0,
203 x1=box1->x1, y1=box1->y1,
204 dx=box1->x1-x0+1, dy=box1->y1-y0+1;
205 if (!box1->num_frames) return(-1);
206 if (j1<0 || j1>box1->num_frame_vectors[box1->num_frames-1] ||
207 j2<0 || j2>box1->num_frame_vectors[box1->num_frames-1]) {
208 fprintf(stderr,"Error in "__FILE__" L%d: idx %d-%d out of range\n",__LINE__,j1,j2);
212 aa[0]=x=box1->frame_vector[j2][0]; /* x */
213 aa[1]=y=box1->frame_vector[j2][1]; /* y */
214 /* maximum is (distance*128)^2 if r is inside the box */
215 aa[2]=d=2*sq(128)+sq((rx-(x0+x1)/2)*128/dx)+sq((ry-(y0+y1)/2)*128/dy);
216 aa[3]=j2; /* vector index */
217 /* get the frame the endvector belongs to */
218 for (i=0;i<box1->num_frames;i++)
219 if (j2<box1->num_frame_vectors[i]) break;
221 /* frame(j1)<=frame(j2) possible */
223 if (i >= box1->num_frame_vectors[frame])
224 i=((frame)?box1->num_frame_vectors[frame-1]:0); /* go around */
225 x=box1->frame_vector[i][0]; /* take a vector */
226 y=box1->frame_vector[i][1];
227 /* distance to upper left end, normalized to 128 */
228 d=sq((x-rx)*128/dx)+sq((y-ry)*128/dy);
229 if (d<aa[2]) { aa[0]=x; aa[1]=y; aa[2]=d; aa[3]=i; }
235 // test for umlauts, if ret>0 and m==1 box1 is changed
236 // m>0 modify box1->dots
237 // m==2 modify box1->y0
238 // called by pgm2asc + ocr0(?)
239 int testumlaut(struct box *box1, int cs, int m, wchar_t *modifier){
241 int r,y,x,x0,x1,y0,y1,dx,dy,m1,m2,m3,
242 xl,xr,yu,yl; // left, right, upper and lower border of dots
243 wchar_t mod='\0'; /* (TeX-) modifier ~"'` for compose() */
244 DBG( wchar_t c_ask='"'; )
246 x0=box1->x0; x1=box1->x1; dx=x1-x0+1;
247 y0=box1->y0; y1=box1->y1; dy=y1-y0+1;
248 m1=box1->m1; m2=box1->m2; m3=box1->m3;
249 xl=x0; xr=x1; yu=yl=y0;
250 if( dy < 5 || 4*y0 > 3*m2+m3 ) return 0; // no low chars: .,-=
251 /* modifier in box included? */
253 /* modifier in box included? */
254 for(y=y0;2*y<y0+y1;y++)if( get_bw(xl,xr,y,y,box1->p,cs,1)==0 ) break;
255 if( 2*y<y0+y1 ){ /* yes => extract */
257 while( get_bw(xl,xr,y,y,box1->p,cs,1)==0 && 2*y<=y0+y1) y++;
258 if( m&2 ) box1->y0=y; /* set new upper bond */
261 if( yu>=yl ) { if(m) box1->dots=0; return 0; } /* nothing found */
262 if( get_bw(xl-1,xl-1,yu,yl-1,box1->p,cs,1)==1 ) // neighbour overlap?
263 while( get_bw(xl ,xl ,yu,yl-1,box1->p,cs,1)==1 && 2*xl<x0+x1) xl++;
264 for(;xl<x1;xl++)if( get_bw(xl,xl,yu,yl,box1->p,cs,1)==1 ) break;
265 for(;xr>xl;xr--)if( get_bw(xr,xr,yu,yl,box1->p,cs,1)==1 ) break;
267 if ( yl-1>yu ) { // tall box ij"a"o"u
269 x=box1->y0; box1->y0=m1; out_x(box1); box1->y0=x;
270 fprintf(stderr,"\n#testumlaut x= %d %d m1=%d m2=%d",x0,y0,m1-y0,m2-y0);
271 fprintf(stderr," yu=%d yl=%d xl=%d xr=%d",yu-y0,yl-y0,xl-x0,xr-x0);
277 if( get_bw(xl,x1+1,yu,yl-1,box1->p,cs,1)==0 ) r=0; // neighbour overlap?
279 if( get_bw(xl ,xl ,yu,yl-1,box1->p,cs,1)==0
280 || get_bw(xl-1,xl-1,yu,yl-1,box1->p,cs,1)==0 ) // be sure there are gap to neighbours
281 if( get_bw(xr ,xr ,yu,yl-1,box1->p,cs,1)==0
282 || get_bw(xr+1,xr+1,yu,yl-1,box1->p,cs,1)==0 )
285 // ...@@@.... RING_ABOVE // ..@@@..@@. TILDE
286 // ..@...@... // @@.@@@@@..
287 // ..@...@... // @.........
290 for (i=yu;i<yl;i++) if (get_bw(xl,xr,i,i,box1->p,cs,1)==1) break;
291 for ( ;i<yl;i++) if (get_bw(xl,xr,i,i,box1->p,cs,1)==0) break;
292 for (j=xl;j<xr;j++) if (get_bw(j,j,yu,i,box1->p,cs,1)==1) break;
293 for ( ;j<xr;j++) if (get_bw(j,j,yu,i,box1->p,cs,1)==0) break;
294 for ( x=j;x<xr;x++) if (get_bw(x,x,yu,i,box1->p,cs,1)==1) break;
295 // vert. gap detected
296 if( j<xr && x<xr && j<x && xr-xl>2
297 && num_obj(xl,xr,yu,yl-1,box1->p,cs)>=2 // not best!!!
298 && num_cross(xl,xr,yu +(yl-yu)/4,yu+ (yl-yu)/4,box1->p,cs) == 2
299 && num_cross(xl,xr,yl-1-(yl-yu)/2,yl-1-(yl-yu)/2,box1->p,cs) == 2
300 ){ // may be the following lines are not quite ok
301 while( get_bw(xl,xr,yl,yl,box1->p,cs,1)==0 && 2*yl<y0+y1) yl++;
303 // out_x(box1);printf(" x,y=%d,%d i=%d xl=%d xr=%d yu=%d yl=%d",x0,y0,i-x0,xl-x0,xr-x0,yu-y0,yl-y0);
306 if( m&2 ) box1->y0=yl;
307 /* if( m&2 ) box1->y0= ( (r==1) ? yu : yl ); */
310 if(r==0){ // divided fr != fi
311 while( get_bw(x0,x1,yu,yu,box1->p,cs,1)==0 && 2*yu<y0+y1) yu++;
319 // if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
320 // > loop(box1->p,xl,yl,xr-xl,cs,0,RI) // +dx/8
321 // && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
322 // < loop(box1->p,xr,yl,xr-xl,cs,0,LE)) // -dx/8 ) // é Nov03
323 if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
324 - loop(box1->p,xr,yu,xr-xl,cs,0,LE)
325 > loop(box1->p,xl,yl,xr-xl,cs,0,RI) // +dx/8
326 - loop(box1->p,xr,yl,xr-xl,cs,0,LE)+1) // -dx/8 ) // é Nov03
327 mod = ACUTE_ACCENT; // '
329 if( xr-xl+1 > 3*(yl-yu+1)
330 && get_bw(xl,xr,yu,yl,box1->p,cs,2)==0 )
331 mod = MACRON; // "-" above
337 // if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
338 // < loop(box1->p,xl,yl,xr-xl,cs,0,RI) // -dx/8
339 // && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
340 // > loop(box1->p,xr,yl,xr-xl,cs,0,LE) ) // +dx/8 ) à Nov03
341 if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
342 - loop(box1->p,xr,yu,xr-xl,cs,0,LE)
343 < loop(box1->p,xl,yl,xr-xl,cs,0,RI) // -dx/8
344 - loop(box1->p,xr,yl,xr-xl,cs,0,LE) -1 ) // +dx/8 ) à Nov03
345 mod = GRAVE_ACCENT; // `
348 fprintf(stderr,"\n#testumlaut x= %d %d m1=%d m2=%d",x0,y0,m1-y0,m2-y0);
349 fprintf(stderr," yu=%d yl=%d xl=%d xr=%d",yu-y0,yl-y0,xl-x0,xr-x0);
351 if( (xr-xl+1) < 2*(yl-yu+1)+2
352 && 2*(xr-xl+1)+2 > (yl-yu+1) ) {
354 i1=loop(box1->p,xl ,(yu+yl)/2,xr-xl+1,cs,0,RI);
355 i1=loop(box1->p,xl+i1,(yu+yl)/2,xr-xl+1,cs,1,RI);
356 i2=loop(box1->p,(xl+xr)/2,yu ,yl-yu+1,cs,0,DO);
357 i2=loop(box1->p,(xl+xr)/2,yu+i2,yl-yu+1,cs,1,DO);
358 for (i=0;i<xr-xl+1 && i<yl-yu+1;i++)
359 if (getpixel(box1->p,xl+i,yu+i)< cs) break; i3=i;
360 for ( ;i<xr-xl+1 && i<yl-yu+1;i++)
361 if (getpixel(box1->p,xl+i,yu+i)>=cs) break; i3=i-i3;
362 for (i=0;i<xr-xl+1 && i<yl-yu+1;i++)
363 if (getpixel(box1->p,xr-i,yu+i)< cs) break; i4=i;
364 for ( ;i<xr-xl+1 && i<yl-yu+1;i++)
365 if (getpixel(box1->p,xr-i,yu+i)>=cs) break; i4=i-i4;
367 fprintf(stderr,"\n#DEBUG DOT_ABOVE %d %d %d %d",i1,i2,i3,i4);
369 if ( (xr-xl<5 && yl-yu<8) /* to small */
370 || (i1>=(xr-xl+1)/2+2 && i2>=(yl-yu+1)/2+2 /* symmetrical */
371 && abs(i3-i4)<=i1/4+2 && abs(i1-i2)<=i1/4+2
372 && abs(i3-i1)<=i1/4+4 && abs(i4-i2)<=i1/4+4)
374 mod = DOT_ABOVE; // "." above, ToDo: improve it!
377 if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
378 > loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/8
379 || loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
380 > loop(box1->p,xl,yl-1,xr-xl,cs,0,RI)-dx/8 )
381 && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
382 > loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/8
383 || loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
384 > loop(box1->p,xr,yl-1,xr-xl,cs,0,LE)-dx/8 )
385 && num_cross(xl,xr,yu ,yu ,box1->p,cs) == 1
386 && ( num_cross(xl,xr,yl ,yl ,box1->p,cs) == 2
387 || num_cross(xl,xr,yl-1,yl-1,box1->p,cs) == 2 ))
388 mod = CIRCUMFLEX_ACCENT; // "^"
390 if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
391 < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10
392 || loop(box1->p,xl,yu+1,xr-xl,cs,0,RI)
393 < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10 )
394 && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
395 < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10
396 || loop(box1->p,xr,yu+1,xr-xl,cs,0,LE)
397 < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10 )
398 && ( num_cross(xl,xr,yu ,yu ,box1->p,cs) == 2
399 || num_cross(xl,xr,yu+1,yu+1,box1->p,cs) == 2 )
400 && num_cross(xl,xr,yl ,yl ,box1->p,cs) == 1 )
401 mod = CARON; // "v" above
403 if( /* test for bow (new0.3.6) */
404 loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
405 + loop(box1->p,xl,yl ,xr-xl,cs,0,RI)
406 - 2*loop(box1->p,xl,(yl+yu)/2,xr-xl,cs,0,RI) > dx/16+1
408 if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
409 < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10
410 || loop(box1->p,xl,yu+1,xr-xl,cs,0,RI)
411 < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10 )
412 && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
413 < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10
414 || loop(box1->p,xr,yu+1,xr-xl,cs,0,LE)
415 < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10 )
416 && ( num_cross(xl,xr,yu ,yu ,box1->p,cs) == 2
417 || num_cross(xl,xr,yu+1,yu+1,box1->p,cs) == 2 )
418 && num_cross(xl,xr,yl ,yl ,box1->p,cs) == 1 )
419 mod = BREVE; // round "u" above
421 if( xr-xl>3 && yl-yu>1 )
422 if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
423 > loop(box1->p,xl,yl,xr-xl,cs,0,RI)
424 && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
425 < loop(box1->p,xr,yl,xr-xl,cs,0,LE)
426 && num_cross(xl,xr,yu,yu,box1->p,cs) == 2
427 && num_cross(xl,xr,yl,yl,box1->p,cs) == 2 )
430 if( xr-xl>2 && yl-yu>2)
431 if( num_cross(xl,xr,(yu+yl)/2,(yu+yl)/2,box1->p,cs) >1 )
432 if( num_cross((xl+xr)/2,(xl+xr)/2,yu,yl,box1->p,cs) >1 )
433 if( num_hole(xl,xr,yu,yl,box1->p,cs,NULL) == 1 )
437 printf("\n#DEBUG umlaut mod=0x%04x x=%d..%d y=%d..%d r=%d %s",
438 (int)mod,yu-box1->y0,yl-box1->y0,
439 xl-box1->x0,xr-box1->x0,r,((mod==CARON)?"CARON":
440 ((mod==ACUTE_ACCENT)?"ACUTE":
441 ((mod==TILDE)?"TILDE":"?"))));
447 if (m) box1->dots=r; // set to 0 also possible after division
448 if (m) box1->modifier=mod; /* should be resetted after compose ??? */
449 MSG(fprintf(stderr,"umlaut mod=%s dots=%d y0o=%d",decode(mod,ASCII),r,y0);)
451 // printf(" modifier=%c",mod);
452 if (modifier) *modifier=mod; /* set modifier */
457 static wchar_t ocr0_eE(ocr0_shared_t *sdata){
458 struct box *box1=sdata->box1;
459 int i,i1,i2,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,bad_e=0,
460 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
461 int dx=x1-x0+1,dy=y1-y0+1, /* size */
463 int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
465 // --- most frequent letter e first!!!
466 // --- test e ---------------------------------------------------
467 for(ad=d=100;dx>2 && dy>3;){ // min 3x4 (smallest seen is 5x6)
468 DBG( wchar_t c_ask='e'; )
469 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
470 if (sdata->holes.num != 1) ad=97*ad/100;
471 /* ToDo: may be a two pass version intolerant/tolerant is better */
472 if( loop(box1->p,x0,y0+dy/2,x1-x0,cs,0,RI)>dx/3 ) Break; // rough test
473 if( loop(box1->p,x0+dx/2,y0,y1-y0,cs,0,DO)>dy/3 ) Break;
474 if( loop(box1->p,x0+dx/2,y1,y1-y0,cs,0,UP)>dy/3 ) Break;
475 if( num_cross(x0,x1,y0+dy/4 ,y0+dy/4 ,box1->p,cs) > 2
476 && num_cross(x0,x1,y0+dy/4+1,y0+dy/4+1,box1->p,cs) > 2 ) Break; // gt
477 x=(x0+x1)/2;i= num_cross(x,x,y0,y1,box1->p,cs); // v0.40
478 if (i!=3) { x=(x0+2*x1)/3;i= num_cross(x,x,y0,y1,box1->p,cs); }
479 if (i!=3) { x=(x0+3*x1)/4;i= num_cross(x,x,y0,y1,box1->p,cs); }
480 if (i!=3) { i= num_cross((x0+2*x1)/3,(x0+x1)/2,y0,y1,box1->p,cs); }
481 i=loop(box1->p,x0,y0+dy/2,x1-x0,cs,0,RI); if( i>dx/2 ) Break;
482 j=loop(box1->p,x0,y0 ,x1-x0,cs,0,RI); if( j<i ) Break;
483 j=loop(box1->p,x0,y1 ,x1-x0,cs,0,RI); if( j<i ) Break;
484 i=loop(box1->p,x0+dx/2,y0,y1-y0,cs,0,DO); if( i>dx/2 ) Break;
485 j=loop(box1->p,x1-dx/3,y0,y1-y0,cs,0,DO); if( j<i ) i=j;
486 j=loop(box1->p,x0 ,y0,y1-y0,cs,0,DO); if( j<i ) Break;
487 j=loop(box1->p,x1 ,y0,y1-y0,cs,0,DO); if( j<i ) Break;
488 i=loop(box1->p,x0+dx/2,y1,y1-y0,cs,0,UP); if( i>dx/2 ) Break;
489 j=loop(box1->p,x0 ,y1,y1-y0,cs,0,UP); if( j<i ) Break;
490 j=loop(box1->p,x1 ,y1,y1-y0,cs,0,UP); if( j<i ) Break;
491 j=2*loop(box1->p,x0, (y0+y1)/2,x1-x0,cs,0,RI)
492 -loop(box1->p,x0,(3*y0+y1)/4,x1-x0,cs,0,RI)
493 -loop(box1->p,x0,(y0+3*y1)/4,x1-x0,cs,0,RI);
494 if (dx>3 && j>=dx/4) Break; // ~g 4x6font
495 for(y=1;y<dy/2;y++) if( num_cross(x0,x1,y0+y,y0+y,box1->p,cs) == 2 ) break;
496 if( y==dy/2 ) Break; // v0.2.5 ~ bad_t
497 for(i=0,j=x0+dx/4;j<=x1-dx/4 && i<=dx/4;j++)
498 if( num_cross(j,j,y0,y1,box1->p,cs) == 3 ) i++;
499 if( dx>4 && dy>5 && (i<dx/4-1 || i==0) ) Break; // ~g but 4x6-e
500 // look for horizontal white line (right gap) => set x,y
501 for(x=0,y=i=y0+dy/3;i<y1-dy/6;i++){
502 j=loop(box1->p,x1,i,y1-y0,cs,0,LE);
503 if(j>=x) { x=j;y=i; }
505 if (x<dx/2){ // no gap found, fat font???
506 // check smallest thickness left > 2* smallest thickness right
507 for(i1=dx,i=y0+dy/3;i<y1-dy/6;i++){
508 j =loop(box1->p,x0 ,i,y1-y0,cs,0,RI); if (j>dx/2) break;
509 j =loop(box1->p,x0+j,i,y1-y0,cs,1,RI);
510 if (j<i1) i1=j; // smallest thickness on left bow
512 for(i2=dx,y=i=y0+dy/3;i<y1-dy/6;i++){
513 j =loop(box1->p,x1 ,i,y1-y0,cs,0,LE);
514 j =loop(box1->p,x1-j,i,y1-y0,cs,1,LE);
515 if(j<i2) { i2=j;y=i; }
516 } if (3*i2>2*i1) Break; // not accepted, if right line is not very thinn
517 x =loop(box1->p,x1 ,y,y1-y0,cs,0,LE);
518 x+=loop(box1->p,x1-x,y,y1-y0,cs,1,LE);
519 x+=loop(box1->p,x1-x,y,y1-y0,cs,0,LE);
520 if (3*i2>i1) ad=99*ad/100;
521 if (2*i2>i1) ad=99*ad/100;
522 bad_e=60; // used later?
525 for(i=1,j=x0+dx/6;j<x1-dx/6 && i;j++)
526 if( num_cross(j,j,y0,y,box1->p,cs) > 1 ) i=0;
533 // @@.,;.@,. <- problem (y) == bad_e>50
538 if (dy>11 && bad_e<50)
539 if ( num_cross(x0,x1,y,y,box1->p,cs) != 1 ) Break; // except "geschwungenem e"
540 if ( num_cross(x0,x1-dx/3,y ,y ,box1->p,cs) != 1
541 && num_cross(x0,x1-dx/3,y+1,y+1,box1->p,cs) != 1 ) Break;
542 // if( num_hole(x0, x1, y0 , y ,box1->p,cs,NULL) < 1 ){
543 if( sdata->holes.num == 0 || sdata->holes.hole[0].y1 >= y-y0){
544 if( sdata->hchar ) Break; // ~ \it t
545 // look if thinn font (may be h-line is broken) Mai00
546 for(j=0,i=x0+dx/8;i<x1-1;i++)
547 if( get_bw(i,i,y0+dy/4,y,box1->p,cs,1) == 1 ) j++;
550 if( sdata->holes.num>0 && sdata->holes.hole[0].y0 > y-y0) Break;
551 if( sdata->holes.num>1 && sdata->holes.hole[1].y0 > y-y0) Break;
552 if( sdata->holes.num==1 && sdata->holes.hole[0].x0 >= dx/2) {
553 ad=95*ad/100; } /* 8*10 @ (=at) is not an e */
554 // look for horizontal gap
555 for(x=0,y=i=y0+dy/4;i<y1-dy/4;i++){
556 j=loop(box1->p,x0,i,x1-x0,cs,0,RI);
557 if(j>=x) { x=j;y=i; }
559 if (y>y0+dy/4 && y<y1-dy/4 && x>dx/2) Break; // s
560 if (x>dx/4) ad=99*ad/100;
562 if( num_cross(x0+dx/2,x1 ,y1-dy/4,y1 ,box1->p,cs) == 0
563 && num_cross(x0+dx/2,x1-1,y1-dy/4,y1 ,box1->p,cs) == 0
564 && num_cross(x0+dx/2,x1 ,y1-dy/4,y1-1,box1->p,cs) == 0 ) {
565 if (sdata->gchar) Break; // ~p
568 /* upper case is for 5x6 box */
569 if( sdata->hchar // broken B ? should also work when linedetection fails
570 && loop(box1->p,x1,y1-dy/3,dx,cs,0,LE)<=dx/8 ) {
571 x = loop(box1->p,x0,y0+dy/2,dx,cs,0,RI);
572 if( loop(box1->p,x0,y0+dy/4,dx,cs,0,RI)<=x
573 && loop(box1->p,x0,y0+dy/8,dx,cs,0,RI)<=x ) Break;
574 if( loop(box1->p,x0,y1-dy/4,dx,cs,0,RI)<=x
575 && loop(box1->p,x0,y1-dy/8,dx,cs,0,RI)<=x ) Break;
577 x = loop(sdata->bp,0,dy-2 ,dx,cs,0,RI);
578 if( loop(sdata->bp,0,dy-1-dy/8,dx,cs,0,RI)>x && dy>16) Break; // some Q
580 if (sdata->gchar) ad=99*ad/100;
581 if (sdata->hchar) ad=99*ad/100;
584 Setac(box1,(wchar_t)'e',ad);
585 if (ad>=100) return 'e';
588 // --- test E ---------------------------------------------------
589 for(ad=d=100;dx>2 && dy>4 ;){ // min 3x4
590 // rewritten for vectors 0.43
591 int i1, i2, i3, i4, i5; // line derivation + corners
592 DBG( wchar_t c_ask='E'; )
593 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
594 /* half distance to the center */
596 /* now we check for the upper right end of the h */
597 if (aa[3][2]>d/2) Break; /* [2] = distance, ~dj... */
598 if (aa[0][2]>d/2) Break; /* upper left end */
599 if (aa[1][2]>d/2) Break; /* lower left end */
600 if (aa[2][2]>d/2) Break; /* lowerright end */
613 // check the bow from below
614 for (i=aa[1][3];i!=aa[2][3];i=(i+1)%box1->num_frame_vectors[0]) {
615 if (y1-box1->frame_vector[ i][1]>dy/4) break; // fatal!
616 } if (i!=aa[2][3]) Break; // ~AHKMNRX
617 // search most left+down between bottom right and top right
618 i1=nearest_frame_vector(box1, aa[2][3],aa[3][3], x0, y1);
619 i5=nearest_frame_vector(box1, i1,aa[3][3], x0, y0);
620 i3=nearest_frame_vector(box1, i1, i5, x1, (y0+y1)/2);
621 i2=nearest_frame_vector(box1, i1, i3, x0, (2*y0+y1)/3);
622 i4=nearest_frame_vector(box1, i3, i5, x0, (y0+2*y1)/3);
623 i =nearest_frame_vector(box1, aa[0][3],aa[1][3], x0-dx/4, (y0+y1)/2);
624 if (2*box1->frame_vector[i][0] < aa[0][0]+aa[1][0]-1-dx/16) Break;
625 if (2*box1->frame_vector[i][0] < aa[0][0]+aa[1][0]) ad=99*ad/100; // f
627 MSG(fprintf(stderr,"i1-5 %d %d %d %d %d",i1,i2,i3,i4,i5);)
629 for( i=1,y=y0; y<y0+dy/4 && i; y++ ) // long black line
630 if( get_bw(x0+dx/3,x1-dx/6,y,y,box1->p,cs,2) == 0 ) i=0;
632 for( i=1,y=y1; y>y1-dy/4 && i; y-- ) // long black line
633 if( get_bw(x0+dx/6,x1-dx/4,y,y,box1->p,cs,2) == 0 ) i=0;
635 for( i=1,y=y0+dy/3; y<y1-dy/3 && i; y++ ){ // black line
636 j=loop(box1->p,x0 ,y,dx,cs,0,RI);
637 j=loop(box1->p,x0+j,y,dx,cs,1,RI); if( j>dx/3 ) i=0;
639 x=x1-dx/3; y=y0; // von oben durchbohren!
640 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y0+dy/4 ) Break;
641 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,DO); if( y>y0+dy/3 ) Break;
642 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,DO); if( x<=x1 || y>y0+dy/2 ) Break;
643 x=x1-dx/3; y=y1; // von unten durchbohren!
644 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( y<y1-dy/4 ) Break;
645 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,UP); if( y<y0-dy/3 ) Break;
646 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,UP); if( x<=x1 || y<y0+dy/2 ) Break;
647 x=x1-dx/3; y=y0; // von oben durchbohren!
648 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y0+dy/4 ) Break;
649 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,DO); if( y>y0+dy/3 ) Break;
651 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,LE,ST); if( x<x0 ) Break;
652 if (dx>15 && x==x0) ad=99*ad/100; // to thin
654 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y1-dy/3 ) Break;
655 // if( num_hole(x0, x1, y0 , y1 ,box1->p,cs,NULL) > 0 ) Break;
656 if (sdata->holes.num > 0) Break;
657 i=loop(box1->p,x0,y0+dy/4,dx,cs,0,RI); if(i>dx/2) Break;
658 j=loop(box1->p,x0,y0+dy/2,dx,cs,0,RI); if(j<i-dx/4 || j>i+dx/8) Break; i=j;
659 j=loop(box1->p,x0,y1-dy/4,dx,cs,0,RI); if(j<i-dx/4 || j>i+dx/8) Break;
660 j=loop(box1->p,x1,y1-dy/4,dx,cs,0,LE);
661 for( x=dx,y=y0+dy/6; y<y1-dy/9; y++ ) // left border straight
662 { i=loop(box1->p,x0,y,dx,cs,0,RI);
663 if (i>j/2 && ad>98) ad=99*ad/100;
666 } if( y<y1-dy/9 ) Break; // t
668 if( get_bw(x0+dx/2,x0+dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break;
671 if (!hchar) ad=ad*99/100;
672 if ( gchar) ad=ad*99/100;
674 Setac(box1,(wchar_t)'E',ad);
675 if (ad>=100) return 'E';
681 static wchar_t ocr0_n(ocr0_shared_t *sdata){
682 struct box *box1=sdata->box1;
683 int i,j,d,x,y,i1,i2,i3,handwritten=0,
684 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
685 int dx=x1-x0+1,dy=y1-y0+1, /* size */
688 // --- test n ---------------------------------------------------
689 // glued rm is very similar to glued nn -> thickness of h-line should grow
690 // may02: tested for 8x12 font
691 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
692 DBG( wchar_t c_ask='n'; )
693 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
694 i= num_cross( 0,dx-1,dy/4,dy/4,sdata->bp,cs);
695 j= num_cross( 0,dx-1,dy/2,dy/2,sdata->bp,cs);
696 if( (i<2 || i>3) && j!=2 ) Break;
697 if( loop(sdata->bp,dx/2,0,dy,cs,0,DO) > dy/8 && sdata->hchar ) Break; /* tt */
698 y=5*dy/8; /* also for handwritten n, where first bow goes not down enough */
699 if( num_cross( 0,dx/2,y ,y ,sdata->bp,cs) != 1
700 && num_cross( 0,dx/2,y-1,y-1,sdata->bp,cs) != 1
701 && num_cross(dx/2,dx-1,y ,y ,sdata->bp,cs) < 1 ) Break; // n rr
703 y=loop(sdata->bp,dx-1-dx/4,0,dy,cs,0,DO); if(y>dy/2) Break;
704 if(y>1)if( get_bw(dx-1-dx/4,dx-1,0,y-2,sdata->bp,cs,1) == 1 ) Break;
707 if( num_cross(0, dx/2,y ,y ,sdata->bp,cs) == 1
708 && num_cross(dx/2,dx-1,y ,y ,sdata->bp,cs) == 0 ) Break; // ~p
710 if( num_cross(0,dx-1,dy/2-dy/8,dy/2-dy/8,sdata->bp,cs) == 2
711 && num_cross(0,dx-1,dy/2, dy/2 ,sdata->bp,cs) == 2 ) { // n rr
713 x =loop(sdata->bp,0,y,dx ,cs,0,RI); if(x> dx/4) Break; // search 1st v-line
714 x+=loop(sdata->bp,x,y,dx-x,cs,1,RI); if(x> dx/2) Break; i1=x; // 1st gap
715 x+=loop(sdata->bp,x,y,dx-x,cs,0,RI); if(x< dx/2) Break; i2=x; // 2nd v-line
716 x+=loop(sdata->bp,x,y,dx-x,cs,1,RI); if(x<3*dx/4) Break; i3=x; // 2nd gap
718 if( num_cross(dx/2,dx-1,y,y,sdata->bp,cs)==2 ) i=3*dy/8; // \it n
719 if (i<2 && i<dy/2) i++; // correct for small fonts like 8x12
720 // the same game for the lower part =>l1 l2 l3 l4 ???
721 for(x=i1;x<i2;x++) if( loop(sdata->bp,x, 0,dy,cs,0,DO)>=i ) break;
722 if(x <i2) Break; // gap detected
723 for(x=i1;x<i2;x++) if( loop(sdata->bp,x,dy-1,dy,cs,0,UP) >dy/4 ) break;
724 if(x==i2) Break; // no gap detected (glued serifs ??? )
725 // glued rm as nn ???
726 for(y=0,x=(i1+i2)/2;x<i2;x++){
727 i=loop(sdata->bp,x,0,dy,cs,0,DO);
728 i=loop(sdata->bp,x,i,dy,cs,1,DO); // measure thickness
729 if( i>y ) y=i; if( i<y/2 ) break;
731 if(x <i2) Break; // unusual property for n
733 if( loop(sdata->bp,dx-1,dy-1-dy/8,dx,cs,0,LE)
734 +loop(sdata->bp, 0,dy-1-dy/8,dx,cs,0,RI)-dx/8-1
735 > loop(sdata->bp,dx-1,dy-1-dy/2,dx,cs,0,LE)
736 +loop(sdata->bp, 0,dy-1-dy/2,dx,cs,0,RI) ) ad=90*ad/100; // broken o
738 if( loop(sdata->bp,dx-1, dy/2,dx,cs,0,LE)==0
739 && loop(sdata->bp,dx-1,dy-1-dy/8,dx,cs,0,RI)>dx/8 ) ad=98*ad/100; // broken o
740 } else { /* check handwritten n */
741 if( num_cross(0,dx-1,dy/2, dy/2 ,sdata->bp,cs) != 3
742 && num_cross(0,dx-1,dy/2-dy/8,dy/2-dy/8,sdata->bp,cs) != 3 ) Break;
743 i =loop(sdata->bp,0,dy/2-dy/8,dx,cs,0,RI); if (i>dx/4) Break;
744 i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,1,RI); if (i>dx/2) Break;
745 i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,0,RI);
746 if( num_cross(i,i, 0,dy/2-2*dy/8,sdata->bp,cs) != 0 ) Break;
747 i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,1,RI);
748 if( num_cross(i,i,dy/2+1, dy-1,sdata->bp,cs) != 0 ) Break;
752 i= loop(sdata->bp,dx-1 ,dy/2,dx,cs,0,LE); if(i>5)
753 if( get_bw(dx-1-i/2,dx-1-i/2,0,dy/2,sdata->bp,cs,1) == 1 ) Break; // ~rr
754 i+=loop(sdata->bp,dx-1-i,dy/2,dx,cs,1,LE);
755 if( get_bw(dx-1-i ,dx-1-i ,0,dy/2,sdata->bp,cs,1) == 0 ) Break; // ~rv
757 if( get_bw(dx/2,dx/2,dy/4,dy/4,sdata->bp,cs,1) == 0
758 && get_bw(dx/2,dx-1,dy-2,dy-2,sdata->bp,cs,1) == 0
759 && get_bw(dx/2,dx/2,dy/4,dy-2,sdata->bp,cs,1) == 1 ) Break; // ~P
762 if( box1->dots>0 && box1->m1 )
763 if( get_bw((x1+x0)/2,x1,box1->m1,y0-1,box1->p,cs,1) == 1 )
764 if( num_cross( 0,dx-1,0 ,0 ,sdata->bp,cs) >2
765 || num_cross( 0,dx-1,1 ,1 ,sdata->bp,cs) >2 ) Break;
768 i=loop(sdata->bp,dx-1, dy-1,dx,cs,0,LE); if (i>dx/2)
769 i=loop(sdata->bp,dx-1, dy-2,dx,cs,0,LE);
770 x=loop(sdata->bp,dx-1,dy-1-dy/4,dx,cs,0,LE);
771 if (sdata->hchar && i-x>1) Break; // ß
772 x=loop(sdata->bp, 0,dy-1,dx,cs,0,LE); // check for serifs
773 i=loop(sdata->bp, 0,dy-2,dx,cs,0,LE); if (i<x) x=i;
774 i=loop(sdata->bp, 0, 1,dx,cs,0,LE); if (i<x) x=i;
775 i=loop(sdata->bp, 0, 2,dx,cs,0,LE); if (i<x) x=i;
776 if (sdata->hchar && x>0) Break; // fl
778 if (num_cross( 0,dx-1,dy/4,dy/4,sdata->bp,cs)>=3) ad=98*ad/100; // small M
779 if (sdata->hchar || 2*y0<box1->m1+box1->m2) ad=96*ad/100;
780 if (sdata->gchar) ad=96*ad/100; // ß fl
781 if (dx<5) { // for small fonts no middle line is possible for m
782 ad=99*ad/100; // 4x6 m
783 if (num_cross(0,dx-1,dy/8,dy/8,sdata->bp,cs)>=2) {
785 if (dy<=4) Setac(box1,'m',97); // only for 4x6 font!
794 static wchar_t ocr0_M(ocr0_shared_t *sdata){
795 struct box *box1=sdata->box1;
797 int d,x,y,i0,i1,i2,i3,t1,hchar=sdata->hchar,gchar=sdata->gchar,
798 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
799 int dx=x1-x0+1,dy=y1-y0+1, /* size */
802 // ------------------ test M ---------------------------
803 for(ad=d=100;dx>3 && dy>3;){ // dy<=dx nicht perfekt! besser mittleres
805 DBG( wchar_t c_ask='M'; )
806 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
807 if( num_cross(0,dx-1, dy/2, dy/2,bp,cs)<3
808 && num_cross(0,dx-1, dy/4, dy/4,bp,cs)<3
809 && num_cross(0,dx-1,5*dy/8,5*dy/8,bp,cs)<3
810 && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)<3
812 if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)<2
813 && num_cross(0,dx-1, dy/8, dy/8,bp,cs)<2 ) Break; /* fat M */
814 if( num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)<2 ) Break;
816 x = loop(bp,dx-1 ,dy-1,dx,cs,0,LE); // ~ melted kl
817 x = loop(bp,dx-1-x,dy-1,dx,cs,1,LE); if( x>dx/2 ) Break;
819 if( loop(bp, 0,7*dy/16,dx,cs,0,RI)
820 + loop(bp,dx-1,7*dy/16,dx,cs,0,LE) > dx/2 ) Break; // ~K
822 if( dy>8 /* following lines should be extend to range check */
823 && loop(bp, dx/4,dy-1, dy,cs,0,UP)<dy/4
824 && loop(bp,3*dx/8,dy-1, dy,cs,0,UP)<dy/4 )
825 if( loop(bp, 0,dy-1-dy/ 8,dx,cs,0,RI)
826 < loop(bp, 0,dy-1-dy/16,dx,cs,0,RI)-dx/32 ) Break; // ~it_u
827 if( num_cross(0,dx-1, dy/2, dy/2,bp,cs)==2
828 && num_cross(0,dx-1, dy/4, dy/4,bp,cs)> 2
829 && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)> 2 ) Break; // ~it_u
830 if( num_cross(0 ,dx-1,3*dy/4,3*dy/4,bp,cs)==2
831 && num_cross(dx/2,dx/2,3*dy/4, dy-1,bp,cs)> 0 ) Break; // ~it_v
833 if( loop(bp,3*dx/4, 0,dy,cs,0,DO)
834 > loop(bp,2*dx/4, 0,dy,cs,0,DO)
835 && loop(bp,3*dx/4,dy-1,dy,cs,0,UP)
836 < loop(bp,2*dx/4,dy-1,dy,cs,0,UP) ) Break; // ~N
837 if( loop(bp,3*dx/4, dy/8,dy,cs,0,DO)
838 > loop(bp,2*dx/4, dy/8,dy,cs,0,DO)
839 && loop(bp,3*dx/4,dy-1-dy/8,dy,cs,0,UP)
840 < loop(bp,2*dx/4,dy-1-dy/8,dy,cs,0,UP) ) Break; // ~serif_N
842 // i0 is lower end of upper serifen (widest gap? )
845 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)!=4 ){ // Is it a N ?
846 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)==3 ){
847 for(y=dy/2+1;y<dy;y++){
848 if( num_cross(0,dx-1,y,y,bp,cs)<3 ) break;
850 if( num_cross(0,dx-1,y,y,bp,cs)==2 ){
851 x =loop(bp,dx-1 ,y-1,dx,cs,0,LE);
852 x+=loop(bp,dx-1-x,y-1,dx,cs,1,LE);
853 x+=loop(bp,dx-1-x,y-1,dx,cs,0,LE);
854 if( loop(bp,dx-x,y-1,dy,cs,0,UP)>y-2 ) Break; // ~N
859 for(i2=0,i1=x=dx/2;x<dx-dx/4;x++){ // lowest pixel
860 y=loop(bp,x,0,dy,cs,0,DO); if(y>i2) {i2=y;i1=x;} else break; }
861 i3=i2+loop(bp,i1,i2,dy-i2,cs,1,DO);
863 if (!sdata->hchar) Break; // rm
866 if (i2==0 && dx>8 && dy>12) Break; // glued and bad splitted serifen-MN
868 // if( num_hole(x0, x1, y0 , y1 ,box1->p,cs,NULL) != 0 ) Break; // small A
869 if (sdata->holes.num != 0) Break;
870 t1=loop(bp,0 ,3*dy/4,dx,cs,0,RI);
871 t1=loop(bp,t1,3*dy/4,dx,cs,1,RI); // thickness of line?
873 if( num_cross(i1,dx-1,i2-1,i2-1,bp,cs)!=2
874 || num_cross(0 ,i1 ,i2-1,i2-1,bp,cs)!=2 ) Break; // too hard ???
877 if( num_cross(0,dx-1,0,0,bp,cs)!=2
878 && num_cross(0,dx-1,1,1,bp,cs)!=2
879 && num_cross(0,dx-1,2,2,bp,cs)!=2 ) Break;
882 if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)==4
883 && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)==4 ){
884 i1 =loop(bp, 0, dy/4,dx,cs,0,RI);
885 i1+=loop(bp,i1, dy/4,dx,cs,1,RI);
886 i1+=loop(bp,i1, dy/4,dx,cs,0,RI);
887 i2 =loop(bp, 0,3*dy/4,dx,cs,0,RI);
888 i2+=loop(bp,i2,3*dy/4,dx,cs,1,RI);
889 i2+=loop(bp,i2,3*dy/4,dx,cs,0,RI);
890 if( i1>=i2 ) Break; // no good M
891 i1+=loop(bp,i1, dy/4,dx,cs,1,RI);
892 i2+=loop(bp,i2,3*dy/4,dx,cs,1,RI);
893 if( i1>=i2 ) Break; // no good M
894 i1+=loop(bp,i1, dy/4,dx,cs,0,RI);
895 i2+=loop(bp,i2,3*dy/4,dx,cs,0,RI);
896 if( i1<=i2 ) Break; // no good M
898 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)==2
899 && num_cross(0,dx-1,dy/4,dy/4,bp,cs)==2 && !hchar ) Break; // ~ \it u
902 if( num_cross(0,dx-1, 0, 0,bp,cs)<2 ) ad=99*ad/100;
903 if (dx>5) /* 4x6 font has only 1 cross at y=1 */
904 if( num_cross(0,dx-1, 1, 1,bp,cs)<2 ) ad=96*ad/100; // kt
905 if( num_cross(dx/2,dx/2, 0, dy-1,bp,cs)!=1) ad=98*ad/100; // kt
906 if (dx<5 && loop(bp,dx/2,0,dy,cs,0,DO)>=3*dy/8) ad=96*ad/100; // 4x6 H
908 if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)<=2
909 && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)<=2
912 for(y=5*dy/16;y<5*dy/8;y++) // look for H-line
913 if( num_cross(0,dx-1,y ,y ,bp,cs)==1 ) break;
914 if( y<5*dy/8 ) ad=95*ad/100;
916 if( num_cross(2+dx/6,dx-3-dx/6,y-2,y-2,bp,cs)==0
917 || num_cross(2+dx/6,dx-3-dx/6,y-1,y-1,bp,cs)==0 ) Break; // ~H bad!
920 if( loop(bp,3*dx/8, 0,dy,cs,0,DO) >dy/2
921 && loop(bp,5*dx/8,dy-1,dy,cs,0,UP) >dy/2 ) ad=95*ad/100;
924 ad=98*ad/100; /* not sure */
925 if( loop(bp,0, dy/4,dx,cs,0,RI)
926 < loop(bp,0,dy-1-dy/8,dx,cs,0,RI)-dx/16 ) Break; // ~wi glued
928 if( gchar ) ad=98*ad/100;
929 if (ad>99 && dx<8) ad=99*ad/100; /* give 5x8 N a chance */
936 static wchar_t ocr0_N(ocr0_shared_t *sdata){
937 struct box *box1=sdata->box1;
938 int d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
939 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
940 int dx=x1-x0+1,dy=y1-y0+1, /* size */
941 (*aa)[4]=sdata->aa, /* corner-points, (x,y,dist^2,vector_idx) */
945 // --- test N ------- +hchar -gchar
946 for(ad=d=100;dx>3 && dy>3;){ // 4x6font
947 DBG( wchar_t c_ask='N'; )
948 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
949 if (sdata->holes.num > 0) ad=98*ad/100; /* # */
950 if (dx<6) ad=99*ad/100;
951 if (dx<5) ad=99*ad/100;
952 /* half distance to the center */
954 /* now we check for the 4 ends of the x */
955 if (aa[0][2]>d) Break;
956 if (aa[1][2]>d) Break;
957 if (aa[2][2]>d) Break;
958 if (aa[3][2]>d) Break;
959 if (aa[3][0]-aa[0][0]<dx/2) Break;
960 if (aa[2][0]-aa[1][0]<dx/2) Break;
961 if (aa[1][1]-aa[0][1]<dy/2) Break;
962 if (aa[2][1]-aa[3][1]<dy/2) Break;
963 if (aa[3][0]-aa[0][0]<4-1) Break; /* to small to hold an N */
964 if (aa[2][0]-aa[1][0]<4-1) Break; /* to small */
965 if (abs(aa[3][1]-aa[0][1])>(dy+2)/5) Break; /* glued tu */
966 if (abs(aa[3][1]-aa[0][1])>(dy+4)/8) ad=98*ad/100; /* glued tu */
967 /* left and right vertical line */
968 d=line_deviation(box1, aa[0][3], aa[1][3]); if (d>2*sq(1024/4)) Break;
969 ad=(100-(d-sq(1024)/2)/sq(1024)/4)*ad/100;
970 d=line_deviation(box1, aa[2][3], aa[3][3]); if (d>2*sq(1024/4)) Break;
972 /* search uppermost left ^ (between near 0,0) */
973 i1=nearest_frame_vector(box1,aa[1][3],aa[2][3], x0+dx/8, y0);
974 x=box1->frame_vector[i1][0];
975 y=box1->frame_vector[i1][1];
976 MSG( fprintf(stderr,"i1= %d (%d,%d) left ^", i1,x-x0,y-y0);)
977 if (y-y0 > 5*dy/8) Break;
978 if (x-x0 > 5*dx/8) Break;
979 /* search uppermost right ^ ~H */
980 i3=nearest_frame_vector(box1,aa[1][3],aa[2][3], x1, y0);
981 MSG( fprintf(stderr,"i3= %d (%d,%d) right ^",\
982 i3, box1->frame_vector[i3][0]-x0,box1->frame_vector[i3][1]-y0);)
984 /* check if upper left and lower right point are joined directly */
985 dbg[0]=d=line_deviation(box1,i1, aa[2][3]);
986 /* check if lower left and lower left point are joined directly */
987 dbg[1]=d=line_deviation(box1, aa[1][3],i1);
988 MSG( fprintf(stderr," i1-a2 %d a1-i1 %d",dbg[0],dbg[1]); )
989 if (dbg[0] > sq(1024/4)) Break;
990 if (dx>4 && dbg[1] > sq(1024/4)) ad=97*ad/100; // d=0..2*sq(1024)
991 if (dx>4 && dbg[1] > sq(1024/3)) Break; // d=0..2*sq(1024)
992 // serif N has d=sq(1024/3)=116508
994 /* serach lowest right v, same frame? N-tilde etc.? */
995 i2=nearest_frame_vector(box1,aa[3][3],aa[0][3], x1, y1-dy/8);
996 x=box1->frame_vector[i2][0];
997 y=box1->frame_vector[i2][1];
998 MSG( fprintf(stderr,"i2= %d (%d,%d) right v",\
999 i2, box1->frame_vector[i2][0]-x0,box1->frame_vector[i2][1]-y0);)
1000 if (y-y0 < 3*dy/8) Break;
1001 if (x-x0 < 3*dx/8) Break;
1003 if ( box1->frame_vector[i3][0]-box1->frame_vector[i1][0]> dx/4
1004 && box1->frame_vector[i3][1]-box1->frame_vector[i1][1]<=dy/8
1005 && y<=box1->frame_vector[i1][1]) Break;
1006 /* check if upper left and lower right point are joined directly */
1007 dbg[2]=d=line_deviation(box1,i2, aa[0][3]);
1008 /* check if lower right and lower right point are joined directly */
1009 dbg[3]=d=line_deviation(box1, aa[3][3],i2);
1010 MSG( fprintf(stderr," i2-a0 %d a3-i2 %d",dbg[2],dbg[3]); )
1011 if (dbg[2] > sq(1024/4)) Break;
1012 if (dbg[3] > sq(1024/4)) ad=97*ad/100; // serif N, ToDo: do it better
1013 if (dbg[3] > sq(1024/3)) Break;
1015 if (abs((box1->frame_vector[i1][1]-y0)
1016 -(y1-box1->frame_vector[i2][1]))>dy/8) ad=99*ad/100; /* ~ tu */
1017 if (abs(((y0+y1)/2-box1->frame_vector[i1][1])
1018 -(box1->frame_vector[i2][1]-(y0+y1)/2))>dy/8) ad=99*ad/100; /* ~ tu */
1019 if (box1->frame_vector[i2][0]
1020 -box1->frame_vector[i1][0]<=dx/8) Break; /* nonsignificant distance */
1021 if (box1->frame_vector[i2][1]
1022 -box1->frame_vector[i1][1]<=dy/8) ad=97*ad/100; /* too flat (ff,H) */
1023 if (box1->frame_vector[i2][1]
1024 -box1->frame_vector[i1][1]<=dy/2) ad=99*ad/100;
1026 fprintf(stderr,"^v %d %d %d %d line deviation %d %d %d %d max %d %d",\
1027 box1->frame_vector[i1][0]-x0,box1->frame_vector[i1][1]-y0,\
1028 box1->frame_vector[i2][0]-x0,box1->frame_vector[i2][1]-y0,\
1029 dbg[0],dbg[1],dbg[2],dbg[3],sq(1024/4),sq(1024));)
1030 ad=(100-(dbg[0]-sq(1024)/2)/sq(1024)/4)*ad/100;
1031 ad=(100-(dbg[1]-sq(1024)/2)/sq(1024)/4)*ad/100;
1032 ad=(100-(dbg[2]-sq(1024)/2)/sq(1024)/4)*ad/100;
1033 ad=(100-(dbg[3]-sq(1024)/2)/sq(1024)/4)*ad/100;
1035 if (!hchar) ad=99*ad/100;
1036 if ( gchar) ad=98*ad/100; // \sc N
1043 static wchar_t ocr0_h(ocr0_shared_t *sdata){
1044 struct box *box1=sdata->box1;
1046 int i,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
1047 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1048 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1050 int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
1052 // --- test h ---------------------------------------------------
1053 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
1054 // rewritten for vectors 0.42
1055 int i1, i2, i3, i4, i5, i6, i7, i8; // line derivation + corners
1056 DBG( wchar_t c_ask='h'; )
1057 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1058 /* half distance to the center */
1060 /* now we check for the upper right end of the h */
1061 if (aa[3][2]<d/4) Break; /* [2] = distance, ~BCDEF... */
1062 if (aa[0][2]>d/2) Break; /* upper left end */
1063 if (aa[1][2]>d/2) Break; /* lower left end */
1064 if (aa[2][2]>d/2) Break; /* lowerright end */
1079 // check the bow from below
1080 for (i4=i=i2;i!=i5;i=(i+1)%box1->num_frame_vectors[0]) {
1081 if (box1->frame_vector[ i][1]
1082 <box1->frame_vector[i4][1]) i4=i; // get next maximum
1083 if (box1->frame_vector[ i][1]<=y0) break; // fatal!
1085 if (box1->frame_vector[i4][1]-y0<dy/4) Break; // ~MN
1086 if (y1-box1->frame_vector[i4][1]<dy/4) Break; // ~BCDEGIJLOQSUYZ
1087 // two steps for i7 to go around pitfalls on italic h
1088 i7=nearest_frame_vector(box1, i6, i8, (x0+x1)/2, (y0+y1)/2);
1089 i7=nearest_frame_vector(box1, i6, i7, x0, (y0+y1)/2);
1090 i3=nearest_frame_vector(box1, i2, i4, (x0+x1)/2, y1);
1091 i5=nearest_frame_vector(box1, i4, i6, (x0+x1)/2, y1);
1093 MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);)
1094 /* ... new part /// old obsolete part ... */
1095 if( get_bw(0 ,dx/2,dy/8 ,dy/8 ,bp,cs,1) != 1 ) Break;
1096 if( get_bw(0 ,dx/2,dy/2 ,dy/2 ,bp,cs,1) != 1 ) Break;
1097 if( get_bw(dx/2 ,dx-1,dy-1-dy/3,dy-1-dy/3,bp,cs,1) != 1 ) Break;
1098 if( get_bw(dx/2 ,dx/2,dy/5 ,dy-1-dy/3,bp,cs,1) != 1 ) Break;
1099 if( get_bw(dx-1-dx/3,dx-1,0 ,1 ,bp,cs,1) == 1 ) Break;
1100 if( get_bw(dx-1-dx/3,dx-1,1 ,dy/6 ,bp,cs,1) == 1 ) Break;
1102 if( get_bw(dx-1-dx/3,dx-1,dy/6 ,dy/5 ,bp,cs,1) == 1 ) Break;
1103 if( get_bw(dx-1-dx/3,dx-1,dy-1-dy/4,dy-1 ,bp,cs,1) == 0 ) Break; // s-
1104 for( x=x0+dx/3;x<x1-dx/3;x++)
1105 if( get_bw(x, x,y1-dy/4, y1, box1->p,cs,1) == 0 ) break;
1106 if( x>=x1-dx/3 ) Break;
1107 for(i=dy/4,y=y0+dy/3;y<=y1 && i;y++){
1108 if( num_cross(x0,x1 ,y,y, box1->p,cs) == 2 ) i--;
1110 for(i=dy/4,y=y0;y<=y0+dy/2 && i;y++){
1111 if( num_cross(x0,x0+dx/2,y,y, box1->p,cs) == 1 ) i--;
1113 // if( num_hole(x0, x1, y0 , y1 ,box1->p,cs,NULL) > 0 ) // could happen
1114 if (sdata->holes.num > 0)
1115 if (sdata->holes.hole[0].y0 > dy/3
1116 && sdata->holes.hole[0].y1 < dy-1-dy/3) Break;
1117 // if( num_hole(x0, x1, y0+dy/3 , y1-dy/3 ,box1->p,cs,NULL) != 1 ) Break; // mini
1118 if( loop(bp,dx-1,dy/3,dx,cs,0,LE)+dx/8
1119 < loop(bp,dx-1,dy/2,dx,cs,0,LE)
1120 && loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)+dx/8
1121 < loop(bp,dx-1,dy/2,dx,cs,0,LE)) Break; // ~k Okt00
1122 i=loop(bp,0,dy-1-dy/4,dx,cs,0,RI);
1123 if (i>1 && num_cross(x0,x0,y0+dy/8+2,y0+dy/2, box1->p,cs) == 1 ){ // fi fu
1124 ad=(99-(1<<i))*ad/100;
1125 if (num_cross(x0,x0,y0,y0+dy/8+2, box1->p,cs) == 0 ) ad=97*ad/100;
1126 if (num_cross(x0+dx/2,x0+dx/2,y0,y0+dy/8+2, box1->p,cs) == 1 ) ad=97*ad/100;
1129 i =loop(bp,0,dy/4,dx,cs,0,RI);
1130 i+=loop(bp,i,dy/4,dx,cs,1,RI)+1;
1131 for ( ; i<dx-dx/3; i++ )
1132 if( loop(bp,i,0,dy,cs,0,DO)>5*dy/8 ) {
1133 ad=98*ad/100; // melted hi, li, but handwritten h
1134 MSG(fprintf(stderr,"ad=%d",ad);) }
1135 if( num_cross(x0,x0,y0+(dy+3)/8,y1,box1->p,cs) > 1 ) {
1136 ad=98*ad/100; // melted fr
1137 MSG(fprintf(stderr,"ad=%d",ad);) }
1139 i=loop(bp,dx-1,3*dy/4,dx,cs,0,LE); // melted "fr" for vertikal letters
1140 if (i>dx/4 && loop(bp,dx-1-i,dy-1,dy,cs,1,UP)>dy/2) {
1141 ad=94*ad/100; MSG(fprintf(stderr,"ad=%d",ad);) }
1143 i=loop(bp,dx-1,1+dy/16,dx,cs,0,LE); if (i<dx/4) {
1145 MSG(fprintf(stderr,"ad=%d",ad);) }
1146 if( num_cross(dx-i+1+dx/8,dx-i+1+dx/8,0,1+dy/16,bp,cs) > 0 ) {
1147 ad=95*ad/100; // melted fi
1148 MSG(fprintf(stderr,"ad=%d",ad);) }
1149 if (loop(box1->p,x1,y0+1+dy/16,dx,cs,0,LE)<dx/4) {
1151 MSG(fprintf(stderr,"ad=%d",ad);) }
1152 if (loop(box1->p,x1,y0 ,dx,cs,0,LE)<dx/4
1153 || loop(box1->p,x1,y0+1,dx,cs,0,LE)<dx/4) {
1155 MSG(fprintf(stderr,"ad=%d",ad);) }
1158 if (sdata->holes.num > 0) ad=97*ad/100;
1160 if ( gchar) ad=98*ad/100;
1161 if (!hchar) ad=97*ad/100;
1162 } else ad=99*ad/100;
1169 static wchar_t ocr0_H(ocr0_shared_t *sdata){
1170 struct box *box1=sdata->box1;
1172 int i,j,j1,d,x,y,ya,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
1173 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1174 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1177 // --- test H ---------------------------------------------------
1178 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
1179 DBG( wchar_t c_ask='H'; )
1180 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1181 if( num_cross(0,dx-1,dy/4 ,dy/4 ,bp,cs) != 2
1182 && num_cross(0,dx-1,dy/4-1,dy/4-1,bp,cs) != 2 ) Break;
1183 if( num_cross(0,dx-1,3*dy/4 ,3*dy/4 ,bp,cs) != 2
1184 && num_cross(0,dx-1,3*dy/4+1,3*dy/4+1,bp,cs) != 2 ) Break;
1185 if( loop(bp,0 ,dy/8,dx,cs,0,RI)
1186 + loop(bp,dx-1,dy/8,dx,cs,0,LE)>dx/2 ) Break; // ~A
1187 for( j1=0,i=1,y=y0+dy/10; y<y1-dy/10 && i; y++ ) // 2 vertikal lines
1188 { j=loop(box1->p,x0 ,y,dx,cs,0,RI)
1189 +loop(box1->p,x1 ,y,dx,cs,0,LE); if( j>dx/2 ) i=0; if(j>j1)j1=j; }
1191 for( i=1,y=dy/4; y<dy-1-dy/4 && i; y++ ) // max - min width
1192 { j=loop(bp,0 ,y,dx,cs,0,RI)
1193 +loop(bp,dx-1,y,dx,cs,0,LE); if( j1-j>dx/5 ) i=0; }
1194 if( !i ) Break; // ~K Jul00
1195 for( i=0,ya=y=y0+dy/3; y<y1-dy/3; y++ ) // horizontal line
1196 { j=loop(box1->p,x0 ,y,dx,cs,0,RI);
1197 j=loop(box1->p,x0+j,y,dx,cs,1,RI); if( j>i ) { i=j; ya=y; } }
1198 if( i<=dx/2 ) Break; ya-=y0;
1199 if( num_cross(0,dx-1,ya ,ya ,bp,cs) != 1
1200 && num_cross(0,dx-1,ya+1,ya+1,bp,cs) != 1 ) Break; /* Dec00 */
1201 for( y=ya; y<dy-dy/4; y++ ) // ~M Dec00
1202 if( num_cross(0,dx-1,y ,y ,bp,cs) > 2
1203 && num_cross(0,dx-1,y+1,y+1,bp,cs) > 2 ) break;
1204 if ( y<dy-dy/4 ) Break;
1205 for(i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
1206 if( get_bw( x, x,y0 ,y0+dy/4,box1->p,cs,1) == 0 ) i=0;
1208 for(i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
1209 if( get_bw( x, x,y1-dy/4,y1 ,box1->p,cs,1) == 0 ) i=0;
1211 for(i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
1212 if( num_cross(x,x,y0+dy/8,y1-dy/8, box1->p,cs) == 1 ) i=0;
1214 for(i=1,y=y0;y<=y0+dy/4 && i;y++){
1215 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
1217 for(i=1,y=y1-dy/4;y<=y1 && i;y++){
1218 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
1220 if( get_bw(x1-dx/8, x1 , y0, y0+dy/8,box1->p,cs,1) != 1 ) Break;
1221 if( get_bw(x0 , x0+dx/8, y1-dy/8, y1,box1->p,cs,1) != 1 ) Break;
1222 i1=loop(bp,dx-1, dy/4,dx,cs,0,LE); if(i1>dx/2) Break;
1223 i2=loop(bp,dx-1, dy/2,dx,cs,0,LE); if(i2<i1-dx/4 || i2>i1+dx/8) Break;
1224 i3=loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE); if(i3<i2-dx/4 || i3>i2+dx/8) Break;
1225 if(abs(i1+i3-2*i2)>dx/16+1) Break;
1226 // test for thick tall N looking like a H
1227 if( num_cross(x0,x1,y0,y1, box1->p,cs) < 2 ) Break; // sure N
1228 i1=loop(bp, 0, dy/4,dx,cs,0,RI);
1229 i1=loop(bp, i1, dy/4,dx,cs,1,RI);
1230 i2=loop(bp, 0,dy-1-dy/4,dx,cs,0,RI);
1231 i2=loop(bp, i2,dy-1-dy/4,dx,cs,1,RI);
1232 i3=loop(bp,dx-1 ,dy-1-dy/4,dx,cs,0,LE);
1233 i3=loop(bp,dx-1-i3,dy-1-dy/4,dx,cs,1,LE);
1234 i =loop(bp, 0,dy/2+1+dy/8,dx,cs,0,RI);
1235 i+=loop(bp, i,dy/2+1+dy/8,dx,cs,1,RI);
1236 i =loop(bp, i,dy/2+1+dy/8,dx,cs,0,RI);
1237 if (i<dx/2-1 && 5*i1>6*i2 && 5*i3>6*i2 && i1>i2 && i3>i2 ) Break;
1239 if ( loop(bp,dx-1, 3*dy/8,dx,cs,0,LE)
1240 -loop(bp,dx-1, dy/8,dx,cs,0,LE)>dx/4
1241 && loop(bp,dx-1, 3*dy/8,dx,cs,0,LE)
1242 -loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)>dx/4 ) Break; // ~K
1243 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 0 ) Break;
1244 if (sdata->holes.num != 0) Break;
1245 if ( gchar) ad=99*ad/100;
1246 if (!hchar) ad=98*ad/100;
1253 static wchar_t ocr0_k(ocr0_shared_t *sdata){
1254 struct box *box1=sdata->box1;
1256 int i,j,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
1257 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1258 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1260 int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
1262 // --- test k ---------------------------------------------------
1263 for(ad=100;dx>2 && dy>3;){ // min 3x4
1264 // rewritten for vectors 0.43
1265 int d, i1, i2, i3, i4, i5, i6, i7, i8; // line derivation + corners
1266 DBG( wchar_t c_ask='k'; )
1267 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1268 /* half distance to the center */
1270 /* now we check for the upper right end of the h */
1271 if (aa[3][2]<d/4) Break; /* [2] = distance, ~BCDEF... */
1272 if (aa[0][2]>d/2) Break; /* upper left end */
1273 if (aa[1][2]>d/2) Break; /* lower left end */
1274 if (aa[2][2]>d/2) Break; /* lowerright end */
1289 // check the bow from below
1290 for (i4=i=i2;i!=i5;i=(i+1)%box1->num_frame_vectors[0]) {
1291 if (box1->frame_vector[ i][1]
1292 <box1->frame_vector[i4][1]) i4=i; // get next maximum
1293 if (box1->frame_vector[ i][1]<=y0) break; // fatal!
1295 if (box1->frame_vector[i4][1]-y0<dy/4) Break; // ~MN
1296 if (y1-box1->frame_vector[i4][1]<dy/4) Break; // ~BCDEGIJLOQSUYZ
1297 i6=nearest_frame_vector(box1, i5, i8, x1, (2*y0+y1)/3);
1298 // two steps for i7 to go around pitfalls on italic h
1299 i7=nearest_frame_vector(box1, i6, i8, x0, y1);
1300 i3=nearest_frame_vector(box1, i2, i4, (x0+x1)/2, y1);
1301 i =nearest_frame_vector(box1, i5, i6, x0, (y0+2*y1)/3);
1302 if (x1-box1->frame_vector[i][0]<dy/4) Break; // h
1303 if (x1-box1->frame_vector[i][0]<dy/2) ad=98*ad/100;
1305 MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);)
1306 if( num_cross(0, dx-1,0,0,bp,cs) != 1
1307 && num_cross(0, dx-1,1,1,bp,cs) != 1 ) Break;
1308 if( num_cross(0,3*dx/4, dy/8 , dy/8 ,bp,cs) != 1
1309 || num_cross(0,3*dx/4,3*dy/16,3*dy/16,bp,cs) != 1 ) Break;
1310 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs) != 2
1311 && num_cross(0,dx-1,dy-2,dy-2,bp,cs) != 2 ) Break;
1313 && num_cross(dx-1,dx-1,dy/4,dy-1,bp,cs) != 2
1314 && num_cross(dx-2,dx-2,dy/4,dy-1,bp,cs) != 2 ) Break;
1315 i1=loop(bp,0,dy/2-dy/4,dx,cs,0,RI);
1316 i2=loop(bp,0,dy/2 ,dx,cs,0,RI);if(i2>dx/2) Break;
1317 i3=loop(bp,0,dy/2+dy/4,dx,cs,0,RI);
1318 if(abs(i1+i3-2*i2)>dx/16+1 || i1<i3-1) Break; // v-line on left side?
1319 if( get_bw(x0 ,x0+dx/2,y0 ,y0+dy/4,box1->p,cs,1) != 1 ) Break;
1320 if( get_bw(x0+dx/2,x1, y1-dy/3,y1 ,box1->p,cs,1) != 1 ) Break;
1321 if( get_bw(x1-dx/4,x1, y0 ,y0+3*dy/16,box1->p,cs,1) == 1 ) Break;
1322 if( get_bw(x1-dx/4,x1, y0+dy/4,y1-dy/4,box1->p,cs,1) != 1 ) Break; //~1
1323 if( get_bw(x1-dx/4,x1, y1-dy/8,y1 ,box1->p,cs,1) != 1 ) Break;
1324 if (sdata->holes.num > 0)
1325 if (sdata->holes.hole[0].y0 > dy/4) Break;
1326 // if( num_hole(x0,x1,y0+dy/4,y1,box1->p,cs,NULL) != 0 ) Break;
1327 for(y=y0+1;y<y0+dy/2;y++) // luecke ???
1328 if( get_bw(x0,x1,y,y,box1->p,cs,1) == 0 ) break;
1329 if( y<y0+dy/2 ) Break;
1330 for(i=1,x=x0;x<=x0+dx/2 && i;x++)
1331 if(get_line(x,y0 ,x ,y1,box1->p,cs,100)>50) i=0;
1332 if( i ) Break; // no vertikal line!
1334 /* check for falling line in the lower left corner */
1335 for (j=x=0,y=5*dy/8;y<7*dy/8;y++) {
1336 i= loop(bp,dx-1,y,dx,cs,0,LE); if(i>x) { x=i;j=y; }
1337 } // x=dx/6 on fat k
1338 if (x + loop(bp,dx-1-x,y,dx,cs,1,LE)/2 <dx/4) Break;
1339 if (x + loop(bp,dx-1-x,y,dx,cs,1,LE)/2 <dx/2) ad=98*ad/100;
1341 i =loop(bp,dx-1,dy-1,dx,cs,0,LE); if(i>dx/2)
1342 i =loop(bp,dx-1,dy-2,dx,cs,0,LE); if(i>dx/2) Break;
1343 i+=loop(bp,dx-1-i,dy-1,dx,cs,1,LE)/2;
1344 if( get_line(x,y,dx-1-i,dy-1,bp,cs,100)<60 ) Break;
1346 for(y=y0+dy/3;y<y1;y++) if( num_cross(x0,x1,y,y,box1->p,cs)==2 ) break;
1349 // num_hole(x0,x1 ,y0 ,y1 ,box1->p,cs,NULL)>0 // ~A happens!
1350 sdata->holes.num > 0 )
1351 if (sdata->holes.hole[0].x1>dx-1-dx/4
1352 || sdata->holes.hole[0].y1>dy-1-dy/4
1353 || sdata->holes.hole[0].y0< dy/4) Break;
1354 // if ( num_hole(x0,x1-dx/4,y0+dy/4,y1-dy/4,box1->p,cs,NULL)==0 ) Break;
1355 i=loop(bp,0,dy-1,dx,cs,0,RI);
1356 i=loop(bp,i,dy-1,dx,cs,1,RI); if (dx>8 && 4*i>3*dx) Break; // ~glued_tz
1357 i =loop(bp,0,dy/4,dx,cs,0,RI);
1359 && i+loop(bp,i,dy/4,dx,cs,1,RI)>dx/2
1360 && loop(bp, 0,0,dx,cs,0,RI)<=dx/4
1361 && loop(bp,dx-1,0,dx,cs,0,LE)>=dx/2 ) ad=90*ad/100; // divided Q
1363 if( 2*y0>(box1->m1+box1->m2) ) ad=99*ad/100;
1365 if ( gchar) ad=98*ad/100;
1366 if (!hchar) ad=98*ad/100;
1373 static wchar_t ocr0_K(ocr0_shared_t *sdata){
1374 struct box *box1=sdata->box1;
1376 int i,j,i1,i2,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
1377 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1378 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1379 ad,ya,xa,yb,xb,yc,xc,yd,xd,ye,xe,yf,xf; /* tmp-vars */
1381 // --- test K ---------------------------------------------------
1382 for(ad=d=100;dx>2 && dy>3;){ // updated 29 Mar 2000 perfect???
1383 DBG( wchar_t c_ask='K'; )
1384 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1385 for(y=dy/8;y<dy-dy/8;y++)
1386 if( !get_bw(0,dx/2,y,y,bp,cs,1) ) break;
1387 if( y<dy-dy/8 ) Break;
1388 for(j=0,i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
1389 y= loop(box1->p,x,y0,y1-y0,cs,0,DO); if (y>3*dy/4) { i=1;break; }
1390 if (dy>15 && j>dy/8){
1391 j =loop(box1->p,x-1,y0+y-1,x1-x0,cs,0,LE)/2;
1392 y+=loop(box1->p,x-j,y0+y-1,y1-y0,cs,0,DO)-1;
1394 if(y>=dy/4) i=0; /* ok, found gap */
1396 for(y=0,x=x0+dx/4;x<=x1-dx/4;x++){ // lower h-gap
1397 i=loop(box1->p,x,y1,dy,cs,0,UP);
1398 /* on small chars bypass possible low left serifs */
1399 if (i>0) { i2=loop(box1->p,x-1,y1-i-1,dy,cs,0,UP);
1400 if (i2>1) i+=i2-1; }
1401 if (i>y) { y=i; i1=x; }
1402 } if( y<=dy/8 ) Break; if (y<dy/4) ad=80*ad/100;
1403 for(i=1,x=x0+dx/3;x<=x1-dx/8 && i;x++){
1404 if( num_cross(x,x,y0,y1, box1->p,cs) == 2 ) i=0;
1406 for(i=1,y=y0;y<=y0+dy/4 && i;y++){
1407 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
1410 for(i=1,y=y0+dy/3;y<=y1-dy/3 && i;y++){
1411 if( num_cross(x0,x1,y,y, box1->p,cs) == 1 ) i=0;
1414 for(i=1,y=y1-dy/4;y<=y1 && i;y++){
1415 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
1417 if( get_bw(x1-dx/3,x1,y0,y0+dy/8,box1->p,cs,1) != 1 ) Break; // ~k
1419 && loop(bp,0, dy/4,dx,cs,0,RI)
1420 +loop(bp,0,3*dy/4,dx,cs,0,RI)
1421 <2*loop(bp,0, dy/2,dx,cs,0,RI)-2-dx/32 ) Break; // ~X
1423 i=loop(box1->p,x1,y0+ dy/4,x1-x0+1,cs,0,LE); if(i>dx/2) Break;
1424 j=loop(box1->p,x1,y0+ dy/2,x1-x0+1,cs,0,LE);
1425 x=loop(box1->p,x1,y0+3*dy/8,x1-x0+1,cs,0,LE); if(x>j) j=x;
1426 if(j<=i ) Break; i=j;
1427 j=loop(box1->p,x1,y1-dy/4,x1-x0+1,cs,0,LE); if(j>=i ) Break;
1428 // out_x(box1); // detailed analysis
1430 // a d <= that are main points of K
1435 ya= dy/4;xa=loop(bp,0,ya,dx,cs,0,RI);xa+=loop(bp,xa,ya,dx,cs,1,RI)/2;
1436 yc=dy-dy/4;xc=loop(bp,0,yc,dx,cs,0,RI);xc+=loop(bp,xc,yc,dx,cs,1,RI)/2;
1437 yb=dy/2; xb=dx-1-loop(bp,dx-1,dy/2,dx,cs,0,LE);
1438 for(yd=ye=yf=xe=y=i=0,xf=xd=dx;y<dy/4;y++){ // range 0..1/4
1439 x =loop(bp,dx-1, y,dx,cs,0,LE); if(x<xd){ xd=x;yd= y; }
1440 x =loop(bp,dx-1,dy-1-y,dx,cs,0,LE); if(x<xf){ xf=x;yf=dy-1-y; }
1441 x =loop(bp,dx-1,dy/2+y,dx,cs,0,LE); if(x>xe){ xe=x;ye=dy/2+y; }
1442 x =loop(bp,dx-1,dy/2-y,dx,cs,0,LE); if(x>xe){ xe=x;ye=dy/2-y; }
1443 #if 0 // removed v0.2.4a2
1444 x =loop(bp,0 ,dy/2+y,dx,cs,0,RI); // middle left border
1445 x+=loop(bp,x ,dy/2+y,dx,cs,1,RI); // test 2nd cross
1446 x+=loop(bp,x ,dy/2+y,dx,cs,0,RI); if(x<xb){ xb=x;yb=dy/2+y; }
1448 x =loop(bp,0 ,dy/2-y,dx,cs,0,RI);
1449 x+=loop(bp,x ,dy/2-y,dx,cs,1,RI); // test 2nd cross
1450 x+=loop(bp,x ,dy/2-y,dx,cs,0,RI); if(x<xb){ xb=x;yb=dy/2-y; }
1451 x =dx-1-loop(bp,dx-1,dy/2-y,dx,cs,0,LE); if(x<xb){ xb=x;yb=dy/2-y; }
1453 xd=dx-1-xd;xe=dx-1-xe;xf=dx-1-xf;
1454 xb+=loop(bp,xb,yb,dx,cs,1,RI)/4; // detect center of line
1455 xe-=loop(bp,xe,ye,dx,cs,1,LE)/4;
1456 xd-=loop(bp,xd,yd,dx,cs,1,LE)/4;
1457 xf-=loop(bp,xf,yf,dx,cs,1,LE)/4;
1460 printf("a=%d %d b=%d %d c=%d %d d=%d %d e=%d %d f=%d %d dxdy %d %d",\
1461 xa,ya,xb,yb,xc,yc,xd,yd,xe,ye,xf,yf,dx,dy);\
1464 if( get_line2(xa,ya,xc,yc,bp,cs,100)<95 ) Break;
1465 if( dx>8 ){ // example szaka0103
1466 if( xe>5*dx/8 || xb>5*dx/8 ) Break; // ~{\it n}
1467 i=loop(bp,xb,yb,xb,cs,1,LE); // thick center? see font22
1468 if( get_line2(xb,yb,xd,yd,bp,cs,100)<95 ) // right up
1469 if( get_line2(xb-i/2,yb,xd,yd,bp,cs,100)<95 ) Break;
1470 if( get_line2(xe,ye,xf,yf,bp,cs,100)<95 ) Break; // right down
1471 xe+=loop(bp,xe,ye,dx,cs,1,RI); if( xe>=xf ) Break; // ~{\it n}
1473 if( dy<16 && !hchar ) Break;
1474 if( loop(bp,0,1,dy,cs,1,DO)<=3*dx/4
1475 && loop(bp,1,1,dy,cs,1,DO)<=3*dx/4
1476 && loop(bp,2,1,dy,cs,1,DO)<=3*dx/4 ) Break; // ~x
1478 if (loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE)<=dx/8){
1479 ad=99*ad/100; /* broken B ? */
1480 if (sdata->holes.num > 0)
1481 if (sdata->holes.hole[0].y1 < dy-1-dy/3) Break;
1482 // if( num_hole(x0,x1,y0,(y0+2*y1)/3,box1->p,cs,NULL)>0) Break; // broken B
1484 if(box1->m3 && !hchar) ad=99*ad/100;
1485 if(box1->m3 && gchar) ad=99*ad/100;
1486 // printf(" ok xe=%d",xe);
1493 static wchar_t ocr0_f(ocr0_shared_t *sdata){
1494 struct box *box1=sdata->box1;
1496 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
1497 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1498 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1499 (*aa)[4]=sdata->aa, /* the for line ends, (x,y,dist^2,vector_idx) */
1500 ab[8][4], /* special points (x,y,dist^2,vector_idx) */
1502 /* x=mindist_to_a y=0 "t"
1503 0>..$$. 0>..$$ 0>..$$ end right bow a--..$$ a--.$7. y>0 "f"
1504 1>.$..$ 1>.$.. 1>.$$$ start right bow .$7. .$..
1505 .@... .@.. 2>.@@. start upper end .@.. .@..
1506 2>.$... 2>.$.. 3>$$$$ crossing bar .$.. $$$.
1507 3>$@$$. 3>$@$. $@@$ $@$. .@..
1508 4>.$... 4>.$.. 4>.$$. lower end .$.. .$..
1509 .@... .@.. .@@. .@.. .@..
1510 .@... .@.. .@@. .@.. .@..
1511 5>.$... 5>.$.. 5>.$$. lower start .$.. .$..
1512 6>..... 6>$... 6>.... optional left bow
1514 // --- test f like t ---------------------------------------------------
1515 for(ad=d=100;dx>2 && dy>5;){ // sometimes no hchar!
1516 // rewritten for vectors 0.43
1517 int d, i1, i2, i3, i4, i5, i6, i7, i8, i9; // line derivation + corners
1518 DBG( wchar_t c_ask='f'; )
1519 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1520 /* half distance to the center */
1522 /* now we check for the upper right end of the h */
1523 if (aa[3][2]>d/2) Break; /* [2] = distance, ~BCDEF... */
1524 if (aa[0][2]>d ) Break; /* upper left end */
1536 i1=nearest_frame_vector(box1,aa[0][3],aa[1][3],x0-dx/2,(5*y0+3*y1)/8);
1537 /* we need i for 4x6 font, where left side of h-bar is near (x0,y1) */
1538 i =aa[1][3]; if (box1->frame_vector[i][1]<y1-dy/8)
1539 i =nearest_frame_vector(box1,aa[1][3],aa[2][3], x0, y1+dy/4);
1540 i2=nearest_frame_vector(box1, i1, i, x1, y1);
1541 i =nearest_frame_vector(box1,aa[1][3],aa[2][3], x1, y1+dy/4);
1542 i3=nearest_frame_vector(box1, i,aa[3][3], x0, y1);
1543 i7=nearest_frame_vector(box1, i3,aa[3][3],(x0+x1)/2, y0);
1544 i8=nearest_frame_vector(box1, i7,aa[0][3], x1, (3*y0+y1)/4);
1545 i9=nearest_frame_vector(box1,aa[3][3],aa[0][3],(x0+2*x1)/3,y0-dy/4);
1546 i5=nearest_frame_vector(box1, i3, i7, x1+dx/4, (5*y0+3*y1)/8);
1547 i4=nearest_frame_vector(box1, i3, i5, x0, (3*y0+y1)/4);
1548 i6=nearest_frame_vector(box1, i5, i7, x0, (y0+3*y1)/4);
1550 MSG(fprintf(stderr,"i1-9 %d %d %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7,i8,i9);)
1552 // check if vertical line is near to the left side
1553 if (box1->frame_vector[i2][0]-x0>dx/2) Break; // ~3
1554 i =nearest_frame_vector(box1, aa[0][3], i2, x1+2*dx, (y0+y1)/2);
1555 // MSG(fprintf(stderr,"i %d",i);)
1556 if (box1->frame_vector[i ][0]
1557 -box1->frame_vector[i9][0]>dx/8) Break; // ~3
1559 if( (box1->dots) ) Break; // Bold-face is gchar
1560 if (dy<=box1->m3-box1->m2+1) Break;
1561 for(x=0,j=y=2+(3*dy+4)/32;y<=5*dy/8;y++){ // upper cross line min=2
1562 i=loop(bp,0,y,dx,cs,0,RI); if( y>dy/4 && i>5*dx/8 ) break;
1563 i=loop(bp,i,y,dx,cs,1,RI); if( i>x ) { x=i;j=y; }
1564 if( y<3*dy/4 && y>dy/4
1565 && num_cross(0,dx-1,y ,y ,bp,cs) != 1
1566 && num_cross(0,dx-1,y+1,y+1,bp,cs) != 1 // against noise
1568 } if( y<=5*dy/8 ) Break; y=j;// if( y>dy/2 || y<dy/8 ) Break;
1569 // x is thickest width of vertical line here
1570 i=loop(bp,(dx+1)/2,0,dy,cs,0,DO)/2;
1572 && num_cross( 0, (dx+1)/2,i,i,bp,cs) > 0
1573 && num_cross((dx+1)/2,dx-1,i,i,bp,cs) > 0 ) Break; // ~Y
1575 if (loop(bp,3*dx/4, 0,dy,cs,0,DO)>dy/8
1576 && loop(bp,3*dx/4-1,0,dy,cs,0,DO)>dy/8) Break; // upper bow
1577 i=3*dy/4; if (box1->m3 && i>=box1->m3) i=box1->m3-1;
1578 if (num_cross(0,dx-1,i,i,bp,cs)!=1) Break;
1580 // the middle bar appear in a wide vertical range, get part below
1581 for (i1=dx,i2=y,j=y+1;j<dy-dy/4;j++){
1582 i=loop(bp,0,j,dx,cs,0,RI);
1583 i=loop(bp,i,j,dx,cs,1,RI); // thickness vert. line
1584 if (i<i1) { i1=i; i2=j; if (2*i<=x) break; }
1585 } i=i1; j=i2; /* i=dx, j=y below horiz-bar */
1586 MSG(fprintf(stderr,"j=%d i=%d y=%d x=%d",j,i,y,x);)
1587 // bar should have twice of the thickness of v-line
1588 if (x<2*i && x<dx) Break;
1589 if (x<i+2+dx/8) ad=97*ad/100; // fat f
1591 // check for the upper bow to the right top side
1592 i3=nearest_frame_vector(box1,aa[2][3],aa[3][3], x0, y0);
1593 MSG(fprintf(stderr,"xy= %d %d %d %d",x0,y0,\
1594 box1->frame_vector[i3][0]-x0,box1->frame_vector[i3][1]-y0);)
1595 ab[7][0]=box1->frame_vector[i3][0];
1596 ab[7][1]=box1->frame_vector[i3][1];
1598 if (ab[7][1]-y0<=dy/16) ad=95*ad/100; // ~t
1599 // because of the dx,dy scaling the horiz. bar could be nearer to (x1,y0)
1600 // as the upper right end of the "t"
1601 if (aa[3][0]-x0>3*dx/4 && aa[3][1]-y0>3*dy/16) ad=99*ad/100; // ~t
1604 j=loop(bp,0,dy/8,dx,cs,0,RI); // if j>dx/2 we have italic f
1605 if ((2*x<dx && j<=dx/2) || 3*x<dx) Break; // bar should be not to small
1606 for(i=dy/8;i<dy;i++)
1607 if (loop(bp,0,i,dx,cs,0,RI)>(j+dx/4)) break;
1608 if (i<dy) Break; // check for v-line
1610 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)<dx/2 )
1611 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)-1
1612 <=loop(bp,dx-1, y ,dx,cs,0,LE) )
1613 if( loop(bp,dx-1, y-1,dx,cs,0,LE)
1614 <=loop(bp,dx-1, y ,dx,cs,0,LE) ) Break; // ~1
1616 if( loop(bp,0,dy/2,dx,cs,0,RI)-1
1617 >loop(bp,0, 1,dx,cs,0,RI) ) Break; // ~X
1619 i=y;j=1; // j used as flag
1620 if( num_cross(0,dx-1,0,0,bp,cs)==1 && hchar) //~r
1621 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs)!=1
1622 && num_cross(0,dx-1,dy-2,dy-2,bp,cs)!=1 ) Break; // ~* etc.
1623 // check for upper bow to right
1624 for(y=1;j && y<i; y++) // no @@ pattern
1625 if( num_cross(0,dx-1,y ,y ,bp,cs) ==2 ) j=0;
1626 if (j==0) { ad=(ad+101)/2; }
1627 for(y=1;j && y<i; y++) // no @@ pattern, try to detect it
1628 for(x=0;j && x<dx ;x++){ // ..
1629 if( (getpixel(bp,x ,y )>=cs || dx<7) && getpixel(bp,x+1,y )>=cs
1630 && getpixel(bp,x ,y-1)< cs && getpixel(bp,x+1,y-1)< cs )
1632 } if(j) ad=98*ad/100; // not detected
1634 // if( num_hole (x0 , x1 , y0, y1,box1->p,cs,NULL) != 0 ) Break; // ~e
1635 if (sdata->holes.num != 0) Break; // ~e
1636 for(i1=i2=dx,y=7*dy/8;y<dy;y++){
1637 x=loop(bp,0 ,y,dx,cs,0,RI);if(x<i1)i1=x;
1638 x=loop(bp,dx-1,y,dx,cs,0,LE);if(x<i2)i2=x;
1640 if(i1>i2+dx/4) Break; // ~t ~e
1641 if(i1>i2+1) ad=96*ad/100; // ~t ~e
1642 if( loop(bp,0,3*dy/4,dx,cs,0,RI)<i1-dx/4 ) Break;
1644 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)>3*dx/4 )
1645 if( loop(bp,dx-1,dy-1,dy,cs,0,UP)<dx/2 ) Break; // ~c
1647 if( loop(bp, 0,2*dy/3 ,dx,cs,0,RI)>2*dx/3
1648 || loop(bp, 0,2*dy/3-1,dx,cs,0,RI)>2*dx/3 )
1649 if( loop(bp,dx-1, dy/4 ,dx,cs,0,LE)>2*dx/3 ) Break; // ~5 ~S
1652 if ( get_bw(x0+dx/8,x0+dx/8,y0+dy/4,y1-dy/16,box1->p,cs,2) == 0
1653 && num_cross(x1-dx/4,x1-dx/4,y0,y1,box1->p,cs)!=2
1654 && num_cross(x1-dx/8,x1-dx/8,y0,y1,box1->p,cs)!=2 ) Break; // ~r
1657 if( num_cross(x0,x1,y1-dy/4,y1-dy/4,box1->p,cs)>1
1658 && num_cross(x0,x1,y0+dy/4,y0+dy/4,box1->p,cs)>1 ) Break; // ~H
1661 if( loop(bp,dx-1 ,3*dy/4,dx,cs,0,LE)-
1662 loop(bp,0 ,3*dy/4,dx,cs,0,RI)>dx/5+1
1663 && loop(bp,dx-1-dx/8,dy-1 ,dy,cs,0,UP)<dy/4 ) {
1664 if( loop(bp,dx-1 ,5*dy/16,dx,cs,0,LE)-
1665 loop(bp,0 ,5*dy/16,dx,cs,0,RI)>=dx/5+1) ad=98*ad/100; // ~E
1666 i=loop(bp,dx/8,0,dy,cs,0,DO);
1667 if (i<dy/8 || i>dy/2) {
1668 ad=98*ad/100; // ~E, could also be a "f" with big serifs
1669 MSG(fprintf(stderr,"ad=%d",ad);) }
1670 if (!gchar) { ad=98*ad/100;
1671 MSG(fprintf(stderr,"ad=%d",ad);) }
1673 i = loop(bp,dx-1 ,3*dy/4,dx ,cs,0,LE)/2;
1674 if (loop(bp,dx-1-i , dy-1,dy/2,cs,0,UP)<dy/4)
1675 if (loop(bp,0 ,3*dy/4,dx ,cs,0,RI)<dx/4) {
1676 ad=98*ad/100; // ~E but serif-f
1677 MSG(fprintf(stderr,"ad=%d",ad);) }
1679 if( loop(bp,0,dy/4,dx ,cs,0,RI)>1
1680 && loop(bp,0, 0,dy/4,cs,0,DO)<dy/4 ) {
1682 MSG(fprintf(stderr,"ad=%d",ad);) }
1684 if (get_bw(x0+dx/16,x1-dx/16,y0,y0,box1->p,cs,2) == 0) { // white pixels?
1686 MSG(fprintf(stderr,"ad=%d",ad);) }
1688 if (!hchar) ad=ad*98/100; // d*=100;d/=128 // not 100% !
1689 if (box1->m4>0 && gchar && ad<99 &&
1690 8*box1->y1 >= box1->m4*7+box1->m3) ad++;
1697 static wchar_t ocr0_bB(ocr0_shared_t *sdata){
1698 struct box *box1=sdata->box1;
1700 int i,j,d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
1701 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1702 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1705 // --- test B ---------------------------------------------------
1706 for(ad=d=100;dx>2 && dy>4;){ // min 3x4
1707 DBG( wchar_t c_ask='B'; )
1708 if (sdata->holes.num < 2) Break; /* tolerant against a tiny hole */
1709 for(i=1,y=y0;y<y1-dy/2 && i;y++)
1710 if( get_bw(x0,x0+dx/2, y , y ,box1->p,cs,1) != 1 ) i=0;
1712 for(i=1,y=y1-dy/2;y<y1 && i;y++)
1713 if( get_bw(x0,x0+dx/3, y , y ,box1->p,cs,1) != 1 ) i=0;
1715 if( get_bw(x1,x1 , y0 , y0 ,box1->p,cs,1) == 1 ) Break;
1716 if( num_cross(x0+dx/2, x0+dx/2,y0,y1 ,box1->p,cs) != 3 )
1717 if( num_cross(x1-dx/3, x1-dx/3,y0,y1 ,box1->p,cs) != 3 ) Break;
1718 /* --- detect center of lower hole --- */
1719 y = loop(box1->p,x0+dx/2,y1 ,dy,cs,0,UP); if (y>1+dy/8) Break;
1720 y+= loop(box1->p,x0+dx/2,y1-y,dy,cs,1,UP); if (y>dy/3) Break;
1721 y=y1-y-loop(box1->p,x0+dx/2,y1-y,dy,cs,0,UP)/2; if (y<y0+3*dy/8) Break;
1722 if (y<y0+dy/2) ad=96*ad/100;
1723 if( num_cross(0,dx-1,y-y0 ,y-y0 ,bp,cs) != 2 )
1724 if( num_cross(0,dx-1,y-y0+1,y-y0+1,bp,cs) != 2 ) Break;
1725 if( num_cross(0,dx-1, dy/4 , dy/4 ,bp,cs) != 2 )
1726 if( num_cross(0,dx-1, dy/4+1, dy/4+1,bp,cs) != 2 )
1727 if( num_cross(0,dx-1, dy/4-1, dy/4-1,bp,cs) != 2 ) Break;
1728 for( y=dy/4;y<3*dy/4;y++ ) if( num_cross(0,dx-1,y,y,bp,cs)==1 ) break;
1729 if( y==3*dy/4 ) Break;
1731 if( loop(box1->p,x0,y0+ y ,dx,cs,0,RI)
1732 > loop(box1->p,x0,y0+dy/4,dx,cs,0,RI)+dx/32 )
1733 if( get_bw(x0,x0,y0,y0,box1->p,cs,1) == 0 )
1734 if( get_bw(x0,x0,y1,y1,box1->p,cs,1) == 0 ) Break; // ~8
1735 i1=loop(box1->p,x0,y0+dy/4,dx,cs,0,RI);
1736 i2=loop(box1->p,x0,y0+dy/2,dx,cs,0,RI);
1737 i =loop(box1->p,x0,y0+dy/2-dy/ 8,dx,cs,0,RI); if(i>i2) i2=i;
1738 i =loop(box1->p,x0,y0+dy/2-dy/16,dx,cs,0,RI); if(i>i2) i2=i;
1739 i3=loop(box1->p,x0,y1-dy/4,dx,cs,0,RI);
1740 if(dy>16 && i3<i2 && i1+i3<2*i2){
1741 if (i3+i1<2*i2-dx/16) ad=98*ad/100; // ~8
1742 if (i3+i1<2*i2-dx/8 ) ad=96*ad/100;
1743 if( loop(box1->p,x0,y0+ 1 ,dx,cs,0,RI)
1744 >= loop(box1->p,x0,y0+ 3 ,dx,cs,0,RI)+dx/32 )
1745 if( loop(box1->p,x0,y0+ 0 ,dx,cs,0,RI)
1746 > loop(box1->p,x0,y0+ 3 ,dx,cs,0,RI)+dx/32 )
1747 if( loop(box1->p,x0,y1- 0 ,dx,cs,0,RI)
1748 > loop(box1->p,x0,y1- 3 ,dx,cs,0,RI)+dx/32 )
1749 if( loop(box1->p,x0,y1- 1 ,dx,cs,0,RI)
1750 > loop(box1->p,x0,y1- 3 ,dx,cs,0,RI)+dx/32 ) Break; // ~8 Aug00
1753 if (sdata->holes.num != 2) Break;
1754 if (sdata->holes.hole[0].y0 < y-1
1755 && sdata->holes.hole[1].y0 < y-1 ) Break;
1756 if (sdata->holes.hole[0].y1 > y+1
1757 && sdata->holes.hole[1].y1 > y+1 ) Break;
1758 // if( num_hole(0,dx-1,0 ,y+1 ,bp,cs,NULL) != 1 ) Break;
1759 // if( num_hole(0,dx-1,y-1,dy-1,bp,cs,NULL) != 1 ) Break;
1762 for( x=dx,y=dy/6; y<dy-dy/8; y++ ) // left border straight
1763 { i=loop(box1->p,x0,y0+y,dx,cs,0,RI); if( i>x+dx/9 ) break;
1765 } if( y<dy-dy/8 ) Break; // ~8 bad_a
1767 for( x=dx,y=1;y<dy/4;y++ ) // right border straight
1768 { i=loop(bp,dx-1,dy-y,dx,cs,0,LE);
1769 if( i<x ) x=i; else if( i>x )break;
1770 } if( y<dy/4 ) Break; // ~ff (serifen?)
1772 x=loop(bp,0,dy/2 ,dx,cs,0,RI);
1773 i=loop(bp,0,dy/2-1,dx,cs,0,RI); if (i>x) x=i; // allow dust
1774 i=loop(bp,0,dy/2+1,dx,cs,0,RI); if (i>x) x=i;
1775 if ( loop(bp,0, dy/8,dx,cs,0,RI)
1776 +loop(bp,0,7*dy/8,dx,cs,0,RI) > 2*x+1 ) Break; // not konvex!
1778 if(!hchar){ // ~ fat_a
1780 x =loop(bp,0,dy/4,dx,cs,0,RI);
1781 if(loop(bp,0,dy/2,dx,cs,0,RI)>x+dx/8) ad=97*ad/100;
1784 if ( (!hchar) && (dx<=10 || dy<=10) ) ad=97*ad/100; // hchar or good_quality
1785 if (gchar) ad=99*ad/100;
1789 // --- test b ---------------------------------------------------
1790 for(ad=d=100;dx>3 && dy>4;){ // min 3x4
1791 DBG( wchar_t c_ask='b'; )
1792 if (sdata->holes.num < 1) Break; /* tolerant against a tiny hole */
1794 if( get_bw(x0 , x0+dx/2, y , y ,box1->p,cs,1) != 1 ) Break;
1795 if(y<y1-dy/32-1) Break;
1796 if( get_bw(x0+ dx/2, x0+dx/2, y1-dy/3, y1 ,box1->p,cs,1) != 1 ) Break;
1797 if( get_bw(x1- dx/2, x1 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
1798 if( get_bw(x1- dx/3, x1 , y0 , y0+dy/5,box1->p,cs,1) == 1 ) Break;
1799 if( get_bw(x1-4*dx/9, x1 , y0+dy/5, y0+dy/5,box1->p,cs,1) == 1 ) Break;
1800 if( num_cross(x0,x1,y0+dy/4 ,y0+dy/4 ,box1->p,cs) > 1 ) // &
1801 if( num_cross(x0,x1,y0+dy/4-1,y0+dy/4-1,box1->p,cs) > 1 )
1803 num_cross(x0,x1,y0+dy/5 ,y0+dy/5 ,box1->p,cs) > 1 ) Break; // fat b
1804 for(i=j=0,y=dy/2;y<dy-dy/8;y++)
1805 if( num_cross(0,dx-1,y,y,bp,cs) == 2 ) i++; else j++;
1806 if( i<2*j ) Break; // v024a4
1807 if (sdata->holes.num != 1) Break;
1808 if (sdata->holes.hole[0].y0 < dy/4) Break;
1809 if ((sdata->holes.hole[0].y1-sdata->holes.hole[0].y0+1)
1810 *(sdata->holes.hole[0].x1-sdata->holes.hole[0].x0+1)*16
1811 < dx*dy) ad=90*ad/100; // hole to small
1812 if( num_hole( x0, x1 , y0+dy/4, y1,box1->p,cs,NULL) != 1 ) Break;
1813 i=loop(bp,dx-1,dy-1 ,dx,cs,0,LE);
1814 j=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE); if(j>i) Break;
1815 if (!hchar) ad=99*ad/100;
1816 if ( gchar) ad=99*ad/100;
1818 if (ad>=100) return 'b';
1824 static wchar_t ocr0_dD(ocr0_shared_t *sdata){
1825 struct box *box1=sdata->box1;
1827 int i,d,x,y,ya,yb,hchar=sdata->hchar,gchar=sdata->gchar,
1828 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1829 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1832 // --- test D ---------------------------------------------------
1833 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
1834 DBG( wchar_t c_ask='D'; )
1835 if (sdata->holes.num < 1) Break; /* tolerant against a tiny hole */
1836 if( get_bw(x0 ,x0+dx/3,y0+dy/2,y0+dy/2,box1->p,cs,1) != 1 ) Break;
1837 if( get_bw(x1-dx/3,x1 ,y0+dy/2,y0+dy/2,box1->p,cs,1) != 1 ) Break;
1838 if( get_bw(x1 ,x1 ,y0 ,y0+dy/16,box1->p,cs,1) == 1 ) Break;
1839 if( get_bw(x1-dx/2,x1 ,y0+dy/4,y0+dy/4 ,box1->p,cs,1) != 1 ) Break;
1840 if( num_cross(x0+dx/2,x0+dx/2,y0 ,y1 ,box1->p,cs) != 2 )
1841 if( num_cross(x1-dx/3,x1-dx/3,y0 ,y1 ,box1->p,cs) != 2 ) Break;
1842 if( num_cross(x0 ,x1 ,y0+dy/3,y0+dy/3,box1->p,cs) != 2 ) Break;
1843 if( num_cross(x0 ,x1 ,y1-dy/3,y1-dy/3,box1->p,cs) != 2 ) Break;
1844 if (sdata->holes.num != 1) Break;
1845 if (sdata->holes.hole[0].y0 > dy/3) Break;
1846 if (sdata->holes.hole[0].y1 < dy-1-dy/3) Break;
1847 // if( num_hole (x0 ,x1 ,y0 ,y1 ,box1->p,cs,NULL) != 1 ) Break;
1848 // test if left edge is straight
1849 for(x=0,y=bp->y-1-dy/8;y>=dy/5;y--){
1850 i=loop(bp,0,y,x1-x0,cs,0,RI);
1851 if( i+2+dx/16<=x ) break;
1854 if (y>=dy/5 ) Break;
1855 /* test if right edge is falling */
1856 for(x=dx,y=0;y<dy/3;y++){
1857 i=loop(bp,bp->x-1,y,x1-x0,cs,0,LE);
1858 if( i>x+dx/16 ) break;
1862 /* test if right edge is raising */
1863 for(x=dx,y=bp->y-1;y>2*dy/3;y--){
1864 i=loop(bp,bp->x-1,y,x1-x0,cs,0,LE);
1865 if( i>x+dx/16 ) break;
1868 if (y>2*dy/3 ) Break;
1869 if( loop(bp,dx-1,dy-1 ,dx,cs,0,LE) <=
1870 loop(bp,dx-1,dy-2-dy/16,dx,cs,0,LE) ) Break; // P
1872 y=loop(bp,dx/2,dy-1,dy,cs,0,UP)-1; if (dy>16) y/=2;
1873 if ( y>=dy/16 ) { y-=dy/16;
1874 if (get_bw(dx/2,dx-1,dy-1-y,dy-1-y,bp,cs,1)==1) Break; // ~A
1877 ya=loop(bp, 0,dy-1,dy,cs,0,UP);
1878 yb=loop(bp,dx/16+1,dy-1,dy,cs,0,UP);
1879 if( ya<dy/2 && ya>dy/16 && ya>yb ) Break; // ~O
1881 if ( loop(bp, dx/2, 0,dy,cs,0,DO)
1882 -loop(bp, dx/2,dy-1,dy,cs,0,UP) > dy/8 ) ad=97*ad/100; // ~b
1886 if (loop(bp, 0, 0,dx,cs,0,RI)>=dx/2
1887 && loop(bp,dx-1,dy-1,dx,cs,0,LE)>=dx/2
1888 && loop(bp, 0,dy/2,dx,cs,0,RI)< 2 ) ad=96*ad/100; // thin O
1890 if(box1->dots) ad=ad*94/100;
1891 if ( gchar) ad=99*ad/100;
1892 if (!hchar) ad=99*ad/100;
1896 // --- test d ---------------------------------------------------
1897 for(d=100;dx>2 && dy>3;){ // min 3x4
1898 DBG( wchar_t c_ask='d'; )
1900 if (sdata->holes.num < 1) Break; /* tolerant against a tiny hole */
1901 if( get_bw(x0 , x0+dx/2, y1-dy/6, y1-dy/9,box1->p,cs,1) != 1 ) Break;
1902 if( get_bw(x0 , x0+dx/2, y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
1903 if( get_bw(x0+dx/2, x1 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
1904 if( get_bw(x1-dx/4, x1 , y0+dy/8, y0+dy/8,box1->p,cs,1) != 1 ) Break;
1905 if( get_bw(x0+dx/2, x0+dx/2, y1-dy/4, y1 ,box1->p,cs,1) != 1 ) Break;
1907 if( get_bw(x0 , x0+dx/3, y0 , y0+dy/5,box1->p,cs,1) == 1 ) Break;
1908 if( get_bw(x0 , x0+dx/3, y0 , y0+dy/6,box1->p,cs,1) == 1 ) Break;
1909 if( get_bw(x0 , x0+dx/4, y1-dy/8, y1 ,box1->p,cs,1) != 1 ) Break;
1910 if( get_bw(x0+dx/2-1,x0+dx/2,y1-dy/8, y1 ,box1->p,cs,1) != 1 ) Break; // ~"A
1911 if( loop(bp,bp->x-1, bp->y/4,x1-x0,cs,0,LE) >
1912 loop(bp,bp->x-1,3*bp->y/4,x1-x0,cs,0,LE)+1 ) Break;
1913 for(i=dx/8+1,x=0;x<dx && i;x++){
1914 if( num_cross(x ,x ,0 ,dy-1, bp,cs) == 2 ) i--;
1916 for(i=dy/6+1,y=dy/4;y<dy && i;y++){
1917 if( num_cross(0 ,dx-1,y ,y , bp,cs) == 2 ) i--;
1918 if( num_cross(0 ,dx-1,y ,y , bp,cs) > 3 ) i++; // ~al
1919 } if( i ) ad=98*ad/100;
1920 for(i=dy/8+1,y=0;y<dy/2 && i;y++){
1921 if( num_cross(0 ,dx-1,y ,y , bp,cs) == 1 )
1922 if( num_cross(dx/2,dx-1,y ,y , bp,cs) == 1 ) i--;
1924 if (sdata->holes.num<1) Break;
1925 if (sdata->holes.num>1) {
1926 if (dx<6) Break; ad=95*ad/100; } // glued j above 8 (4x6 sample)
1927 MSG(fprintf(stderr,"hole[0].y0,y1= %d %d",sdata->holes.hole[0].y0,sdata->holes.hole[0].y1););
1928 if ( sdata->holes.hole[0].y0 < dy/4 ) Break;
1929 if (dy-sdata->holes.hole[0].y1 > dy/4+1) Break; // glued et
1930 // if( num_hole(x0 , x1 , y0+dy/4 , y1 ,box1->p,cs,NULL) !=1 ) Break;
1931 if( num_cross(0 ,dx-1,dy-1-dy/4,dy-1-dy/4,bp,cs) != 2 ) { // glued al
1932 if (dy>15) { Break; } else ad=96*ad/100;
1934 if (!hchar) ad=98*ad/100;
1935 if ( gchar) ad=99*ad/100;
1942 static wchar_t ocr0_F(ocr0_shared_t *sdata){
1943 struct box *box1=sdata->box1;
1945 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
1946 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
1947 int dx=x1-x0+1,dy=y1-y0+1, /* size */
1950 // --- test F ---------------------------------------------------
1951 for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx
1952 DBG( wchar_t c_ask='F'; )
1953 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
1954 if( get_bw(x0+dx/2,x0+dx/2,y0,y0+dy/8,box1->p,cs,1) != 1 ) Break;
1955 if( get_bw(x0,x0+dx/4,y1-dy/4,y1-dy/4,box1->p,cs,1) != 1 ) Break;
1956 if( get_bw(x0,x0+dx/2,y0+dy/4,y0+dy/4,box1->p,cs,1) != 1 ) Break;
1958 for (x=0,y=0;y<dy/4;y++) {
1959 j=loop(bp,dx-1,dy-1-y,dx,cs,0,LE); if(j<3 || 3*j<dx) break; // ~f Jun00
1961 } if (y<dy/4 || x<dx/2) Break;
1963 for( i=1,y=0; y<dy/4 && i; y++ ){ // long black line
1964 j=loop(bp,0,y,dx,cs,0,RI);
1965 j=loop(bp,j,y,dx,cs,1,RI); if( j>dx/2 ) i=0; }
1968 x=loop(bp,0,dy-1-dy/4,dx,cs,0,RI);
1969 x=loop(bp,x,dy-1-dy/4,dx,cs,1,RI); // strichdicke
1970 for( i=1,y=dy/3; y<dy-1-dy/3 && i; y++ ) // black line
1971 { j=loop(bp,0,y,dx,cs,0,RI);
1972 j=loop(bp,j,y,dx,cs,1,RI); if( j>dx/3 && ((j>2*x && dx>8) || j>x+1)) i=0; }
1975 y=dy/8; if (y<1) y=1;
1976 for( i=1; y<dy-1-dy/2; y++ ){ // search horizontal white gap
1977 x =loop(bp,dx-1,y,dx,cs,0,LE); if(x<2) continue; // skip serifs
1978 j =loop(bp,dx-x,y,dy/4,cs,0,UP);
1979 x+=loop(bp,dx-x,y-j+1,dx,cs,0,LE); if (x>=dx/3) { i=0; break; }
1983 // check for vertical line on left side
1984 for(i=1,y=1;y<=dy/2 && i;y++)
1985 if( get_bw(0,dx/2,y,y,bp,cs,1) != 1 ) i=0;
1988 for(i=1,y=dy/2;y<dy && i;y++)
1989 if( get_bw(0,dx/3,y,y,bp,cs,1) != 1 ) i=0;
1992 i=loop(bp,dx-1,dy-1,dx,cs,0,LE); // serif or E ?
1994 if (loop(bp,dx-1,(dy+4)/8,dx,cs,0,LE)>dx/8 // no serif
1995 || loop(bp, 0, dy-3,dx,cs,0,RI)<1) break;
1998 if( get_bw(dx-1-dx/4,dx-1,dy-1-dy/4,dy-1,bp,cs,1) == 1 ) Break; // ~E
1999 if( get_bw(dx-1 ,dx-1,0 ,dy/3,bp,cs,1) != 1 ) Break;
2001 if( loop(bp,0, bp->y/4,dx,cs,0,RI) <
2002 loop(bp,0,3*bp->y/4,dx,cs,0,RI)-1 ) Break;
2003 // if( num_hole(x0 , x1 , y0 , y1 ,box1->p,cs,NULL) >0 ) Break;
2004 if (sdata->holes.num > 0) Break;
2005 for(i=0,x=dx/4;x<dx-1;x++)
2006 if( num_cross(x,x,0,dy-2,bp,cs) == 2 ) i++;
2007 if ( i<1 ) Break; // 0.2.4a4
2009 if(dy<20) /* special case of small fi, not very elegant */
2010 if( get_bw( 1, 1,1,1,bp,cs,1) == 1
2011 && get_bw( 0, 0,2,2,bp,cs,1) == 1
2012 && get_bw(dx-2,dx-1,0,0,bp,cs,1) == 0
2013 && get_bw( 0, 1,0,0,bp,cs,1) == 0
2014 && get_bw( 0, 0,0,1,bp,cs,1) == 0 ) Break;
2016 // check for screen font f
2017 i= loop(bp,0,3*bp->y/4,dx,cs,0,RI)-1;
2018 if (i>=0 && loop(bp,dy-1,i,dy,cs,0,UP)<=3*dy/4 ) ad=ad*98/100;
2020 // check for screen font P
2021 i= loop(bp,bp->x-1,bp->y/4,dx,cs,0,LE);
2023 j=i+loop(bp,bp->x-1-i,bp->y/4, dx ,cs,1,LE);
2024 j= loop(bp,bp->x-1-j,bp->y/4,3*dy/4,cs,0,DO);
2026 i=loop(bp,bp->x-1,0,dx,cs,0,LE);
2029 if (i) ad=98*ad/100;
2033 if (!hchar) if ((box1->m2-box1->y0)*8>=dy) { // ignore bad m1..4
2034 if ( num_cross(2*dx/3,2*dx/3,0,dy-1,bp,cs) < 2 ) ad=90*ad/100; // ~r
2036 if (gchar) ad=99*ad/100;
2043 static wchar_t ocr0_uU(ocr0_shared_t *sdata){
2044 struct box *box1=sdata->box1;
2046 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
2047 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2048 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2052 // --- test uU ---------------------------------------------------
2053 // in Mitte so breit wie oben (bei V kontinuierlich schmaler)
2054 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
2055 DBG( wchar_t c_ask='u'; )
2056 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2057 for(y=y0+dy/4;y<y1-dy/4;y++) /* also handwritten u */
2058 if( num_cross(x0,x1,y,y,box1->p,cs) < 2 ) break;
2059 if( y<y1-dy/4 ) Break;
2060 if( get_bw(dx/2,dx/2,dy/2,dy-1,bp,cs,1)==0 ) Break;
2061 if( get_bw(dx/2,dx-1,dy/2,dy/2,bp,cs,1)==0 ) Break;
2062 for(i=0,x=3*dx/8;x<dx-dx/4;x++){
2063 y=loop(bp,x,0,dy,cs,0,DO); if(y>i)i=y; if(y<i && i>1) break;
2064 } if( i<dy/4 ) Break; x--;
2065 if( get_bw(0,x ,i-1,i-1,bp,cs,1)==0 ) Break;
2066 if( get_bw(x,dx-1,i-1,i-1,bp,cs,1)==0 ) Break;
2068 for(i=dy/8+2,y=dy/8;y<dy-(dy+2)/4 && i;y++){ // 12%+1 Fehler
2069 j=num_cross(0,dx/2-((y>dy/2)?dx/8:0),y,y,bp,cs);
2070 if( y<dy/2 && num_cross(dx/2,dx-1,y,y,bp,cs)>1 ) i--; // ~{\it v}
2071 if( y<dy/2 && (j<1 && j>2) ) { i--; ad=90*ad/100; }
2072 if( y>dy/2 && j!=1 ) { i--; ad=95*ad/100; }
2074 for(i=dy/16+1,y=dy/8;y<dy-dy/4 && i;y++){ // 12%+1 Fehler
2075 j=num_cross(dx-dx/2,dx-1,y,y,bp,cs);
2076 if( y>dy/2 && (j<1 && j>2) ) i--;
2077 if( y<dy/2 && j!=1 ) i--;
2079 for(i=1,x=x0+dx/3;x<=x1-dx/3 && i;x++){
2080 if( get_bw( x, x, y0, y0+dy/3,box1->p,cs,1) != 1 ) i=0;
2082 for(i=dx/4+1,x=x0+dx/3;x<=x1-dx/3 && i;x++){
2083 if( get_bw( x, x,y0+dy/3,y1-dy/3,box1->p,cs,3) != 2 ) i--;
2085 for(i=1,x=x0+dx/3;x<=x1-dx/3 && i;x++){
2086 if( get_bw( x, x,y1-dy/2,y1,box1->p,cs,3) == 2 ) i=0;
2087 if( get_bw( x, x,y1-dy/3,y1,box1->p,cs,3) == 2 ) ad=98*ad/100;
2089 if( num_cross(0 ,dx/2, dy/4, dy/4,bp,cs)==2
2090 && num_cross(dx-dx/2,dx-1,dy-dy/4,dy-dy/4,bp,cs)==1 ) Break; // ~{\it v}
2092 i=loop(bp,0,dy-1-dy/16,dx,cs,0,RI);
2093 j=loop(bp,0,dy-1-dy/8 ,dx,cs,0,RI);
2094 if( i<j ) Break; // ~ll v0.2.4a3
2096 if( loop(bp,dx-1,dy/16,dx,cs,0,LE)
2097 > loop(bp,dx-1,dy/8 ,dx,cs,0,LE)+1+dx/32 ) Break; // ~bad 0 (thinn)
2099 if( loop(bp, 0, dy-1,dx,cs,1,RI)==dx
2100 && loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/16
2101 && loop(bp, 0,3*dy/4,dx,cs,0,RI)>dx/16
2102 && loop(bp,dx-1, dy/2,dx,cs,0,LE)>dx/16
2103 && loop(bp, 0, dy/2,dx,cs,0,RI)>dx/16
2104 ) Break; // melted ll
2106 i=loop(bp, 0,dy-2-dy/8,dx,cs,0,RI);
2107 j=loop(bp,dx-1,dy-2-dy/8,dx,cs,0,LE);
2108 if ( i>dx/4 && j>dx/4 && i+j>=dx/2) Break; // v
2109 if (i+j>=dx/2) ad=97*ad/100;
2111 if ( num_cross(0,dx-1,dy/2,dy/2,bp,cs)!=2 ) ad=96*ad/100; // w
2112 if ( loop(bp,dx/2,dy-1,dy,cs,0,UP)>0 ) ad=98*ad/100; // w
2114 if (ad==100) ad=99; // ToDo: only if lines.wt<100
2116 if (gchar) ad=98*ad/100;
2118 if (box1->dots>0) ad=99*ad/100;
2125 static wchar_t ocr0_micro(ocr0_shared_t *sdata){
2126 struct box *box1=sdata->box1;
2128 int i,j,d,x,y,i2,hchar=sdata->hchar,gchar=sdata->gchar,
2129 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2130 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2133 // --- test \mu µ MICRO_SIGN --------------------------------------
2134 // in Mitte so breit wie oben (bei V kontinuierlich schmaler)
2135 if( gchar && !hchar )
2136 for(ad=d=100;dx>2 && dy>4;){ // min 3x4
2137 DBG( wchar_t c_ask='u'; )
2138 if (sdata->holes.num > 1) break; /* tolerant against a tiny hole */
2139 for(y=y0+dy/8;y<box1->m3-dy/4;y++)
2140 if( num_cross(x0,x1,y,y,box1->p,cs) < 2 ) break;
2141 if( y<box1->m3-dy/4 ) break;
2142 if( get_bw(dx/2,dx/2,3*dy/8,7*dy/8,bp,cs,1)==0 ) break;
2143 if( get_bw(dx/2,dx-1,3*dy/8,7*dy/8,bp,cs,1)==0 ) break;
2144 for(y=dy/2;y<dy;y++){
2145 x=loop(bp,dx-1,y,dx,cs,0,LE); if(8*x>5*dx) break;
2146 } if( y>=dy || 2*y>box1->m3+box1->m4) break; i2=y;
2147 for(i=0,x=2*dx/8;x<dx-1-dx/4;x++){
2148 y=loop(bp,x,0,dy,cs,0,DO); if(y>i)i=y; if(y<i && i>1) break;
2149 } if( i<dy/4 ) break; x--;
2150 if( get_bw(0,x ,i-1,i-1,bp,cs,1)==0 ) break;
2151 if( get_bw(x,dx-1,i-1,i-1,bp,cs,1)==0 ) break;
2152 for(i=dy/16+1,y=dy/8;y<dy-(box1->m4-box1->m3)-dy/4 && i;y++){ // 12%+1 Fehler
2153 j=num_cross(0,dx/2,y,y,bp,cs);
2154 if( y<dy/2 && num_cross(dx/2,dx-1,y,y,bp,cs)>1 ) i--; // ~{\it v}
2155 if( y<dy/2 && (j<1 && j>2) ) i--;
2156 if( y>dy/2 && j!=1 ) i--;
2158 for(i=dy/16+1,y=dy/8;y<dy-(box1->m4-box1->m3)-dy/4 && i;y++){ // 12%+1 Fehler
2159 j=num_cross(dx-dx/2,dx-1,y,y,bp,cs);
2160 if( y>dy/2 && (j<1 && j>2) ) i--;
2161 if( y<dy/2 && j!=1 ) i--;
2163 for(i=1,x=x0+dx/3;x<=x1-dx/3 && i;x++){
2164 if( get_bw( x, x, y0, y0+dy/4,box1->p,cs,1) != 1 ) i=0;
2166 for(i=dx/4+1,x=x0+dx/3;x<=x1-dx/3 && i;x++){
2167 if( get_bw( x, x,y0+dy/4,y1-dy/2,box1->p,cs,3) != 2 ) i--;
2169 if( num_cross(0 ,dx/2, dy/4, dy/4,bp,cs)!=1 ) break;
2170 if( num_cross(dx-dx/2,dx-1,dy-dy/2,dy-dy/2,bp,cs)!=1 ) break;
2171 if( get_bw( (dx+2)/4,dx-1,dy-2-3*dy/16,dy-1,bp,cs,1) == 1 ) break;
2172 if( num_cross(0,dx/4,dy-1,dy-1,bp,cs)!=1 ) break;
2174 Setac(box1,MICRO_SIGN,ad);
2180 static wchar_t ocr0_vV(ocr0_shared_t *sdata){
2181 struct box *box1=sdata->box1;
2183 int i,j,d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
2184 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2185 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2189 // --- test v -------------------------------------------------
2190 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
2191 DBG( wchar_t c_ask='v'; )
2192 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2193 x=loop(bp,dx/2,0,dx,cs,1,RI)+dx/2; // be sure in the upper gap
2194 y=loop(bp, x,0,(dy+1)/2,cs,0,DO)-1; // (x,y) should be in the gap
2195 if (x>3*dx/4 || y<dy/4) Break;
2196 if( get_bw(x0,x0+x,y0+y,y0+y,box1->p,cs,1) != 1 ) Break;
2197 if( get_bw(x0+x,x1,y0+y,y0+y,box1->p,cs,1) != 1 ) Break;
2198 if( get_bw(x0+x,x0+x,y1-dy/2,y1, box1->p,cs,1) != 1 ) Break;
2199 if( get_bw(x0+x, x0+x ,y0, y0+dy/3,box1->p,cs,1) == 1 ) // it v?
2200 if( get_bw(x0+x+1,x0+x+1,y0, y0+dy/3,box1->p,cs,1) == 1 ) Break;
2203 if(((num_cross( 0,dx/2+1,dy/ 8,dy/ 8,bp,cs)!=1)
2204 && (num_cross( 0,dx/2+1,dy/16,dy/16,bp,cs)!=1) // it v
2205 && (num_cross(dx/2+1,dx -1,dy/ 8,dy/ 8,bp,cs)!=1)) /* () added on Sep00 */
2206 || ((num_cross( 0,dx-1,dy-1-dy/8,dy-1-dy/8,bp,cs)> 1)
2207 && (num_cross( 0,dx-1,dy-1 ,dy-1 ,bp,cs)> 1)) ) Break;
2209 if( get_bw(0 ,dx/8,dy-1-dy/6,dy-1,bp,cs,1)==1 ) Break;
2210 if( get_bw(dx-1-dx/8,dx-1,dy-1-dy/6,dy-1,bp,cs,1)==1 ) Break;
2211 if( loop(bp,0 ,dy/6 ,dx,cs,0,RI)
2212 >=loop(bp,0 ,dy-1-dy/3,dx,cs,0,RI) && dy>6 ) Break;
2213 if( loop(bp,0 ,dy-1-dy/3,dx,cs,0,RI)
2214 >loop(bp,0 ,dy-1-dy/8,dx,cs,0,RI)
2215 && loop(bp,dx-1,dy-1-dy/3,dx,cs,0,LE)
2216 >loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE) ) Break; // better OR ?
2217 if( loop(bp,0 ,dy-1-dy/3,dx,cs,0,RI)
2218 >=loop(bp,0 ,dy-1-dy/8,dx,cs,0,RI)
2219 && loop(bp,dx-1,dy-1-dy/3,dx,cs,0,LE)
2220 >=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE) ) ad=99*ad/100; // font21
2221 if( loop(bp,dx-1,dy/6 ,dx,cs,0,LE)
2222 >=loop(bp,dx-1,dy-1-dy/3,dx,cs,0,LE) && dy>6 ) Break;
2223 x=loop(bp,0,dy-1,dx,cs,0,RI); // 3*x>dx changed to 2*x>dx May2001 JS
2224 x=loop(bp,x,dy-1,dx,cs,1,RI); if ( dx>14 && 2*x>dx ) Break; // U
2225 if( num_cross(0 ,dx/2, dy/4, dy/4,bp,cs)==2
2226 && num_cross(dx-dx/2,dx-1,dy-dy/4,dy-dy/4,bp,cs)==2 ) Break; // ~{\it u}
2229 // measure thickness of lower v
2230 i=loop(bp, 0,dy-1-dy/16,dx,cs,0,RI)
2231 +loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE);
2232 j=loop(bp, 0,dy-1-dy/4 ,dx,cs,0,RI)
2233 +loop(bp,dx-1,dy-1-dy/4 ,dx,cs,0,LE);
2234 if( box1->m1 && hchar && dy>15 && j>=i-dx/32 ) Break; // ~Y
2236 /* V has serifs only on upper site! Y also on bottom, check it. Okt00 */
2237 i=loop(bp, 0, 0,dx,cs,0,RI);
2238 i=loop(bp, i, 0,dx,cs,1,RI); i1=i; // thickness
2239 i=loop(bp, 0, 1,dx,cs,0,RI);
2240 i=loop(bp, i, 1,dx,cs,1,RI); if(i>i1) i1=i; // thiggest
2241 i=loop(bp, 0,dy/4,dx,cs,0,RI);
2242 i=loop(bp, i,dy/4,dx,cs,1,RI); i2=i;
2243 i=loop(bp, 0,dy ,dx,cs,0,RI);
2244 i=loop(bp, i,dy ,dx,cs,1,RI); i3=i; // thickness
2245 i=loop(bp, 0,dy-1,dx,cs,0,RI);
2246 i=loop(bp, i,dy-1,dx,cs,1,RI); if(i>i3) i3=i; // thiggest
2249 && i3-i2 > dx/32+2 ) Break; // ~serif_Y
2251 if( y0 < box1->m2 ) // uppercase V ?
2252 if( i1-i2 < dx/32+2 ) /* no serif detected */
2253 if( num_cross(0,dx-1,dy-1-dy/4,dy-1-dy/4,bp,cs)==1 ){
2254 j=loop(bp, 0,dy-1-dy/4 ,dx,cs,0,RI);
2255 j=loop(bp, j,dy-1-dy/4 ,dx,cs,1,RI);
2256 if (j<i2+1) Break; // ~Y
2257 if (j<=i2+1) ad=99*ad/100; // ~Y
2260 ad=99*ad/100; // be carefull (remove later)
2262 if( loop(bp,0 ,dy-1-dy/4,dx,cs,0,RI)
2263 >loop(bp,0 ,dy-1 ,dx,cs,0,RI) ) ad=96*ad/100;
2265 if (gchar) ad=99*ad/100;
2268 Setac(box1, bc, ad);
2274 static wchar_t ocr0_rR(ocr0_shared_t *sdata){
2275 struct box *box1=sdata->box1;
2277 int i,j,d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
2278 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2279 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2282 // --- test r -------
2283 for(ad=d=100;dy>3 && dx>1;){ // dy>dx, 4x6 font, dx=2 smallest prop-font
2284 DBG( wchar_t c_ask='r'; )
2285 if (sdata->holes.num > 0
2286 && ( sdata->holes.hole[0].y1 > dy/2 // tiny hole in upper left
2287 || sdata->holes.hole[0].x1 > dx/2 ) // is tolerated, ~Pp
2288 ) Break; /* tolerant against a tiny hole */
2289 if( 2*dy<box1->m3-box1->m1) Break;
2291 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)<=dx/8 ) Break;
2292 x= loop(bp,dx-1,dy/2,dx,cs,0,LE); if (x<=dx/2) ad=99*ad/100; // ~t
2293 if (loop(bp,dx-1-x/2,0,dy,cs,0,DO)>dy/8) ad=99*ad/100; // ~t
2295 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)<=dx/8+2 ) Break; // ~v Jun00
2297 i=dy-(dy+20)/32; // ignore dust on the ground
2299 for( y=4*dy/8; y<i; y++ ){ // center down v-line
2300 if( y<dy-2*dy/8 && num_cross(0,dx-1,y,y,bp,cs) !=1 ) break;
2301 i1= loop(bp,0 ,y,dx,cs,0,RI); if(i1>3*dx/8) break;
2302 i2= loop(bp,dx-1,y,dx,cs,0,LE); if(i1>i2) break;
2304 -1))/2 >= 4*dx/8 ) break; // mass middle should be left
2308 for( x=4*dx/8; x<dx-dx/8; x++ ){ // right upper h-line
2309 if( get_bw(x,x,0,(dy+2)/4,bp,cs,1) !=1 ) break; }
2310 if (x<dx-dx/8) Break;
2312 if( loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE)>5*dx/8 // not a C
2313 && get_bw(dx-1-dx/8,dx-1,dy-1-dy/4,dy-1,bp,cs,1) ==1 ) Break;
2315 if( loop(bp, 0,5*dy/8,dx,cs,0,RI)<=dx/8
2316 && loop(bp,dx-1,5*dy/8,dx,cs,0,LE)>=5*dy/8
2317 && loop(bp,dx/2, dy-1,dy,cs,0,UP)<=dy/8 ) Break; // ~c
2319 if( loop(bp, 0,3*dy/8,dx,cs,0,RI)
2320 > loop(bp,dx-1,3*dy/8,dx,cs,0,LE)+dx/8 ) {
2321 if( loop(bp, 0, dy/8,dx,cs,0,RI)<dx/8 ) Break; // ~z (broken)
2325 if( loop(bp,0,dy/3,dx,cs,0,RI)>3*dx/4 ) Break; // ~i
2326 if( loop(bp,0,dy/4,dx,cs,0,RI)>3*dx/8 // ~I
2327 && get_bw(0,dx/8,0,dy/4,bp,cs,1) ==1 ) Break;
2328 if( num_cross(0,dx-1,dy/2, dy/2 ,bp,cs)!=1
2329 && num_cross(0,dx-1,dy/2+1,dy/2+1,bp,cs)!=1 ) Break; // ~n 024a3
2331 // itallic t is sometimes not high enough, look for v-like shape
2332 for(y=3*dy/4;y<dy-1;y++)
2333 if( num_cross(0,dx-1,y, y ,bp,cs)==2
2334 && num_cross(0,dx-1,y+1+dy/32,y+1+dy/32,bp,cs)==2 ) break; // ~t
2336 if (loop(bp,dx-1-dx/4,dy-1,dx,cs,0,UP)<dy/4) ad=98*ad/100; // ~f (serif)
2337 if( num_cross(dx-1,dx-1,0,3*dy/4,bp,cs)>1 ) ad=95*ad/100; // ~f
2338 if( num_cross(dx/2 ,dx/2 ,0,dy-1,bp,cs)>2
2339 && num_cross(dx/2+1,dx/2+1,0,dy-1,bp,cs)>2 ) Break; // ~f
2341 if (box1->dots) ad=98*ad/100; /* could be modified latin2-r */
2342 if (hchar) ad=96*ad/100;
2343 if (gchar) ad=97*ad/100;
2345 break; // not 100% sure!
2347 // --- test R ---------------------------------------------------
2348 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
2349 DBG( wchar_t c_ask='R'; )
2350 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
2351 if( num_cross(x0,x1,y1-dy/8,y1-dy/8, box1->p,cs) < 2 ) Break; // ~P
2352 if (loop(bp, dx/2, dy/4,dy,cs,0,DO)>dy/2) Break; // ~C
2353 if (loop(bp, dx/2, 0,dy,cs,0,DO)>dy/8
2354 && loop(bp, dx/2,dy/16,dx,cs,0,RI)<dx/2
2356 for(i=1,y=y0+dy/8;y<=y1-dy/8 && i;y++){ // left v-line
2357 if( get_bw(x0 , x0+dx/2,y, y,box1->p,cs,1) != 1 ) i=0;
2359 for(i=1,x=x0+3*dx/8;x<=x1-dx/4 && i;x++){ // upper h-line
2360 if( get_bw( x, x, y0, y0+dy/4,box1->p,cs,1) != 1 ) i=0;
2362 for(y=0,x=x0+dx/4;x<=x1-dx/4;x++){ // lower h-gap
2363 i=loop(box1->p,x,y1,dy,cs,0,UP);
2364 /* on small chars bypass possible low left serifs */
2365 if (i>0) { i2=loop(box1->p,x-1,y1-i-1,dy,cs,0,UP);
2366 if (i2>1) i+=i2-1; }
2367 if (i>y) { y=i; i1=x; }
2368 } if( y<=dy/8 ) Break; if (y<dy/4) ad=80*ad/100;
2369 for(i=1,x=x0+dx/3;x<=x1-dx/8 && i;x++){ // vert crossed 2 ???
2370 if( num_cross(x,x,y0,y1, box1->p,cs) == 2 ) i=0;
2372 for(i=1,y=y0;y<=y0+3*dy/8 && i;y++){ // upper 2 vert lines
2373 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
2375 for(i=1,y=y0+dy/3;y<=y1-dy/3 && i;y++){ // midle h line
2376 if( num_cross(x0,x1,y,y, box1->p,cs) == 1 ) i=0;
2377 } if( i ) ad=95*ad/100; /* sometimes there is a small gap */
2378 for(i=1,y=y1-dy/4;y<=y1 && i;y++){ // lower 2 vert lies
2379 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
2381 if( get_bw(x1-dx/3,x1,y0,y0+dy/4,box1->p,cs,1) != 1 ) Break; // pixel ru
2382 x=loop(bp,dx-1, dy/4,dx,cs,0,LE); if(x>dx/2) Break; i=x; // ru
2383 x=loop(bp,dx-1, dy/2,dx,cs,0,LE); if(x<=i ) Break; i=x; // rc
2384 x=loop(bp,dx-1, 5*dy/8,dx,cs,0,LE); if(x>i ) i=x;
2385 x=loop(bp,dx-1, 6*dy/8,dx,cs,0,LE); if(x>i ) i=x;
2386 x=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE); if(x>=i ) Break; // rd
2388 i1=loop(bp,0, dy/4,dx,cs,0,RI); // straight
2389 i2=loop(bp,0, dy/2,dx,cs,0,RI);
2390 i3=loop(bp,0,dy-1-dy/4,dx,cs,0,RI); if( abs(i1+i3-2*i2)>1+dx/16 ) Break;
2392 if (loop(bp,dx-1, dy/2,dx,cs,0,LE)>=loop(bp,dx-1, dy-1,dx,cs,0,LE)
2393 && loop(bp,dx-1,3*dy/16,dx,cs,0,LE)>=loop(bp,dx-1,dy/16,dx,cs,0,LE)+dx/8 ) Break; // ~ff
2395 if (loop(bp,dx-1,dy-2 ,dx,cs,0,LE)
2396 >loop(bp,dx-1,dy-2-dy/8,dx,cs,0,LE)) {
2398 if (loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE)==0
2399 && loop(bp,dx-1,dy-2-dy/8,dx,cs,0,LE)>0 ) Break; // broken B ??
2403 i=num_hole (x0,x1,y0,y1-dy/3,box1->p,cs,NULL);
2404 // j=num_hole (x0,x1,y0,y1 ,box1->p,cs,NULL);
2405 if (i==0) ad=90*ad/100; /* some times there is a small gap */
2406 if (j>1 || j>i) Break;
2408 if (sdata->holes.num < 1) ad=90*ad/100;
2409 if (sdata->holes.num==1)
2410 if (sdata->holes.hole[0].y1 > 3*dy/4) ad=95*ad/100; // alpha
2412 if (!hchar) ad=98*ad/100;
2413 if ( gchar) ad=98*ad/100;
2420 static wchar_t ocr0_m(ocr0_shared_t *sdata){
2421 struct box *box1=sdata->box1;
2423 int i,d,x,y,i1,i2,i3,i4,i5,hchar=sdata->hchar,gchar=sdata->gchar,
2425 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2426 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2429 // --- test m -------
2430 for(ad=d=100;dx>4 && dy>3;){
2431 DBG( wchar_t c_ask='m'; )
2432 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2433 if (sdata->holes.num > 0) ad=96*ad/100;
2434 x =loop(bp,dx-1,dy/2,dx,cs,0,LE); if(3*x>dx) Break; // ~K
2436 i=num_cross(0,dx-1,y ,y ,bp,cs); if (i!=3)
2437 i=num_cross(0,dx-1,y+1,y+1,bp,cs);
2438 if (i<3 && i>5) Break; // m ru rn, handwritten m
2439 // im or glued.mm cut to nm
2440 if (i>3) { ad=99*ad/100; MSG(fprintf(stderr,"ad=%d",ad);) }
2441 for (i=0,y=dy-1-dy/8;y>dy/2;y--) {
2442 i=num_cross(0,dx-1,y,y,bp,cs); if (i>2) break;
2444 for ( ;y>dy/2;y--) {
2445 i=num_cross(0,dx-1,y,y,bp,cs); if (i!=3) break;
2446 } if (i>5) Break; y++; i5=y;
2447 if (y> dy/2) handwritten=10;
2448 if (y>3*dy/4) handwritten=60;
2449 /* @@...............
2455 @@@@@,.@@@@,,,@@@ <- i5
2461 x =loop(bp,0,y,dx ,cs,0,RI); if(x> dx/4) Break; // search 1st v-line
2462 x+=loop(bp,x,y,dx-x,cs,1,RI); if(x> dx/2) Break; i1=x; // first gap
2463 x+=loop(bp,x,y,dx-x,cs,0,RI); if(x>3*dx/4) Break; i2=x; // 2nd v-line
2464 x+=loop(bp,x,y,dx-x,cs,1,RI); if(x>6*dx/8) Break; i3=x; // 2nd gap
2465 x+=loop(bp,x,y,dx-x,cs,0,RI); if(x<5*dx/8) Break; i4=x; // 3th v-line
2466 if (x>=dx) Break; // missing 3th v-line, ~W
2467 MSG(fprintf(stderr,"y=%d x=%d %d %d %d",y,i1,i2,i3,i4);)
2468 if( abs((i2-i1)-(i4-i3)) > 2+((i2-i1)+(i4-i3))/4 ) Break; // same gap width? rn
2469 if( abs((i2-i1)-(i4-i3)) > 2+((i2-i1)+(i4-i3))/8 ) ad=98*ad/100; // same gap width? rn
2470 // the same game for the lower part =>l1 l2 l3 l4 ???
2471 i =loop(bp,0,5*dy/8,dx,cs,0,RI);
2472 i =loop(bp,i,5*dy/8,dx,cs,1,RI);
2473 x =loop(bp,0,dy-dy/32-1,dx,cs,0,RI);
2474 x =loop(bp,x,dy-dy/32-1,dx,cs,1,RI);
2475 if( x > i+1 ) i=1; else i=0; /* looks like serif m, Okt00 */
2476 for(y=0,x=i1;x<i2;x++) {
2477 i=loop(bp,x,dy-1,dy,cs,0,UP); if (i>y) y=i;
2479 if(y<dy/4 || y<y1-y0-i5-1-dy/16) Break; // no gap detected
2480 for(y=0,x=i3;x<i4;x++) {
2481 i=loop(bp,x,dy-1,dy,cs,0,UP); if (i>y) y=i;
2483 if(y<dy/4) Break; // no gap detected
2484 for(x=i1;x<i4;x++) if( loop(bp,x,0,dy,cs,0,DO)>=dy/2 ) break;
2485 if(x<i4 && handwritten<10) Break; // gap detected
2486 // glued rn as m ??? hmm seems a ballance act
2487 if(i2-i1>i4-i3+dx/16){
2488 for(y=0,x=(i1+i2)/2;x<i2;x++){
2489 i=loop(bp,x,0,dy,cs,0,DO);
2490 i=loop(bp,x,i,dy,cs,1,DO); // measure thickness
2491 if( i>y ) y=i; if( 2*i<y ) Break;
2493 if(x <i2) Break; // unusual property for m (see n)
2495 if(gchar) ad=99*ad/100;
2496 if(hchar) ad=99*ad/100;
2498 if( loop(bp,dx-1,dy/16,dx,cs,0,LE)<2
2499 && loop(bp,dx-1,dy/4 ,dx,cs,0,LE)>3 ) Break; // melted WT
2501 x=loop(bp,dx-1,dy/2,dx,cs,0,LE);
2502 if (x>2 && loop(bp,dx-1-x/2,0,dy,cs,0,DO)<dy/2) Break; // melt toc
2503 if (loop(bp,(i3+i4)/2,0,dy,cs,0,DO)>dy/2) Break; // N
2506 if( loop(bp,1, dy/4,dx,cs,0,RI)
2507 >loop(bp,0,7*dy/8,dx,cs,0,RI) )
2508 Setac(box1,'m',98*ad/100);
2510 if (handwritten<10){
2511 x =loop(bp,0,dy/4,dx,cs,0,RI);
2512 x+=loop(bp,x,dy/4,dx,cs,1,RI);
2513 for( ;x<i4;x++){ // x=i1 ?
2514 i=loop(bp,x,0,dy,cs,0,DO);
2515 if (i>=dy/4) ad=99*ad/100;
2516 if (i>(dy+2)/4) ad=95*ad/100;
2519 if(x<i4) Break; // gap detected
2522 if (box1->dots) ad=99*ad/100;
2524 if (ad>=100) return 'm';
2531 static wchar_t ocr0_tT(ocr0_shared_t *sdata){
2532 struct box *box1=sdata->box1;
2534 int i,i1,i2,i3,i4,j,d,x,y,yb,hchar=sdata->hchar,gchar=sdata->gchar,
2535 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2536 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2539 // --- test T ---------------------------------------------------
2540 for(ad=d=100;dx>2 && dy>3;){ // dx>1 dy>2*dx
2541 DBG( wchar_t c_ask='T'; )
2542 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2543 // upper horizontal line
2544 i1= loop (bp, dx/8,0,dy,cs,0,DO); // left side
2545 i2= loop (bp,dx-1-dx/8,0,dy,cs,0,DO); // right side
2546 i3= loop (bp, dx/8,i1,dy,cs,1,DO); // left side
2547 i4= loop (bp,dx-1-dx/8,i2,dy,cs,1,DO); // right side
2548 if (i1>dy/4 || i2>dy/4) Break;
2549 for (x=dx/8;x<dx-1-dx/8;x++) {
2550 i= loop (bp,x,0,dy,cs,0,DO);
2551 if (i>i1+dy/8 && i>i2+dy/8) break;
2552 if (i<i1-dy/8 && i<i2-dy/8) break;
2553 } if (x<dx-1-dx/8) Break;
2554 if( get_bw( 0,dx-1, dy/2, dy/2,bp,cs,1) != 1 ) Break;
2555 if( get_bw( 0,(dx-1)/8, dy/2,dy-1-dy/8,bp,cs,1) == 1 ) Break;
2556 if( get_bw( 0,3*dx/16, dy/2,dy-1-dy/4,bp,cs,1) == 1 ) Break;
2557 if( get_bw(dx-1-dx/4,dx-1, dy/2,dy-1-dy/4,bp,cs,1) == 1 ) Break;
2559 for( y=dy/4;y<3*dy/4;y++){ // oberer Balken?
2560 i=dx/4+loop(bp,dx/4,y,dx,cs,0,RI); // left side of vertical line
2561 j= loop(bp, i,y,dx,cs,1,RI); // width of vertical line
2562 if (3*j>dx+1 || i+j>=dx || i+j/2<dx/2-1) break; // ~r?7
2563 } if (y<3*dy/4) Break; // Jan07
2565 for( y=3*dy/4;y<dy;y++){
2566 i= loop(bp,dx/4,y,dx,cs,0,RI);
2567 i= loop(bp, i,y,dx,cs,1,RI);if(4*i>3*x) break; //~I
2570 i =dx/4+loop(bp,dx/4,dy/4,dx,cs,0,RI);if(i>3*dx/4) Break; // ~7
2571 i+= loop(bp,i ,dy/4,dx,cs,1,RI);if(i>3*dx/4) Break;
2573 if( num_cross(0,dx-1, dy-1, dy-1,bp,cs) != 1
2574 && num_cross(0,dx-1, dy-2, dy-2,bp,cs) != 1 ) Break;
2575 if( num_cross(0,dx-1,2*dy/3,2*dy/3,bp,cs) != 1
2576 && num_cross(0,dx-1,2*dy/3,2*dy/3,bp,cs) != 1 ) Break;
2577 if (box1->m3 && 2*y1>box1->m3+box1->m4
2578 && loop(bp,0, 0,dy/2,cs,0,DO)>=dy/4
2579 && loop(bp,0,dy-1,dy ,cs,0,UP)<=dy/2) ad=96*ad/100; // ~J
2580 if (gchar) ad=98*ad/100;
2581 if( loop(bp,0,dy-1,dx,cs,0,RI)<=dx/8) ad=99*ad/100; // ~J
2582 i = loop(bp,0,dy/2,dx,cs,0,RI);
2583 j = loop(bp,i,dy/2,dx,cs,1,RI);
2584 if( 2*i>=dx || 2*(dx-j-i)<i) ad=95*ad/100; // ~J
2587 if (ad>=100) return 'T';
2590 // --- test t ---------------------------------------------------
2591 // written t can look like a + or even with missing right side
2592 // smallest t found in win-screenshot (prop-font) dx=2
2593 for(ad=d=100;dx>1 && dy>=box1->m3-box1->m2-1;){ // sometimes no hchar!
2594 DBG( wchar_t c_ask='t'; )
2595 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2596 if (dy<=box1->m3-box1->m2+1) ad=96*ad/100; // bad line detection?
2597 for(x=0,yb=j=y=dy/32+3*dy/16;y<5*dy/8;y++)if(y>0){ // upper cross line
2598 i=loop(bp,0,y,dx,cs,0,RI);
2599 i=loop(bp,i,y,dx,cs,1,RI); if( i>x ) { x=i;yb=j=y; } // hor. line
2600 i=num_cross(0,dx-1,y ,y ,bp,cs);
2601 j=num_cross(0,dx-1,y+1,y+1,bp,cs); if (i>2 && j>2) break;
2603 && num_cross(0,dx-1,y ,y ,bp,cs) != 1
2604 && ( num_cross(0,dx-1,y+dy/8,y+dy/8,bp,cs) != 1 || dy<13) // against noise
2606 } if( y<4*dy/8 ) Break;
2607 if (dy>12 && x>4 && x>dx/2 && yb<=(dy+4)/8)
2608 if ( loop(bp,dx-1-3*x/4,yb,dy,cs,1,UP)
2609 <=loop(bp,dx-1-1*x/4,yb,dy,cs,1,UP)+1 )
2610 if ( loop(bp,0 ,dy/2,dy,cs,1,UP)>dx/8 ) Break; // ~C
2612 if (x<dx/2) ad=95*ad/100; // unusual small ?
2613 if (x>=dx && 9*dx>=8*dy) { ad=99*ad/100; } // +
2615 i=loop(bp,dx-1,0,dx,cs,0,LE);
2616 for(y=0;y<dy/4;y++){
2617 if( num_cross(0,dx-1,y ,y ,bp,cs) == 2
2618 && num_cross(0,dx-1,y+1,y+1,bp,cs) == 2 ) break;
2619 j=loop(bp,dx-1,y,dx,cs,0,LE); if(j-i>1) break; i=j;
2621 if( y<dy/4 ) Break; // ~f
2623 i=loop(bp,dx-1,yb,dx,cs,0,LE);
2624 for(y=dy/8;y<yb;y++)
2625 if( loop(bp,dx-1,y,dx,cs,0,LE)>i ) break;
2628 j=loop(bp,0, dy/2,dx,cs,0,RI);
2629 j=loop(bp,j, dy/2,dx,cs,1,RI); i=j; // thickness
2630 j=loop(bp,0, dy/4,dx,cs,0,RI);
2631 j=loop(bp,j, dy/4,dx,cs,1,RI); if (j<i) i=j; // thickness
2632 j=loop(bp,0,3*dy/4,dx,cs,0,RI);
2633 j=loop(bp,j,3*dy/4,dx,cs,1,RI); if (j<i) i=j; // thickness
2634 if( 2*x<3*i ) Break;
2636 if( loop(bp,dx-1,dy/2,dx,cs,0,LE)-dx/8
2637 <=loop(bp,dx-1, yb ,dx,cs,0,LE) )
2638 if( loop(bp,dx-1, yb ,dx,cs,0,LE)-dx/8
2639 >=loop(bp,dx-1,yb/2,dx,cs,0,LE) ) Break; // ~1 ???
2642 for(y=1;j && y<yb; y++) // no @@ pattern
2643 for(x=0;j && x<dx-2;x++){ // ..
2644 if( getpixel(bp,x ,y )>=cs && getpixel(bp,x+1,y )>=cs
2645 && getpixel(bp,x ,y-1)< cs && getpixel(bp,x+1,y-1)< cs ) { j=0;break; }
2648 if( num_cross(0,dx-1,dy-2,dy-2,bp,cs) == 2
2649 && num_cross(0,dx-1,dy-1,dy-1,bp,cs) == 2 ) Break; // ~* (5er)
2652 && loop(bp, 0, 3*dy/4,dx,cs,0,RI)
2653 >=loop(bp, 0, dy-2,dx,cs,0,RI)
2654 && loop(bp,dx-1, 3*dy/4,dx,cs,0,LE)
2655 <=loop(bp,dx-1, dy-2,dx,cs,0,LE)
2656 && loop(bp,dx-1, 1,dx,cs,0,LE)+dx/16
2657 <loop(bp,dx-1,3*dy/16,dx,cs,0,LE)
2658 && ( loop(bp, 0, 1,dx,cs,0,RI)
2659 >loop(bp, 0,3*dy/16,dx,cs,0,RI)+dx/16
2660 || loop(bp,dx-1, 0,dx,cs,0,LE)==0
2661 || loop(bp,dx-1, 1,dx,cs,0,LE)==0) ) ad=96*ad/100; // ~f Jan02
2662 if(dx<8 && dy>12){ // thin f's could easily confound with t
2663 x=loop(bp,dx-1,3*dy/16,dx,cs,0,LE);
2665 if (loop(bp,dx-x,0,dy,cs,0,DO)<3*dy/16
2666 && loop(bp, 0, 3*dy/4,dx,cs,0,RI)+1
2667 >=loop(bp, 0, dy-2,dx,cs,0,RI)
2668 && loop(bp,dx-1, 3*dy/4,dx,cs,0,LE)
2669 <=loop(bp,dx-1, dy-2,dx,cs,0,LE) ) Break;
2672 if( num_cross( 0,dx-1,2*dy/3,2*dy/3,bp,cs) > 1
2673 && num_cross( 0,dx/2,2*dy/3,2*dy/3,bp,cs) > 0
2674 && num_cross(dx/2,dx-1,2*dy/3,2*dy/3,bp,cs) > 0 )
2675 if (sdata->holes.num > 0)
2676 if (sdata->holes.hole[0].y0 > dy/4) Break; // ~6
2677 // if ( num_hole( x0, x1, y0+dy/4, y1, box1->p,cs,NULL) > 0 ) Break; // ~6
2679 if( num_cross(0,dx-1,3*dy/4, 3*dy/4, bp,cs) >= 2
2680 && num_cross(0,dx-1,3*dy/4-1,3*dy/4-1,bp,cs) >= 2 ){
2681 ad=99*ad/100; /* italic t ? */
2682 if (loop(bp,dx/2 ,dy-1,dy,cs,0,UP)>dy/4) Break; // ~h
2683 if (loop(bp,dx/2+1,dy-1,dy,cs,0,UP)>dy/4) Break; // ~h
2686 x= loop(bp,dx-1,dy/2,dx,cs,0,LE);
2687 i= loop(bp,dx-1,dy/8,dx,cs,0,LE);
2688 if (i>x && loop(bp,dx-x,0,dy,cs,0,DO)>=dy/2) ad=90*ad/100; /* ~\ */
2690 x= loop(bp,0, 0,dx,cs,0,RI);
2691 i= loop(bp,0, 1,dx,cs,0,RI); if (i<x) x=i;
2692 i= loop(bp,0,dy/4,dx,cs,0,RI);
2693 if (i-x>1) Break; // l
2695 // this happens quite often, do not be to strong
2696 if (!box1->m2) ad=99*ad/100;
2698 if (!hchar) ad=99*ad/100; /* some times t is not long enough */
2699 if( y0>=box1->m2-(box1->m2-box1->m1)/4 ) ad=99*ad/100; /* to short */
2700 if( y0>=box1->m2 ) ad=99*ad/100; /* to short */
2703 if (sdata->holes.num > 0) ad=95*ad/100;
2704 if (gchar) ad=99*ad/100;
2705 if (box1->dots) ad=90*ad/100;
2712 static wchar_t ocr0_sS(ocr0_shared_t *sdata){
2713 struct box *box1=sdata->box1;
2715 int d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
2716 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2717 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2721 // --- test sS near 5 ---------------------------------------------------
2722 for(ad=d=100;dx>2 && dy>3;){ // min 3x4 (4x6 font)
2723 DBG( wchar_t c_ask='s'; )
2724 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2725 if( num_cross( dx/2, dx/2,0,dy-1,bp,cs)!=3
2726 && num_cross(5*dx/8,3*dx/8,0,dy-1,bp,cs)!=3
2728 if( num_cross(0,dx-1,dy/2 ,dy/2 ,bp,cs)!=1
2729 && num_cross(0,dx-1,dy/2-1,dy/2-1,bp,cs)!=1 ) Break;
2730 // get the upper and lower hole koords
2732 x =loop(bp,0,y,dx,cs,0,RI); if(x>3*dx/8) Break; /* slanted too */
2733 x +=loop(bp,x,y,dx,cs,1,RI); if(x>5*dx/8) Break; /* fat too */
2734 i1 =loop(bp,x,y,dx,cs,0,RI); i1=(i1+2*x)/2; // upper center x
2736 x =loop(bp,dx-1 ,y,dx,cs,0,LE); if(x>dx/4) Break;
2737 x +=loop(bp,dx-1-x,y,dx,cs,1,LE); if(dx>5 && dy>7 && x>dx/2) Break;
2738 if (x>3*dx/4) Break; if(x>dx/2) { ad=98*ad/100; MSG({})}
2739 i2 =loop(bp,dx-1-x,y,dx,cs,0,LE); i2=dx-1-(i2+2*x)/2; // upper center x
2740 for( y=dy/4;y<dy/2;y++ ) // Mai00 ~3
2741 if( get_bw(0,i1,y,y,bp,cs,1) != 1 ) break;
2743 y=dy/2-loop(bp,dx-1,dy/2,dy/2,cs,1,UP);
2744 // if( !joined(bp,i1,dy/4,dx-1,y,cs) ){
2745 // break; // sometimes thick small fonts have no gap
2747 for(y=dy/4;y<dy/2;y++){
2748 x=loop(bp,dx-1,y,dx,cs,0,LE);if(x>dx/8) break;
2750 if(y==dy/2) Break; // Mai00
2752 y=dy/2+loop(bp,0,dy/2,dy/2,cs,1,DO);
2753 if( !joined(bp,0,y,i2,11*dy/16,cs) ) Break;
2755 if (sdata->holes.num > 0)
2756 if (sdata->holes.hole[0].y0 > dy/4) Break; // ???
2757 // if( num_hole( x0, x1, y0+dy/4, y1, box1->p,cs,NULL) > 0 ) Break;
2759 i1=loop(bp,dx-1,dy-1,dx,cs,0,LE);
2760 i2=loop(bp,dx-1,dy-2,dx,cs,0,LE);
2761 if (i2-i1 >= dx/4) Break; // ~{ 5x7font
2763 i1=loop(bp, 0, 0,dx,cs,0,RI);
2764 i2=loop(bp, 0, 1,dx,cs,0,RI);
2765 if (i2-i1 >= dx/4) Break; // ~} 5x7font
2767 // sS5 \sl z left upper v-bow ?
2769 i1=loop(bp, 0,dy/2,dx,cs,0,RI);
2770 i1=loop(bp, i1,dy/2,dx,cs,1,RI);
2771 if (4*i1>=3*dx) ad=97*ad/100; // ~5 7-segment
2773 i1=loop(bp,0, dy/16,dx,cs,0,RI);
2774 i2=loop(bp,0,4*dy/16,dx,cs,0,RI);
2775 i3=loop(bp,0,7*dy/16,dx,cs,0,RI);
2776 if( 2*i2+dx/32 >= i1+i3 ){
2777 if( 2*i2+dx/32 > i1+i3 || dx>9 ) Break;
2779 i1+=loop(bp,i1, dy/16,dx,cs,1,RI);
2780 i2+=loop(bp,i2,4*dy/16,dx,cs,1,RI);
2781 i3+=loop(bp,i3,7*dy/16,dx,cs,1,RI);
2782 if( 2*i2+dx/32 >= i1+i3 ) Break;
2785 for(y=7*dy/16;y<5*dy/8;y++){
2786 if( num_cross( 0,dx-1,y ,y ,bp,cs)==2 )
2787 if( num_cross( 0,dx-1,y+1,y+1,bp,cs)==1 )
2788 if( num_cross( 0,dx/4,y,y,bp,cs)==1 ) break; // ~5
2789 } if(y<5*dy/8) Break; // v0.2.4a5
2790 if ( loop(bp, dx-1,dy-2-dy/32,dx,cs,0,LE)
2791 > loop(bp, 0, 1+dy/32,dx,cs,0,RI) + dx/4 ) Break; // ~5 Dec00
2793 if (gchar) { ad=98*ad/100; MSG({}) }
2794 if( hchar ){ // S but 5 is very similar! check it
2796 if ( loop(bp, dx-1,dy-1-dy/32,dx,cs,0,LE)
2797 > loop(bp, 0, 0+dy/32,dx,cs,0,RI) ) ad=99*ad/100; // ~5
2798 if ( loop(bp, 0,dy-1-dy/32,dx,cs,0,RI)
2799 > loop(bp, dx-1, 0+dy/32,dx,cs,0,LE) ) ad=99*ad/100; // ~5
2807 static wchar_t ocr0_gG(ocr0_shared_t *sdata){
2808 struct box *box1=sdata->box1;
2810 int i,j,d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
2811 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
2812 int dx=x1-x0+1,dy=y1-y0+1, /* size */
2815 // --- test g ---------------------------------------------------
2816 /* some g's have crotchet at upper right end, so hchar can be set */
2818 for(ad=d=100;dx>2 && dy>4;){ // min 3x5
2819 DBG( wchar_t c_ask='g'; )
2820 if (sdata->holes.num > 3) Break; /* tolerant against a tiny hole */
2821 if( get_bw(x0+dx/2, x0+dx/2, y1-dy/2, y1,box1->p,cs,1) != 1 ) Break;
2822 if( get_bw(x1-dx/4, x1 , y1-dy/4, y1,box1->p,cs,1) != 1 ) Break; // ~p
2823 if( get_bw(x0+dx/2, x0+dx/2, y0, y0+dy/2,box1->p,cs,1) != 1 ) Break;
2825 if( num_cross(x0+dx/2, x0+dx/2, y0, y1, box1->p,cs) < 3 )
2826 if( num_cross(x1-dx/2, x1-dx/2, y0, y1, box1->p,cs) < 3 ) Break;
2827 if (sdata->holes.num < 1) Break;
2828 for (i=0;i<sdata->holes.num;i++){
2829 if (sdata->holes.hole[i].y1 < 5*dy/8+1) break;
2830 } if (i==sdata->holes.num) Break; // no upper hole found
2831 // if( num_hole ( x0, x1, y0, y0+5*dy/8, box1->p,cs,NULL) != 1 ) Break;
2832 for(y=dy/4;y<dy;y++) if( num_cross(0,dx-1,y,y,bp,cs)==2 ) break;
2833 if( y==dy ) Break; // ~q
2834 if( get_bw(0,dx/2,7*dy/8,7*dy/8,bp,cs,1) != 1 ) Break; // ~q
2835 y =loop(bp,dx/16,0,dy,cs,0,DO); if(y<=dy/8)
2836 y+=loop(bp,dx/16,y,dy,cs,1,DO); if(16*y>=15*dy) Break; // ~B
2838 if (num_cross(x1, x1, (y0+y1)/2, y1, box1->p,cs)>1) {
2840 if (num_cross(x1 , x1 , y0, (y0+y1)/2, box1->p,cs)<1 ) ad=96*ad/100;
2841 if (num_cross(x1-1, x1-1, y0, (y0+y1)/2, box1->p,cs)<1 ) ad=95*ad/100;
2843 // looking for a gap
2844 for (x=0,y=dy/4;y<dy-dy/4;y++){
2845 i=loop(bp,dx-1,y,dy,cs,0,LE); if (i>x) x=i;
2846 } // in a good font x is greater dx/2
2848 if (x<dx/2) { // bad font? or %
2849 if( num_cross(x0,x1 ,y0+dy/4,y0+dy/4,box1->p,cs) > 2
2850 || num_cross(x0,x1 ,y0+dy/8,y0+dy/8,box1->p,cs) > 2) ad=90*ad/100;
2851 if( num_cross(x0,x1+dx/4,y1-dy/4,y1-dy/4,box1->p,cs) > 2
2852 || num_cross(x0,x1+dx/4,y1-dy/8,y1-dy/8,box1->p,cs) > 2) ad=90*ad/100;
2854 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs) >2 ) ad=99*ad/100; // ~/o
2856 /* test for horizontal symmetry ~8 */
2857 for (y=0;y<dy;y++) for (x=0;x<dx/2;x++)
2858 if ((getpixel(bp,x,y)<cs)!=(getpixel(bp,dx-1-x,y)<cs)) { y=dy+1; break; }
2859 if (y==dy) Break; /* ~8 */
2861 if (box1->m4==0) ad=98*ad/100;
2862 if ( hchar) ad=96*ad/100;
2863 if (!gchar) ad=96*ad/100;
2868 // --- test rundes G ---------------------------------------------
2869 for(ad=d=100;dx>3 && dy>4;){ // min 3x4
2870 DBG( wchar_t c_ask='G'; )
2871 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
2872 if( get_bw(x0 ,x0+dx/2,y0+dy/3,y0+dy/3,box1->p,cs,1) != 1 ) Break;
2873 if( get_bw(x0+dx/2,x1-dx/4,y0 ,y0+dy/4,box1->p,cs,1) != 1 ) Break;
2874 if( get_bw(x0+dx/2,x0+dx/2,y1-dy/4,y1 ,box1->p,cs,1) != 1 ) Break;
2875 if( get_bw(x0 ,x0+dx/2,y1-dy/3,y1-dy/3,box1->p,cs,1) != 1 ) Break; // ~S
2876 for( y=y0+dy/4;y<y1-dy/3;y++ )
2877 if( get_bw(x1-dx/2,x1,y,y,box1->p,cs,1) == 0 ) break;
2878 if( y==y1-dy/3 ) Break; // no gap
2880 if( num_cross(x0+dx/2 , x0+dx/2 , y0, y, box1->p,cs) != 1
2881 || num_cross(x0+dx/2+1, x0+dx/2+1, y0, y, box1->p,cs) != 1 ) Break; // ~e
2884 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); // left bow?
2885 if( y<y0+dy/4 ) Break; // filter W
2887 x=x1; y=y1-dy/3; // upper right offen bow
2888 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,LE,ST);
2889 if( x<x1-3*dx/8 ) Break;
2890 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,LE);
2891 if( x<x0+dx/2 ){ // not sure, try again (not best)
2893 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,LE,ST);
2894 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,LE);
2895 if( x<x0+dx/2 ) Break;
2897 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,UP); // upper end right midle
2899 if( y<y0+3*dy/8 ) Break;
2900 if( y>y1-dy/4 ) Break;
2902 x=x1-dx/3;y=y1; // follow left C-bow, filter S
2903 turmite(box1->p,&x,&y,x0,x1,y0+dy/4,y1,cs,LE,UP); // w=LE b=UP
2904 if( y>y0+dy/4+1 ) Break; /* leave box below for S or on top for CG */
2905 MSG(fprintf(stderr,"xy= %d %d",x-x0,y-y0);)
2906 /* if (y<y0) y++; else x++; */ /* enter the box again */
2907 turmite(box1->p,&x,&y,x0,x1,y0 ,y1,cs,RI,UP);
2908 MSG(fprintf(stderr,"xy= %d %d",x-x0,y-y0);)
2910 if (sdata->holes.num > 0) Break;
2911 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) > 0 ) Break;
2912 if( dx>4 && dy>6){ // no (<[
2913 for(i=1,y=0;i && y<dy/3;y++)
2914 if( num_cross(0,dx-1,y,y,bp,cs) == 2 ) i=0;
2915 if( i ) ad=98*ad/100;
2916 for(i=1,y=0;i && y<dy/3;y++)
2917 if( num_cross(0,dx-1,dy-1-y,dy-1-y,bp,cs) == 2 ) i=0;
2920 for(i=1,y=dy/2;i && y<dy;y++)
2921 if( num_cross(0,dx-1,y,y,bp,cs) == 2 ) i=0;
2923 for(i=0,y=3*dy/4;y<dy;y++){
2924 x=loop(bp,0,y,dx,cs,0,RI); // Kante abfallend <=> Z
2925 if( x<i-dx/20 ) break;
2929 // only check the middle!
2930 for(i=0,i1=y=dy/4;y<dy-dy/4;y++){ // look for horizontal line
2931 x=loop(bp,dx-1 ,y,dx/4,cs,0,LE);
2932 x=loop(bp,dx-1-x,y,dx/2,cs,1,LE); if(x>i){ i=x;i1=y; }
2933 } if( i1<=dy/4 || i1>=dy-dy/4 ) Break; // around the middle ?
2934 // check from above for gap and left vertical line (~S)
2935 x =loop(bp,0,i1,dx ,cs,0,RI);
2936 x+=loop(bp,x,i1,dx-x,cs,1,RI); // left vertical bow
2937 x+=loop(bp,x,i1,dx-x,cs,0,RI); if (x>=dx) ad=90*ad/100;
2938 MSG(fprintf(stderr,"h-bar y dx %d %d ad= %d",i1,i,ad);)
2940 i=1; // Mar06: adapted to 4x6 font
2941 for(x=dx/2;x<dx-1 && i;x++) // look for @@ (instead +1 use +delta?)
2942 for(y=dy/2;y<dy-1 && i;y++){ // .@
2943 if( getpixel(bp,x ,y )>=cs
2944 && getpixel(bp,x+1,y )< cs
2945 && getpixel(bp,x+1,y-1)< cs
2946 && getpixel(bp,x ,y-1)< cs ) { i=0;break; }
2948 if(i) ad=95*ad/100; // ~C
2949 if(!hchar) ad=98*ad/100;
2950 if( gchar) ad=98*ad/100;
2955 // --- test \it g like 9 ----------------------------------------------
2956 for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx
2957 DBG( wchar_t c_ask='g'; )
2958 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
2959 if( num_cross(x0+dx/2,x0+dx/2,y0,y1,box1->p,cs) != 3 // pre select
2960 && num_cross(x0+dx/4,x1-dx/4,y0,y1,box1->p,cs) != 3 ) Break;
2961 for( x=0,i=y=y0+dy/2;y<=y1-3*dy/16;y++){ // suche kerbe
2962 j=loop(box1->p,x0,y,dx,cs,0,RI);
2963 if( j>2 && j>dx/4 && y<y1-3 && j<dx/2 ) // long bow
2964 j+=loop(box1->p,x0+j-2,y+1,dx,cs,0,RI)-2;
2965 if( j>x ) { x=j; i=y; }
2967 if( x<4*dx/8 ) Break;
2968 if( num_cross(x0+dx/2,x1,i ,y1,box1->p,cs) != 1
2969 && num_cross(x0+dx/2,x1,i+1,y1,box1->p,cs) != 1 ) Break;
2970 if( num_hole(x0,x1,y0,i+1,box1->p,cs,NULL)!=1 ) Break;
2971 if( num_hole(x0,x1,i-1,y1,box1->p,cs,NULL)!=0 ) Break;
2972 if( loop(box1->p,x0,y1 ,dy,cs,0,RI)>dx/3 &&
2973 loop(box1->p,x0,y1-1,dy,cs,0,RI)>dx/3) Break; // no q
2974 for( x=0,i=y=y0+dy/3;y<=y1-dy/3;y++){ // suche kerbe
2975 j=loop(box1->p,x1,y,dx,cs,0,LE);
2976 if( j>x ) { x=j; i=y; }
2977 } if( x>dx/2 ) Break; // no g
2978 i1=loop(bp,dx-1,dy/8 ,dx,cs,0,LE); if(i1>dx/2) Break;
2979 i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE);
2980 i2=loop(bp,dx-1,dy/2 ,dx,cs,0,LE); if(i1+i3<2*i2-dx/8) Break; // konvex
2981 i1=loop(bp,dx-1,dy/4 ,dx,cs,0,LE); if(i1>dx/2) Break;
2982 i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE);
2983 for(y=dy/4;y<dy-1-dy/4;y++){
2984 i2=loop(bp,dx-1,y,dx,cs,0,LE);
2985 if(i1+i3-2*i2<-1-dx/16) break; // konvex from right ~g ~3
2986 } if(y<dy-1-dy/4) Break;
2987 x=loop(bp,dx -1,6*dy/8,dx,cs,0,LE); if(x>0){ x--; // robust
2988 y=loop(bp,dx-x-1, dy-1,dy,cs,0,UP);
2989 if(y<dy/8) Break; // ~q (serif!)
2992 if( num_cross(x0,x1 ,y0+dy/4,y0+dy/4,box1->p,cs) > 2) ad=90*ad/100;
2993 if( num_cross(x0,x1+dx/4,y1-dy/4,y1-dy/4,box1->p,cs) > 2
2994 || num_cross(x0,x1+dx/4,y1-dy/8,y1-dy/8,box1->p,cs) > 2) ad=90*ad/100;
2996 if (box1->m4==0) ad=98*ad/100;
2997 if ( hchar) ad=96*ad/100;
2998 if (!gchar) ad=96*ad/100;
2999 if (ad>99) ad=99; // never be sure to have a 9
3006 // rewritten for vector usage v0.41
3007 static wchar_t ocr0_xX(ocr0_shared_t *sdata){
3008 struct box *box1=sdata->box1;
3009 // pix *bp=sdata->bp; // obsolete
3010 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
3011 x0=box1->x0, x1=box1->x1, y0=box1->y0, y1=box1->y1; // ,cs=sdata->cs;
3012 int dx=x1-x0+1, dy=y1-y0+1, /* size */
3013 (*aa)[4]=sdata->aa, /* the for line ends, (x,y,dist^2,vector_idx) */
3017 // --- test xX ---------------------------------------------------
3018 // rewritten for vectors 0.41
3019 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
3020 int ld, i1, i2, i3, i4; // lien derivation, 4 inner edges
3021 DBG( wchar_t c_ask='x'; )
3022 if (sdata->holes.num > 0) Break; /* # */
3023 /* half distance to the center */
3025 /* now we check for the 4 ends of the x */
3026 if (aa[0][2]>d) Break;
3027 if (aa[1][2]>d) Break;
3028 if (aa[2][2]>d) Break;
3029 if (aa[3][2]>d) Break;
3030 if (aa[3][0]-aa[0][0]<dx/2) Break;
3031 if (aa[2][0]-aa[1][0]<dx/2) Break;
3032 if (aa[1][1]-aa[0][1]<dy/2) Break;
3033 if (aa[2][1]-aa[3][1]<dy/2) Break;
3034 /* searching for 4 notches between neighbouring ends */
3036 /* only left side */
3037 for (j=i=aa[0][3];i!=aa[1][3];i=(i+1)%box1->num_frame_vectors[0]) {
3038 if (box1->frame_vector[i][0]
3039 >=box1->frame_vector[j][0]) j=i; /* notice most right vector */
3041 /* calculate the distance to the center */
3042 x=box1->frame_vector[j][0];
3043 y=box1->frame_vector[j][1]; i1=j;
3044 if (abs(aa[0][0]+aa[1][0]+aa[2][0]+aa[3][0]-4*x)>(dx+2)) Break;
3045 if (abs(aa[0][1]+aa[1][1]+aa[2][1]+aa[3][1]-4*y)>(dy+2)) Break;
3046 if ( aa[0][0]+aa[1][0]-2*x>=0) Break;
3047 if ( aa[1][0] >= x ) Break;
3048 if ( aa[0][0] > x ) Break;
3049 if ( aa[0][0] >= x ) ad=99*ad/100;
3050 if (x-x0<dx/8) Break;
3051 if (x-x0<dx/4) ad=99*ad/100;
3052 /* check if upper left and center point are joined directly */
3053 ld=line_deviation(box1, aa[0][3], j);
3054 MSG(fprintf(stderr," 0-X %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3055 if (ld >2*sq(1024/4)) Break;
3056 /* check if lower left and center point are joined directly */
3057 ld=line_deviation(box1, j, aa[1][3]);
3058 MSG(fprintf(stderr," X-1 %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3059 if (ld >2*sq(1024/4)) Break;
3061 /* only lower side */
3062 for (j=i=aa[1][3];i!=aa[2][3];i=(i+1)%box1->num_frame_vectors[0]) {
3063 if (box1->frame_vector[i][1]
3064 <=box1->frame_vector[j][1]) j=i; /* notice most upper vector */
3066 /* calculate the distance to the center */
3067 x=box1->frame_vector[j][0];
3068 y=box1->frame_vector[j][1]; i2=j;
3069 if (abs(aa[0][0]+aa[1][0]+aa[2][0]+aa[3][0]-4*x)>(dx+2)) Break;
3070 if (abs(aa[0][1]+aa[1][1]+aa[2][1]+aa[3][1]-4*y)>(dy+2)) Break;
3071 if ( aa[1][1]+aa[2][1]-2*y<=0) Break;
3072 /* check if lower left and center point are joined directly */
3073 ld=line_deviation(box1, aa[1][3], j);
3074 MSG(fprintf(stderr," 1-X %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3075 if (ld >2*sq(1024/4)) Break;
3076 /* check if lower right and center point are joined directly */
3077 ld=line_deviation(box1, j, aa[2][3]);
3078 MSG(fprintf(stderr," X-2 %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3079 if (ld >2*sq(1024/4)) Break;
3081 /* only right side */
3082 for (j=i=aa[2][3];i!=aa[3][3];i=(i+1)%box1->num_frame_vectors[0]) {
3083 if (box1->frame_vector[i][0]
3084 <=box1->frame_vector[j][0]) j=i; /* notice most left vector */
3086 /* calculate the distance to the center */
3087 x=box1->frame_vector[j][0];
3088 y=box1->frame_vector[j][1]; i3=j;
3089 if (abs(aa[0][0]+aa[1][0]+aa[2][0]+aa[3][0]-4*x)>(dx+2)) Break;
3090 if (abs(aa[0][1]+aa[1][1]+aa[2][1]+aa[3][1]-4*y)>(dy+2)) Break;
3091 if ( aa[2][0]+aa[3][0]-2*x<=0) Break;
3092 if ( aa[3][0] <= x ) Break;
3093 if ( aa[2][0] < x ) Break;
3094 if ( aa[2][0] <= x ) ad=99*ad/100;
3095 if (dx-(x-x0)<dx/8) Break;
3096 if (dx-(x-x0)<dx/4) ad=99*ad/100;
3097 /* check if lower right and center point are joined directly */
3098 ld=line_deviation(box1, aa[2][3], j);
3099 MSG(fprintf(stderr," 2-X %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3100 if (ld >2*sq(1024/4)) Break;
3101 /* check if upper right and center point are joined directly */
3102 ld=line_deviation(box1, j, aa[3][3]);
3103 MSG(fprintf(stderr," X-3 %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3104 if (ld >2*sq(1024/4)) Break;
3106 /* only upper side */
3107 for (j=i=aa[3][3];i!=aa[0][3];i=(i+1)%box1->num_frame_vectors[0]) {
3108 if (box1->frame_vector[i][1]
3109 >=box1->frame_vector[j][1]) j=i; /* notice lowest vector */
3111 /* calculate the distance to the center */
3112 x=box1->frame_vector[j][0];
3113 y=box1->frame_vector[j][1]; i4=j;
3114 if (abs(aa[0][0]+aa[1][0]+aa[2][0]+aa[3][0]-4*x)>(dx+2)) Break;
3115 if (abs(aa[0][1]+aa[1][1]+aa[2][1]+aa[3][1]-4*y)>(dy+2)) Break;
3116 if ( aa[3][1]+aa[0][1]-2*y>=0) Break;
3117 /* check if upper left and center point are joined directly */
3118 ld=line_deviation(box1, aa[3][3], j);
3119 MSG(fprintf(stderr," 3-X %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3120 if (ld >2*sq(1024/4)) Break;
3121 /* check if lower left and center point are joined directly */
3122 ld=line_deviation(box1, j, aa[0][3]);
3123 MSG(fprintf(stderr," X-0 %d %d dist= %d/%d",x-x0,y-y0,ld,2*sq(1024/4));)
3124 if (ld >2*sq(1024/4)) Break;
3126 // center crossing of diagonal lines is small?
3127 if (box1->frame_vector[i3][0] - box1->frame_vector[i1][0] > dx/2) Break;
3129 if (gchar) ad=99*ad/100;
3130 bc='x'; if(hchar) bc='X';
3134 // --- test \it x ---------------------------------------------------
3136 for(ad=d=99;dx>4 && dy>4;){ // min 3x4
3137 DBG( wchar_t c_ask='x'; )
3138 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3139 if( get_bw(x0,x0+dx/4,y0+dy/2,y0+dy/2,box1->p,cs,1) != 0 ) Break;
3140 if( get_bw(x1-dx/4,x1,y0+dy/2,y0+dy/2,box1->p,cs,1) != 0 ) Break;
3141 if( num_cross(x0+dx/4,x1-dx/4,y0+dy/2,y0+dy/2, box1->p,cs) != 1 ) Break;
3142 if( num_cross(x0,x1,y0+dy/4,y0+dy/4, box1->p,cs) != 3
3143 && num_cross(x0,x1,y0+dy/8,y0+dy/8, box1->p,cs) < 3 ) Break;
3144 if( num_cross(x0,x1,y1-dy/4,y1-dy/4, box1->p,cs) != 3
3145 && num_cross(x0,x1,y1-dy/8,y1-dy/8, box1->p,cs) < 3 ) Break;
3146 if( gchar ) ad=97*ad/100;
3147 if( hchar ) ad=96*ad/100;
3156 static wchar_t ocr0_yY(ocr0_shared_t *sdata){
3157 struct box *box1=sdata->box1;
3159 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
3160 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
3161 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3162 ad,xa,ya,xb,yb,xc,yc,xd,yd; /* tmp-vars */
3165 // --- test italic yY --------------------------------------------
3166 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
3167 DBG( wchar_t c_ask='y'; )
3168 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3169 if (sdata->holes.num > 0) ad=97*ad/100;
3170 if( num_cross(0,dx-1,dy/8,dy/8,bp,cs) < 2
3171 && num_cross(0,dx-1, 1, 1,bp,cs) < 2 ) Break;
3172 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs) != 1
3173 && num_cross(0,dx-1,dy-2,dy-2,bp,cs) != 1 ) Break;
3174 if( num_cross(dx-1,dx-1,0,dy-1,bp,cs) != 1
3175 && num_cross(dx-2,dx-2,0,dy-1,bp,cs) != 1 ) Break;
3176 if( num_cross(dx/3,dx/3,dy/4,dy-1,bp,cs) != 2
3177 && num_cross(dx/2,dx/2,dy/4,dy-1,bp,cs) != 2 ) Break;
3178 for(yc=y=0,xc=x=dx/4;x<dx-dx/4;x++){ // search deepest point
3179 i=loop(bp,x,0,dy,cs,0,DO); if(i>y){ yc=y=i;xc=x; }
3180 } if( y>12*dy/16 || y<3*dy/8 ) Break;
3181 ya=dy/8; xa=xc-loop(bp,xc,ya,dx,cs,0,LE); if(xa< 0) Break;
3182 yb=dy/8; xb=xc+loop(bp,xc,yb,dx,cs,0,RI); if(xb>=dx) Break;
3183 for(y=dy/8;y<yc-dy/8;y++){
3184 if( num_cross(xc,dx-1,y,y,bp,cs) != 1 ) break;
3185 if( num_cross(0 ,xc ,y,y,bp,cs) < 1 ) break;
3186 } if(y<yc-dy/8) Break;
3187 yd=dy-1-dy/8;xd=dx-1-loop(bp,dx-1,yd,dx,cs,0,LE);
3188 g_debug(fprintf(stderr," debug_yY: \n"
3193 g_debug(fprintf(stderr,"a-e: %d %d %d %d %d %d %d %d",
3194 xa,ya,xb,yb,xc,yc,xd,yd);)
3195 if(xd>6*dx/8) ad=99*ad/100; // why this???
3196 if (loop(bp,dx-1,dy-1,dx,cs,0,LE)<1) Break;
3197 // printf(" abcd=%d %d %d %d %d %d %d %d -",xa,ya,xb,yb,xc,yc,xd,yd);
3198 if( get_line2(xb,yb,xd,yd,bp,cs,100)<95 ) Break;
3199 // if( get_line2(xc,yc,xd,yd,bp,cs,100)<95 ) Break;
3202 if(gchar && !hchar) bc='y'; else
3203 if(hchar && (!gchar || dy<14)) bc='Y'; else ad=98*ad/100; // SMALL-CAPS ???
3207 // --- test yY ---------------------------------------------------
3208 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
3209 DBG( wchar_t c_ask='y'; )
3210 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3211 if( get_bw(x0,x0,y1-dy/8,y1,box1->p,cs,1) == 1 ) {
3212 if( get_bw(x0,x0+4*dx/8,y0+dy/8,y0+dy/8,box1->p,cs,1) != 1 ) Break;
3214 if( get_bw(x0,x0+3*dx/8,y0+dy/8,y0+dy/8,box1->p,cs,1) != 1 ) Break;
3216 if( num_cross(0,dx-1,dy/8,dy/8,bp,cs) != 2
3217 && num_cross(0,dx-1, 1, 1,bp,cs) != 2 ) Break;
3218 if( num_cross(dx/2,dx/2,0, 1,bp,cs) != 0 ) Break;
3219 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs) != 1
3220 && num_cross(0,dx-1,dy-2,dy-2,bp,cs) != 1 ) Break;
3221 if( num_cross(dx-1,dx-1,0,dy-1,bp,cs) != 1
3222 && num_cross(dx-2,dx-2,0,dy-1,bp,cs) != 1
3223 && num_cross(dx-dx/8-1,dx-dx/8-1,0,dy-1,bp,cs) != 1 ) Break;
3224 if( loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)+dx/8+1 // Jul00
3225 < loop(bp, 0,dy-1-dy/8,dx,cs,0,RI) ) Break;
3226 for(y=0,x=dx/4;x<dx-dx/4;x++){ // search lowest point
3227 i=loop(bp,x,0,dy,cs,0,DO); if(i>y) y=i;
3228 } if( y>10*dy/16 || y<2*dy/8 ) Break;
3229 for(xc=xb=xa=dx,yc=yb=ya=y=0;y<dy/4;y++){
3230 x =loop(bp, 0 , y,dx,cs,0,RI); if(x<xa){ xa=x;ya=y; }
3231 x =loop(bp,dx-1 , y,dx,cs,0,LE); if(x<xb){ xb=x;yb=y; }
3234 for(i=dx,yc=y=dy/4;y<3*dy/4;y++){
3235 if( num_cross(0,dx-1,y,y,bp,cs) < 2 ) break;
3236 x =loop(bp,dx-1 ,y,dx,cs,0,LE);
3237 x+=loop(bp,dx-1-x,y,dx,cs,1,LE);
3238 j =loop(bp,dx-1-x,y,dx,cs,0,LE); if(j<=i){ i=j;yc=y;xc=dx-1-x-j/2; }
3240 yc+=loop(bp,xc,yc,i,cs,1,DO)/2;
3241 xa+= loop(bp,xa ,ya,dx,cs,1,RI)/2;
3242 xb=dx-1-loop(bp,dx-1,yb,dx,cs,1,LE)/2;
3243 yd=dy-1-dy/8;xd=dx-1-loop(bp,dx-1,yd,dx,cs,0,LE); if(xd>6*dx/8) Break;
3244 /* check for serife at lower end */
3245 for (i=0,x=dx-1;i<dy/4;i++) {
3246 j=loop(bp,dx-1,dy-1-i,dx,cs,0,LE);
3247 if (j>x+dx/16+1) break; /* detect serif */
3249 } if (i<dy/4) xd-=loop(bp,xd,yd,dx,cs,1,LE)/2;
3250 MSG( fprintf(stderr," debug_yY: \n"
3255 MSG(fprintf(stderr,"a-e: %d %d %d %d %d %d %d %d",
3256 xa,ya,xb,yb,xc,yc,xd,yd);)
3257 // check upper left line
3258 if( get_line2(xa,ya,xc ,yc,bp,cs,100)<95
3259 && get_line2(xa,ya,xc-1,yc,bp,cs,100)<95 ) Break;
3260 // check upper right line
3261 if( get_line2(xb,yb,xc ,yc,bp,cs,100)<95
3262 && get_line2(xb,yb,xc-1,yc,bp,cs,100)<95 ) {
3263 // Times-Italic y ???
3264 xb+=loop(bp,xb,yb,dx/4,cs,1,RI)-1;
3265 yb+=loop(bp,xb,yb,dy/8,cs,1,DO)-1;
3266 if( get_line2(xb,yb,xc ,yc,bp,cs,100)<95 ) Break;
3268 if( get_line2(xc,yc,xd,yd,bp,cs,100)<95 ) Break;
3270 // decission between V and Y is sometimes very difficult
3271 // hope that the following code is the ultimate solution
3272 if( yc>=5*dy/8 && !gchar)
3273 if( get_line2(xa,ya,xd ,yd,bp,cs,100)>95 )
3274 if( get_line2(xb,yb,xd ,yd,bp,cs,100)>95 )
3275 { if (dx>4) { Break; } else ad=ad*98/100; } // ~V
3276 xa=loop(bp,0,dy/8,dx,cs,0,RI);
3277 xb=loop(bp,0,dy/2,dx,cs,0,RI);
3278 xc=loop(bp,0,dy-1,dx,cs,0,RI);
3279 if( 2*xb< xa+xc ) ad=98*ad/100; // ~V
3280 if( 2*xb<=xa+xc ) ad=98*ad/100;
3281 if( 2*xb<=xa+xc+1 ) ad=98*ad/100;
3284 if ((!gchar) && (!hchar)) ad=98*ad/100;
3285 if(y0<box1->m2-(box1->m2-box1->m1)/4)
3286 { bc='Y'; if(gchar) ad=98*ad/100; }
3294 static wchar_t ocr0_zZ(ocr0_shared_t *sdata){
3295 struct box *box1=sdata->box1;
3296 int i1,i2,i3,i4,i5,dbg[9],
3297 d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
3298 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
3299 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3300 (*aa)[4]=sdata->aa, /* the for line ends, (x,y,dist^2,vector_idx) */
3304 // --- test zZ -------
3305 for(ad=d=100;dx>3 && dy>3;){ // dy>dx
3306 DBG( wchar_t c_ask='z'; ) /* for debugging purpose */
3307 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3308 if (sdata->holes.num > 0) ad=98*ad/100; /* # */
3309 /* half distance to the center */
3311 /* now we check for the 4 edges of the z */
3312 if (aa[0][2]>d) Break;
3313 if (aa[1][2]>d) Break;
3314 if (aa[2][2]>d) Break;
3315 if (aa[3][2]>d) Break;
3316 if (aa[3][0]-aa[0][0]<dx/2) Break;
3317 if (aa[2][0]-aa[1][0]<dx/2) Break;
3318 if (aa[1][1]-aa[0][1]<dy/2) Break;
3319 if (aa[2][1]-aa[3][1]<dy/2) Break;
3320 if (aa[3][0]-aa[0][0]<4-1) Break; /* to small to hold a z */
3321 if (aa[2][0]-aa[1][0]<4-1) Break; /* to small */
3322 if (aa[3][1]-y0>dy/8) ad=99*ad/100;
3323 if (aa[0][1]-y0>dy/8) ad=99*ad/100;
3324 if (2*dx<dy) ad=99*ad/100;
3326 fprintf(stderr,"xy= %d %d aa %d %d %d %d %d %d %d %d", \
3327 x0,y0,aa[0][0]-x0,aa[0][1]-y0,aa[1][0]-x0,aa[1][1]-y0,\
3328 aa[2][0]-x0,aa[2][1]-y0,aa[3][0]-x0,aa[3][1]-y0);)
3329 /* upper and lower horizontal line */
3330 d=line_deviation(box1, aa[3][3], aa[0][3]); if (d>2*sq(1024/4)) Break;
3331 ad=(100-(d-sq(1024)/2)/sq(1024)/4)*ad/100;
3332 d=line_deviation(box1, aa[1][3], aa[2][3]); if (d>2*sq(1024/4)) Break;
3334 /* search uppermost right > */
3335 i1=nearest_frame_vector(box1,aa[0][3],aa[1][3], x1, y0);
3336 x=box1->frame_vector[i1][0];
3337 y=box1->frame_vector[i1][1];
3338 if (y-y0 > 5*dy/8) Break;
3339 if (x-x0 < 3*dx/8) Break;
3340 if (x-aa[0][0]<=dx/4) Break; // ~lI
3341 if (x-aa[0][0]<=dx/3) ad=98*ad/100; // ~lI
3342 if (x-aa[0][0]<=dx/2) ad=99*ad/100; // ~lI
3343 /* search most right > ~2 */
3344 i3=nearest_frame_vector(box1,aa[0][3],aa[1][3], x1+2*dx, (y0+y1)/2);
3345 MSG(fprintf(stderr,"xy= %d %d %d %d %d %d",x0,y0,x-x0,y-y0,box1->frame_vector[i3][0]-x0,box1->frame_vector[i3][1]-y0);)
3346 if ( box1->frame_vector[i3][1]-y0> dy/4
3347 && box1->frame_vector[i3][0]-x>=0) Break;
3348 if ( box1->frame_vector[i3][1]-y> dy/8
3349 && box1->frame_vector[i3][0]-x>=-dx/8) ad=98*ad/100;
3350 if ( box1->frame_vector[i3][1]-y> dy/8
3351 && box1->frame_vector[i3][0]-x>= 0) ad=97*ad/100;
3352 if (box1->frame_vector[i3][0]-aa[0][0]
3353 < aa[3][0]-box1->frame_vector[i3][0]) break; // ~lI
3354 if (box1->frame_vector[i3][0]-aa[0][0]
3355 <(aa[3][0]-box1->frame_vector[i3][0])*2) ad=98*ad/100; // ~lI
3356 /* better test for a bow or peaked angle */
3357 /* upper part of a 2, on a Z a and b should be at c
3358 .....$@@@@@@a...c. o1 (o1-a)=(dx+5)^2 =dx^2+10*dx+25
3359 ...$$@@@@@@@@@.... (o1-b)=(dx+1)^2+4^2=dx^2+ 2*dx+18
3373 i4=nearest_frame_vector(box1,aa[2][3],aa[0][3], x1+dx, y0);
3374 i5=nearest_frame_vector(box1,aa[2][3],aa[0][3], x1, y0-dx);
3375 d=sq(box1->frame_vector[i5][0]-box1->frame_vector[i4][0])
3376 +sq(box1->frame_vector[i5][1]-box1->frame_vector[i4][1]);
3377 if (d>2*sq(dx/8+1)) break;
3379 /* check if upper left and upper right point are joined directly */
3380 dbg[0]=d=line_deviation(box1, aa[0][3], i1); if (d >2*sq(1024/4)) Break;
3381 /* check if lower right and upper left point are joined directly */
3382 dbg[1]=d=line_deviation(box1, i1, aa[1][3]); if (d >2*sq(1024/4)) Break;
3384 /* search lowest left < */
3385 i2=nearest_frame_vector(box1,aa[2][3],aa[3][3], x0, y1);
3386 x=box1->frame_vector[i2][0];
3387 y=box1->frame_vector[i2][1];
3388 if (y-y0 < 3*dy/8) Break;
3389 if (x-x0 > 5*dx/8) Break;
3390 if (aa[2][0]-x<=dx/4) Break; // ~lI
3391 if (aa[2][0]-x<=dx/3) ad=98*ad/100; // ~lI
3392 if (aa[2][0]-x<=dx/2) ad=99*ad/100; // ~lI
3393 /* check if upper right and lower left point are joined directly */
3394 dbg[2]=d=line_deviation(box1,i2, aa[3][3]); if (d >2*sq(1024/4)) Break;
3395 /* check if lower left and lower right point are joined directly */
3396 dbg[3]=d=line_deviation(box1, aa[2][3],i2); if (d >2*sq(1024/4)) Break;
3398 if (box1->frame_vector[i1][0]
3399 -box1->frame_vector[i2][0]<=dx/8) Break; /* nonsignificant distance */
3401 fprintf(stderr,"^v %d %d %d %d line deviation %d %d %d %d max %d %d",\
3402 box1->frame_vector[i1][0]-x0,box1->frame_vector[i1][1]-y0,\
3403 box1->frame_vector[i2][0]-x0,box1->frame_vector[i2][1]-y0,\
3404 dbg[0],dbg[1],dbg[2],dbg[3],2*sq(1024/4),2*sq(1024));)
3405 ad=(100-(dbg[0]-sq(1024)/2)/sq(1024)/4)*ad/100;
3406 ad=(100-(dbg[1]-sq(1024)/2)/sq(1024)/4)*ad/100;
3407 ad=(100-(dbg[2]-sq(1024)/2)/sq(1024)/4)*ad/100;
3408 ad=(100-(dbg[3]-sq(1024)/2)/sq(1024)/4)*ad/100;
3410 if ( gchar) ad=98*ad/100;
3419 static wchar_t ocr0_wW(ocr0_shared_t *sdata){
3420 struct box *box1=sdata->box1;
3422 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,handwritten=0,
3423 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
3424 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3425 ad,ya,yb,xa,xb,xc,xd,xe,t1; /* tmp-vars */
3428 // ------- test w ~{\it w} ---------------
3429 for(ad=d=100;dx>3 && dy>3;){ // dy<=dx
3430 DBG( wchar_t c_ask='w'; )
3431 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3433 // \ xc / <=ya connected xa-xb-xc-xd-xe
3435 // get two lowest points i3,i4,ya
3439 for(y=dy/8;y< dy/2;y++) if( num_cross(0,dx-1,y,y,bp,cs)< 2 ) break;
3442 if (dx>4) { /* 4x6 is to small */
3443 for(y=dy-1-dy/16;y>3*dy/4;y--)
3444 if( num_cross(0,dx-1,y,y,bp,cs)==2 ) break;
3445 if(y==3*dy/4) Break;
3448 t1=loop(bp,0 ,dy/4,dx,cs,0,RI);
3449 t1=loop(bp,t1,dy/4,dx,cs,1,RI); // thickness of line?
3450 for(i=j=0 ;y> dy/4;y--) if( num_cross(0,dx-1,y,y,bp,cs)==4 ) i++;
3451 else if( num_cross(0,dx-1,y,y,bp,cs)>=3 ) j++;
3452 if(i+5<dy/4 && 7*t1<dy) Break; // only for large letters
3453 if(i+j==0 && (dy>6 || dx>4)) Break;
3454 if(i+j==0 && dx<=4){
3455 if (abs(loop(bp, 1,dy-1,dy,cs,0,UP)
3456 -loop(bp,dx-2,dy-1,dy,cs,0,UP))>dy/8+1) Break; // 4x6 N
3457 if ( ( loop(bp, 1, 0,dy,cs,0,DO)>=dy-2
3458 && loop(bp, 0,dy-1,dy,cs,0,UP)>0)
3459 || ( loop(bp,dx-2, 0,dy,cs,0,DO)>=dy-2
3460 && loop(bp,dx-1,dy-1,dy,cs,0,UP)>0)) Break; // 4x6 UV
3461 ad=ad*99/100; // 4x6 font
3462 MSG(fprintf(stderr,"ad=%d",ad);)
3464 if( num_cross(0,dx-1, 1, 1,bp,cs)< 2
3465 && num_cross(0,dx-1,dy/16,dy/16,bp,cs)< 2 ) Break;
3466 x =loop(bp,0 ,yb,dx,cs,0,RI);
3467 xb=loop(bp,x ,yb,dx,cs,1,RI);xb=x+xb/2; if(xb>dx/2) Break;
3468 x =loop(bp,dx-1 ,yb,dx,cs,0,LE);
3469 xd=loop(bp,dx-1-x,yb,dx,cs,1,LE);xd=dx-1-x-xd/2;if(xd<3*dx/8) Break;
3470 for(y=0,xc=x=xb+1;x<xd;x++)
3471 if((i=loop(bp,x,dy-1,dy,cs,0,UP))>y){xc=x;y=i;}
3472 if(dx>4 && !y) Break;
3474 y=loop(bp,xc,ya,dy,cs,1,UP);if(y)y--;
3475 if (dy>6 || dx>4) { // ~4x6 font
3476 if( num_cross(0 ,xc ,ya-y ,ya-y ,bp,cs)!= 2
3477 && num_cross(0 ,xc ,ya-y/2,ya-y/2,bp,cs)!= 2 ) Break;
3478 if( num_cross(xc,dx-1,ya-y ,ya-y ,bp,cs)!= 2
3479 && num_cross(xc,dx-1,ya-y/2,ya-y/2,bp,cs)!= 2 ) Break;
3482 x =loop(bp,0 ,1 ,dx,cs,0,RI);
3483 xa=loop(bp,x ,1 ,dx,cs,1,RI);
3484 if( x+xa>xb ){ // may be, here is a small but thick letter
3485 // later add some proofs
3490 x =loop(bp,dx-1 ,1 ,dx,cs,0,LE);
3491 xe=loop(bp,dx-1-x,1 ,dx,cs,1,LE);xe=dx-1-x-xe/2;
3492 MSG( fprintf(stderr,"a-e: %d %d %d %d %d %d %d %d %d %d",
3493 xa,1,xb,yb,xc,ya,xd,yb,xe,1);)
3494 if (ya<dy/2 && xc<dx/2) ad=95*ad/100; /* ~N */
3495 i= loop(bp,xa ,1 ,dx,cs,1,RI);
3496 for (x=xa;x<xa+i;x++)
3497 if( get_line2(x,1,xb,yb,bp,cs,100)>94 ) break;
3498 if (x==xa+i) Break; // no vert. line found
3499 if( get_line2(xb,yb-1,xc,ya ,bp,cs,100)<95
3500 && get_line2(xb,yb-1,xc,ya+dy/32,bp,cs,100)<95
3501 && get_line2(xb,yb-1,xc,ya+dy/16,bp,cs,100)<95 ) Break;
3502 if( get_line2(xc, ya,xd, yb,bp,cs,100)<95
3503 && get_line2(xc+1,ya,xd, yb,bp,cs,100)<95 ) Break;
3504 if( get_line2(xd,yb,xe ,1+dy/16,bp,cs,100)<95
3505 && get_line2(xd,yb,dx-1 ,1+dy/8 ,bp,cs,100)<95 // round w
3506 && get_line2(xd,yb,xe+dx/20,1+dy/16,bp,cs,100)<95 ) Break;
3507 // if( num_hole(0,dx-1,0,dy-1,bp,cs,NULL) != 0 ) Break;
3509 MSG(fprintf(stderr,"ad=%d",ad);)
3510 for(i=0,y=5*dy/8;y<dy;y++){
3511 x=loop(bp,dx-1,y,dx,cs,0,LE); if( x>i ) i=x; if( x<i-2 ) break;
3512 if (x<i) ad=98*ad/100;
3514 MSG(fprintf(stderr,"ad=%d",ad);)
3515 ac=((hchar)?'W':'w');
3516 if (gchar) ad=98*ad/100;
3520 // --- test ~w {\it w} ohmega? also handwritten -------
3522 for(ad=d=100;dx>3 && dy>3;){ // dy<=dx 4x6font (like a H with fat bar)
3523 DBG( wchar_t c_ask='w'; )
3524 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3526 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)<2 ) Break;
3527 if( num_cross(0,dx-1,dy/8,dy/8,bp,cs)<2 ) handwritten=40;
3528 if( num_cross(0,dx-1,dy/4,dy/4,bp,cs)<2 ) handwritten=80;
3529 for(i=0,y=0;y<dy-1;y++)
3530 if( num_cross(0,dx-1,y,y,bp,cs)==3 ) i++;
3531 if(i<=dy/8) Break; // three legs
3533 // \ xc / <=yb connected xa-xb-xc-xd-xe
3535 for(y=dy/2;y<dy-1-dy/8;y++)
3536 if( num_cross(0,dx-1,y,y,bp,cs)==3 ) break;
3538 x =loop(bp,0 ,yb,dx,cs,0,RI);
3539 x+=loop(bp,x ,yb,dx,cs,1,RI); if(x>dx/2) Break;
3540 xb=loop(bp,x ,yb,dx,cs,0,RI);xb=x+xb/2; if(xb>dx/2) Break;
3541 x =loop(bp,dx-1 ,yb,dx,cs,0,LE);
3542 x+=loop(bp,dx-1-x,yb,dx,cs,1,LE);
3543 xd=loop(bp,dx-1-x,yb,dx,cs,0,LE);xd=dx-1-x-xd/2;if(xd<3*dx/8) Break;
3544 if( num_cross(xb,xd,yb,yb ,bp,cs)!= 1 ) Break;
3545 if( num_cross(xb,xb,yb,dy-1,bp,cs)!= 1 ) Break;
3546 if( num_cross(xd,xd,yb,dy-1,bp,cs)!= 1 ) Break;
3547 if( num_cross(xb,xb, 0,yb ,bp,cs)!= 0 ) Break;
3548 if( num_cross(xd,xd, 0,yb ,bp,cs)!= 0 ) Break;
3549 // if( num_hole(0,dx-1,0,dy-1,bp,cs,NULL) != 0 ) Break;
3550 if (sdata->holes.num != 0) Break;
3552 for(i=0,y=3*dy/4;y<dy;y++){
3553 x=loop(bp,dx-1,y,dx,cs,0,LE); if( x>i ) i=x; if( x<i-2 ) break;
3554 } if( y<dy ) Break; // fail for overlapping neighbouring slanted chars?
3555 ac=((hchar)?'W':'w');
3556 if (gchar) ad=98*ad/100;
3563 static wchar_t ocr0_aA(ocr0_shared_t *sdata){
3564 struct box *box1=sdata->box1;
3566 int i,d,x,y,i1,i2,i3,i4,hchar=sdata->hchar,gchar=sdata->gchar,
3567 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
3568 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3569 ad,ya; /* tmp-vars */
3571 // --- test A ---------------------------------------------------
3572 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
3573 DBG( wchar_t c_ask='A'; )
3574 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
3575 // first selection (rough sieve)
3576 if( get_bw(dx/2 ,dx/2 ,dy-1-dy/8,dy-1,bp,cs,1) == 1
3577 && get_bw(dx/2-1,dx/2-1,dy-1-dy/8,dy-1,bp,cs,1) == 1 ) Break; // ~B
3578 ya=0; /* upper end, not 0 for modified A etc. */
3580 for (ya=0;ya<dy/2;ya++)
3581 if (num_cross(0,dx-1,ya,ya,bp,cs)==0) break;
3582 if (ya>=dy/2) ya=0; // already subtracted?
3583 if( num_cross(0,dx-1,ya+ 1 ,ya+ 1 ,bp,cs)!=1 // 600dpi
3584 && num_cross(0,dx-1,ya+ dy/8 ,ya+ dy/8 ,bp,cs)!=1
3585 && num_cross(0,dx-1,ya+ dy/16 ,ya+ dy/16 ,bp,cs)!=1
3586 && num_cross(0,dx-1,ya+ dy/8+1,ya+ dy/8+1,bp,cs)!=1 ) Break;
3587 if( num_cross(0,dx-1, 7*dy/8 , 7*dy/8 ,bp,cs)!=2
3588 && num_cross(0,dx-1, 7*dy/8-1, 7*dy/8-1,bp,cs)!=2 ) Break;
3589 if ( num_cross( 0,dx/8,ya+dy/8,ya+0,bp,cs)>0 ) Break; // ~R
3590 for(y=ya+dy/8;y<ya+dy/2;y++) if( num_cross(0,dx-1,y,y,bp,cs) > 1 ) break;
3591 if( y==ya+dy/2 ) Break; i1=y;
3592 if (dy>20) i1++; /* get arround some noise fat font */
3594 x =loop(bp,0,i1,dx,cs,0,RI); if(x>3*dx/4) Break;
3595 x+=loop(bp,x,i1,dx,cs,1,RI); if(x>3*dx/4) Break; i2=x;
3596 x+=loop(bp,x,i1,dx,cs,0,RI); if(x<3*dx/8) Break; i2=(x+i2)/2;
3598 y+=loop(bp,i2,y,dy,cs,1,DO);
3599 y+=loop(bp,i2,y,dy,cs,0,DO); if(y>3*dy/4) ad=ad*99/100;
3600 if (y>5*dy/6) { MSG(fprintf(stderr,"x,y,i1,i2= %d %d %d %d",x,y,i1,i2);) }
3601 if (y>5*dy/6) Break;
3603 if( sdata->holes.num != ((box1->modifier==RING_ABOVE)?2:1)
3604 || sdata->holes.hole[0].y1-ya >= dy-1-dy/4) Break;
3605 // if( num_hole ( x0, x1, y0, y1-dy/4 ,box1->p,cs,NULL) != 1 ) Break;
3608 for(x=dx/3;x<2*dx/3;x++){
3609 i4=num_cross(i2,x,y ,dy-1,bp,cs);if(i4<1 || i4>2)
3610 i4=num_cross(i2,x,y+dy/16,dy-1,bp,cs);if(i4<1 || i4>2) break;
3612 } if(i4<1 || i4>2 || i3==0){
3613 // ToDo: MSG(fprintf(stderr,"x,y,i4,i3= %d %d %d %d",x,y,i4,i3);)
3616 if( get_bw(dx-1-dx/4, dx-1, dy-1-dy/4, dy-1, bp,cs,1) != 1 ) Break;
3618 i1=loop(bp,dx-1,ya+ (dy-ya)/4,dx,cs,0,LE);
3619 i2=loop(bp,dx-1,ya+ (dy-ya)/2,dx,cs,0,LE);
3620 i3=loop(bp,dx-1,dy-1-(dy-ya)/4,dx,cs,0,LE);
3621 if( 2*i2-dx/8>i1+i3 ) ad=99*ad/100; /* 6*8 font */
3622 if( 2*i2+dx/4<i1+i3 || 2*i2-dx/4>i1+i3 ) Break;
3624 i1=loop(bp,0 ,ya+ (dy-ya)/4,dx,cs,0,RI); // linke senkr. linie
3625 i2=loop(bp,0 ,ya+ (dy-ya)/2,dx,cs,0,RI);
3626 i3=loop(bp,0 ,dy-1-(dy-ya)/4,dx,cs,0,RI);
3627 if( 2*i2-dx/8>i1+i3 ) ad=98*ad/100; /* 6*8 font */
3628 if( 2*i2+dx/4<i1+i3 || 2*i2-dx/4>i1+i3 || i1<i3) Break;
3630 // lower ends could be round on thick fonts
3631 for(i3=dx,y=ya+(dy-ya)/4;y<7*dy/8;y++){ // increasing width
3632 i1=loop(bp, 0, y,dx,cs,0,RI);
3633 i2=loop(bp,dx-1, y,dx,cs,0,LE);
3634 if(i1+i2>i3+dx/16) break; if( i1+12<i3 ) i3=i1+i2;
3635 } if(y<7*dy/8) Break;
3636 if ( loop(bp, 0,dy-1-dy/8,dx,cs,0,RI)
3637 -loop(bp, 0,dy/2 ,dx,cs,0,RI)>0) ad=97*ad/100; // italic-a
3639 if (!hchar) ad=99*ad/100; // italic-a
3643 // --- test a -------------------------------------------
3644 // with a open bow above the circle starting
3645 // on the right side of the circle
3646 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
3647 DBG( wchar_t c_ask='a'; )
3648 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
3649 if( get_bw(x0 , x0+dx/2, y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
3650 if( get_bw(x1-dx/3, x1 , y0+dy/3, y0+dy/3,box1->p,cs,1) != 1 ) Break;
3651 if( get_bw(x1-dx/3, x1 , y0+dy/4, y0+dy/4,box1->p,cs,1) != 1 ) Break;
3652 if( get_bw(x0+dx/2, x0+dx/2, y1-dy/3, y1, box1->p,cs,1) != 1 ) Break;
3653 if( get_bw(x0+dx/2, x0+dx/2, y0 , y0+dy/3,box1->p,cs,1) != 1 ) Break;
3654 if( get_bw(x0+dx/3, x1-dx/3, y0 , y0 ,box1->p,cs,1) != 1 ) Break;
3655 if( get_bw(x0+dx/4, x1-dx/2, y1 , y1 ,box1->p,cs,1) != 1 )
3656 if( get_bw(x0+dx/4, x1-dx/3, y1-1 , y1-1 ,box1->p,cs,1) != 1 ) Break;
3657 if( get_bw(x0 , x0 , y0+dy/2, y1 ,box1->p,cs,1) != 1 )
3658 if( get_bw(x0+dx/8, x0+dx/8, y0+dy/2, y1 ,box1->p,cs,1) != 1 ) Break;
3659 if( loop(bp,3*dx/8,0,dy,cs,0,DO) > 3*dy/16 ) Break; // ~d
3660 if( num_cross(0,dx-1,dy/4 ,dy/4 , bp,cs) >2 // ~glued am != an
3661 && num_cross(0,dx-1,dy/4+1,dy/4+1, bp,cs) >2 ) Break;
3663 for( x=dx/4;x<dx-dx/4;x++ ){ // ar
3664 i=loop(bp,x, 0,y1-y0,cs,0,DO); if (i>dy/2) break;
3665 i=loop(bp,x,dy-1,y1-y0,cs,0,UP); if (i>dy/2) break;
3666 } if( x<dx-dx/4 ) Break;
3668 for(i=dx/8+1,x=dx/4;x<=dx-1-dx/4 && i;x++){
3669 if( num_cross(x,x,0,bp->y-1, bp,cs) == 3 ) i--;
3672 i1=loop(bp,0, dy/8,dx,cs,0,RI);
3673 i3=loop(bp,0,3*dy/4,dx,cs,0,RI);
3674 for(y=dy/8+1;y<3*dy/4;y++){
3675 i2=loop(bp,0,y,dx,cs,0,RI);if(2*i2>i1+i3+1) break;
3676 } if(y==3*dy/4) Break; // ~6
3677 // ~ s (small thick s), look for vertikal line piece
3678 for(x=3*dx/4;x<dx;x++)
3679 if( loop(bp,x,dy/4,dy/2,cs,1,DO)>dy/4 ) break;
3682 if (sdata->holes.num != 1) ad=96*ad/100; else
3683 if (sdata->holes.num == 1)
3684 if( num_hole ( x0, x1, y0+dy/3, y1 ,box1->p,cs,NULL) != 1 ) Break;
3685 // if( num_hole ( x0, x1, y0, y1, box1->p,cs,NULL) != 1 ) Break;
3686 if( num_hole ( x0, x1, y0, y1-dy/3 ,box1->p,cs,NULL) != 0 ){
3687 i =loop(bp,0,dy/4,dx,cs,0,RI);
3688 i =loop(bp,i,dy/4,dx,cs,1,RI);
3689 if(i<dx/4+1) Break; // fat a
3690 i =loop(bp,0,dy/4,dx,cs,0,RI);
3691 i+=loop(bp,i,dy/4,dx,cs,1,RI);
3692 for(y=dy/4;y<dy/2;y++)
3693 if( num_cross(0,dx-1,y,y, bp,cs) !=2 ) break;
3694 x =loop(bp,0,y-1,dx,cs,0,RI);
3695 x+=loop(bp,x,y-1,dx,cs,1,RI);
3696 if(x>i) Break; // ~ 8
3698 /* test for horizontal symmetry ~8 */
3699 for (y=0;y<dy;y++) for (x=0;x<dx/2;x++)
3700 if ((getpixel(bp,x,y)<cs)!=(getpixel(bp,dx-1-x,y)<cs)) { y=dy+1; break; }
3701 if (y==dy) Break; /* ~8 */
3703 if (hchar) ad=96*ad/100;
3704 if (gchar) ad=96*ad/100;
3708 // --- test hand written a ---------------------------------------------------
3709 // rarely char, without bow above the circle
3710 for(ad=d=100;dx>3 && dy>3;){ // min 4x4
3711 DBG( wchar_t c_ask='a'; )
3712 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
3713 if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
3714 if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
3715 if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/2 , y1, box1->p,cs,1) != 1 ) Break;
3716 if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
3717 if( get_bw(x0+dx/3 , x0+dx/3,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
3718 i = loop(bp,dx/2, 0 ,dy,cs,0,DO); if (i>dy/4) Break;
3719 i+= loop(bp,dx/2, i ,dy,cs,1,DO); if (i>dy/2) Break;
3720 i = loop(bp,dx/2, i ,dy,cs,0,DO); if (i<dy/4) Break;
3721 if( get_bw(x0 , x0 ,y1 , y1 ,box1->p,cs,1) == 1 ) Break;
3723 if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 2 ) Break;
3724 if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND
3725 if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
3726 i = loop(bp,dx/2,dy-1 ,dy,cs,0,UP); if (i>dy/3) Break;
3727 y = i+loop(bp,dx/2,dy-1-i,dy,cs,1,UP); if (i>dy/2) Break;
3728 // normal 'a' has a well separated vertical line right from the circle
3729 // but fat 'a' is like a 'o', only bigger on the right side
3730 if( num_cross(x0+dx/2-1,x1,y1 ,y1 ,box1->p,cs) < 2 /* 4x6font */
3731 && num_cross(x0+dx/2-1,x1,y1-i,y1-i ,box1->p,cs) < 2 /* 2 or 3 */
3732 && num_cross(x0+dx/2-1,x1,y1-y,y1-y ,box1->p,cs) < 2 )
3733 { if (loop(bp, 0,dy-1-dy/16,dx,cs,0,RI)
3734 <4*loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)) { Break;}
3737 if( num_cross(x0,x1,y0+dy/2 , y0+dy/2,box1->p,cs) < 2
3738 || num_cross(x0,x1,y0+dy/3 , y0+dy/3,box1->p,cs) < 2 ) Break; // Jun00
3740 if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/4,box1->p,cs) != 1 )
3741 if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/4,box1->p,cs) != 1 ) Break;
3742 if (sdata->holes.num != 1)
3743 if( num_hole(x0,x1-2,y0 ,y1 ,box1->p,cs,NULL) != 1 )
3744 // if( num_hole(x0,x1 ,y0 ,y1 ,box1->p,cs,NULL) != 1 )
3746 if( num_hole(x0,x1 ,y0+dy/3,y1-1 ,box1->p,cs,NULL) != 0 ) Break;
3748 if( loop(bp,0 ,0 ,x1-x0,cs,0,RI)<=
3749 loop(bp,0 ,2 ,x1-x0,cs,0,RI) ) Break;
3751 if( loop(bp,dx-1,dy-1,x1-x0,cs,0,LE)> dx/4
3752 && loop(bp,dx-1,dy-2,x1-x0,cs,0,LE)> (dx+4)/8 ) ad=97*ad/100;
3754 x=loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE);
3755 i=loop(bp,dx-1, dy/4,dx,cs,0,LE); if (abs(x-i)>dx/4) Break;
3757 for( x=dx/4;x<dx-dx/4;x++ ){ // ar
3758 i=loop(bp,x, 0,y1-y0,cs,0,DO); if (i>dy/2) break;
3759 i=loop(bp,x,dy-1,y1-y0,cs,0,UP); if (i>dy/2) break;
3760 } if( x<dx-dx/4 ) Break;
3762 if( num_cross(x0 , x1, y1, y1,box1->p,cs) == 1 )
3763 if( num_cross(x0 , x1, y0, y0,box1->p,cs) == 1 )
3764 if( loop(bp,dx-1, 0,y1-y0,cs,0,DO)> dy/4
3765 && loop(bp,dx-1,dy-1,y1-y0,cs,0,UP)> dy/4 ) Break; // ~o
3766 if( loop(bp,dx/2,dy-1,y1-y0,cs,0,UP)> dy/4 ) Break; // ~q
3768 if (hchar) ad=98*ad/100;
3769 if (gchar) ad=98*ad/100;
3770 // handwritten-a (alpha)
3774 // --- test A_A_WITH_OGONEK 0x0104 Centr.Eur.Font -------------------------
3775 /* not sure if we should move this to a get_CentralEuropean-function */
3776 for(ad=d=100;dx>2 && dy>4;){ // min 3x4
3777 DBG( wchar_t c_ask='A'; )
3778 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
3779 // first selection (grobes Sieb)
3780 if( get_bw(dx/2,dx/2,dy-1-dy/8,dy-1,bp,cs,1) == 1 ) break; // ~B
3781 if( num_cross(0,dx-1, 1 , 1 ,bp,cs)!=1 // 600dpi
3782 && num_cross(0,dx-1, dy/8 , dy/8 ,bp,cs)!=1
3783 && num_cross(0,dx-1, dy/16 , dy/16 ,bp,cs)!=1
3784 && num_cross(0,dx-1, dy/8+1, dy/8+1,bp,cs)!=1 ) break;
3785 if( num_cross(0,dx-1, dy-1 , dy-1 ,bp,cs)!=1 ) break;
3786 if( num_cross(0,dx-1, dy/4 , dy/4 ,bp,cs)!=2
3787 && num_cross(0,dx-1, dy/3 , dy/3 ,bp,cs)!=2 ) break;
3788 if ( num_cross( 0,dx/8,dy/8, 0,bp,cs)>0 ) break; // ~R
3789 for(y=dy/8;y<dy/2;y++) if( num_cross(0,dx-1,y,y,bp,cs) > 1 ) break;
3790 if( y==dy/2 ) break; i1=y;
3791 if (dy>20) i1++; /* get arround some noise fat font */
3793 x =loop(bp,0,i1,dx,cs,0,RI); if(x>3*dx/4) break;
3794 x+=loop(bp,x,i1,dx,cs,1,RI); if(x>3*dx/4) break; i2=x;
3795 x+=loop(bp,x,i1,dx,cs,0,RI); if(x<3*dx/8) break; i2=(x+i2)/2;
3797 y+=loop(bp,i2,y,dy,cs,1,DO);
3798 y+=loop(bp,i2,y,dy,cs,0,DO); if(y>3*dy/4) ad=ad*99/100;
3799 if (y>5*dy/6) break;
3801 if( sdata->holes.num != 1 || sdata->holes.hole[0].y1 >= dy-1-dy/4) break;
3802 // if( num_hole ( x0, x1, y0, y1-dy/4 ,box1->p,cs,NULL) != 1 ) break;
3805 for(x=dx/3;x<2*dx/3;x++){
3806 i4=num_cross(i2,x,y ,dy-1,bp,cs);if(i4<1 || i4>2)
3807 i4=num_cross(i2,x,y+dy/16,dy-1,bp,cs);if(i4<1 || i4>2) break;
3809 } if(i4<1 || i4>2 || i3==0){
3810 // ToDo: g_debug_A(printf(" A: x,y,i4,i3= %d %d %d %d\n",x,y,i4,i3);)
3813 if( get_bw(dx-1-dx/4, dx-1, dy-1-dy/4, dy-1, bp,cs,1) != 1 ) break;
3814 /* dy/4 changed to dy/6 because of screenfonts */
3815 /* there are strange fonts, one has a serif on the upper end of A */
3816 if ( num_cross( 0,dx/8,dy/6, 0,bp,cs)>0 ) break;
3817 if ( num_cross(dx-1-dx/4,dx-1, 0,dy/6,bp,cs)>0 ) break;
3819 i1=loop(bp,dx-1, dy/4,dx,cs,0,LE);
3820 i2=loop(bp,dx-1, dy/2,dx,cs,0,LE);
3821 i3=loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE);
3822 if( 2*i2+dx/4<i1+i3 || 2*i2-dx/8>i1+i3 ) break;
3824 i1=loop(bp,0 , dy/4,dx,cs,0,RI); // linke senkr. linie
3825 i2=loop(bp,0 , dy/2,dx,cs,0,RI);
3826 i3=loop(bp,0 ,dy-1-dy/4,dx,cs,0,RI);
3827 if( 2*i2+dx/4<i1+i3 || 2*i2-dx/8>i1+i3 || i1<i3) break;
3829 // lower ends could be round on thick fonts
3830 for(i3=dx,y=dy/4;y<6*dy/8;y++){ // increasing width
3831 i1=loop(bp, 0, y,dx,cs,0,RI);
3832 i2=loop(bp,dx-1, y,dx,cs,0,LE);
3833 if(i1+i2>i3+dx/16) break; if( i1+12<i3 ) i3=i1+i2;
3834 } if(y<6*dy/8) break;
3836 if (!hchar) ad=96*ad/100;
3837 if (!gchar) ad=98*ad/100;
3838 Setac(box1,(wchar_t)LATIN_CAPITAL_LETTER_A_WITH_OGONEK,ad);
3844 static wchar_t ocr0_cC(ocr0_shared_t *sdata){
3845 struct box *box1=sdata->box1;
3847 int i,j,d,x,y,i1,i2,i3,i4,i5,hchar=sdata->hchar,gchar=sdata->gchar,
3848 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
3849 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3850 ad,t1; /* tmp-vars */
3853 // --- test c,C ---------------------------------------------------
3854 for(ad=d=100;dx>2 && dy>2;){ // min 3x4
3855 DBG( wchar_t c_ask='c'; )
3856 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
3857 if( get_bw(x0 , x0+dx/3,y0+dy/2, y0+dy/2,box1->p,cs,1) != 1 ) Break;
3858 if( get_bw(x0+dx/2, x0+dx/2,y1-dy/3, y1, box1->p,cs,1) != 1 ) Break;
3859 if( get_bw(x0+dx/2, x0+dx/2,y0 , y0+dy/3,box1->p,cs,1) != 1 ) Break;
3860 if( num_cross(x0,(x0+x1)/2,(y0+y1)/2,(y0+y1)/2,box1->p,cs) > 1 ) Break; // ~ocr-a-[
3862 for(y=y0+dy/4;y<y0+3*dy/4;y++)
3863 if( get_bw(x0+dx/2,x1,y,y,box1->p,cs,1) == 0 ) break;
3864 if( y==y0+3*dy/4 ) Break; i1=y; // i1: upper end of right gap
3866 // measure thickness of line!
3867 t1=loop(bp, 0,dy/2,dx,cs,0,RI);
3868 t1=loop(bp,t1,dy/2,dx,cs,1,RI);
3871 for(y=i1,i2=0,x=x0+dx/2;x<x0+6*dx/8;x++){
3872 i=y-1+loop(box1->p,x0+dx/2,i1,dy,cs,0,DO);
3873 if( i>i2 ) { i2=i; }
3874 } if(i2<y0+5*dy/8-t1/2) Break; // i2: lowest white point above lower bow
3876 i3=y+1-loop(box1->p,x0+5*dx/8,i1,dy,cs,0,UP);
3877 i =y+1-loop(box1->p,x0+4*dx/8,i1,dy,cs,0,UP); if(i<i3) i3=i;
3878 if(i3>y0+ dy/4+t1/2) Break; // highest
3880 for(y=i1;y<y1-dy/8;y++)
3881 if( get_bw(x0+dx/2,x1,y,y,box1->p,cs,1) == 1 ) break;
3882 if( y-i1<dy/6 ) Break; i2=y-1; // lower end of right gap
3883 // pixelbased num_cross for streight lines could fail on small fonts
3884 if( num_cross(x1-dx/4,x1-dx/4,i2,y0,box1->p,cs) < 1 ) Break; // ~L
3885 if (loop(box1->p,x0,y0+3*dy/4,dx,cs,0,RI)>dx/16)
3886 if( num_cross(x0+dx/2,x1,i3 ,y1,box1->p,cs) < 1
3887 && num_cross(x0+dx/2,x1,y1-dy/4,y1,box1->p,cs) < 1 ) Break; // ~r
3890 for(x=dx/2;x<dx-1 && i;x++) // look for @@ (instead +1 use +delta?)
3891 for(y=dy/2;y<dy-1-dy/8 && i;y++){ // .@
3892 if( getpixel(bp,x ,y )>=cs
3893 && getpixel(bp,x+1,y )< cs
3894 && getpixel(bp,x+1,y-1)< cs
3895 && getpixel(bp,x ,y-1)< cs ) { i=0;break; }
3897 if(!i) ad=95*ad/100; // ~G
3899 i=loop(bp,0,dy/2,dx,cs,0,RI);
3900 for(y=0;y<dy;y++)if( loop(bp,0,y,dx,cs,0,RI)<i-1-dx/32 ) break;
3901 if( y<dy ) Break; // ~r
3903 for(i5=0,i4=dx,y=dy/2;y>=dy/4;y--){
3904 x =loop(bp,0,y,dx,cs,0,RI);
3905 x+=loop(bp,x,y,dx,cs,1,RI); if(x>i5) i5=x;
3906 i =loop(bp,x,y,dx,cs,0,RI); if(i<i4) i4=i;
3907 if( i5<x-dx/32 && i>i4+dx/32 ) break; // unusual for c, more a bad e?
3908 } if( y>=dy/4 ) Break;
3910 if( !hchar ){ // test for e where the middle line is partly removed
3911 x= loop(bp,0,dy/2,dx,cs,0,RI);
3912 x=x +loop(bp,x,dy/2,dx,cs,1,RI);
3913 y=dy/2-loop(bp,x,dy/2,dy,cs,0,UP)-1;
3914 i=x +loop(bp,x,y,dx,cs,1,RI);
3915 i=i +loop(bp,i,y,dx,cs,0,RI);
3916 if( num_cross(x ,x ,1,dy/2,bp,cs) > 1
3917 || num_cross(x+1,x+1,1,dy/2,bp,cs) > 1 )
3918 if( num_cross(i-1,i-1,1,dy/2,bp,cs) > 1
3919 || num_cross(i ,i ,1,dy/2,bp,cs) > 1 ) Break; // ~bad e
3921 if( dy>16 && dy>3*dx && hchar ){ // ~[
3922 x= loop(bp,0, dy/16,dx,cs,0,RI);
3923 x=+loop(bp,0,dy-1-dy/16,dx,cs,0,RI);
3924 i= loop(bp,0, dy/2 ,dx,cs,0,RI)*2;
3926 if( num_cross(0,dx-1,dy/4,dy/4,bp,cs) < 2 ) Break;
3929 if( get_bw(x0,x0,y0 ,y1 ,box1->p,cs,2) != 2
3930 && get_bw(x0,x1,y0 ,y0 ,box1->p,cs,2) != 2
3931 && get_bw(x0,x1,y1 ,y1 ,box1->p,cs,2) != 2
3932 && get_bw(x1,x1,y0+1,y1-1,box1->p,cs,1) != 1 ) Break; /* ~[ */
3934 x =loop(bp, 0,dy/2,dx,cs,0,RI);
3935 i =loop(bp,dx-1,dy/2,dx,cs,0,LE);
3936 if( (i<dx/2 || i<3) && hchar && dy>7 )
3937 if( loop(bp, 0,7*dy/8,dx,cs,0,RI) > x+dx/8
3938 && loop(bp, 0, dy/8,dx,cs,0,RI) > x+dx/8
3939 && loop(bp,dx-1,dy-1-dy/ 8,dx,cs,0,LE)
3940 > loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)
3941 && loop(bp,dx-1, dy/ 8,dx,cs,0,LE)
3942 > loop(bp,dx-1, dy/16,dx,cs,0,LE) ) Break; // ~(
3944 // printf(" hchar=%d i1=%d i2=%d %d\n",hchar,i1-y0,i2-y0,9*dy/16);
3945 // ~G without characteristic crotchet
3946 if (hchar && dy>15 && dx>7 && i2-y0<9*dy/16 && i1-y0<=dy/4)
3947 if ( loop(bp,5*dx/8,i2-y0,dy,cs,0,DO) > 2*dy/8 ){
3954 for(x=dx/2;x<dx-1 && i;x++) // look for @@ (instead +1 use +delta?)
3955 for(y= 1;y<dy/4 && i;y++){ // .@
3956 if( getpixel(bp,x ,y )>=cs
3957 && getpixel(bp,x+1,y )< cs
3958 && getpixel(bp,x+1,y-1)< cs
3959 && getpixel(bp,x ,y-1)< cs ) { i=0;break; }
3961 if (i) ad=98*ad/100; // ~(
3962 if (dy>2*dx) ad=99*ad/100;
3964 if( loop(bp,dx-1,dy/2,dx,cs,0,LE) < 6*dx/8 ) ad=98*ad/100;
3966 i= loop(bp,dx-1,dy/16,dx,cs,0,LE);
3967 j= loop(bp,dx/2,0 ,dy,cs,0,DO);
3968 if (i>=dx/2 && j>dy/8 && j>2 && j<dy/2) Break; // t
3970 if (dy>=3*dx && dy>12) ad=99*ad/100; // (
3971 i= loop(bp,dx-1,dy-1,dy,cs,0,UP);
3972 j= loop(bp,dx/2,dy-1,dy,cs,0,UP);
3973 if (i==0 && j>dy/8) ad=95*ad/100; // <
3974 i= loop(bp,dx-1, 0,dy,cs,0,DO);
3975 j= loop(bp,dx/2, 0,dy,cs,0,DO);
3976 if (i==0 && j>dy/8) ad=95*ad/100; // <
3977 if (loop(bp,0,dy-1-dy/8,dx,cs,0,RI)>= 3*dx/4) ad=98*ad/100; // <
3978 if (loop(bp,0,dy-1-dy/8,dx,cs,0,RI)>=(dx+1)/2) ad=98*ad/100; // <
3979 if (loop(bp,0, dy/8,dx,cs,0,RI)>=dx/2) ad=98*ad/100; // <
3981 if (gchar) ad=98*ad/100; // could happen for 5x7 font
3982 bc=((hchar)?'C':'c');
3989 static wchar_t ocr0_lL(ocr0_shared_t *sdata){
3990 struct box *box1=sdata->box1;
3992 int i,j,d,x,y,i0,i1,i2,i3,i4,hchar=sdata->hchar,gchar=sdata->gchar,
3993 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
3994 int dx=x1-x0+1,dy=y1-y0+1, /* size */
3997 // --- test L ---------------------------------------------------
3998 for(ad=d=100;dx>2 && dy>4;){ // min 3x4
3999 DBG( wchar_t c_ask='L'; )
4000 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
4001 i=loop(bp,dx-1,dy/2,dx,cs,0,LE);
4002 if (i<3 && dy>8) {Break;}
4003 if (i<dx/2) ad=98*ad/100; // ~G
4005 if (dx<8 && 3*loop(bp,dx-1,0,dy,cs,0,DO)<=dy) break; // ~G
4006 for( i=i1=0,y=y1-dy/4;y<=y1;y++){ // check bottom line (i1)
4007 j=loop(box1->p,x0 ,y,dx,cs,0,RI);
4008 j=loop(box1->p,x0+j,y,dx,cs,1,RI); if( j>i ){ i=j;i1=y; }
4009 } if( i<3*dx/4 ) Break; i1=i; // length of horizontal line
4010 // line thickness (i2)
4011 i=loop(box1->p,x0 ,y0+dy/2,dx,cs,0,RI); if( i>dx/2 ) Break;
4012 j=loop(box1->p,x0+i,y0+dy/2,dx,cs,1,RI); if( i+j>dx/2 ) Break; i2=j;
4013 if (loop(bp,dx-1, 0,dx,cs,0,LE)<dx/8
4014 && loop(bp,dx-1, dy/4,dx,cs,0,LE)>dx/2
4015 && loop(bp, 0,5*dy/8,dx,cs,0,RI)<dx/4
4016 && loop(bp,dx-1,3*dy/4,dx,cs,0,LE)<dx/4) Break; // ~G
4017 for( i=1,y=y0;y<=y1-dy/4 && i;y++){ // check vertical line
4018 j=loop(box1->p,x0 ,y,dx,cs,0,RI);
4019 if ( j>(dx+2)/4+(y1-dy/4-y)*dx/2/dy ) { i=0; break; }
4020 x=loop(box1->p,x0+j,y,dx,cs,1,RI);
4021 if( ((x>i2+1 || 4*x<3*i2) && y>y0+dy/8) || 4*x>3*i1 ) i=0;
4023 if( num_cross(0, dx-1-dx/8, dy-1-dy/2, dy-1-dy/2,bp,cs) != 1 ) Break;
4024 if( num_cross(0, dx-1 , dy/3 , dy/3,bp,cs) != 1 ) Break;
4025 if( num_cross(0, dx-1 , dy/8 , dy/8,bp,cs) != 1 ) Break;
4026 if (loop(bp,0,dy-1,dx,cs,0,RI)
4027 -loop(bp,0,dy-3,dx,cs,0,RI)>1+dx/16) ad=96*ad/100; // ~c
4028 if (loop(box1->p,x0+dx/4,y1,dy,cs,0,UP)>1+dy/16) ad=99*ad/100; // ~4
4030 if ( gchar) ad=98*ad/100;
4031 if (!hchar) ad=99*ad/100;
4032 if (5*dx<2*dy && loop(box1->p,x0,y1,dx,cs,0,RI)>dx/4) ad=99*ad/100; // ~l
4036 // --- test l ---------------------------------------------------
4037 // recognize a "l" is a never ending problem, because there are lots of
4038 // variants and the char is not very unique (under construction)
4039 // --- test italic l ---------------------------------------------------
4040 // --- test l ~italic (set flag-italic) --------------------------------
4041 // if unsure d should be multiplied by 80..90%
4042 for(ad=d=100; dy>dx && dy>5;){ // min 3x4
4043 DBG( wchar_t c_ask='l'; )
4044 if( box1->dots>0 ) Break;
4045 if( num_cross(0, dx-1,dy/2,dy/2,bp,cs) != 1
4046 || num_cross(0, dx-1,dy/4,dy/4,bp,cs) != 1 ) Break;
4048 for(i1=0,i2=dx,y=dy/4;y<dy-dy/4;y++){
4049 j = loop(bp,0,y,dx,cs,0,RI);
4050 j = loop(bp,j,y,dx,cs,1,RI);
4051 if( j>i1 ) { i1=j; } // thickest
4052 if( j<i2 ) { i2=j; } // thinnest
4054 if ( i1>2*i2 ) Break;
4055 if(box1->m3 && dy<=box1->m3-box1->m2) ad=94*ad/100;
4056 if( box1->m2-box1->m1>1 && y0>=box1->m2 ) ad=94*ad/100;
4057 for(i0=0,i3=0,y=0;y<dy/4;y++){
4058 j = loop(bp,0,y,dx,cs,0,RI);
4059 if( j>i3 ) { i3=j; } // widest space
4060 j = loop(bp,j,y,dx,cs,1,RI);
4061 if( j>i0 ) { i0=j;i3=0; } // thickest
4063 if ( i0>4*i2 || 3*i3>2*dx)
4064 if ( loop(bp,dx-1,dy-1,dx,cs,0,LE)>3*dx/8
4065 || loop(bp, 0,dy-1,dx,cs,0,RI)>3*dx/8) Break; // ~7
4068 x =loop(bp,0, 0,dx,cs,0,RI);
4069 i3=loop(bp,x, 0,dx,cs,0,RI);
4070 x =loop(bp,0, 1,dx,cs,0,RI);
4071 x =loop(bp,x, 1,dx,cs,0,RI); if(x>i3) i3=x;
4072 x =loop(bp,0,dy-1,dx,cs,0,RI);
4073 i4=loop(bp,x,dy-1,dx,cs,0,RI);
4074 x =loop(bp,0,dy-2,dx,cs,0,RI);
4075 x =loop(bp,x,dy-2,dx,cs,0,RI); if(x>i4) i4=x;
4076 if( i3>i1+dx/8+1 && i4>i1+dx/8+1 ) Break; // ~I
4078 for(i=dx,j=0,y=1;y<dy/4;y++){
4079 x=loop(bp,dx-1,y,dx,cs,0,LE); if(x>i+1) break; i=x;
4080 if( num_cross(0,dx-1,y ,y ,bp,cs)==2
4081 && num_cross(0,dx-1,y+1+dy/32,y+1+dy/32,bp,cs)==2 ) j=1;
4082 } if ( y<dy/4 ) Break;
4083 if(j){ // if loop at the upper end, look also on bottom
4084 for(y=3*dy/4;y<dy;y++){
4085 if( num_cross(0,dx-1,y ,y ,bp,cs)==2
4086 && num_cross(0,dx-1,y-1-dy/32,y-1-dy/32,bp,cs)==2 ) break;
4087 } if ( y==dy ) Break;
4090 // if( get_bw(x0,x1,y0,y1,p,cs,2) == 0 ) Break; // unsure !I|
4093 if( get_bw(dx-1-dx/8,dx-1,0,dy/6,bp,cs,1) != 1 )
4094 if( get_bw(dx-1-dx/8,dx-1,0,dy/2,bp,cs,1) == 1 ) Break;
4096 if( get_bw(dx-1-dx/8,dx-1,dy/4,dy/3,bp,cs,1) != 1 ) // large I ???
4097 if( get_bw(0 ,dx/8,dy/4,dy/3,bp,cs,1) != 1 )
4098 if( get_bw(dx-1-dx/8,dx-1,0 ,dy/8,bp,cs,1) == 1 )
4099 if( get_bw(0 ,dx/8,0 ,dy/8,bp,cs,1) == 1 ) ad=ad*97/100;
4100 if( get_bw(dx-1-dx/8,dx-1,dy/2,dy-1,bp,cs,1) != 1 ) // r ???
4101 if( get_bw(0 ,dx/8,dy/2,dy-1,bp,cs,1) == 1 )
4102 if( get_bw(dx-1-dx/8,dx-1,0 ,dy/3,bp,cs,1) == 1 )
4103 if( get_bw(0 ,dx/8,0 ,dy/3,bp,cs,1) == 1 ) Break;
4105 for( y=1;y<12*dy/16;y++ )
4106 if( num_cross(0, dx-1, y , y ,bp,cs) != 1 // sure ?
4107 && num_cross(0, dx-1, y-1, y-1,bp,cs) != 1 ) break;
4108 if( y<12*dy/16 ) Break;
4111 for( y=dy/2;y<dy-1;y++ )
4112 if( get_bw(dx/4,dx-1-dx/4,y,y,bp,cs,1) != 1 ) break;
4115 // test ob rechte Kante gerade
4116 for(x=dx,y=bp->y-1-5*dy/16;y>=dy/5;y--){ // rechts abfallende Kante/Knick?
4117 i=loop(bp,bp->x-1,y,x1-x0,cs,0,LE);
4118 if( i-2-dx/16>=x ) break;
4121 if (y>=dy/5 ) Break;
4123 // test ob linke Kante gerade
4124 for(x=0,y=bp->y-1-dy/5;y>=dy/5;y--){ // rechts abfallende Kante/Knick?
4125 i=loop(bp,0,y,x1-x0,cs,0,RI);
4126 if( i+2+dx/16<x ) break;
4129 if (y>=dy/5 ) Break;
4130 if (box1->m4 && y1<box1->m4)
4131 if ( get_bw(x0,x1,y1+1,box1->m4+dy/8,box1->p,cs,1) == 1 )
4132 ad=ad*97/100; // unsure !l|
4133 i=loop(bp,dx-1,dy/16,dx,cs,0,LE);
4134 j=loop(bp,dx-1,dy/2 ,dx,cs,0,LE);
4136 if( get_bw(dx-1-i/2,dx-1-i/2,0,dy/2,bp,cs,1) == 1 ) Break; // ~t
4138 for(y=5*dy/8;y<dy;y++)
4139 if( num_cross(0,dx-1,y,y,bp,cs) == 2 ) break;
4141 i =loop(bp,0,y,dx,cs,0,RI);
4142 i+=loop(bp,i,y,dx,cs,1,RI);
4143 i+=loop(bp,i,y,dx,cs,0,RI)/2; // middle of v-gap
4144 if( num_cross(0,i,5*dy/8,5*dy/8,bp,cs)==0
4145 && num_cross(i,i,5*dy/8, y,bp,cs)==0 ) Break; // ~J
4148 && loop(bp, 0,3*dy/4,dx,cs,0,RI)>=dx/4
4149 && loop(bp, 0,7*dy/8,dx,cs,0,RI)<=dx/8
4150 && loop(bp,dx-1,3*dy/4,dx,cs,0,LE)<=dx/8
4151 && loop(bp,dx-1,7*dy/8,dx,cs,0,LE)<=dx/8 ) Break; // ~J
4153 if ( 2*i3>5*i1 ) // hmm \tt l can look very similar to 7
4154 if ( loop(bp,0,dy/4,dx,cs,0,RI)>dx/2
4155 && get_bw(0,dx/8,0,dy/4,bp,cs,1) == 1 ) Break; // ~7
4157 if ( loop(bp,dx-1,dy/2,dx,cs,0,LE)>dx/2
4158 && get_bw(3*dx/4,dx-1,3*dy/4,dy-1,bp,cs,1) == 1) {
4159 if (loop(bp,0,dy-1,dx,cs,0,RI)<dx/8) ad=99*ad/100; // ~L
4160 if(5*dx>2*dy) ad=99*ad/100; // ~L
4161 if(5*dx>3*dy) ad=99*ad/100; // ~L
4163 if(!hchar){ // right part (bow) of h is never a l
4164 if( get_bw(dx/4,dx/4, 0,dy/4,bp,cs,1) == 1
4165 && get_bw(dx/4,dx/4,dy/2,dy-1,bp,cs,1) == 0 ) Break;
4167 if( dx>3 && dy>3*dx )
4168 if( loop(bp,dx/4,dy-1 ,dy,cs,0,UP)< dy/4
4169 && loop(bp, 0,dy-1-dy/8,dx,cs,0,RI)>=dx/2
4170 && loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)<=dx/4 ){
4172 if ( loop(bp,dx-1,dy/2,dx,cs,0,LE)==0 ) Break;
4176 if( get_bw( x, x, 0,dy/4 ,bp,cs,1) == 1 ) break;
4177 // works only for perpenticular char
4178 if( get_bw( x,x+dx/16, 0,dy/16,bp,cs,1) == 0
4179 && get_bw( x,x+dx/16,dy/4 ,dy/2 ,bp,cs,1) == 0
4180 && get_bw( x,x+dx/16,dy/16,dy/4 ,bp,cs,1) == 1 ){
4181 for(i=dx,y=0;y<dy/4;y++){
4182 x=loop(bp,0,y,dx,cs,0,RI);
4185 if( x>=loop(bp,0,y+1,dx,cs,0,RI) )
4186 if( loop(bp,0 ,0,dy,cs,0,DO)>1 )
4187 if( loop(bp,0 ,0,dy,cs,0,DO)
4188 - loop(bp,dx/16+1,0,dy,cs,0,DO) < dx/16+1 ) Break; // ~1 Jul00,Nov00
4189 if( num_cross(0,dx/2,y-1,y-1,bp,cs)==2 ) Break; // ~1
4191 if(dx<8 && dy<12){ // screen font
4192 i= loop(bp,0,0,dy,cs,0,DO);
4193 if( loop(bp,dx/2,1,dy,cs,1,DO)>=dy-2
4194 && loop(bp,0,dy/2,dx,cs,0,RI)>=2
4195 && i>1 && i<dy/2 ) Break; // ~1
4197 if( get_bw(x1,x1,y0 ,y1 ,box1->p,cs,2) != 2
4198 && get_bw(x0,x1,y0 ,y0 ,box1->p,cs,2) != 2
4199 && get_bw(x0,x1,y1 ,y1 ,box1->p,cs,2) != 2
4200 && get_bw(x0,x0+dx/4,y0+1+dy/16,y1-1-dy/16,box1->p,cs,1) != 1 ) Break; /* ~] */
4201 i=loop(bp,dx-1,dy/2,dx,cs,0,LE);
4202 if( loop(bp, 0,dy/2,dx,cs,0,RI)>=dx/2
4203 && (i<dx/2 || i==0) ) ad=98*ad/100; // ~]
4204 if( get_bw(x0,x0,y0 ,y1 ,box1->p,cs,2) != 2
4205 && get_bw(x0,x1,y0 ,y0 ,box1->p,cs,2) != 2
4206 && get_bw(x0,x1,y1 ,y1 ,box1->p,cs,2) != 2
4207 && get_bw(x1-dx/4,x1,y0+1+dy/16,y1-1-dy/16,box1->p,cs,1) != 1 ) Break; /* ~[ */
4209 x =loop(bp, 0,dy/2,dx,cs,0,RI); // konvex/konkav? ~()
4210 i =loop(bp,dx-1,dy/2,dx,cs,0,LE);
4211 if( loop(bp, 0,7*dy/8,dx,cs,0,RI) > x+dx/8
4212 && loop(bp, 0, dy/8,dx,cs,0,RI) > x+dx/8
4213 && loop(bp,dx-1,7*dy/8,dx,cs,0,LE) < i-dx/8
4214 && loop(bp,dx-1, dy/8,dx,cs,0,LE) < i-dx/8 ) Break; // ~(
4215 if( loop(bp, 0,7*dy/8,dx,cs,0,RI) < x-dx/8
4216 && loop(bp, 0, dy/8,dx,cs,0,RI) < x-dx/8
4217 && loop(bp,dx-1,7*dy/8,dx,cs,0,LE) > i+dx/8
4218 && loop(bp,dx-1, dy/8,dx,cs,0,LE) > i+dx/8 ) Break; // ~)
4220 i= loop(bp, 0, 0,dy,cs,0,DO); // horizontal line?
4221 if(dy>=12 && i>dy/8 && i<dy/2){
4222 if( loop(bp,dx-1,3*dy/16,dx,cs,0,LE)-dx/8
4223 >loop(bp,dx-1, i,dx,cs,0,LE)
4224 || loop(bp,dx-1,3*dy/16,dx,cs,0,LE)-dx/8
4225 >loop(bp,dx-1, i+1,dx,cs,0,LE) )
4226 if( loop(bp,dx-1,8*dy/16,dx,cs,0,LE)-dx/8
4227 >loop(bp,dx-1, i,dx,cs,0,LE)
4228 || loop(bp,dx-1,8*dy/16,dx,cs,0,LE)-dx/8
4229 >loop(bp,dx-1, i+1,dx,cs,0,LE) )
4230 if( loop(bp, 0,3*dy/16,dx,cs,0,RI)-dx/8
4231 >loop(bp, 0, i,dx,cs,0,RI)
4232 || loop(bp, 0,3*dy/16,dx,cs,0,RI)-dx/8
4233 >loop(bp, 0, i+1,dx,cs,0,RI) )
4234 if( loop(bp, 0,8*dy/16,dx,cs,0,RI)-dx/8
4235 >loop(bp, 0, i,dx,cs,0,RI)
4236 || loop(bp, 0,8*dy/16,dx,cs,0,RI)-dx/8
4237 >loop(bp, 0, i+1,dx,cs,0,RI) ) Break; // ~t
4238 if( loop(bp, 0,i-1,dx,cs,0,RI)>1 && dx<6 ) Break; // ~t
4239 if( loop(bp, 0,8*dy/16,dx,cs,0,RI)>dx/8
4240 && loop(bp, 0, i,dx,cs,1,RI)>=dx-1
4241 && loop(bp,dx-1,8*dy/16,dx,cs,0,LE)>dx/8
4242 && loop(bp,dx-1, i-1,dx,cs,0,LE)>dx/8 ) Break; // ~t
4244 // if( vertical_detected && dx>5 )
4245 if( loop(bp,0, 1,dx,cs,0,RI)>=dx/2
4246 && ( loop(bp,0,dy-2,dx,cs,0,RI)<=dx/8
4247 || loop(bp,0,dy-1,dx,cs,0,RI)<=dx/8 ) )
4248 if( ( loop(bp,dx-1, 0,dx,cs,0,LE)<=dx/8
4249 || loop(bp,dx-1, 1,dx,cs,0,LE)<=dx/8 )
4250 && loop(bp,dx-1,dy-2,dx,cs,0,LE)>=dx/2 ) ad=98*ad/100; // ~/
4252 if( get_bw(x0,x1,y0,y1,box1->p,cs,2) == 0 ) ad=99*ad/100;
4254 if (!hchar || loop(bp,0,dy/4,dx,cs,0,RI)>dx/2){ // ~z
4255 i=loop(bp,0,dy/16 ,dx,cs,0,RI);
4256 i=loop(bp,i,dy/16 ,dx,cs,1,RI); j=i;
4257 i=loop(bp,0,dy/16+1,dx,cs,0,RI);
4258 i=loop(bp,i,dy/16+1,dx,cs,1,RI); if (i>j) j=i;
4259 i=loop(bp,0,dy/16+2,dx,cs,0,RI);
4260 i=loop(bp,i,dy/16+2,dx,cs,1,RI); if (i>j) j=i;
4261 if (j*4>=dx*3) ad=98*ad/100; // ~z
4262 if (j*8>=dx*7) ad=96*ad/100; // ~z
4265 if( get_bw(x0,x0,y1,y1,box1->p,cs,2) == 0 ) ad=99*ad/100;
4266 if( get_bw(x1,x1,y1,y1,box1->p,cs,2) == 0 ) ad=99*ad/100;
4267 if (ad==100) ad--; /* I have to fix that:
4279 if(!hchar) ad=ad*99/100;
4280 if( gchar) ad=ad*99/100;
4282 // if( i<100 ) Break; ????
4283 // if( loop(bp,0, 1,dx,cs,0,RI)<=dx/8
4284 // && loop(bp,0,dy/2,dx,cs,0,RI)<=dx/8
4285 // && loop(bp,0,dy-2,dx,cs,0,RI)<=dx/8 ) vertical_detected=1;
4291 static wchar_t ocr0_oO(ocr0_shared_t *sdata){
4292 struct box *box1=sdata->box1;
4294 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
4295 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
4296 int dx=x1-x0+1,dy=y1-y0+1, /* size */
4300 // --- test o,O ---------------------------------------------------
4301 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
4302 DBG( wchar_t c_ask='o'; )
4303 if (sdata->holes.num !=1 ) Break;
4304 if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
4305 if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
4306 if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/2 , y1, box1->p,cs,1) != 1 ) Break;
4307 if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
4308 if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/2 , y1-dy/3,box1->p,cs,1) != 0 ) Break;
4309 if (sdata->holes.hole[0].y0 > dy/3
4310 || sdata->holes.hole[0].y1 < dy-1-dy/3) Break;
4312 if( num_cross(x0+dx/2 ,x0+dx/2 ,y0, y1 ,box1->p,cs) != 2
4313 && num_cross(x0+dx/2+1,x0+dx/2+1,y0, y1 ,box1->p,cs) != 2 ) Break;
4314 if( num_cross(x0+dx/3,x1-dx/4,y0 , y0 ,box1->p,cs) != 1 ) // AND
4315 if( num_cross(x0+dx/3,x1-dx/4,y0+1 , y0+1,box1->p,cs) != 1 ) Break;
4316 if( num_cross(x0+dx/4,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen"
4317 if( num_cross(x0+dx/4,x1-dx/3,y1-1 , y1-1,box1->p,cs) != 1 ) Break;
4318 if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
4319 if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
4320 if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
4321 if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
4323 if( loop(bp,0 ,0 ,x1-x0,cs,0,RI)<=
4324 loop(bp,0 ,2 ,x1-x0,cs,0,RI) ) Break;
4326 x=loop(bp,dx-1,dy-1-dy/3,x1-x0,cs,0,LE); // should be minimum
4327 for( y=dy-1-dy/3;y<dy;y++ ){
4328 i=loop(bp,dx-1,y,x1-x0,cs,0,LE);
4329 if( i<x ) break; x=i;
4334 if( loop(bp,0, dy/16,dx,cs,0,RI)
4335 + loop(bp,0,dy-1-dy/16,dx,cs,0,RI)
4336 <= 2*loop(bp,0, dy/2 ,dx,cs,0,RI)+dx/8 ) Break; // not konvex
4337 if( loop(bp,0 , 1+dy/16,dx,cs,0,RI) + dx/4
4338 <= loop(bp,dx-1, 1+dy/16,dx,cs,0,LE) ) Break; // Dec00
4340 if( loop(bp,dx-1, dy/16,dx,cs,0,LE)>dx/8 )
4341 if( loop(bp,0 , dy/16,dx,cs,0,RI)<dx/16 ) Break;
4342 if( loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/8 )
4343 if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)<dx/16 ) Break;
4344 if( get_bw(x1-dx/32,x1,y0,y0+dy/32,box1->p,cs,1) == 0
4345 && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0
4346 // && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1
4347 && ( get_bw(0,dx/32,0,dy/32,bp,cs,1) == 1
4348 || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) Break; // ~D
4350 // search lowest inner white point
4351 for(y=dy,j=x=0;x<dx;x++) {
4352 i =loop(bp,x,dy-1 ,y1-y0,cs,0,UP);
4353 i+=loop(bp,x,dy-1-i,y1-y0,cs,1,UP);
4354 if (i<=y) { y=i; j=x; }
4357 for(y=dy-1-i;y<dy-1;y++)
4358 if( num_cross(j,dx-1,y,y,bp,cs) > 1 ) ad=99*ad/100; // ~a \it a
4359 for(y=0;y<dy-1-i;y++)
4360 if( num_cross(0,dx-1,y,y,bp,cs) > 2 ) ad=98*ad/100; // ~a \it a
4361 if (loop(bp,dx-1,dy-1,x1-x0,cs,0,LE)<dx/8) ad=98*ad/100; // \it a
4362 if (loop(bp,dx-1, 0,x1-x0,cs,0,LE)<dx/8) ad=98*ad/100; // \it a
4363 if (loop(bp,dx-1,dy-1-dy/8,x1-x0,cs,0,LE)+1+dx/16
4364 <loop(bp, 0,dy-1-dy/8,x1-x0,cs,0,RI))
4365 { ad=99*ad/100; MSG(fprintf(stderr,"ad=%d",ad);) } // \it a
4366 if (loop(bp,dx-1,dy-1,y1-y0,cs,0,UP)+1+(dy+3)/8
4367 <loop(bp, 0,dy-1,y1-y0,cs,0,UP))
4368 { ad=98*ad/100; MSG(fprintf(stderr,"ad=%d",ad);) } // \it a
4370 if (abs(loop(bp,dx/2, 0,dy,cs,0,DO)
4371 -loop(bp,dx/2,dy-1,dy,cs,0,UP))>dy/8
4372 || num_cross(0,dx-1, 0, 0,bp,cs) > 1
4373 || num_cross(0,dx-1,dy-1,dy-1,bp,cs) > 1
4374 ) ad=98*ad/100; // ~bq
4376 if( hchar && 2*y0<box1->m1+box1->m2 ) i=1; else i=0;
4377 if (gchar) ad=99*ad/100;
4380 if ( bc=='O' && ad>99) ad=99; /* we can never 100% sure, 0O */
4382 if (bc=='O') Setac(box1,'0',ad);
4383 if (bc=='o') Setac(box1,'0',98*ad/100);
4389 static wchar_t ocr0_pP(ocr0_shared_t *sdata){
4390 struct box *box1=sdata->box1;
4392 int i,j,d,x,y,i1,i2,i3,i4,hchar=sdata->hchar,gchar=sdata->gchar,
4393 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
4394 int dx=x1-x0+1,dy=y1-y0+1, /* size */
4398 // --- test pP ---------------------------------------------------
4399 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
4400 DBG( wchar_t c_ask='p'; )
4401 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
4402 if( get_bw(0 , dx/2,3*dy/4,3*dy/4,bp,cs,1) != 1 ) Break;
4403 if( get_bw(0 , dx/2, dy/2, dy/2,bp,cs,1) < 1 ) Break;
4404 if( get_bw(dx/4, dx-1, dy/4, dy/4,bp,cs,1) != 1 ) Break;
4405 i= loop(bp,dx-1,3*dy/4,dx,cs,0,LE); if (i<dx/4) Break;
4406 if( num_cross(x1-3*i/4,x1-3*i/4, y0, y1-3*dy/16,box1->p,cs) != 2 )
4407 if( num_cross(x0+dx/2 ,x0+dx/2 , y0, y1-3*dy/16,box1->p,cs) != 2 )
4408 if( num_cross(x0+dx/2+1,x0+dx/2+1, y0, y1-3*dy/16,box1->p,cs) != 2 ) Break;
4409 if( num_cross(0,dx-1,7*dy/8 ,7*dy/8 ,bp,cs) != 1 )
4410 if( num_cross(0,dx-1,7*dy/8-1,7*dy/8-1,bp,cs) != 1 ) Break;
4411 if( num_cross(0,dx-1, dy/4 , dy/4 ,bp,cs) != 2 )
4412 if( num_cross(0,dx-1, dy/4-1, dy/4-1,bp,cs) != 3 ) // \it p with nice kurve
4413 if( num_cross(0,dx-1, dy/4 , dy/4 ,bp,cs) != 2 )
4414 if( num_cross(0,dx-1, dy/4+1, dy/4+1,bp,cs) != 2 ) Break;
4416 i= loop(bp,0,dy/2,dx,cs,0,RI); if(i<1) i++;
4417 if( num_cross(i-1,dx-1, dy/4 , dy/4 ,bp,cs) != 2 )
4418 if( num_cross(i-1,dx-1, dy/4+1, dy/4+1,bp,cs) != 2 ) Break;
4420 i1= loop(bp, 0,3*dy/8,dx,cs,0,RI); if (i1>=dx/2) ad=90*ad/100;
4421 i2=i1+loop(bp,i1,3*dy/8,dx,cs,1,RI); // upper x-position of v line
4422 i3= loop(bp, 0,7*dy/8,dx,cs,0,RI);
4423 i4=i3+loop(bp,i3,7*dy/8,dx,cs,1,RI); // lower x-position of v line
4424 // out_x(box1);printf(" p:");
4425 for ( y=dy/8; y<7*dy/8; y++ ){
4426 x=i2+ (8*y-3*dy)*(i4-i2)/(4*dy); // right limit of line
4427 i= loop(bp,0,y,dx,cs,0,RI); if(i>x+dx/16) break;
4428 } if ( y<7*dy/8 ) Break;
4429 for ( x=0,j=y=dy/3; y<dy-dy/8; y++ ){ // suche unterkante (also 4x6)
4430 i=loop(bp,dx-1,y,dx,cs,0,LE);
4431 if ( i>x ) { x=i; j=y; } if(x>dx/2) break;
4432 } if ( x<dx/2 || x>=dx) Break;
4433 if( get_bw(3*dx/4,dx-1, y , dy-1,bp,cs,1) == 1 ) Break;
4435 i=num_hole (x0,x1,y0,y1-dy/5,box1->p,cs,NULL);
4436 // j=num_hole (x0,x1,y0,y1 ,box1->p,cs,NULL);
4439 if (j!=1 && dx< 8) ad=96*ad/100;
4440 if (j!=1 && dx>=8) ad=98*ad/100;
4441 if (i==0 && j==0) ad=90*ad/100; /* some times there is a small gap */
4442 if (i>1 || j>1 || j>i) Break;
4444 // check for serif F
4445 i= loop(bp,bp->x-1, bp->y/4, dx ,cs,0,LE);
4446 i=i+loop(bp,bp->x-1-i,bp->y/4, dx ,cs,1,LE);
4447 j= loop(bp,bp->x-1-i,bp->y/4,3*dy/4,cs,0,DO);
4448 if (j>dy/2) ad=80*ad/100; // its an serif-F
4450 if( ((!hchar) && (!gchar)) || (hchar && gchar)) ad=95*ad/100;
4452 if( hchar && ((!gchar) || dy<14)) bc='P';
4453 if ( hchar && gchar) ad=98*ad/100; // \ss sz
4454 if ((!hchar) && !gchar) ad=98*ad/100;
4462 static wchar_t ocr0_qQ(ocr0_shared_t *sdata){
4463 struct box *box1=sdata->box1;
4465 int i,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
4466 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
4467 int dx=x1-x0+1,dy=y1-y0+1, /* size */
4470 // --- test Q ---------------------------------------------------
4471 for(ad=d=100;dx>2 && dy>4;){ // min 3x4
4472 DBG( wchar_t c_ask='Q'; )
4473 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
4474 if( get_bw(x0 ,x0+dx/3,y0+dy/3,y0+dy/3,box1->p,cs,1) != 1 ) Break;
4475 if( get_bw(x1-dx/3,x1 ,y0+dy/3,y0+dy/3,box1->p,cs,1) != 1 ) Break;
4476 if( get_bw(x0+dx/2,x0+dx/2,y1-dy/3,y1, box1->p,cs,1) != 1 ) Break;
4477 if( get_bw(x0+dx/2,x0+dx/2,y0 ,y0+dy/4,box1->p,cs,1) != 1 ) Break;
4478 if( get_bw(x0+dx/2,x0+dx/2,y0+dy/3,y1-dy/2,box1->p,cs,1) == 1 ) Break;
4479 if( get_bw(x1 ,x1 ,y0 ,y0 ,box1->p,cs,1) == 1 ) Break; //alpha
4480 if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) < 2 ) Break;
4481 if( num_cross(x0+dx/5,x1-dx/5,y0 , y0 ,box1->p,cs) != 1 ) // AND
4482 if( num_cross(x0+dx/5,x1-dx/5,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
4483 if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
4484 if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
4485 if( get_bw(x1 ,x1 ,y1-dy/8 , y1 ,box1->p,cs,1) == 0 )
4486 if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
4487 if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
4488 // i=num_hole(x0,x1,y0,y1,box1->p,cs,NULL);
4491 if( i!=1 && (i!=2 || num_hole(x0,x1,y0+dy/2,y1,box1->p,cs,NULL)!=1) ) Break;
4493 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,LE,ST); if( x<x1-dx/2 ) Break;
4494 turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,LE);
4495 if( x<x1-dx/2 ) { if (gchar) ad=98*ad/100; else ad=90*ad/100; }
4496 if( loop(bp,0 ,0 ,dx,cs,0,RI)
4497 < loop(bp,0 ,2 ,dx,cs,0,RI) ) Break;
4498 if( loop(bp,0 ,dy/8+2,dx,cs,0,RI)
4499 +loop(bp,dx-1,dy/8+2,dx,cs,0,LE) > 5*dx/8 ) Break; // ~4 Okt00
4501 x= loop(bp,dx-1,3*dy/8,dy,cs,0,LE); if( x>dx/4 ) Break;
4502 if( loop(bp,dx-1-x,0 ,dy,cs,0,DO)
4503 <= loop(bp,dx-2-x,0 ,dy,cs,0,DO) ) Break; // 4
4505 if( loop(bp,dx-1,dy-2,dx,cs,0,LE)
4506 <= loop(bp,dx-1,dy/2,dx,cs,0,LE) )
4507 if( loop(bp, 1,dy-1,dy,cs,0,UP)
4508 <= loop(bp,dx/2,dy-1,dy,cs,0,UP) )
4509 if( loop(bp, 0,dy-2,dx,cs,0,RI)>dx/2 )
4510 if( loop(bp, 0, 0,dx,cs,0,RI)>dx/2 ) Break; // 4
4512 if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE)
4513 + loop(bp, 0,3*dy/4,dx,cs,0,RI)
4514 < loop(bp,dx-1,2*dy/4,dx,cs,0,LE)
4515 + loop(bp, 0,2*dy/4,dx,cs,0,RI) ) ad=94*ad/100; // 4
4516 if( loop(bp,0 ,3*dy/4,dx,cs,1,RI) >= dx ) ad=94*ad/100; // 4
4519 if( loop(bp,dx-1,dy/3,dx,cs,0,LE)> dx/4 ) Break;
4520 j=loop(bp,dx/2,dy-1,dy,cs,0,UP);
4521 if (j>1 && j>dy/8) {
4522 if( get_bw(0,dx/2,dy-1-j/2,dy-1-j/2,bp,cs,1) == 1 ) { // ~RA
4523 if (j<5) ad=95*ad/100;
4529 for(i=0,y=0;y<dy/2;y++)
4530 if( num_cross(0,dx-1,y,y,bp,cs) > 2 ) i++; if(i>dy/8) Break; // ~a \it a
4531 if (i>0) ad=99*ad/100;
4533 // ~o look at the lower right side for falling line
4534 for(j=x=0,y=dy/2;y<dy;y++){
4535 i=loop(bp,dx-1,y,dx,cs,0,LE);if(i>x){ x=i; }
4537 if( j>dx/16 ) Break; // falling line detected
4539 if (j==0) Break; // no falling line => no Q
4540 if (j<=dx/16) ad=98*ad/100;
4541 if(y1<=box1->m3) ad=98*ad/100; // ~q no underlength! rare
4542 if(!hchar) ad=96*ad/100;
4546 // --- test q ---------------------------------------------------
4547 for(ad=d=100;dx>2 && dy>3;){ // min 3x4
4548 DBG( wchar_t c_ask='q'; )
4549 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
4550 for ( y=y0; 2*y<=y0+y1; y++ ){ // detect ring
4551 if( num_cross(x0,x1, y, y,box1->p,cs) == 2 ) Break;
4552 } if (2*y>y0+y1) Break; /* < */
4553 for ( y=(y0+y1)/2; y<=y1; y++ ){ // detect vert line
4554 if( num_cross(x0, x1, y, y,box1->p,cs) == 1
4555 && num_cross(x0,x0+dx/2, y, y,box1->p,cs) == 0 ) Break;
4556 } if (y>y1) Break; /* O (y==y1 for 4x6font-q) */
4557 for ( x=0,j=y=y0+dy/3; y<=y1-dy/8; y++ ){ // detect baseline
4558 i=loop(box1->p,x0,y,dx,cs,0,RI);
4559 if ( i>x ) { x=i; j=y; }
4560 if ( x>dx/2 ) break;
4561 } if ( x<dx/2 || x>=dx) Break;
4562 if (y1-j+1<dy/4) ad=96*ad/100; // ~\it{a}
4563 if( num_cross(x0+x/2,x0+x/2, j, y1,box1->p,cs) != 0 ) ad=96*ad/100; // ~g
4564 if( loop(box1->p,x0+dx/16,j,dy,cs,0,UP)<1+dy/16 ){
4566 if (hchar || !gchar) Break; // 4
4568 if( loop(box1->p,x0+dx/16,j-dy/32-1,dy,cs,1,RI)>=dx-dx/8
4569 || loop(box1->p,x0+dx/16,j-dy/16-1,dy,cs,1,RI)>=dx-dx/8 ){
4572 if( get_bw(x1-dx/3, x1, y0+dy/3, y0+dy/3,box1->p,cs,1) != 1 ) Break;
4573 if( get_bw(x0, x0+dx/3, y0+dy/3, y0+dy/3,box1->p,cs,1) != 1 ) Break;
4574 if( get_bw(x0, x0+dx/4, y1-dy/8, y1-dy/9,box1->p,cs,1) == 1 ) Break;
4575 if( get_bw(x0, x0+dx/4, y1-dy/5, y1-dy/9,box1->p,cs,1) == 1 ) ad=99*ad/100;
4576 if( num_cross(x0+dx/2,x0+dx/2, y0, j ,box1->p,cs) != 2 ) Break;
4577 // if( num_hole (x0 ,x1 , y0, y1 ,box1->p,cs,NULL) != 1 )
4578 if (sdata->holes.num != 1)
4579 { if (dx<16) ad=98*ad/100; else Break; }
4580 if( num_hole (x0 ,x1 , y0, j ,box1->p,cs,NULL) != 1 )
4581 { if (dx<16) ad=98*ad/100; else Break; }
4583 if( loop(bp,0,dy-1-dy/4,dx,cs,0,RI)>5*dx/8
4584 && get_bw(dx/4,dx/4,dy-1-dy/4,dy-1,bp,cs,1)==1 ) Break; // ~\it g
4585 // what about unsure m1-m4?
4586 if(!gchar){ ad=ad*99/100; } // ~4
4587 if( hchar){ ad=ad*99/100; } // ~49
4594 static wchar_t ocr0_iIjJ(ocr0_shared_t *sdata){
4595 struct box *box1=sdata->box1;
4597 int i,j,d,x,y,i1,i2,i3,i4,i5,hchar=sdata->hchar,gchar=sdata->gchar,
4598 ax,ay,bx,by,cx,cy,ex,ey,
4599 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
4600 int dx=x1-x0+1,dy=y1-y0+1, /* size */
4601 ad,ya,yb,yc,yd,ye,yf,xa,xb, /* tmp-vars */
4602 (*aa)[4]=sdata->aa; /* the for line ends, (x,y,dist^2,vector_idx) */
4604 // --- test i ---------------------------------------------------
4605 // if(box1->dots==1) // what about \it neighbouring ij
4606 for(ad=d=100;dy>3 && dx>0;){ // min 3x4 without dot
4607 DBG( wchar_t c_ask='i'; )
4608 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
4609 // ToDo: ':' check that high of dot is smaller than the vert. line!
4621 if (box1->dots!=1) ad=98*ad/100;
4622 while(dy>3*dx && box1->m2){ // test for vertical i without detected dot
4623 i= loop(bp,dx/2,dy-1 ,dy,cs,0,UP);
4624 if (dy-1-i<box1->m3-2) break;
4625 i+=loop(bp,dx/2,dy-1-i,dy,cs,1,UP);
4626 // distance upper end to m2 > (m2-m1)/3
4627 if (3*abs(dy-1-i-box1->m2)>box1->m2-box1->m1) break;
4628 if( get_bw(x0,x1,y0,(box1->m1+box1->m2)/2,box1->p,cs,1) == 1 )
4629 if( get_bw(x0,x1,y1-i ,y1-i ,box1->p,cs,1) == 0
4630 || get_bw(x0,x1,y1-i-1,y1-i-1,box1->p,cs,1) == 0
4631 || get_bw(x0,x1,y1-i-2,y1-i-2,box1->p,cs,1) == 0 )
4634 return 'i'; /* beleave me, thats an "i"! */
4637 // if( box1->dots!=1 ) Break;
4638 if( box1->m2 && 2*y0>=box1->m2+box1->m1 ) ya=box1->m1;
4641 for (y=ya;2*y<ya+y1;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) == 1 ) break;
4642 if (2*y>=ya+y1) Break; // hmm, gap only, no dot?
4644 if (box1->m2 && ya>box1->m2+2) Break;
4645 for ( ;2*y<y1+ya;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) break;
4646 if (2*y>=ya+y1) Break; // hmm no gap
4647 for ( ;2*y<y1+ya;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) == 1 ) break;
4649 if (5*yb>=3*ya+2*y1) ad=99*ad/100; // large gap
4650 if (2*yb>= ya+ y1) ad=97*ad/100; // very large gap, ~:
4651 if (5*yb>=2*ya+3*y1) Break; // huge gap, ~:
4652 if (loop(bp,dx-1,y+(y1-ya+1)/32,dx,cs,0,LE)>dx/2) // unusual (right part of ouml)
4655 // printf(" num_cross dy/2=%d %d\n",dy/2, num_cross(0,dx-1,dy/2,dy/2,bp,cs));
4656 // printf(" dots=%d\n",box1->dots); out_x(box1);
4658 for (y=y1;y>ya;y--) if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) break;
4659 if (y>(ya+3*y1)/4) Break;
4660 if (y>(ya+2*y1)/3) ad=96*ad/100;
4662 y=(y1-yb+1)/2+yb-y0; /* only one vertical line, italic i is more an tall S */
4663 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) Break;
4664 for(;y<=y1-y0;y++){ if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break; } yc=y;
4665 for(;y<=y1-y0;y++){ if( num_cross(0,dx-1,y,y,bp,cs) != 2 ) break; } yd=y;
4666 if( yd<3*(y1-yb+1)/4+yb-y0 ) Break;
4667 y=(y1-yb+1)/2+yb-y0;
4668 for(;y>0;y--){ if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break; } ye=y;
4669 for(;y>0;y--){ if( num_cross(0,dx-1,y,y,bp,cs) != 2 ) break; } yf=y;
4670 if( yf>(y1-yb+1)/4+yb-y0 ) Break;
4672 xa=loop(bp, 0,yc-1,dx,cs,0,RI);
4673 xb=loop(bp,dx-1,yc-1,dx,cs,0,LE);
4675 xb-loop(bp,dx-1,yc,dx,cs,0,LE) /* Dec00 */
4676 > xa-loop(bp, 0,yc,dx,cs,0,RI) ){
4677 y= loop(bp,dx-xb,yc-1,dy,cs,0,DO);
4679 i=loop(bp,dx-xb-1,yc-1+y-1,dy,cs,0,DO);
4682 if( yc-1+y < yd-1 ) Break;
4684 y= loop(bp,11*xa/16,yc-1,dy,cs,0,DO);
4685 if( yc-1+y < yd-2 ) Break;
4689 x=loop(bp,0 ,ye+1,dx,cs,0,RI);
4690 y=loop(bp,x-1,ye+1,dy,cs,0,UP);
4691 i=loop(bp,x ,ye+2-y,dy,cs,0,UP);
4693 if( ye+1-y > yf+1 ) Break;
4695 if( 2*y0 <= box1->m1+box1->m2
4696 && loop(bp,0, 0,dx,cs,0,RI)+1
4697 < loop(bp,0,dx/2,dx,cs,0,RI) ) ad=97*ad/100;
4699 if( gchar ) // i is more often than j, be sure that realy correct Mai00
4700 if( loop(bp, 0,2*dy/4,dx,cs,0,RI)
4701 -loop(bp,dx-1,2*dy/4,dx,cs,0,LE)>dx/8 ) Break;
4703 // could be a broken + or similar thing?
4704 if( 3 * ya > box1->m1 + 2*box1->m2 ) ad=90*ad/100;
4706 if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/2
4707 && loop(bp,dx-1, dy-1,dx,cs,0,LE)<dx/4 ) Break; // ~d=cl
4709 // test for é
4710 if( dx>5 && num_cross(x0+dx/2,x0+dx/2, ya, y1 ,box1->p,cs) >= 3 )
4716 // --- test j ---------------------------------------------------
4717 // if(box1->dots==1) // what about \it neighbouring ij
4718 for(ad=d=100;dy>4 && dx>0;){ // min 3x4
4719 DBG( wchar_t c_ask='j'; )
4720 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
4722 if( box1->m2 && 2*y0>=box1->m2+box1->m1 ) ya=box1->m1;
4724 for(y=ya;2*y<ya+y1;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) == 1 ) break;
4725 if(2*y>=ya+y1) Break; // hmm only gap
4727 if( box1->m2 && ya>box1->m2+2 ) Break;
4728 for( ;2*y<y1+ya;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) break;
4729 if(2*y>=ya+y1) Break; // hmm no gap
4730 for( ;2*y<y1+ya;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) == 1 ) break;
4731 if(2*y>=ya+y1) Break; // hmm very large gap
4733 if( loop(bp,dx-1,y+(y1-ya+1)/32,dx,cs,0,LE)>dx/2 ) Break; // unusual (right part of ouml)
4735 // printf(" num_cross dy/2=%d %d\n",dy/2, num_cross(0,dx-1,dy/2,dy/2,bp,cs));
4736 // printf(" dots=%d\n",box1->dots); out_x(box1);
4738 for(y=(ya+y1)/2;y<=y1;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) break;
4741 y=(y1-yb+1)/2+yb-y0; /* only one vertical line, italic i is more an tall S */
4742 if( num_cross(0,dx-1,y,y,bp,cs) >2 ) Break;
4743 for(;y<=y1-y0;y++){ if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break; } yc=y;
4744 for(;y<=y1-y0;y++){ if( num_cross(0,dx-1,y,y,bp,cs) != 2 ) break; } yd=y;
4745 if( yd<3*(y1-yb+1)/4+yb-y0 ) Break;
4746 y=(y1-yb+1)/2+yb-y0;
4747 for(;y>0;y--){ if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break; } ye=y;
4748 for(;y>0;y--){ if( num_cross(0,dx-1,y,y,bp,cs) != 2 ) break; } yf=y;
4749 if( yf>(y1-yb+1)/4+yb-y0 ) Break;
4751 xa=loop(bp, 0,yc-1,dx,cs,0,RI);
4752 xb=loop(bp,dx-1,yc-1,dx,cs,0,LE);
4754 xb-loop(bp,dx-1,yc,dx,cs,0,LE) /* Dec00 */
4755 > xa-loop(bp, 0,yc,dx,cs,0,RI) ){
4756 y= loop(bp,dx-xb,yc-1,dy,cs,0,DO);
4758 i=loop(bp,dx-xb-1,yc-1+y-1,dy,cs,0,DO);
4761 if( yc-1+y < yd-1 ) Break;
4763 y= loop(bp,11*xa/16,yc-1,dy,cs,0,DO);
4764 if( yc-1+y < yd-2 ) Break;
4768 x=loop(bp,0 ,ye+1,dx,cs,0,RI);
4769 y=loop(bp,x-1,ye+1,dy,cs,0,UP);
4770 i=loop(bp,x ,ye+2-y,dy,cs,0,UP);
4772 if( ye+1-y > yf+1 ) Break;
4774 if( 2*y0 <= box1->m1+box1->m2
4775 && loop(bp,0, 0,dx,cs,0,RI)+1
4776 < loop(bp,0,dx/2,dx,cs,0,RI) ) ad=97*ad/100;
4777 if (loop(bp,0,dy-1,dx,cs,0,RI)
4778 -loop(bp,0,dy-3,dx,cs,0,RI)>1+dx/16) ad=96*ad/100; // ~c
4780 if( gchar ) // i is more often than j, be sure that realy correct Mai00
4781 if( loop(bp, 0,2*dy/4,dx,cs,0,RI)
4782 -loop(bp,dx-1,2*dy/4,dx,cs,0,LE)<=dx/8 ) Break;
4783 // could be a broken + or similar thing?
4784 if( 3 * ya > box1->m1 + 2*box1->m2 ) ad=80*ad/100;
4785 if (!gchar) ad=96*ad/100;
4786 if( box1->dots!=1 ) ad=98*ad/100;
4792 // --- test I ---------------------------------------------------
4793 for(ad=d=100;dy>4 && dy>dx && 5*dy>4*(box1->m3-box1->m2);){ // min 3x4
4794 DBG( wchar_t c_ask='I'; )
4795 if( box1->dots==1 ) Break;
4796 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
4798 x =loop(bp,0, dy/2,dx,cs,0,RI); // konvex? divided Q
4799 if(loop(bp,0,7*dy/8,dx,cs,0,RI) > x+dx/8) Break;
4800 for( y=dy/16;y<dy-1-dy/16;y++ )
4801 if( num_cross(0, dx-1, y , y ,bp,cs) != 1 )
4802 if( num_cross(0, dx-1, y+dy/16 , y+dy/16 ,bp,cs) != 1 ) break;
4803 if( y<dy-1-dy/16 ) Break;
4804 x =loop(bp,0, dy/2,dx,cs,0,RI);
4805 i5=loop(bp,x, dy/2,dx,cs,1,RI); // center width
4806 for(y=dy/4;y<3*dy/4;y++ ){ // same width ?
4807 x =loop(bp,0, y,dx,cs,0,RI);
4808 x =loop(bp,x, y,dx,cs,1,RI); // width
4809 if( abs(x-i5)>1+dx/8 ) break;
4810 } if( y<3*dy/4 ) Break;
4814 for(i2=i1=0,y=0;y<dy/4;y++ ){
4815 x =loop(bp,0, y,dx,cs,0,RI);
4816 x =loop(bp,x, y,dx,cs,1,RI); if(x>i1){ i1=x;i2=y; }
4818 for(i4=i3=0,y=3*dy/4;y<dy;y++ ){
4819 x =loop(bp,0, y,dx,cs,0,RI);
4820 x =loop(bp,x, y,dx,cs,1,RI); if(x>i3){ i3=x;i4=y; }
4822 if( abs(i3-i1)>1+dx/8 ) Break; // if i3>>i5 more sure!
4823 if( i1>i5 ){ // look for edges else *80%
4825 if(i1+1<i5 && !hchar) Break; // Jun00
4827 // calculate upper and lower mass center
4828 x =loop(bp,0, dy/8,dx,cs,0,RI); i1=x;
4829 x+=loop(bp,x, dy/8,dx,cs,1,RI); i1=(i1+x-1)/2;
4831 x =loop(bp,0,dy-1-dy/8,dx,cs,0,RI); i2=x;
4832 x+=loop(bp,x,dy-1-dy/8,dx,cs,1,RI); i2=(i2+x-1)/2;
4833 x =loop(bp,0,dy-2-dy/8,dx,cs,0,RI); i=x;
4834 x+=loop(bp,x,dy-2-dy/8,dx,cs,1,RI); i=(i+x-1)/2; if( i>i2 ) i2=i;
4836 // printf(" get_line(%d,%d) %d\n",i1,i2,
4837 // get_line2(i1,dy/8,i2,dy-1-dy/8,bp,cs,100));
4838 if( get_line2(i1,dy/8,i2,dy-1-dy/8,bp,cs,100)<95 ) Break;
4839 x =(i1-i2+4)/8; i1+=x; i2-=x;
4841 // upper and lower width (what about serifs?)
4843 x =loop(bp,i1, y+0,dx,cs,1,LE); i=x;
4844 x =loop(bp,i1, y+1,dx,cs,1,LE); if(x>i)i=x;
4845 x =loop(bp,i1, y+0,dx,cs,1,RI); j=x;
4846 x =loop(bp,i1, y+1,dx,cs,1,RI); if(x>j)j=x; if(abs(i-j)>1+dx/8)Break;
4847 x =loop(bp,i2,dy-y-1,dx,cs,1,LE); j=x;
4848 x =loop(bp,i2,dy-y-2,dx,cs,1,LE); if(x>j)j=x; if(abs(i-j)>1+dx/8)Break;
4849 x =loop(bp,i2,dy-y-1,dx,cs,1,RI); j=x;
4850 x =loop(bp,i2,dy-y-2,dx,cs,1,RI); if(x>j)j=x; if(abs(i-j)>1+dx/8)Break;
4853 if( loop(bp,dx-1,dy/16 ,dx,cs,0,LE)
4854 > loop(bp,dx-1,dy/4 ,dx,cs,0,LE)+1+dx/32 ) Break; // ~bad ) (thinn)
4856 for(i=0,y=dy/16;y<15*dy/16 && i<2;y++)
4857 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) i++;
4860 if(!hchar){ // right part (bow) of h is never a l
4861 if( get_bw(dx/4,dx/4, 0,dy/4,bp,cs,1) == 1
4862 && get_bw(dx/4,dx/4,dy/2,dy-1,bp,cs,1) == 0 ) Break;
4863 if( loop(bp, 0,dy/4,dx,cs,0,RI)> dx/4
4864 && loop(bp,dx-1,dy/4,dx,cs,0,LE)<=dx/4
4865 && loop(bp, 1, 0,dy,cs,0,DO)<=dy/4 ) Break; // ~z
4868 if( get_bw(x1,x1,y0 ,y1 ,box1->p,cs,2) != 2
4869 && get_bw(x0,x1,y0 ,y0 ,box1->p,cs,2) != 2
4870 && get_bw(x0,x1,y1 ,y1 ,box1->p,cs,2) != 2
4871 && get_bw(x0,x0,y0+1,y1-1,box1->p,cs,1) != 1 ) Break; /* ~] */
4873 if ( loop(bp,dx-1, dy/4,dx,cs,0,LE) > dx/2
4874 && loop(bp,dx-1,3*dy/4,dx,cs,0,LE) > dx/2
4875 && loop(bp, 0, dy/2,dx,cs,0,RI) < dx/4 ) Break; /* ~[ */
4877 x =loop(bp, 0,dy/2,dx,cs,0,RI); // konvex/konkav? ~()
4878 i =loop(bp,dx-1,dy/2,dx,cs,0,LE);
4879 if( loop(bp, 0,7*dy/8,dx,cs,0,RI) > x+dx/8
4880 && loop(bp, 0, dy/8,dx,cs,0,RI) > x+dx/8
4881 && loop(bp,dx-1,7*dy/8,dx,cs,0,LE) < i-dx/8
4882 && loop(bp,dx-1, dy/8,dx,cs,0,LE) < i-dx/8 ) Break; // ~(
4883 if( loop(bp, 0,7*dy/8,dx,cs,0,RI) < x-dx/8
4884 && loop(bp, 0, dy/8,dx,cs,0,RI) < x-dx/8
4885 && loop(bp,dx-1,7*dy/8,dx,cs,0,LE) > i+dx/8
4886 && loop(bp,dx-1, dy/8,dx,cs,0,LE) > i+dx/8 ) Break; // ~)
4887 if( loop(bp, 0, dy/8,dx,cs,0,RI)
4888 -(dx-loop(bp,dx-1,7*dy/8,dx,cs,0,LE)) > dx/4 ) Break; // ~/
4889 if( loop(bp, 0, 0,dx,cs,0,RI) > dx/2 // ToDo: check for serifs
4890 && loop(bp, 0, dy/8,dx,cs,0,RI) > dx/2
4891 && loop(bp,dx-1,dy-1 ,dx,cs,0,LE) > dx/2
4892 && loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE) > dx/2 ) ad=99*ad/100; // ~/
4894 if (box1->m2 && 3*y0>box1->m1+2*box1->m2)
4895 if( get_bw(x0+dx/8,x1-dx/8,box1->m1,(box1->m1+box1->m2)/2,box1->p,cs,1) == 1 )
4898 if(i1+1<i5 && !hchar){ ad=65*ad/100; MSG({}) } // ~ slanted I
4900 // be sure only for serif
4901 i3=loop(bp,dx-1, dy/4,dx,cs,0,LE);
4902 i4=loop(bp, 0,dy-1-dy/4,dx,cs,0,RI);
4904 || get_bw(x1-i3/4,x1-i3/4,y0,y0+dy/4,box1->p,cs,1) != 1
4905 || get_bw(x0+i4/4,x0+i4/4,y1-dy/4,y1,box1->p,cs,1) != 1 )
4906 { ad=99*ad/100; MSG(fprintf(stderr,"ad=%d",ad);) } // ToDo: improve it
4907 if(!hchar){ ad=96*ad/100; MSG({}) } // ~bad_small_r
4908 if (box1->m4 && y1<box1->m4) { // probably lower dot?
4909 if ((dx>2 && get_bw(x0+1,x1-1,y1+1,box1->m4,box1->p,cs,1) == 1)
4910 || (dx<3 && get_bw(x0 ,x1 ,y1+1,box1->m4,box1->p,cs,1) == 1)) {
4919 for(bx=0,ax=dx,ay=by=y=0;y<dy/4;y++){
4920 i =loop(bp,dx-1 ,y,dx,cs,0,LE); if (dx-i-1>bx) { bx=dx-1-i; by=y; }
4921 i+=loop(bp,dx-1-i,y,dx,cs,1,LE); if (dx-i-1<ax) { ax=dx-i; ay=y; }
4923 for(cx=dx,ex=0,ey=cy=y=dy-1;y>dy-1-dy/4;y--){
4924 i =loop(bp,0,y,dx,cs,0,RI); if (i<cx) { cx=i; cy=y; }
4925 i+=loop(bp,i,y,dx,cs,1,RI); if (i>ex) { ex=i; ey=y; }
4927 x=(3*ax+cx)/4; y=(3*ay+cy)/4; i= loop(bp,x,y,dx,cs,0,RI);
4928 x=(3*bx+ex)/4; y=(3*by+ey)/4; j= loop(bp,x,y,dx,cs,0,LE);
4929 if (j>0 && (2*i>3*j || 3*i<2*j )) ad=99*ad/100;
4930 if (j>0 && ( i>2*j || 2*i< j )) ad=97*ad/100;
4931 i=loop(bp,0,0,dy,cs,0,DO);
4932 if (i>dy/8 && i<dy/2) ad=99*ad/100; // ~1
4933 if (loop(bp,dx-1,0,dx,cs,0,LE)
4934 -loop(bp, 0,0,dx,cs,0,RI)>dx/4) ad=96*ad/100; // ~l 5x7
4936 if( get_bw(x0,x1,y0,y1,box1->p,cs,2) == 0 ) ad=99*ad/100;
4937 if (gchar) ad=98*ad/100; // J
4938 if (box1->m3 && 2*y1<=box1->m2+box1->m3) ad=96*ad/100; // '
4943 // --- test J --------------------------------------------------- 22Nov06
4944 for(ad=d=100;dy>4 && dy>=dx && dx>2;){ // min 3x4 ~Y)]d',
4945 // rewritten for vectors 0.42
4946 int ld, i1, i2, i3, i4, i5, i6, i7; // line derivation + corners
4947 DBG( wchar_t c_ask='J'; )
4948 if (sdata->holes.num > 0) Break; /* no hole */
4949 /* half distance to the center */
4951 /* now we check for the upper right end of the J */
4952 if (aa[3][2]>d) Break; /* [2] = distance */
4953 /* searching for 4 notches between neighbouring ends */
4967 /* Warning: aa0 can be left upper or left lower point for type B */
4968 /* get a point on the inner low left side of the J */
4969 i =nearest_frame_vector(box1,aa[3][3],aa[1][3],(x0+x1)/2,y0);
4970 i1=nearest_frame_vector(box1,i ,aa[1][3], x1+dx,(y0+3*y1)/4);
4971 /* get the most left point on the lower part of the J */
4972 i2=nearest_frame_vector(box1,i1,aa[3][3], x0-2*dx, y1-dy/8);
4973 /* get a point on the middle of the bottom of the J */
4974 i3=nearest_frame_vector(box1,aa[1][3],aa[2][3], (x0+x1)/2, y1);
4975 /* get a point on the outer low right side of the J */
4976 i4=nearest_frame_vector(box1,aa[1][3],aa[3][3], x1, (y0+2*y1)/3);
4977 /* get a point on the outer right side below top serif */
4978 i5=nearest_frame_vector(box1,aa[2][3],aa[3][3], (x0+2*x1)/3,y0);
4979 /* get a point on the left side of upper serif */
4980 i6=nearest_frame_vector(box1,aa[3][3],i1, x0, y0);
4981 /* get a point on the most right left side of upper serif */
4982 i7=nearest_frame_vector(box1,i6,i1, x1, y0);
4983 MSG(fprintf(stderr," i1-i7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);)
4985 /* check the highest point on lower left area */
4986 i =nearest_frame_vector(box1,i1,i3,x0,y0);
4987 if (box1->frame_vector[i ][1]-y0<dy/4) Break; // U
4988 if (box1->frame_vector[i ][1]-y0<=dy/2) ad=97*ad/100; // imperfect a
4989 /* check the lowest point on upper left area, serife? */
4990 j =nearest_frame_vector(box1,i6,i7,x0,y1);
4991 if (box1->frame_vector[i ][1]
4992 -box1->frame_vector[j ][1]<=dy/4) Break; // imperfect a
4993 if (box1->frame_vector[i7][1]>y0+dy/4) Break; // not to low
4994 if (box1->frame_vector[i1][1]
4995 -box1->frame_vector[i7][1]<dy/2) Break;
4996 if (box1->frame_vector[i4][1]
4997 -box1->frame_vector[i5][1]<dy/2) Break;
4998 if (box1->frame_vector[i7][0]<x0+dx/2) Break;
4999 if (box1->frame_vector[i1][0]
5000 -box1->frame_vector[i2][0]<=dx/8) Break; // ~1
5001 if (box1->frame_vector[i1][0]
5002 -box1->frame_vector[i2][0]<=dx/4) ad=ad*99/100; // ~1
5003 if (box1->frame_vector[i6][1]>y0+dy/8) ad=99*ad/100; // ~1
5004 if (aa[0][2]==0) { // ]?
5006 if (aa[1][2]==0) ad=98*ad/100;
5007 if (aa[2][2]<=aa[3][2]) ad=97*ad/100;
5010 /* check for left bow */
5011 for (j=i=i2;i!=i4;i=(i+1)%box1->num_frame_vectors[0]) {
5012 if (box1->frame_vector[ i][0] /* [0]=x */
5013 <box1->frame_vector[i1][0]) break; /* curve? */
5014 } if (i==i4) Break; // ~I
5015 /* check for no right bow */
5016 for (j=i=i2;i!=i4;i=(i+1)%box1->num_frame_vectors[0]) {
5017 if (box1->frame_vector[ i][0] /* [0]=x */
5018 >box1->frame_vector[i4][0]) break;
5019 } if (i!=i4) Break; // ~I
5020 /* check for no right bow */
5021 for (j=i=i5;i!=i6;i=(i+1)%box1->num_frame_vectors[0]) {
5022 if (box1->frame_vector[ i][1] > y0+dy/4) break;
5023 } if (i!=i6) Break; // ~Y
5024 /* check if upper left and lower left points are joined directly */
5025 ld=line_deviation(box1, i7, i1);
5026 MSG(fprintf(stderr," i7,i1 %d %d linedist= %d/%d",i7,i1,ld,2*sq(1024/4));)
5027 if (ld >2*sq(1024/4)) Break;
5028 if (5*ld >4*2*sq(1024/4)) ad=99*ad/100; // ~3
5029 if (6*ld >4*2*sq(1024/4)) ad=99*ad/100; // ~3
5030 if (7*ld >4*2*sq(1024/4)) ad=99*ad/100; // ~3
5031 if (8*ld >4*2*sq(1024/4)) ad=99*ad/100; // ~3
5032 /* check if lower right and upper right points are joined directly */
5033 ld=line_deviation(box1, i4, i5);
5034 MSG(fprintf(stderr," i4,i5 %d %d linedist= %d/%d",i4,i5,ld,2*sq(1024/4));)
5035 if (ld >2*sq(1024/4)) Break;
5036 if (5*ld >4*2*sq(1024/4)) ad=99*ad/100;
5038 // J exists as gchar and ~gchar
5039 if(!hchar){ ad=99*ad/100; }
5046 static wchar_t ocr0_brackets(ocr0_shared_t *sdata){
5047 struct box *box1=sdata->box1;
5049 int i,j,d,x,y,i1,i2,i3,i4,i5,i6,hchar=sdata->hchar,
5050 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
5051 int dx=x1-x0+1,dy=y1-y0+1, /* size */
5052 (*aa)[4]=sdata->aa, /* corner-points, (x,y,dist^2,vector_idx) */
5053 ad,r1,r2; /* tmp-vars */
5056 // --- test > derived from xX ---------------------------------------------------
5057 // rewritten for vectors v0.41
5058 for(ad=d=100;dx>1 && dy>2;){ // min 3x2
5059 // 0 - indizes 0,1,i1,i2 pointing to edges of the char
5066 DBG( wchar_t c_ask='>'; )
5067 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5068 if (sdata->holes.num > 0 && (dx<6 || dy<6)) Break; /* # */
5069 /* calculate the half distance to the center */
5071 /* now we check for the 2 left ends of the > */
5072 if (aa[0][2]>d) Break; /* upper left end */
5073 if (aa[1][2]>d) Break; /* lower left end */
5074 if (aa[1][1]-aa[0][1]<dy/2) Break;
5075 /* searching for 4 notches between neighbouring ends */
5077 /* run along left side from top to bottom */
5078 for (j=i=aa[0][3];i!=aa[1][3];i=(i+1)%box1->num_frame_vectors[0]) {
5079 if (box1->frame_vector[i][0]
5080 >=box1->frame_vector[j][0]) j=i; /* notice most right vector */
5081 } if (j==i || j==aa[0][3]) Break;
5082 /* calculate the distance to the center */
5083 x=box1->frame_vector[j][0];
5084 y=box1->frame_vector[j][1];
5085 if (2*x-aa[0][0]-aa[1][0]<dx) ad=99*ad/100;
5086 if (abs(aa[0][1]+aa[1][1]-2*y)>(dy+2)) Break;
5087 if ( aa[0][0]+aa[1][0]-2*x>=0) Break;
5089 d=line_deviation(box1, aa[0][3], j) >sq(1024/4);
5090 /* check if upper left and center point are joined directly */
5091 MSG(fprintf(stderr,"x %d %d dist= %d/%d",x-x0,y-y0,d,sq(1024/4));)
5092 if (d >sq(1024/4)) Break; ad=ad-d*100/sq(1024);
5093 MSG(fprintf(stderr,"ad=%d", ad);)
5094 d=line_deviation(box1, j, aa[1][3]);
5095 /* check if lower left and center point are joined directly */
5096 MSG(fprintf(stderr,"x %d %d dist= %d/%d",x-x0,y-y0,d,sq(1024/4));)
5097 if (d >sq(1024/4)) Break; ad=ad-d*100/sq(1024);
5098 MSG(fprintf(stderr,"ad=%d", ad);)
5100 /* run along right side from bottom to top */
5101 for (j=i=aa[1][3];i!=aa[0][3];i=(i+1)%box1->num_frame_vectors[0]) {
5102 if (box1->frame_vector[i][0]
5103 >=box1->frame_vector[j][0]) j=i; /* notice most right vector */
5104 // MSG(fprintf(stderr,"search right: %d %d %d %d",i,j,aa[1][3],aa[0][3]);)
5105 } if (j==i || j==aa[1][3]) Break;
5106 /* calculate the distance to the center */
5107 x=box1->frame_vector[j][0];
5108 y=box1->frame_vector[j][1];
5109 if ( (aa[0][0]+aa[1][0]-2*x)>= 0 ) Break;
5110 if (abs(aa[0][1]+aa[1][1]-2*y)>(dy+2)/4) Break;
5111 if (aa[0][0]>=x || aa[1][0]>=x) Break;
5113 d=line_deviation(box1, j, aa[0][3]);
5114 /* check if upper left and center point are directly joined directly */
5115 MSG(fprintf(stderr,"x %d %d dist= %d/%d",x-x0,y-y0,d,sq(1024/4));)
5116 if (d >sq(1024/4)) Break; ad=ad-d*100/sq(1024);
5117 MSG(fprintf(stderr,"ad=%d", ad);)
5118 d=line_deviation(box1, aa[1][3], j);
5119 /* check if lower left and center point are directly joined */
5120 MSG(fprintf(stderr,"x %d %d dist= %d/%d",x-x0,y-y0,d,sq(1024/4));)
5121 if (d >sq(1024/4)) Break; ad=ad-d*100/sq(1024);
5122 MSG(fprintf(stderr,"ad=%d", ad);)
5125 ToDo: calculate momentums or max derivations
5126 along lines to distinguish )]}>
5130 if (sdata->gchar) ad=98*ad/100;
5131 if (sdata->hchar) ad=99*ad/100;
5136 // --- test /\\ ------------------------------------------------
5139 for(ad=d=100;dx>3 && dy>3;){ // min 4x4 for 4x6 font
5140 DBG( wchar_t c_ask='/'; )
5141 if (sdata->holes.num > 0) Break; /* tolerant against a tiny hole */
5143 for(i=y=0;y<dy;y++){
5144 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) i++;
5145 if( loop(bp, 0,y,dx,cs,0,RI)
5146 + loop(bp,dx-1,y,dx,cs,0,LE)<3*dx/8 ) break;
5149 if ( i>2 || (i>0 && dy<16)) Break;
5151 /* get the center as exact as possible */
5152 i2=dx-1-loop(bp,dx-1,dy/2 ,dx,cs,0,LE) // be exact for small fonts
5153 +dx-1-loop(bp,dx-1,dy/2+dy%2-1,dx,cs,0,LE)
5154 + loop(bp, 0,dy/2 ,dx,cs,0,RI)
5155 + loop(bp, 0,dy/2+dy%2-1,dx,cs,0,RI);
5156 if (abs(i2-2*dx)>1+dx/2) Break;
5157 if (abs(i2-2*dx)> dx/2) ad=99*ad/100;
5159 i1=loop(bp,dx-1,dy/16,dx,cs,0,LE); // right side
5160 i3=loop(bp,dx-1,dy-1 ,dx,cs,0,LE);
5161 i4=loop(bp, 0,0 ,dx,cs,0,RI); // left side
5162 i6=loop(bp, 0,dy-1 ,dx,cs,0,RI);
5163 i=(box1->m4+box1->m3)/2-box1->m2;
5165 // out_x(box1);printf("() %d %d %d %d %d %d %d\n",i,i1,i2,i3,i4,i5,i6);
5168 for(i=i4,y=0;y<dy;y++){
5169 x=loop(bp,0 ,y,dx,cs,0,RI);if(abs(x-i)>dx/6+1 ) break; i=x;
5171 for(i=i1,y=0;y<dy;y++){
5172 x=loop(bp,dx-1,y,dx,cs,0,LE);if(abs(x-i)>dx/6+1 ) break; i=x;
5174 if(i1<=dx/8 && i6<=dx/8 && i4-(dx-i3)>dx/4 ) { Setac(box1,(bc='/'),ad);break; }
5175 if(i4<=dx/8 && i3<=dx/8 && i6-(dx-i1)>dx/4 ) { Setac(box1,(bc='\\'),ad);break; }
5178 // --- test ()<> ------------------------------------------------
5181 for(ad=d=100;dx>1 && dy>4;){ // min 3x4
5182 DBG( wchar_t c_ask='('; )
5183 if (sdata->holes.num > 1) {Break;}; /* tolerant against a tiny hole */
5185 for(i=y=0;y<dy;y++){
5186 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) i++;
5187 if( loop(bp, 0,y,dx,cs,0,RI)
5188 + loop(bp,dx-1,y,dx,cs,0,LE)<3*dx/8 ) break;
5190 if( y<dy ) {Break;};
5191 if ( i>2 || (i>0 && dy<16)) {Break;};
5193 /* look for the extrema => r1..r2 */
5194 for(i=dx,r1=r2=y=dy/2-dy/8;y<=dy/2+dy/8;y++){
5195 j=loop(bp, 0,y,dx,cs,0,RI); if(j==i) r2=y; if(j<i){ r2=r1=y; i=j; }
5196 j=loop(bp,dx-1,y,dx,cs,0,LE); if(j==i) r2=y; if(j<i){ r2=r1=y; i=j; }
5198 i1=loop(bp,dx-1, dy/16,dx,cs,0,LE);
5199 i2=loop(bp,dx-1,y ,dx,cs,0,LE);
5200 i3=loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE);
5201 i4=loop(bp, 0,dy/16 ,dx,cs,0,RI);
5202 i5=loop(bp, 0,y ,dx,cs,0,RI);
5203 i6=loop(bp, 0,dy-1-dy/16,dx,cs,0,RI);
5205 // from Aug06 vector-version of greater is used
5206 // if(i2==0 && 3*i5>dx && i4<=dx/8 && i6<=dx/8) { Setac(box1,(bc='>'),98);{Break;}; }
5207 if(i5==0 && 3*i2>dx && i1<=dx/8 && i3<=dx/8) { Setac(box1,(bc='<'),98);{Break;}; }
5209 if( dx > 2 && 9*dx>=5*dy ){ // 4x6 screen-font (3*5)
5211 if (dx<8) ad=99*ad/100;
5212 if (dx<6) ad=96*ad/100;
5213 if( 2*dx > JOB->res.avX && 4*dx>dy ) ad=98;
5214 // printf(" %d %d %d %d %d %d\n",i5,i1,i3,i2,i4,i6);
5215 if( i5==0 && i1<=dx/8+1 && i3<=dx/8+1 && i1+i3<=dx/8+1
5216 && i2>=dx/2 && i4>=3*dx/4 && i6>=3*dx/4 ) {
5217 if (2*loop(bp, 0, y/2,dx,cs,0,RI)+1+dx/16<i4+i5) ad=95*ad/100;
5218 if (2*loop(bp, 0,dy-1-y/2,dx,cs,0,RI)+1+dx/16<i6+i5) ad=95*ad/100;
5219 Setac(box1,(bc='<'),ad);{Break;};
5221 /* obsolete code Aug06, will be removed if new code is stable
5222 if( i2==0 && i4<=dx/8 && i6<=dx/8
5223 && i5>=dx/2 && i1>=3*dx/4 && i3>=3*dx/4 ) {
5224 if (2*loop(bp,dx-1, y/2,dx,cs,0,LE)+1+dx/16<i1+i2) ad=95*ad/100;
5225 if (2*loop(bp,dx-1,dy-1-y/2,dx,cs,0,LE)+1+dx/16<i3+i2) ad=95*ad/100;
5226 Setac(box1,(bc='>'),ad);{Break;};
5231 i1=loop(bp,dx-1,dy/16,dx,cs,0,LE);
5232 i2=loop(bp,dx-1,dy/2 ,dx,cs,0,LE);
5233 i3=loop(bp,dx-1,dy-1 ,dx,cs,0,LE);
5234 i4=loop(bp, 0,0 ,dx,cs,0,RI);
5235 i5=loop(bp, 0,dy/2,dx,cs,0,RI);
5236 i6=loop(bp, 0,dy-1,dx,cs,0,RI);
5237 i=(box1->m4+box1->m3)/2-box1->m2;
5239 // out_x(box1);printf("() %d %d %d %d %d %d %d\n",i,i1,i2,i3,i4,i5,i6);
5240 if(2*i2<i1+i3 && 2*i5>i4+i6 && 2*dx<dy && dy>=i){
5241 Setac(box1,(bc=')'),98);break; }
5242 if(2*i2>i1+i3 && 2*i5<i4+i6 && 2*dx<dy && dy>=i){
5243 if(2*i2<=i1+i3+1 || 2*i5>=i4+i6-1) ad=98*ad/100;
5244 if(2*i2<=i1+i3+2 || 2*i5>=i4+i6-2) ad=98*ad/100;
5245 for(x=y=0;y<dy/4;y++){
5246 i=loop(bp,0,y,dx,cs,0,RI);if( i>x ) x=i;
5248 for(y=0;y<(dy+2)/4;y++){
5249 i=loop(bp,0,y+dy/8,dx,cs,0,RI);if( i<x ) break;
5251 if( y==(dy+2)/4 ) {Break;}; // ~l (left upper side must be convex) Jul00
5252 Setac(box1,(bc='('),ad); break;
5256 // --------- test [] --------------------------------
5257 for(ad=d=98;dx>2 && dy>4 && dy>=2*dx;){ // (3,6) on 4x6 font
5258 DBG( wchar_t c_ask=']'; )
5259 if (sdata->holes.num > 1) { Break;} /* tolerant against a tiny hole */
5260 if (!hchar) ad=97*ad/100;
5262 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
5263 } if (y<dy) {Break;};
5264 if( get_bw(x0,x1,y0 ,y0 ,box1->p,cs,2) == 2
5265 && get_bw(x0,x1,y0+1,y0+1,box1->p,cs,2) == 2 ) {Break;};
5266 if( get_bw(x0,x1,y1 ,y1 ,box1->p,cs,2) == 2
5267 && get_bw(x0,x1,y1-1,y1-1,box1->p,cs,2) == 2 ) {Break;};
5268 if( get_bw(x0 ,x0,y0 ,y1 ,box1->p,cs,2) == 0
5269 || get_bw(x0+1 ,x0+1,y0 ,y1 ,box1->p,cs,2) == 0 )
5270 if( get_bw(x0+dx/2,x1,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 )
5271 { Setac(box1,(bc='['),ad);break; }
5272 if( get_bw(x1 ,x1,y0 ,y1 ,box1->p,cs,2) == 0
5273 || get_bw(x1-1 ,x1-1,y0 ,y1 ,box1->p,cs,2) == 0 )
5274 if( get_bw(x0,x1-dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 )
5275 { Setac(box1,(bc=']'),ad);break; }
5279 #if CODE_NOT_COMPLETED
5280 // --- test ] -------
5281 for(ad=d=100;dx>2 && dy>3;){
5282 DBG( wchar_t c_ask=']'; )
5283 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5284 if (sdata->holes.num > 0) ad=98*ad/100; /* # */
5285 /* 1/8 distance to the center */
5287 /* now we check for the 4 ends of the x */
5288 if (aa[0][2]>d) Break;
5289 if (aa[1][2]>d) Break;
5290 if (aa[2][2]>d) Break;
5291 if (aa[3][2]>d) Break;
5292 if (aa[3][0]-aa[0][0]<7*dx/8) Break;
5293 if (aa[2][0]-aa[1][0]<7*dx/8) Break;
5294 if (aa[1][1]-aa[0][1]<7*dy/8) Break;
5295 if (aa[2][1]-aa[3][1]<7*dy/8) Break;
5296 if (aa[3][0]-aa[0][0]<2) Break; /* to small */
5297 if (aa[2][0]-aa[1][0]<2) Break; /* to small */
5298 MSG( fprintf(stderr," aa %d %d %d %d %d %d %d %d d %d %d %d %d",\
5299 aa[0][0]-x0,aa[0][1]-y0,aa[1][0]-x0,aa[1][1]-y0,\
5300 aa[2][0]-x0,aa[2][1]-y0,aa[3][0]-x0,aa[3][1]-y0,\
5301 aa[0][2],aa[1][2],aa[2][2],aa[3][2]);)
5302 /* left and right vertical line */
5303 d=line_deviation(box1, aa[0][3], aa[1][3]); if (d>2*sq(1024/4)) Break;
5304 ad=(100-(d-sq(1024)/2)/sq(1024)/4)*ad/100;
5305 d=line_deviation(box1, aa[2][3], aa[3][3]); if (d>2*sq(1024/4)) Break;
5307 /* search uppermost left ^ */
5308 i1=nearest_frame_vector(box1,aa[1][3],aa[2][3], x0, y0);
5309 x=box1->frame_vector[i1][0];
5310 y=box1->frame_vector[i1][1];
5311 if (y-y0 > 5*dy/8) Break;
5312 if (x-x0 > 5*dx/8) Break;
5313 /* search uppermost right ^ ~H */
5314 i3=nearest_frame_vector(box1,aa[1][3],aa[2][3], x1, y0);
5315 if ( box1->frame_vector[i3][0]-x> dx/4
5316 && box1->frame_vector[i3][1]-y<=dy/8) Break;
5318 /* check if upper left and lower right point are joined directly */
5319 dbg[0]=d=line_deviation(box1,i1, aa[2][3]); if (d >2*sq(1024/4)) Break;
5320 /* check if lower left and lower left point are joined directly */
5321 dbg[1]=d=line_deviation(box1, aa[1][3],i1); if (d >2*sq(1024/4)) Break;
5323 if (!hchar) ad=99*ad/100;
5324 if ( gchar) ad=98*ad/100; // \sc N
5327 if (ad>=100) return ac;
5331 // --------- test ocr-a-[] --------------------------------
5333 for(ad=d=98;dx>5 && dy>7 && 2*dy>3*dx;){ // only for accurate font at the moment
5334 DBG( wchar_t c_ask='['; )
5335 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
5336 if (!hchar) ad=97*ad/100;
5337 if( num_cross(0,dx-1, 0, 0,bp,cs) != 1 ) break;
5338 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs) != 1 ) break;
5339 if ( loop(bp,dx-1,dy/2,dx,cs,0,LE)
5340 +loop(bp, 0,dy/2,dx,cs,0,RI) <= dx/4 ) break; // O
5341 for(y=dy/8;y<dy-dy/8;y++){
5342 if( num_cross(0,dx,y,y,bp,cs) != 2 ) break;
5343 } if (y<dy-dy/8) break;
5344 if( get_bw((3*x0+5*x1)/8,x1,y0+3*dy/16,y1-3*dy/16,box1->p,cs,1) == 0)
5345 { Setac(box1,(bc='['),ad);break; }
5346 if( get_bw(x0,(5*x0+3*x1)/8,y0+3*dy/16,y1-3*dy/16,box1->p,cs,1) == 0)
5347 { Setac(box1,(bc=']'),ad);break; }
5350 // --------- test {} --------------------------------
5351 for(ad=d=99;dx>2 && dy>5 && 2*dy>3*dx;){
5352 DBG( wchar_t c_ask='{'; )
5353 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5354 if (!hchar) ad=97*ad/100;
5356 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
5358 for(x=0;x<dx/2;x++){
5359 if( num_cross(dx-1-x,dx-1-x,0,dy-1,bp,cs) != 2 ) break;
5360 } if (y<dx/2) Break;
5361 if ( num_cross(dx-1,dx-1,dy/4,dy-1-dy/4,bp,cs) != 0 ) Break;
5362 if ( num_cross( 0, 0,dy/4,dy-1-dy/4,bp,cs) != 1 ) Break;
5363 if ( loop(bp,0,dy-1,dx,cs,0,RI)>3*dx/4 ) ad=99*ad/100;
5364 if ( loop(bp,0, 0,dx,cs,0,RI)>3*dx/4 ) ad=99*ad/100; // <
5365 if ( loop(bp,0, 0,dy,cs,0,DO)<dy/2-1 ) ad=98*ad/100;
5366 if ( loop(bp,0,dy-1,dy,cs,0,UP)<dy/2-2 ) ad=98*ad/100; // (
5367 if ( loop(bp,dx-1,0,dx,cs,0,LE)
5368 + loop(bp,dx-1,2,dx,cs,0,LE)
5369 - 2*loop(bp,dx-1,1,dx,cs,0,LE) >=dx/8 ) ad=98*ad/100; // <
5370 if ( loop(bp,dx-2,dy-1,dy,cs,0,UP)>dy/4 ) Break; // f
5371 if ( get_bw(x0,x0,y0,y0+dy/4,box1->p,cs,1) == 1
5372 || get_bw(x0,x0,y1-dy/4,y1,box1->p,cs,1) == 1 ) Break;
5373 Setac(box1,(bc='{'),ad);Break;
5375 for(ad=d=99;dx>2 && dy>5 && 2*dy>3*dx;){
5376 DBG( wchar_t c_ask='}'; )
5377 if (!hchar) ad=97*ad/100;
5379 if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
5381 for(x=0;x<dx/2;x++){
5382 if( num_cross(x,x,0,dy-1,bp,cs) != 2 ) break;
5383 } if (y<dx/2) Break;
5384 if ( num_cross( 0, 0,dy/4,dy-1-dy/4,bp,cs) != 0 ) Break;
5385 if ( num_cross(dx-1,dx-1,dy/4,dy-1-dy/4,bp,cs) != 1 ) Break;
5386 if ( loop(bp,dx-1,dy-1,dx,cs,0,LE)>3*dx/4 ) {ad=99*ad/100;}
5387 if ( loop(bp,dx-1, 0,dx,cs,0,LE)>3*dx/4 ) {ad=99*ad/100;} // >
5388 if ( loop(bp,dx-1, 0,dy,cs,0,DO)<dy/2-1 ) {ad=98*ad/100;}
5389 if ( loop(bp,dx-1,dy-1,dy,cs,0,UP)<dy/2-2 ) {ad=98*ad/100;} // )
5390 if ( loop(bp,0,0,dx,cs,0,RI)
5391 + loop(bp,0,2,dx,cs,0,RI)
5392 - 2*loop(bp,0,1,dx,cs,0,RI) >=dx/8 ) ad=98*ad/100; // <
5393 if ( loop(bp,1,dy-1,dy,cs,0,UP)>dy/4 ) Break; // ???
5394 if ( get_bw(x1,x1,y0,y0+dy/4,box1->p,cs,1) == 1
5395 || get_bw(x1,x1,y1-dy/4,y1,box1->p,cs,1) == 1 ) Break;
5396 Setac(box1,(bc='}'),ad);Break;
5402 /* ---------- empty prototype function for copy and expand ---------- */
5403 static wchar_t ocr0_XXX(ocr0_shared_t *sdata){
5404 struct box *box1=sdata->box1;
5406 int i,j,d,x,y,i0,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
5407 x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
5408 int dx=x1-x0+1,dy=y1-y0+1, /* size */
5409 ac,ad; /* tmp-vars */
5411 // --- test XXX ---------------------------------------------------
5417 /* ----------------------- part9 -------------------------------- */
5418 static wchar_t ocr0p9(ocr0_shared_t *sdata){
5419 struct box *box1=sdata->box1;
5421 int i,j,d,x,y,x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
5422 int dx=x1-x0+1,dy=y1-y0+1, /* size */
5423 i1,i2,i3,i4; /* tmp-vars */
5424 int xa,xb, /* used for store significant points of char */
5425 dbg[9]={0,0,0,0,0,0,0,0,0}, /* debugging space */
5427 wchar_t ac,bc=UNKNOWN; // bestletter
5428 int hchar; // char is higher than e
5429 int gchar; // char has ink lower than m3
5430 // --- hchar --- gchar -------------------------
5431 hchar=0;if( 2*y0<=2*box1->m2-(box1->m2-box1->m1) ) hchar=1;
5432 gchar=0;if( 2*y1>=2*box1->m3+(box1->m4-box1->m3) ) gchar=1;
5433 // if the char is slightly moved down correction can be done
5434 if ( y0<box1->m2 && y1>box1->m3 && 2*y1<box1->m3+box1->m4) // moved
5435 if( 2*(y0-(y1-box1->m3))<=2*box1->m2-(box1->m2-box1->m1) ) hchar=1;
5437 /* reserved for the future */
5438 // --- test beta,\3,sz,"s ---------------------------------------------
5439 if(bc==UNKNOWN && hchar)
5440 for(ad=d=100;dx>3 && dy>6;){ // min 4x7
5441 DBG( wchar_t c_ask='S'; )
5442 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
5443 /* this part is provisorium, should be changed!
5450 if( num_cross(x0 ,x1 ,y0+dy/4 ,y0+dy/4 ,box1->p,cs) != 2
5451 && num_cross(x0 ,x1 ,y0+dy/4+1,y0+dy/4+1,box1->p,cs) != 2 ) break;
5452 for(i=1+dy/16,y=y0+dy/8;y<y1-dy/4 && i>0;y++){
5453 if( y<y1-6*dy/16 ){ if( num_cross(x0 ,x1 ,y,y,box1->p,cs) != 2 ) i--;}
5454 else { if( num_cross(x0 ,x1 ,y,y,box1->p,cs) < 2 ) i--;}
5455 if( get_bw(x0,x0+dx/2,y,y,box1->p,cs,1) == 0 ) i--;
5457 if( get_bw(x1-dx/2,x1,y,y,box1->p,cs,1) == 0 ) i--;
5461 for(y=y0+dy/3;y<y1-dy/3;y++){
5462 i =loop(box1->p,x1,y,dx,cs,0,LE);
5463 if( i>=dx/8 ) break;
5464 i+=loop(box1->p,x1-i,y,dx,cs,1,LE);
5465 if( i>=dx/2 ) break;
5466 } if( y>=y1-dy/3 ) break;
5468 for(y=y0+dy/5;y<y0+dy/3;y++)
5469 if( get_bw(x1-dx/6,x1,y,y,box1->p,cs,1) == 1 ) break;
5470 if( y>=y0+dy/3 ) break;
5472 for(y=y0+dy/2;y<y1;y++)
5473 if( get_bw(x1-dx/6,x1,y,y,box1->p,cs,1) == 1 ) break;
5476 for(y=y1-dy/3;y<y1-dy/8;y++){
5477 i=loop(box1->p,x1,y,dx,cs,0,LE);
5479 && get_bw(x1-dx/8,x1-dx/8,y,y1,box1->p,cs,1) == 1 ) break;
5480 } if( y<y1-dy/8 ) break; // ~Q
5482 if( box1->m3==0 || 2*y1<box1->m3+box1->m4 )
5483 if( loop(box1->p,x1,y1, dx,cs,0,LE)==0
5484 && loop(box1->p,x1,y1-dy/4,dx,cs,0,LE)>dx/8 ) break; // ~R
5487 for(x=x0+dx/4;x<x1-dx/4;x++)
5488 if( num_cross(x,x,y0,y1,box1->p,cs) == 3 ) break;
5489 if( x>=x1-dx/4 ) break;
5491 i=loop(bp,dx/2,dy-1,dy,cs,0,UP)+dy/64; // Jul00
5492 for(x=dx/5;x<dx/2;x++)
5493 if( loop(bp,x,dy-1,dy,cs,0,UP) > i ) break;
5494 if( x==dx/2 ) break;
5496 x=x0+loop(bp,0,dy/4,dx,cs,0,RI);
5498 if( get_bw(x,x,y0,y0+dy/4,box1->p,cs,1) == 0 ) break;
5499 if( x<x1-dx/3 ) break;
5502 // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) != 0 ) break;
5503 if (sdata->holes.num != 0) break;
5505 bc=LATIN_SMALL_LETTER_SHARP_S;
5506 Setac(box1,(wchar_t)bc,98);
5509 // --- test + ------------------------------------------------
5510 for(ad=d=100;dx>2 && dy>2;){ // min 3x3
5511 DBG( wchar_t c_ask='+'; )
5512 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5513 xa=(dx+1)/3-1; ya=(dy+1)/3-1;
5515 if( get_bw(x0,x0+xa,y0,y0+ya,box1->p,cs,1) == 1 ) Break;
5516 if( get_bw(x0,x0+xa,y1-ya,y1,box1->p,cs,1) == 1 ) Break;
5517 if( get_bw(x1-xb,x1,y0,y0+ya,box1->p,cs,1) == 1 ) Break;
5518 if( get_bw(x1-xa,x1,y1-ya,y1,box1->p,cs,1) == 1 ) Break;
5519 for(i=0,y=y0+ya;y<=y1-ya;y++){ // horizontal line
5520 if( get_bw(x0+dx/9,x1-dx/9,y,y,box1->p,cs,2) == 0 ) { i=y; break; }
5522 if (3*dx<2*dy) ad=99*ad/100; // ~t
5526 if (ad>=100) return ac;
5529 // --- test $ ------------------------------------------------
5530 for(ad=d=99;dx>3 && dy>5;){ // min 3x4
5531 DBG( wchar_t c_ask='$'; )
5532 if (sdata->holes.num != 2) Break;
5534 if( get_bw(x0,x0+dx/5,y0 ,y0+dy/18,box1->p,cs,1) == 1 ) Break;
5535 if( get_bw(x0,x0+dx/9,y1-dy/23,y1 ,box1->p,cs,1) == 1 ) Break;
5536 if( get_bw(x1-dx/9,x1,y0 ,y0+dy/18,box1->p,cs,1) == 1 ) Break;
5537 if( get_bw(x1-dx/5,x1,y1-dy/23,y1 ,box1->p,cs,1) == 1 ) Break;
5538 if( get_bw(x0,x0+dx/3,y0+dy/3 ,y0+dy/2 ,box1->p,cs,1) != 1 ) Break;
5539 if( get_bw(x1-dx/3,x1,y1-dy/2 ,y1-dy/3 ,box1->p,cs,1) != 1 ) Break;
5540 i1=x0+loop(box1->p,x0,y0,dx,cs,0,RI); if( i1<x0+dx/3 || i1>x1-dx/5 ) Break;
5541 i2=x0+loop(box1->p,x0,y1,dx,cs,0,RI); if( i2<x0+dx/5 || i2>i1 ) Break;
5542 ad= get_line2(i1,y0,i2,y1,box1->p,cs,100)*ad/100;
5543 // check upper left and lower right half circle, $
5544 for (x=0,i3=y=0;y<dy/3;y++)
5545 if( num_cross(x0,x1,y0+dy/2-y,y0+dy/2-y,box1->p,cs) == 2 ) {
5546 i = loop(box1->p,x0,y0+dy/2-y,dx,cs,0,RI);
5547 if (i>x) { x=i; i3=y0+dy/2-y; }
5548 } if (x<=dx/4) Break;
5549 for (x=0,i4=y=0;y<dy/3;y++)
5550 if( num_cross(x0,x1,y0+dy/2+y,y0+dy/2+y,box1->p,cs) == 2 ) {
5551 i = loop(box1->p,x0,y0+dy/2+y,dx,cs,0,RI);
5552 if (i>x) { x=i; i4=y0+dy/2+y; }
5553 } if (x<=dx/4) Break;
5557 if (ad>=100) return ac;
5560 // --- test & ------------------------------------------------
5561 for(ad=d=99;dx>3 && dy>4;){ /* 4x6 font */
5562 DBG( wchar_t c_ask='&'; )
5563 if (sdata->holes.num != 2) Break;
5564 if( get_bw(x1-dx/9,x1,y0,y0+dy/4,box1->p,cs,1) == 1 ) Break; // g
5565 if( loop(bp,dx/2,0,dy,cs,0,DO)>dy/2) Break;
5566 i1=loop(bp,0,dy/8 ,dx,cs,0,RI); if (i1>dx/2) Break;
5567 i =loop(bp,0,dy/4 ,dx,cs,0,RI); if (i1>dx/2) Break; if (i<i1) i1=i;
5568 i3=loop(bp,0,dy-dy/4 ,dx,cs,0,RI); if (i3>dx/2) Break;
5569 i =loop(bp,0,dy-dy/4-1,dx,cs,0,RI); if (i3>dx/2) Break; if (i<i3) i3=i;
5571 for( i2=0, y=dy/4; y<=dy/2+1; y++ ){
5572 i =loop(bp,0,y,dx,cs,0,RI); if( i>i2 ) i2=i;
5574 if(2*i2-i1-i3<1) Break;
5575 // if( num_hole(x0,x1 ,y0,y1,box1->p,cs,NULL)!=2 ) Break;
5576 if( num_hole(x0,x1-dx/4,y0,y1,box1->p,cs,NULL)!=2 ) Break;
5577 if( num_cross(dx-1,dx-1,dy/4,dy-1,bp,cs) < 1 ) Break;
5578 for( x=dx-1; x>=dx/2; x-- ){
5579 if( num_cross(x,x,dy/4,dy-1,bp,cs) > 1 ) break;
5580 } if( x<=3*dx/4 && x<dx-2) Break;
5581 if( num_cross(0,dx-1,dy-1-dy/4,dy-1-dy/4,bp,cs) > 3 ) { // glued ah
5582 if (dy>15) { Break; } else ad=96*ad/100;
5584 if (!hchar) ad=98*ad/100;
5587 if (ad>=100) return bc;
5590 // --- test \it & like \epsilon\tau ------------------------------
5592 for(ad=d=100;dx>7 && dy>7;){
5593 DBG( wchar_t c_ask='&'; )
5594 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
5595 if( num_cross(0,dx-1, dy/4, dy/4,bp,cs) != 3 ) break;
5596 if( num_cross(0,dx-1, dy/2, dy/2,bp,cs) != 4 ) break;
5597 if( num_cross(dx/2,dx-1,dy/2, dy/2,bp,cs) != 2 ) break;
5598 if( num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs) != 2 ) break;
5599 if( num_cross(0,dx-1, dy-1, dy-1,bp,cs) != 1 ) break;
5600 if( num_cross( 0, 0,0,dy-1,bp,cs) != 1 ) break;
5601 if( num_cross( dx/3, dx/3,0,dy-1,bp,cs) != 4 ) break;
5602 if( num_cross(13*dx/16,13*dx/16,0,dy/8,bp,cs) != 0 ) break;
5603 if( num_cross(4*dx/8,4*dx/8,dy-dy/4,dy-1,bp,cs) != 1 ) break;
5604 if( num_cross(3*dx/8,3*dx/8,dy-dy/4,dy-1,bp,cs) != 1 ) break;
5605 if( num_cross(5*dx/8,5*dx/8,dy-dy/4,dy-1,bp,cs) != 1 ) break;
5606 if( num_hole(x0 ,(x0+x1)/2,y0, y1,box1->p,cs,NULL) != 1 ) break;
5607 if( num_hole(x0+dx/8,x1-dx/4,y0,y1-dy/4,box1->p,cs,NULL) != 1 ) break;
5610 if (ad>=100) return ac;
5613 // --- test ? ---------------------------------------------------
5614 for(ad=d=98;dx>2 && dy>5;){ // min 3x(4+2)
5615 DBG( wchar_t c_ask='?'; )
5616 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5617 if ( num_cross(x0, x1, y0, y0, box1->p, cs) !=1 ) Break; // ~?
5618 if ( num_cross(x0, x1, y1, y1, box1->p, cs) > 1 ) Break; // ~?
5619 for(y=y0;y<y1;y++) // new y1
5620 if( get_bw(x0, x1, y, y,box1->p,cs,1) != 1 ) break; // lower end
5621 if (2*y<y0+y1) Break;
5623 if (y==y1 && box1->m4) { // probably lower dot not catched in box?
5624 if (get_bw(x0+1,x1-1,y1+1,box1->m4,box1->p,cs,1) != 1 ) Break;
5626 for(;i1>y1;i1--) // new y1
5627 if( get_bw(x0, x1,i1,i1,box1->p,cs,1) == 1 ) break; // lower dot
5629 y--; i=y-y0+1; // new dy
5630 for (y=0;y<dy/2;y++)
5631 if( num_cross(x0, x1, y0+y, y0+y, box1->p, cs) == 2 ) break;
5633 // if( num_hole( x0, x1, y0, y1, box1->p,cs,NULL) > 0 ) Break;
5634 if (sdata->holes.num > 0) Break;
5635 for(y=y0+dy/2;y<=i1;y++)
5636 if( get_bw(x0,x1,y,y,box1->p,cs,1) == 0 ) break;
5639 if( get_bw(x0,x1,y,y,box1->p,cs,1) == 1 ) break;
5640 if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) Break;
5641 if( get_bw(x0+7*dx/8,x1,y,i1,box1->p,cs,1) == 1 ) Break; // broken thin 2
5643 Setac(box1,(wchar_t)bc,98);
5646 // --- test !| ---------------------------------------------------
5647 for(ad=d=99; dy>4 && dy>2*dx;){ // min 3x4
5648 DBG( wchar_t c_ask='!'; )
5649 if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
5650 // measure thickness
5651 if (num_cross(x0,x1,y0 ,y0 ,box1->p,cs)!=1) Break;
5652 if (num_cross(x0,x1,y0+dy/2,y0+dy/2,box1->p,cs)!=1) Break;
5653 for(y=y0;y<y1;y++) // new y1
5654 if( get_bw(x0, x1, y, y,box1->p,cs,1) != 1 ) break; // lower end
5655 if (2*y<y0+y1) Break;
5656 if (y==y1 && y>box1->m3-dy/8) ad=ad*97/100; /* missing dot? */
5658 if (y==y1 && box1->m4) { // probably lower dot not catched in box?
5659 if ((dx>2 && get_bw(x0+1,x1-1,y1+1,box1->m4,box1->p,cs,1) == 1)
5660 || (dx<3 && get_bw(x0 ,x1 ,y1+1,box1->m4,box1->p,cs,1) == 1 )) {
5662 for(;i1>y1;i1--) // new y1
5663 if( get_bw(x0, x1,i1,i1,box1->p,cs,1) == 1 ) break; // lower dot
5666 for( i1=0,y=y0;y<=i2;y++){
5667 i=num_cross(x0,x1,y,y,box1->p,cs); if(i>1) break;
5668 if(i==0 && i1==0) i1=y;
5669 } if(y<=i2 || i1==0 || i1<y0+dy/2) Break;
5671 if( loop(bp,dx-1,dy/8,dx,cs,0,LE)
5672 -loop(bp,dx-1, 0,dx,cs,0,LE)>dx/4+1 ) Break; // f
5674 if (!hchar) ad=96*ad/100;
5675 Setac(box1,(wchar_t)'!',ad);
5678 // --- test * five egdes (jagges? beames?) what is the right english word? ----
5679 for(ad=d=99;dx>2 && dy>4;){
5680 DBG( wchar_t c_ask='*'; )
5681 if (sdata->holes.num > 0) Break; /* tolerant against a tiny hole */
5682 if( num_cross(0,dx-1, 0,dy-1,bp,cs) != 1
5683 && num_cross(0,dx-1, 1,dy-2,bp,cs) != 1 ) Break;
5684 if( num_cross(0,dx-1,dy-1,dy-1,bp,cs) != 2
5685 && num_cross(0,dx-1,dy-2,dy-2,bp,cs) != 2 ) Break;
5686 x=dx/2;y=(6*dy+8)/16; // center point 6/8=6/2^3 rounded
5687 /* upwarts from center */
5688 dbg[0]=i=get_line2(x,y,x ,0,bp,cs,100); if(i<95) Break;
5689 if (dx<8) /* be exact on small fonts, where get_line2 returns 100 (ToDo change) */
5690 if (get_bw(x,x,0,y,bp,cs,2)==2) Break;
5692 dbg[1]=i=get_line2(0,y,dx-1,y,bp,cs,100); if(i<95) Break;
5694 if (get_bw(0,dx-1,y ,y ,bp,cs,2)==2
5695 && get_bw(0,dx-1,y+1,y+1,bp,cs,2)==2) Break;
5697 i=get_line2(x,y,(5*dx+4)/8,dy-1,bp,cs,100);
5698 j=get_line2(x,y,(6*dx+4)/8,dy-1,bp,cs,100); if(j>i) dbg[2]=i=j;
5701 dbg[3]=i=get_line2(x, y,(2*dx+4)/8,dy-1,bp,cs,100); if(i<95) Break; // straight up
5702 /* check for lower gap at bottom */
5703 dbg[4]=i=get_bw( x, x,dy-1-dy/8,dy-1,bp,cs,1); if(i==1) Break;
5704 dbg[5]=i=get_line2( dx/4,dy/4, 0,0,bp,cs,101); if(i<95) Break; // upper left gap
5705 dbg[6]=i=get_line2(dx-1-dx/4,dy/4,dx-1,0,bp,cs,101); if(i<95) Break; // upper right gap
5706 MSG(fprintf(stderr,"%d %d %d %d %d %d %d",dbg[0],dbg[1],dbg[2],dbg[3],dbg[4],dbg[5],dbg[6]);)
5707 Setac(box1,(wchar_t)'*',ad);
5710 // --- test * six egdes (jagges? beames?) what is the right english word? ----
5711 for(ad=d=100;dx>4 && dy>4;){
5712 DBG( wchar_t c_ask='*'; )
5713 if (sdata->holes.num > 0) Break; /* tolerant against a tiny hole */
5714 if( num_cross(0,dx-1, dy/8, dy/8,bp,cs) != 3
5715 && num_cross(0,dx-1, 1+dy/8, 1+dy/8,bp,cs) != 3) Break;
5716 if( num_cross(0,dx-1,dy-2-dy/8,dy-2-dy/8,bp,cs) != 3) Break;
5717 if( num_cross(0 , 0, 0,dy-1,bp,cs) != 2) Break;
5718 if( num_cross(dx-1,dx-1, 0,dy-1,bp,cs) != 2) Break;
5719 if( num_cross(0,dx-1,dy/2,dy/2,bp,cs) != 1) Break;
5720 if( num_cross( 0 ,dx/8,dy/2,dy/2,bp,cs) != 0) Break;
5721 if( num_cross(dx-1-dx/8,dx-1,dy/2,dy/2,bp,cs) != 0) Break;
5723 dbg[0]=i=get_line2(0,dy-2-dy/8,dx-1,dy/8,bp,cs,100); if(i<95) Break; // black upwarts beam
5724 dbg[1]=i=get_line2(0,dy/8,dx-1,dy-2-dy/8,bp,cs,100); if(i<95) Break; // black downwards beam
5725 /* check vertical line */
5726 dbg[2]=i=get_line2(dx/2,0,dx/2, dy-1,bp,cs,100); if(i<95) Break;
5728 MSG(fprintf(stderr,"%d %d %d %d %d %d",dbg[0],dbg[1],dbg[2],dbg[3],dbg[4],dbg[5]);)
5729 Setac(box1,(wchar_t)'*',98);
5732 // --- test @ - a popular char should be detectable! added in version v0.2.4a5
5734 for(ad=d=99;dx>5 && dy>7;){
5735 DBG( wchar_t c_ask='@'; )
5736 if (sdata->holes.num > 3) Break; /* tolerant against a tiny hole */
5737 if (loop(bp, 0,dy/2,dx,cs,0,RI)>dx/4) Break;
5738 if (loop(bp,dx-1,dy/2,dx,cs,0,LE)>dx/4) Break;
5739 if (loop(bp,dx/2,dy-1,dy,cs,0,UP)>dx/8) Break;
5740 if (loop(bp,dx/2, 0,dy,cs,0,DO)>dx/8) Break;
5741 /* ..@@@@..<- 8*10 example
5753 i=num_cross(0,dx-1,y,y,bp,cs);
5754 if (i<3 || i>4) Break;
5755 if( i != 4 && dx>8 ) ad=98*ad/100;
5757 i=num_cross(x,x,0,dy-1,bp,cs); if (i<2) Break;
5758 if (i!=4) { j=num_cross(x+1,x+1,0,dy-1,bp,cs);
5759 if (abs(4-j)<abs(i-4)) i=j; }
5760 if (i!=4) { j=num_cross(x+2,x+2,0,dy-1,bp,cs);
5761 if (abs(4-j)<abs(i-4)) i=j; }
5762 if (i<3 || i>4) Break;
5763 if (i!=4) ad=97*ad/100;
5764 if( num_cross(0, x,y,y,bp,cs) != 2 ) Break;
5765 if( num_cross(x,dx-1,y,y,bp,cs) != 2 ) Break;
5766 if( num_cross(x,x,0, y,bp,cs) != 2 ) Break;
5767 if( num_cross(x,x,y,dy-1,bp,cs) != 2 ) Break;
5769 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 1 ) Break;
5770 if (sdata->holes.num != 1) Break;
5771 if( num_hole(x0+dx/8,x1-3*dx/16,y0+dy/8,y1-dy/8,box1->p,cs,NULL) != 1 ) Break;
5773 Setac(box1,(wchar_t)'@',ad);
5776 // --- test paragraph v0.2.6
5777 if(bc==UNKNOWN && hchar)
5778 for(ad=d=100;dx>4 && dy>15;){
5779 DBG( wchar_t c_ask='$'; )
5780 if (sdata->holes.num > 3) break; /* tolerant against a tiny hole */
5781 if( get_bw( 0,dx/2,3*dy/4,3*dy/4,bp,cs,1) == 1 ) break;
5782 if( get_bw(3*dx/4,dx-1,3*dy/4,3*dy/4,bp,cs,1) == 0 ) break;
5783 if( get_bw( 0,dx/4, dy/4, dy/4,bp,cs,1) == 0 ) break;
5784 if( get_bw( dx/2,dx-1, dy/4, dy/4,bp,cs,1) == 1 ) break;
5785 if( get_bw(dx/2,dx/2, 0, dy/4,bp,cs,1) == 0 ) break;
5786 if( get_bw(dx/2,dx/2,dy-1-dy/4, dy-1,bp,cs,1) == 0 ) break;
5787 if( num_cross(dx/2,dx/2,0,dy-1,bp,cs) != 4 ) break;
5788 if( num_cross(x0,x1,y0+dy/2,y0+dy/2,box1->p,cs) != 2 ) break;
5789 if( num_hole( x0,x1,y0+dy/4,y1-dy/4,box1->p,cs,NULL) != 1 ) break;
5790 Setac(box1,SECTION_SIGN,96);
5791 break; // paragraph=0xA7=167
5797 /* ----------------------- partx -------------------------------- */
5798 static wchar_t ocr0px(ocr0_shared_t *sdata){
5799 struct box *box1=sdata->box1;
5801 int i,j,d,x,y,x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
5802 int dx=x1-x0+1,dy=y1-y0+1, /* size */
5803 i1,i2,i3,i4,j1,cs=sdata->cs; /* tmp-vars */
5804 int ya,ad; /* used for store significant points of char */
5805 wchar_t ac,bc=UNKNOWN; // bestletter
5806 int hchar; // char is higher than e
5807 int gchar; // char has ink lower than m3
5808 // --- hchar --- gchar -------------------------
5809 hchar=0;if( 2*y0<=2*box1->m2-(box1->m2-box1->m1) ) hchar=1;
5810 gchar=0;if( 2*y1>=2*box1->m3+(box1->m4-box1->m3) ) gchar=1;
5811 // if the char is slightly moved down correction can be done
5812 if ( y0<box1->m2 && y1>box1->m3 && 2*y1<box1->m3+box1->m4) // moved
5813 if( 2*(y0-(y1-box1->m3))<=2*box1->m2-(box1->m2-box1->m1) ) hchar=1;
5815 /* reserved for special chars, to test at the end */
5816 // --- test 'ff' ---------------------------------------------------
5817 // ToDo: better check and call test 'f' and 'f' with subboxes
5819 for(ad=98;dx>4 && dy>6;){ // Dec00 body copied from H
5820 DBG( wchar_t c_ask='f'; )
5821 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
5822 if( num_cross(0,dx-1, dy/4 , dy/4 ,bp,cs) != 2
5823 && num_cross(0,dx-1,3*dy/16,3*dy/16,bp,cs) != 2 ) break;
5824 if( num_cross(0,dx-1,3*dy/4 ,3*dy/4 ,bp,cs) != 2
5825 && num_cross(0,dx-1,3*dy/4+1,3*dy/4+1,bp,cs) != 2 ) break;
5826 if( loop(bp,0 ,dy/8,dx,cs,0,RI)
5827 + loop(bp,dx-1,dy/8,dx,cs,0,LE)>dx/2 ) break; // ~A
5828 for( j1=0,i=1,y=y0+dy/10; y<y1-dy/10 && i; y++ ) // 2 vertikal lines
5829 { j=loop(box1->p,x0 ,y,dx,cs,0,RI)
5830 +loop(box1->p,x1 ,y,dx,cs,0,LE);
5831 if( j>10*dx/16 ) i=0; if ( j>j1 ) j1=j; }
5833 for( x=dx/4; x<dx/2; x++ ){ // lower gap
5834 y=loop(bp,x ,dy-1,dy,cs,0,UP);
5835 if ( y > 3*dy/8 ) break;
5836 if ( 10*y > dy ){ /* italic */
5837 i=loop(bp,x ,dy-y,dx,cs,0,RI);
5838 if( i>1 && y+loop(bp,x+i-1,dy-y,dy,cs,0,UP)>3*dy/8 ) break;
5840 } if( x>=dx/2 ) break;
5841 x=loop(box1->p,x0 ,y1-dy/8,dx,cs,0,RI)
5842 +loop(box1->p,x1 ,y1-dy/8,dx,cs,0,LE);
5843 for( i=1,y=dy/4; y<dy-1-dy/4 && i; y++ ) // max - min width
5844 { j=loop(bp,0 ,y,dx,cs,0,RI)
5845 +loop(bp,dx-1,y,dx,cs,0,LE); if( j-x>dx/5 ) i=0; }
5846 if( !i ) break; // ~K Jul00
5847 for( i=0,ya=y=y0+dy/4; y<y1-dy/3; y++ ) // horizontal line
5848 { j=loop(box1->p,x0 ,y,dx,cs,0,RI);
5849 j=loop(box1->p,x0+j,y,dx,cs,1,RI); if( j>i ) { i=j; ya=y; } }
5850 if( i<=dx/2 ) break; ya-=y0;
5851 if( num_cross(0,dx-1,ya ,ya ,bp,cs) != 1
5852 && num_cross(0,dx-1,ya+1,ya+1,bp,cs) != 1 ) break; /* Dec00 */
5853 for( y=ya; y<dy-dy/4; y++ ) // ~M Dec00
5854 if( num_cross(0,dx-1,y ,y ,bp,cs) > 2
5855 && num_cross(0,dx-1,y+1,y+1,bp,cs) > 2 ) break;
5856 if ( y<dy-dy/4 ) break;
5857 for(i=1,x=x0+dx/2;x<=x1-dx/4 && i;x++){
5858 if( get_bw( x, x,y0 ,y0+dy/4,box1->p,cs,1) == 0 ) i=0;
5860 for(i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
5861 if( get_bw( x, x,y1-dy/4,y1 ,box1->p,cs,1) == 0 ) i=0;
5863 for(i=1,x=x0+dx/4;x<=x1-dx/4 && i;x++){
5864 if( num_cross(x,x,y0+dy/8,y1-dy/8, box1->p,cs) == 1 ) i=0;
5866 for(i=1,y=y0;y<=y0+dy/4 && i;y++){
5867 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
5869 for(i=1,y=y1-dy/4;y<=y1 && i;y++){
5870 if( num_cross(x0,x1,y,y, box1->p,cs) == 2 ) i=0;
5872 if( num_cross(x0 ,x0+dx/8 ,y0+dy/8 ,y0 ,box1->p,cs) != 0 ) ad=96*ad/100;
5873 if( get_bw(x1-dx/8, x1 , y0, y0+dy/8,box1->p,cs,1) != 1 ) break;
5874 if( get_bw(x0 , x0+dx/8, y1-dy/8, y1,box1->p,cs,1) != 1 ) break;
5875 i1=loop(bp,dx-1, dy/4,dx,cs,0,LE); if(i1>dx/2) break;
5876 i2=loop(bp,dx-1, dy/2,dx,cs,0,LE); if(i2<i1-dx/4 || i2>i1+dx/8) break;
5877 i3=loop(bp,dx-1,dy-1-dy/4,dx,cs,0,LE); if(i3<i2-dx/4 || i3>i2+dx/8) break;
5878 if(abs(i1+i3-2*i2)>dx/16+1) break;
5879 if( num_hole(x0,x1,y0+dy/4,y1,box1->p,cs,NULL) != 0 ) break;
5880 if (!hchar) ad=96*ad/100;
5881 if (!gchar) ad=99*ad/100;
5882 ac=LATIN_SMALL_LIGATURE_FF;
5886 // --- test ae ---------------------------------------------------
5888 for(ad=98;dx>4 && dy>6;){ // provisorium
5889 DBG( wchar_t c_ask=LATIN_SMALL_LETTER_AE; )
5890 if (sdata->holes.num > 4) Break; /* tolerant against a tiny hole */
5891 if( num_cross( dx/4,dx-1,3*dy/16,3*dy/16,bp,cs) != 2
5892 && num_cross(dx-1-dx/4,dx-1,3*dy/16,3*dy/16,bp,cs) != 1 ) Break;
5893 if( num_cross(0,dx-1,3*dy/ 4,3*dy/ 4,bp,cs) < 2 ) Break;
5894 if( num_cross(0,dx-1, 0, dy-1,bp,cs) < 3 ) Break;
5895 if( num_cross(dx-1,0, 0, dy-1,bp,cs) < 3 ) Break;
5896 if( num_cross(0,dx-1, dy/16, dy/16,bp,cs) < 2 )
5897 if( num_cross(0,dx-1,1+dy/16,1+dy/16,bp,cs) < 2 ) Break;
5898 if( num_cross(0,dx-1,dy-1-dy/16,dy-1-dy/16,bp,cs) < 2 ) Break;
5899 for( x=0,i2=y=dy/4; y<3*dy/4; y++ ){
5900 j=loop(bp,0,y,dx,cs,0,RI); if(j>x) { i2=y; x=j; }
5901 } if( x<dx/4 || x>3*dx/4 ) Break;
5902 for( x=0,i4=y=dy/4; y<3*dy/4; y++ ){
5903 j=loop(bp,dx-1,y,dx,cs,0,LE); if(j>x) { i4=y; x=j; }
5904 } if( x<dx/4 || x>3*dx/4 ) Break;
5905 for( x=0,i4=y=dy/8; y<3*dy/4; y++ ){
5906 j=loop(bp,dx-1 ,y,dx,cs,0,LE);
5907 j=loop(bp,dx-1-j,y,dx,cs,1,LE);
5908 if(j>x) { i4=y; x=j; }
5909 } if( x<dx/4 ) Break;
5910 if( num_hole(x0,x0+3*dx/4,y0+dy/4,y1,box1->p,cs,NULL) != 1 ) Break;
5911 if( num_hole(x0+dx/2-1,x1,y0,y1-dy/4,box1->p,cs,NULL) != 1 ) Break;
5912 ac=LATIN_SMALL_LETTER_AE;
5914 if (ad>=100) return ac;
5918 // --- test AE ---------------------------------------------------
5920 for(ad=98;dx>5 && dy>6;){ // provisorium
5921 DBG( wchar_t c_ask=LATIN_CAPITAL_LETTER_AE; )
5922 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
5923 if( num_cross(0,dx-1,3*dy/16,3*dy/16,bp,cs) < 2 ) Break;
5924 if( num_cross(0,dx-1,3*dy/ 4,3*dy/ 4,bp,cs) < 2 ) Break;
5925 if( num_cross(0,dx-1, 0, dy-1,bp,cs) < 3 ) Break;
5926 if( num_cross(0,dx-1, dy/16, dy/16,bp,cs) != 1
5927 && num_cross(0,dx-1, dy/32, dy/32,bp,cs) != 1
5928 && num_cross(0,dx-1, 0, 0,bp,cs) != 1 ) Break;
5929 // check for upper horizontal line
5930 j=loop(bp,dx-1 ,0,dx,cs,0,LE); x=j;
5931 j=loop(bp,dx-1-j,0,dx,cs,1,LE);
5932 i=loop(bp,dx-1 ,1,dx,cs,0,LE); if (i<x) x=i;
5933 i=loop(bp,dx-1-i,1,dx,cs,1,LE);
5937 for( x=dx,i1=i3=0,i2=y=dy/4; y<3*dy/4; y++ ){
5938 j=loop(bp, 0,y,dx,cs,0,RI); if(j>x) break; x=j;
5939 j=loop(bp, j,y,dx,cs,1,RI); if(j>i1) { i1=j; i2=y; }
5940 j=loop(bp,dx-1 ,y,dx,cs,0,LE);
5941 j=loop(bp,dx-1-j,y,dx,cs,1,LE); if(j>i3) { i3=j; i4=y; }
5942 } if( y<3*dy/4 || i1<dx/4-1 || i3<dx/4-1) Break;
5943 for( i1=i3=0,y=0; y<dy/8; y++ ){
5944 j=loop(bp,dx-1 , y,dx,cs,0,LE);
5945 j=loop(bp,dx-1-j, y,dx,cs,1,LE); if(j>i1) { i1=j; }
5946 j=loop(bp,dx-1 ,dy-1-y,dx,cs,0,LE);
5947 j=loop(bp,dx-1-j,dy-1-y,dx,cs,1,LE); if(j>i3) { i3=j; }
5948 } if( i1<=dx/4 || i3<=dx/4 ) Break;
5949 for( x=dx-1-dx/8; x>dx/2; x-- ){ // look for right the E
5950 if( num_cross(x,x, 0,dy-1,bp,cs) == 3 )
5951 if( num_cross(x,x, 0,dy/4,bp,cs) == 1 )
5952 if( num_cross(x-1,dx-1-dx/8,3*dy/4,3*dy/4,bp,cs) == 0 )
5953 if( num_cross(x,x,3*dy/4,dy-1,bp,cs) == 1 ) break;
5954 } if (x<=dx/2) Break; // not found
5955 if (sdata->holes.num != 1) Break;
5956 if( num_hole(x0,x0+3*dx/4,y0,y1-dy/4,box1->p,cs,NULL) != 1 ) Break;
5957 // if( num_hole(x0, x1,y0,y1 ,box1->p,cs,NULL) != 1 ) Break;
5958 ac=LATIN_CAPITAL_LETTER_AE;
5960 if (ad>=100) return ac;
5964 // --- test /0 /o /O O_WITH_STROKE -----------------------------------------
5965 for(ad=99;dx>4 && dy>4;){ // provisorium
5966 DBG( wchar_t c_ask=LATIN_SMALL_LETTER_O_WITH_STROKE; )
5967 if (sdata->holes.num > 3) Break; /* tolerant against a tiny hole */
5968 if( num_cross( 0,dx-1,dy/2,dy/2,bp,cs) != 3 ) Break;
5969 if( num_cross(dx/2,dx/2, 0,dy-1,bp,cs) != 3 ) Break;
5970 if (loop(bp,dx-1,3*dy/8,dx,cs,0,RI)>dx/8) Break;
5971 if (loop(bp, 0,5*dy/8,dx,cs,0,RI)>dx/8) Break;
5972 if( num_cross( 0,dx-1, 0, 0,bp,cs) > 2 ) Break;
5973 if( num_cross(dx/4,dx-1, 0, 0,bp,cs) > 2 ) Break;
5974 if( num_cross( 0,dx-1,dy-1,dy-1,bp,cs) > 2 ) Break;
5975 if( num_cross( 0,3*dx/4,dy-1,dy-1,bp,cs) > 2 ) Break;
5976 if( num_cross( 0, 0, 0,dy-1,bp,cs) > 2 ) Break;
5977 if( num_cross(dx-1,dx-1, 0,dy-1,bp,cs) > 2 ) Break;
5978 if( num_cross( 0, 0,dy/4,dy-1,bp,cs) > 2 ) Break;
5979 if( num_cross(dx-1,dx-1, 0,3*dy/4,bp,cs) > 2 ) Break;
5980 i1 =loop(bp,dx-1 , 0,dx,cs,0,LE); if( i1>dx/8 ) Break;
5981 i1+=loop(bp,dx-1-i1, 0,dx,cs,1,LE); if( i1>dx/3 ) Break; i1=dx-1-i1;
5982 i2 =loop(bp, 0,dy-1,dx,cs,0,RI); if( i2>dx/8 ) Break;
5983 for(y=1;y<dy-1;y++){
5984 x=i1+y*(i2-i1)/dy-dx/8; if(x<0)x=0;
5985 j=loop(bp,x,y,dx,cs,0,RI); if( j>3*dx/16 ) break;
5986 } if( y<dy-1 ) Break;
5987 if( num_cross( 0 ,dx/4,dy/2,dy/2,bp,cs) != 1 ) Break;
5988 if( num_cross(dx-1-dx/4,dx-1,dy/2,dy/2,bp,cs) != 1 ) Break;
5989 if( num_cross(dx/4,dx-1-dx/4,dy/2,dy/2,bp,cs) != 1 ) Break;
5990 if (sdata->holes.num != 2) Break;
5991 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 2 ) Break;
5993 if ( hchar && 2*y0<box1->m1+box1->m2 )
5994 ac=LATIN_CAPITAL_LETTER_O_WITH_STROKE;
5995 else ac=LATIN_SMALL_LETTER_O_WITH_STROKE;
5997 if (ad>=100) return ac;
6001 // --- test /c /C C_WITH_STROKE CENT_SIGN --------------------------
6002 // here only the version with a continuously vertical line (not broken variant)
6004 for(ad=98;dx>4 && dy>4;){ // provisorium
6005 DBG( wchar_t c_ask=CENT_SIGN; )
6006 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
6007 if( num_cross( 0,dx-1,dy/2,dy/2,bp,cs) != 2 ) Break;
6008 if( num_cross(0,dx-1-dx/4,dy/2,dy/2,bp,cs) != 2 ) Break;
6009 if( num_cross(dx/2,dx/2, 0,dy-1,bp,cs) != 3 ) Break;
6010 if( num_cross( 0,dx-1, 0, 0,bp,cs) > 2 ) Break;
6011 if( num_cross(dx/4,dx-1, 0, 0,bp,cs) > 2 ) Break;
6012 if( num_cross( 0,dx-1,dy-1,dy-1,bp,cs) > 2 ) Break;
6013 if( num_cross( 0,3*dx/4,dy-1,dy-1,bp,cs) > 2 ) Break;
6014 if( num_cross( 0, 0, 0,dy-1,bp,cs) > 2 ) Break;
6015 if( num_cross(dx-1,dx-1, 0,dy-1,bp,cs) > 3 ) Break;
6016 if( num_cross( 0, 0,dy/4,dy-1,bp,cs) > 2 ) Break;
6017 if( num_cross(dx-1,dx-1, 0,3*dy/4,bp,cs) > 3 ) Break;
6018 i1 =loop(bp,dx-1 , 0,dx,cs,0,LE); if( i1>dx/4 ) Break;
6019 i1+=loop(bp,dx-1-i1, 0,dx,cs,1,LE); if( i1>dx/4 ) Break; i1=dx-1-i1;
6020 i2 =loop(bp, 0,dy-1,dx,cs,0,RI); if( i2>dx/4 ) Break;
6022 x=i1+y*(i2-i1)/dy; if(x>dx/16+1) x-=dx/16+1;
6023 j=loop(bp,x,y,dx,cs,0,RI); // fprintf(stderr,"\n x=%d j=%d",x,j);
6024 if( j>(dx+4)/8 ) ad=96*ad/100;
6025 if( j>(dx+2)/4 ) break;
6027 if( num_cross( 0 ,dx/4,dy/2,dy/2,bp,cs) != 1 ) Break;
6028 if( num_cross(dx-1-dx/4,dx-1,dy/2,dy/2,bp,cs) != 0 ) Break;
6029 if( num_cross(dx/4,dx-1-dx/4,dy/2,dy/2,bp,cs) != 1 ) Break;
6030 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 1 ) Break;
6031 if (sdata->holes.num != 1) Break;
6035 if (ad>=100) return ac;
6039 // --- test EURO_CURRENCY_SIGN -----------------------------------------
6041 for(ad=98;dx>4 && dy>6;){ // provisorium
6042 DBG( wchar_t c_ask='&'; )
6043 if (sdata->holes.num > 1) break; /* tolerant against a tiny hole */
6044 if( num_cross(dx/2,dx/2, 0,dy-1,bp,cs) != 4 ) break;
6045 if( num_cross( 0,dx-1, 0, 0,bp,cs) != 1 ) break;
6046 if( num_cross( 0,dx-1,dy-1,dy-1,bp,cs) != 1 ) break;
6047 if( num_cross( 0,dx-1,dy/2,dy/2,bp,cs) != 1 ) break;
6048 for(i=0,y=dy/4;y<dy-dy/4-1;y++){ // check if no gap on left side
6049 x=loop(bp,0,y,dx,cs,0,RI); if( x>dx/4 ) break;
6050 j=loop(bp,x,y,dx,cs,1,RI); if( j>i ) i=j;
6051 } if( y<dy-dy/4-1 || i<dx/2 ) break;
6052 for(y=dy/4;y<dy-dy/4-1;y++){ // check for right horizontal gap
6053 x=loop(bp,dx-1,y,dx,cs,0,LE); if( x>dx/2 ) break;
6054 } if( y>=dy-dy/4-1 ) break;
6055 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 0 ) break;
6056 if (sdata->holes.num != 0) break;
6057 ac=EURO_CURRENCY_SIGN;
6059 if (ad>=100) return ac;
6062 // --- test LETTER_C_WITH_CEDILLA ---------------------------------------------------
6065 for(ad=98;dx>3 && dy>6;){ // provisorium
6066 DBG( wchar_t c_ask='c'; )
6067 if (sdata->holes.num > 0) break; /* no tolerant against tiny holes */
6068 j=loop(bp,dx-1,dy/16 ,dy,cs,0,LE);
6069 x=loop(bp,dx-1,dy/16+1,dy,cs,0,LE); if (x<j) j=x;
6070 if (3*x>dx) Break; // ~4 ocr-b
6071 if( num_cross(0,dx-1,3*dy/16,3*dy/16,bp,cs) > 2 ) break;
6072 if( num_cross(0,dx-1, 0, dy-1,bp,cs) < 2 ) break;
6073 if( num_cross(0,dx-1, dy/16, dy/16,bp,cs) > 2 ) break;
6074 for( x=dx,i2=y=dy/4; y<3*dy/4; y++ ){
6075 j=loop(bp,0,y,dx,cs,0,RI); if(j<x) { i2=y; x=j; }
6076 } if( x>0 ) break; i1=x;
6077 for( x=0,i4=y=dy/4; y<5*dy/8; y++ ){
6078 j=loop(bp,dx-1,y,dx,cs,0,LE); if(j>x) { i4=y; x=j; }
6079 } if( x<dx/2 ) break; i3=x;
6080 j =loop(bp,dx/2,0,dy,cs,0,DO);
6081 j+=loop(bp,dx/2,j,dy,cs,1,DO); if(j>dy/4) break;
6082 j =loop(bp,dx/2,j,dy,cs,0,DO); if(j<dy/2) break;
6083 j =loop(bp,dx-1 ,dy-1-dy/8,dx,cs,0,LE); if(j<dx/4 || 4*j>3*dx) break;
6084 j =loop(bp,dx-1-j/2,dy-1-dy/8,dy,cs,0,UP); if(j>dy/2) break; // ~()
6085 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 0 ) break;
6086 if (sdata->holes.num) break;
6087 if( hchar ) ac= LATIN_CAPITAL_LETTER_C_WITH_CEDILLA;
6088 else ac= LATIN_SMALL_LETTER_C_WITH_CEDILLA;
6090 if (ad>=100) return ac;
6094 // --- test # ---------------------------------------------------
6095 for(ad=99;dx>4 && dy>4;){ // never sure?
6096 DBG( wchar_t c_ask='#'; )
6097 if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
6098 if (sdata->holes.num < 1) Break;
6099 if( num_cross(0,dx-1, dy/8, dy/8,bp,cs) != 2 ) Break;
6100 if( num_cross(0,dx-1,dy-1-dy/8,dy-1-dy/8,bp,cs) != 2 ) Break;
6101 if( num_cross(0,dx-1, dy/2, dy/2,bp,cs) != 2 ) Break;
6102 if( num_cross(0,dx/2, dy/2, dy/2,bp,cs) != 1 ) Break;
6103 /* fat "#" have only small ends on left and right side, we tolerate this */
6104 j=loop(bp, 0,dy/8,dx,cs,0,RI); if(j<1 || j<dx/16) Break; if (j<dx/8) {ad=ad*96/100;}
6105 j=loop(bp, 0,dy/2,dx,cs,0,RI); if(j<1 || j<dx/16 || j>=dx/2) Break; if (j<dx/8) {ad=ad*96/100;}
6106 j=loop(bp,dx-1,dy/2,dx,cs,0,LE); if(j<1 || j<dx/16 || j>=dx/2) Break; if (j<dx/8) {ad=ad*96/100;}
6107 j=loop(bp,dx-1,dy-1,dx,cs,0,LE); if(j<1 || j<dx/16) Break; if (j<dx/8) {ad=ad*96/100;}
6108 for( i1=i3=0,y=dy/4; y<dy/2; y++ ){
6109 j=loop(bp,0, y,dx,cs,0,RI); if(j>3*dx/4) { i1=0; break; }
6110 j=loop(bp,j, y,dx,cs,1,RI); if(j>i1) { i1=j; }
6111 j=loop(bp,0,dy-1-y,dx,cs,0,RI); if(j>3*dx/4) { i1=0; break; }
6112 j=loop(bp,j,dy-1-y,dx,cs,1,RI); if(j>i3) { i3=j; }
6114 if (i1<dx-dx/4 || i3<dx-dx/4) Break;
6115 if (i1<dx-dx/8) ad=97*ad/100;
6116 if (i3<dx-dx/8) ad=97*ad/100;
6117 if (sdata->holes.num != 1) {ad=95*ad/100;}
6118 if( num_hole(x0+dx/8,x1-dx/8,y0+dy/8,y1-dy/8,box1->p,cs,NULL) != 1 ) Break;
6119 // if( num_hole(x0 ,x1 ,y0 ,y1 ,box1->p,cs,NULL) != 1 ) Break;
6122 if( gchar ) {ad=99*ad/100;}
6124 if (ad>=100) return ac;
6127 // --- test bullet, full_box, grabbed cursor, ZapfDingBats_156
6129 for(ad=96;dx>4 && dy>4 && 2*dx>dy;){ // provisorium
6130 DBG( wchar_t c_ask='#'; )
6131 if( get_bw(x0,x1,y0,y1,box1->p,cs,2) != 0 ) break;
6133 if (gchar && !hchar) ad=80*ad/100;
6135 if (ad>=100) return ac;
6138 /* --- test | (vertical line, could be a I or l) --- */
6139 for(ad=99;dy>4 && 2*dx<dy;){ /* v0.44 */
6140 DBG( wchar_t c_ask='|'; )
6141 /* test if everything is filled black */
6142 if( get_bw(x0+dx/8,x1-dx/8,y0+dy/9,y1-dy/9,box1->p,cs,2) != 0 ) break;
6143 /* more unsure if the borders are not exact */
6144 if( get_bw(x0 ,x0+dx/8,y0+dy/9,y1-dy/9,box1->p,cs,2) != 0 ) ad=99*ad/100;
6145 if( get_bw(x1-dx/8,x1 ,y0+dy/9,y1-dy/9,box1->p,cs,2) != 0 ) ad=99*ad/100;
6146 if( get_bw(x0+dx/8,x1-dx/8,y0 ,y0+dy/8,box1->p,cs,2) != 0 ) ad=99*ad/100;
6147 if( get_bw(x0+dx/8,x1-dx/8,y1-dy/8,y1 ,box1->p,cs,2) != 0 ) ad=99*ad/100;
6148 if (3*dx<dy) ad=98*ad/100;
6149 if (4*dx<dy) ad=99*ad/100;
6150 if (box1->m2 && 2*y1> box1->m2+box1->m3) Break;
6151 if (box1->m2 && 3*y1>2*box1->m2+box1->m3) ad=95*ad/100;
6153 if (!hchar) ad=98*ad/100;
6157 // --- test % ---------------------------------------------------
6158 for(ad=100;dx>5 && dy>7;){ // provisorium
6159 DBG( wchar_t c_ask='%'; )
6160 if (sdata->holes.num > 2) break; /* tolerant against a tiny hole */
6161 if( num_cross(x0,x1 ,y0+dy/4,y0+dy/4,box1->p,cs) != 3
6162 && num_cross(x0,x1 ,y0+dy/8,y0+dy/8,box1->p,cs) != 3 ) Break;
6163 if( num_cross(x0,x1+dx/4,y1-dy/4,y1-dy/4,box1->p,cs) != 3
6164 && num_cross(x0,x1+dx/4,y1-dy/8,y1-dy/8,box1->p,cs) != 3 ) Break;
6165 if( num_cross(x0,x1, y0, y1,box1->p,cs) < 4
6166 && num_cross(x0+dx/8,x1, y0, y1,box1->p,cs) < 4
6167 && num_cross(x0,x1+dx/4, y0, y1,box1->p,cs) < 4
6168 && dx>7 && dy>15) Break;
6169 if( num_cross(x0,x1, y0, y1,box1->p,cs) !=5 ) ad=99*ad/100;
6171 if (dx>7 && dy>12) {
6172 if( num_hole(x0 ,x1 ,y0,y1-dy/4,box1->p,cs,NULL) != 1 ) Break;
6173 if( num_hole(x0+dx/4,x1+dx/4,y0+dy/4,y1,box1->p,cs,NULL) != 1 ) Break;
6174 if( num_hole(x0 ,x1+dx/4,y0,y1 ,box1->p,cs,NULL) != 2 ) Break;
6175 } else ad=98*ad/100;
6176 // use box1->p instead of b, because % is a sum of 3 objects
6177 if ( loop(box1->p,x0,y0 ,dx,cs,0,RI)
6178 <= loop(box1->p,x0,y0+dy/16+1,dx,cs,0,RI) ) ad=96*ad/100; // X
6179 if ( loop(box1->p,x1,y1 ,dx,cs,0,LE)
6180 <= loop(box1->p,x1,y1-1-dy/16,dx,cs,0,LE) ) ad=96*ad/100; // X
6181 for (x=0;x<dx;x++) { /* look for a vertical line and break if found */
6182 if ( get_bw(x0+x,x0+x,y0+dy/8,y1-dy/8,box1->p,cs,2) != 2 ) break;
6183 } if (x<dx) Break; // ~gluedVI
6184 if (gchar) ad=98*ad/100;
6187 if (ad>=100) return ac;
6190 // --- test Omega ---------------------------------------------------
6191 for(ad=d=99;dx>7 && dy>7;){ // min 3x4
6192 DBG( wchar_t c_ask=GREEK_CAPITAL_LETTER_OMEGA; )
6193 if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
6194 if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
6195 if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
6196 if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 0 ) Break;
6198 if( num_cross(x0+dx/2,x0+dx/2,y0 , y1-dy/3,box1->p,cs) != 1 ) Break;
6199 if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND
6200 if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
6201 if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 2 ) // against "rauschen"
6202 if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 2 ) Break;
6203 if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
6204 if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
6205 if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
6206 if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
6207 if (sdata->holes.num) Break;
6208 // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 0 ) break;
6210 if( loop(bp,0 ,0 ,x1-x0,cs,0,RI)<=
6211 loop(bp,0 ,2 ,x1-x0,cs,0,RI) ) Break;
6212 if( loop(bp,dx/2,dy-dy/4,x1-x0,cs,0,RI)>dx/4
6213 || loop(bp,dx/2,dy-dy/4,x1-x0,cs,0,LE)>dx/4 ) Break;
6214 if( loop(bp,dx/2,3*dy/8,x1-x0,cs,0,RI)<dx/4
6215 || loop(bp,dx/2,3*dy/8,x1-x0,cs,0,LE)<dx/4 ) Break;
6217 i=loop(bp,0,dy-1-dy/16,x1-x0,cs,0,RI); if(i>dx/8) Break;
6218 x=loop(bp,i,dy-1-dy/16,x1-x0,cs,1,RI); i+=x; if(i<3*dx/8 || i>dx/2) Break;
6219 x=loop(bp,i,dy-1-dy/16,x1-x0,cs,0,RI); i+=x; if(i<dx/2 || i>5*dx/8) Break;
6220 x=loop(bp,i,dy-1-dy/16,x1-x0,cs,1,RI); i+=x; if(i<7*dx/8) Break;
6222 /* look for a vertikal gap at lower end */
6223 for( x=dx/4;x<3*dx/4;x++ ){
6224 i=loop(bp,x,dy-1,y1-y0,cs,0,UP);
6225 if( i>3*dy/4 ) break;
6227 if( x>=3*dx/4 ) Break;
6229 if( !hchar ) ad=60*ad/100;
6230 bc=GREEK_CAPITAL_LETTER_OMEGA;
6238 // -------------------- OCR engine ;) ----------------------------
6239 wchar_t ocr0(struct box *box1, pix *bp, int cs){
6240 // pix p=*(box1->p);
6241 int i,j,d,x,y,x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
6242 int dx=x1-x0+1,dy=y1-y0+1, /* size */
6243 rx,ry,r1,r2,i1,i2,ad; /* tmp-vars */
6244 // ad,ac will be used in future
6245 wchar_t bc = UNKNOWN; // bestletter
6246 wchar_t um = SPACE; // modifier '"
6247 int hchar; // char is higher than e
6248 int gchar; // char has ink lower than m3
6249 int aa[4][4]; /* corner points, see xX, (x,y,dist^2,vector_idx) v0.41 */
6250 ocr0_shared_t sdata; // data used in all subfunctions
6255 // --- hchar --- gchar -------------------------
6256 hchar=0;if( y0 < box1->m2-(box1->m2-box1->m1)/2 ) hchar=1;
6257 gchar=0;if( y1 > box1->m3+(box1->m4-box1->m3)/2 ) gchar=1;
6258 // if the char is slightly moved down correction can be done
6259 if ( y0<box1->m2 && y1>box1->m3 && 2*y1<box1->m3+box1->m4) // moved
6260 if( 2*(y0-(y1-box1->m3))<=2*box1->m2-(box1->m2-box1->m1) ) hchar=1;
6265 /* search for nearest points to the 4 courners, typical for xX */
6266 /* this is faster as calling nearest_frame_vector 4 times */
6267 aa[0][0]=aa[1][0]=aa[2][0]=aa[3][0]=(x0+x1)/2; /* set to center */
6268 aa[0][1]=aa[1][1]=aa[2][1]=aa[3][1]=(y0+y1)/2; /* set to center */
6269 aa[0][2]=aa[1][2]=aa[2][2]=aa[3][2]=2*sq(128); /* distance to box edges */
6270 aa[0][3]=aa[1][3]=aa[2][3]=aa[3][3]=0; /* vector index */
6271 /* searching for 4 diagonal line ends */
6272 for (i=0;i<box1->num_frame_vectors[0];i++) {
6273 x=box1->frame_vector[i][0]; /* take a vector */
6274 y=box1->frame_vector[i][1];
6275 /* distance to upper left end, normalized to 128 */
6276 j=0; d=sq((x-x0)*128/dx)+sq((y-y0)*128/dy);
6277 // fprintf(stderr," setaa i= %2d xy= %3d %3d d=%5d aa[3]=%2d\n",i,x-x0,y-y0,d,aa[0][3]);
6278 if (d<aa[j][2]) { aa[j][0]=x; aa[j][1]=y; aa[j][2]=d; aa[j][3]=i; }
6279 /* distance to lower left end */
6280 j=1; d=sq((x-x0)*128/dx)+sq((y-y1)*128/dy);
6281 if (d<aa[j][2]) { aa[j][0]=x; aa[j][1]=y; aa[j][2]=d; aa[j][3]=i; }
6282 /* distance to lower right end */
6283 j=2; d=sq((x-x1)*128/dx)+sq((y-y1)*128/dy);
6284 if (d<aa[j][2]) { aa[j][0]=x; aa[j][1]=y; aa[j][2]=d; aa[j][3]=i; }
6285 /* distance to upper right end */
6286 j=3; d=sq((x-x1)*128/dx)+sq((y-y0)*128/dy);
6287 if (d<aa[j][2]) { aa[j][0]=x; aa[j][1]=y; aa[j][2]=d; aa[j][3]=i; }
6289 for (i=0;i<16;i++) sdata.aa[i/4][i%4]=aa[i/4][i%4];
6291 /* extract number position and size of holes and store in a table
6292 * - hole coordinates are relative to box (x-x0,y-y0)
6295 if (box1->num_frames>0) // speedup v0.42
6296 num_hole(x0,x1,y0,y1,box1->p,cs,&sdata.holes); // call once
6297 // printf(" num_holes=%d\n",sdata.holes.num);
6300 after division of two glued chars, boundaries could be wrong,
6301 check this first (ToDo: only if a flag set?)
6303 if (2*y0 < box1->m2+box1->m3)
6304 if (box1->m4>box1->m3 && 2*box1->y1>box1->m4+box1->m3){
6305 /* could be a "I" from divided "Ij" or "Ig" */
6306 for(y=(box1->m3+box1->m2)/2;2*y<box1->m3+box1->m4;y++)
6307 if( get_bw(x0,x1,y,y,box1->p,cs,1)==0 ) break;
6308 if(2*y<box1->m3+box1->m4)
6309 if( get_bw((x0+x1)/2,(x0+x1)/2,y,box1->m4,box1->p,cs,1)==0 ){
6311 if (y>y0) y1=box1->y1=y;
6315 DBG( IFV fprintf(stderr,"\nDBG L%d (%d,%d): ",__LINE__,box1->x0,box1->y0); )
6316 DBG( IFV out_b(box1,sdata.bp,0,0,dx,dy,160); )
6317 DBG( IFV fprintf(stderr,"# aa[] %d %d %d %d %d %d %d %d (4 corners)"
6319 aa[0][0]-x0,aa[0][1]-y0,aa[1][0]-x0,aa[1][1]-y0,
6320 aa[2][0]-x0,aa[2][1]-y0,aa[3][0]-x0,aa[3][1]-y0,
6321 aa[0][2], aa[1][2], aa[2][2], aa[3][2]);)
6322 DBG( IFV fprintf(stderr,"\n# holes %d gchar=%d hchar=%d",sdata.holes.num, gchar, hchar);)
6324 // --- test thin lines - ---------------------------------
6325 for( ad=100; 2*dy<box1->m3-box1->m2 && 3*dx>=4*dy && dx>2; ){ // min 3x3 (small font)
6326 DBG( wchar_t c_ask='-'; )
6327 if( get_bw(x0+dx/8+1,x1-dx/8-1,y0+dy/8+((dy>2)?1:0),
6328 y1-dy/8-((dy>2)?1:0),box1->p,cs,2)==2 ) break;
6329 if( box1->dots ) { Setac(box1,'=',97);break; }
6330 if (dx<=2*dy) ad=98*ad/100;
6331 if (dx<=3*dy) ad=99*ad/100;
6332 if (!box1->m4) ad=96*ad/100;
6335 if ( dx<2*dy) ad=98*ad/100;
6336 if (2*dx<3*dy) ad=98*ad/100;
6341 Setac(box1,'-',ad); if (ad>=100) return '-';
6344 // --- test thin lines = ---------------------------------
6345 for( ; dy>2 && dx>2; ){ // min 3x3 (small font)
6346 DBG( wchar_t c_ask='='; )
6347 for( y=y0;y<y1;y++) // remove upper empty space
6348 if( get_bw(x0+dx/10,x1-dx/10,y ,y ,box1->p,cs,1)==1 ) break;
6349 if( get_bw(x0+dx/10,x1-dx/10,y ,y ,box1->p,cs,2)==2 ) break;
6350 if( get_bw(x0 ,x1 ,(y+y1)/2,(y+y1)/2,box1->p,cs,1)==1 ) break;
6351 if( get_bw(x0+dx/10,x1-dx/10,y1 ,y1 ,box1->p,cs,2)==2 ) break;
6352 Setac(box1,'=',100);
6355 // --- test dots : ---------------------------------
6356 for( ad=100; dy>2 && dy>=2*dx; ){ // max 3x3 (small font)
6358 DBG( wchar_t c_ask=':'; )
6359 // check the gap hight
6360 for( i1=dy/16;i1<dy/2;i1++)
6361 if( get_bw(x0+dx/8,x1-dx/8,y0+i1,y0+i1,box1->p,cs,1)==0 ) break;
6362 if (i1>=dy/2) break;
6363 for( i2=dy/16;i2<dy/2;i2++)
6364 if( get_bw(x0+dx/8,x1-dx/8,y1-i2,y1-i2,box1->p,cs,1)==0 ) break;
6365 if (i2>=dy/2) Break;
6366 MSG(fprintf(stderr,"gap y12 %d %d",i1,i2);)
6368 if (box1->m3 && y1>box1->m3) ad=98*ad/100; // ~;
6369 if (box1->m3 && 2*y0> box1->m2+box1->m1) ad=98*ad/100; // ~i
6370 if (gchar) ad=99*ad/100;
6371 ad=ad-abs(i1-i2)/dy*20;
6372 if (abs(i1-dx)>dy/4) Break; // round or quadratic dots?
6373 if (abs(i1-dx)>dy/8) ad=98*ad/100;
6374 if (abs(i2-dx)>dy/4) Break; // round or quadratic dots?
6375 if (abs(i2-dx)>dy/8) ad=98*ad/100;
6376 if (box1->dots!=1) ad=96*ad/100;
6377 Setac(box1,':',ad); // dx<=3 ad--
6378 if (ad>=100) return ':';
6381 // --- test dots ; ---------------------------------
6382 if( 2*y0> box1->m2+box1->m1 ) // ~i
6383 if( 4*y1>=3*box1->m3+box1->m2 ) // ~:
6384 for( ad=100; dy>5 && dx>1 && dy>2*dx; ){ // max 3x3 (small font)
6385 DBG( wchar_t c_ask=';'; )
6386 // better would it be to detect round pixelcluster on top
6387 // check high of upper and lower dot
6388 for( i1=0;i1<dy/2;i1++)
6389 if( get_bw(x0,x1,y0+i1,y0+i1,box1->p,cs,1)==0 ) break;
6390 if (i1>=dy/2) break;
6391 for( i2=0;i2<dy/2;i2++)
6392 if( get_bw(x0,x1,y1-i2,y1-i2,box1->p,cs,1)==0 ) break;
6395 /* test for horizontal symmetry ~i */
6396 for (y=0;y<dy;y++) for (x=0;x<dx/2;x++)
6397 if ((getpixel(bp,x,y)<cs)!=(getpixel(bp,dx-1-x,y)<cs)) { y=dy+1; break; }
6398 if (y==dy) ad=96*ad/100; /* ~i */
6400 if (i2==i1 && y1<=box1->m3) ad=97*ad/100;
6401 if (i2-i1<dy/8) ad=99*ad/100;
6402 Setac(box1,';',ad); // dx<=3 ad--
6403 if (ad>=100) return ';';
6406 // --- first test small dots . ---------------------------------
6407 if( 3*dy<box1->m4-box1->m1 && abs(dx-dy)<(dx+dy)/4+2
6408 && 3*y1>=(2*box1->m3+ box1->m2) // dot near baseline?
6409 && 5*y0>=(3*box1->m3+2*box1->m2) ){ // Jul00
6410 DBG( wchar_t c_ask='.'; )
6411 d=0; r1=60;r2=140; ad=99;
6412 for(x=x0;x<=x1;x++)for(y=y0;y<=y1;y++){ /* circle equation */
6413 rx=100*(2*x-(x0+x1))/dx; // normalize to 15bit number
6414 ry=100*(2*y-(y0+y1))/dy;
6415 if( rx*rx + ry*ry < r1*r1 ) if( getpixel(box1->p,x,y)>=cs ){ d++;x=x1+1;y=y1+1; }
6416 if( rx*rx + ry*ry > r2*r2 ) if( getpixel(box1->p,x,y)< cs ){ d++;x=x1+1;y=y1+1; }
6417 // fprintf(stderr,"\nDBG . x= %3d %3d r= %6d %6d %6d", rx, ry, rx*rx+ry*ry, r1*r1, r2*r2);
6420 if( loop(box1->p,x0,y0,x1-x0,cs,0,RI)
6421 <= loop(box1->p,x0,y1,x1-x0,cs,0,RI)
6422 || loop(box1->p,x1,y0,x1-x0,cs,0,LE)
6423 >= loop(box1->p,x1,y1,x1-x0,cs,0,LE) )
6425 bc='.'; if (box1->dots) { Setac(box1,':',ad); ad=98*ad/100; }
6429 // --- first test small dots , ---------------------------------
6430 if( 3*dy<2*(box1->m4-box1->m1)
6431 && 2*y0> box1->m2+box1->m3
6433 || get_bw(0,dx/2,dy/2,dy-1,bp,cs,1)==0) ){ // ocr-a-,
6434 DBG( wchar_t c_ask=','; )
6436 if (dy==1 && dx==1) ad=98*ad/100;
6437 if (dy==2 && dx==1) ad=99*ad/100; // this is a problem case
6438 if (dx>=dy) ad=99*ad/100;
6439 if( 2*dy >= box1->m4-box1->m1) ad=98*ad/100;
6440 if( loop(box1->p,x0,y0,x1-x0,cs,0,RI) /* simple line */
6441 > loop(box1->p,x0,y1,x1-x0,cs,0,RI)
6442 && loop(box1->p,x1,y0,x1-x0,cs,0,LE)
6443 < loop(box1->p,x1,y1,x1-x0,cs,0,LE) ) { ad=99*ad/100; }
6444 else { /* with upper circle */
6445 if( loop(box1->p,x0,(y0+y1+1)/2,x1-x0,cs,0,RI)<dx/2 ) ad=98*ad/100;
6446 if( loop(box1->p,x1, y1 ,x1-x0,cs,0,LE)<dx/2 ) ad=98*ad/100;
6447 if( loop(box1->p,x0,y1-((dy>5)?1:0),x1-x0,cs,0,LE)>(dx+1)/2 )
6448 if( loop(box1->p,x0, y1 ,x1-x0,cs,0,LE)>(dx+1)/2 ) ad=96*ad/100;
6450 if(box1->dots==1) { Setac(box1,';',ad); ad=99*ad/100; }
6453 // --- first test small dots '" ---------------------------------
6454 if( 2*dy < box1->m4 -box1->m1+1
6455 && 2*y0 < box1->m2 +box1->m3
6456 && 3*y1 < box1->m2+2*box1->m3+2 ){
6457 DBG( wchar_t c_ask='\''; )
6459 if (2*y1 >= box1->m2+box1->m3) { ad=96*ad/100; MSG({}) } // ~!
6460 if (3*y1>=2*box1->m2+box1->m3) { ad=96*ad/100; MSG({}) }
6461 if (get_bw(x0,x1,(box1->m2+box1->m3)/2,box1->m4,box1->p,cs,1)!=0)
6462 { ad=98*ad/100; MSG({}) }
6464 && num_cross(x0,x1,y1,y1,box1->p,cs) == 2) { // " "
6466 // ocr-a-" has no gap!
6467 if ( get_bw((x0+x1)/2,(x0+x1)/2,y0,y1,box1->p,cs,1)!=0 ) ad=96*ad/100;
6469 if ( num_cross(x0,x1, y0 , y0 ,box1->p,cs)!=1) ad=96*ad/100;
6470 if ( num_cross(x0,x1,(y0+y1)/2,(y0+y1)/2,box1->p,cs)!=1) ad=98*ad/100;
6471 if (dx>dy) { ad=96*ad/100; MSG({}) }
6473 if (2*y0 > box1->m1+box1->m2) ad=99*ad/100;
6475 if (ad>=100) return bc;
6477 // --- TILDE ~ ---------------------------------
6478 if( 2*dy<box1->m4-box1->m1 && dx>=dy && dx>3 && dy>1
6479 && 2*y0< box1->m1+box1->m2
6480 && 3*y1<2*box1->m2+box1->m3 ){
6481 if( loop(box1->p,x0,y0,dx,cs,0,RI)
6482 > loop(box1->p,x0,y1,dx,cs,0,RI)
6483 && loop(box1->p,x1,y0,dx,cs,0,LE)
6484 < loop(box1->p,x1,y1,dx,cs,0,LE)
6485 && num_cross(x0,x1,y0,y0,box1->p,cs) == 2
6486 && num_cross(x0,x1,y1,y1,box1->p,cs) == 2 ) {
6487 DBG( wchar_t c_ask='~'; )
6492 // --- CIRCUMFLEX, hat ^ ---------------------------------
6493 if( 2*dy<box1->m4-box1->m1 && dx>=dy && dx>2 && dy>1
6494 && 2*y0< box1->m1+box1->m2
6495 && 3*y1<2*box1->m2+box1->m3 ){
6496 DBG( wchar_t c_ask='^'; )
6497 if( ( loop(box1->p,x0,y0 ,dx,cs,0,RI)
6498 > loop(box1->p,x0,y1 ,dx,cs,0,RI)-dx/8
6499 || loop(box1->p,x0,y0 ,dx,cs,0,RI)
6500 > loop(box1->p,x0,y1-1,dx,cs,0,RI)-dx/8 )
6501 && ( loop(box1->p,x1,y0 ,dx,cs,0,LE)
6502 > loop(box1->p,x1,y1 ,dx,cs,0,LE)-dx/8
6503 || loop(box1->p,x1,y0 ,dx,cs,0,LE)
6504 > loop(box1->p,x1,y1-1,dx,cs,0,LE)-dx/8 )
6505 && num_cross(x0,x1,y0 ,y0 ,box1->p,cs) == 1
6506 && ( num_cross(x0,x1,y1 ,y1 ,box1->p,cs) == 2
6507 || num_cross(x0,x1,y1-1,y1-1,box1->p,cs) == 2 )) {
6512 // ------------------------------------------------------
6513 // if( dots==1 ){ um='\''; }
6514 #if 0 /* ToDo: change to vectors, call here or in whatletter */
6515 if (box1->dots==0) { // i-dots ??? (if dots==0 is wrong)
6517 for(;y<y0+dy/2;y++)if( get_bw(x0+dx/4,x1,y,y,box1->p,cs,1)==1) break;
6520 for(;y<y0+dy/2;y++)if( get_bw(x0,x1,y,y,box1->p,cs,1)==0) break;
6521 if( y<y0+dy/2 && 5*(y-i1+1)>box1->m2-box1->m1){
6522 testumlaut(box1,cs,2,&um); // set modifier + new y0 ???
6528 um = box1->modifier;
6530 if ( /* um==ACUTE_ACCENT || */ um==DIAERESIS){
6532 if( get_bw(x0,x1,y,y,box1->p,cs,1)==0) { y0=y; dy=y1-y0+1; break; } // scan "a "o "u
6535 // --- test numbers 0..9 --- separated for faster compilation
6536 if( JOB->cfg.only_numbers ) return ocr0n(&sdata);
6538 // bc=ocr1(box1,bp,cs);
6539 if(bc!=UNKNOWN && box1->num_ac>0 && box1->wac[0]==100)
6540 return bc; // for fast compilable tests
6542 // ------ separated for faster compilation
6543 // ToDo: inser ocr0_shared_t here and split into a,b,cC,d,e,f,g9,...
6544 #define IF_NOT_SURE if(bc==UNKNOWN || box1->num_ac==0 || box1->wac[0]<100)
6546 IF_NOT_SURE bc=ocr0_eE(&sdata);
6547 IF_NOT_SURE bc=ocr0_f(&sdata);
6548 IF_NOT_SURE bc=ocr0_bB(&sdata);
6549 IF_NOT_SURE bc=ocr0_dD(&sdata);
6550 IF_NOT_SURE bc=ocr0_F(&sdata);
6551 IF_NOT_SURE bc=ocr0_uU(&sdata);
6552 IF_NOT_SURE bc=ocr0_micro(&sdata);
6553 IF_NOT_SURE bc=ocr0_vV(&sdata);
6554 IF_NOT_SURE bc=ocr0_rR(&sdata);
6555 IF_NOT_SURE bc=ocr0_m(&sdata);
6556 IF_NOT_SURE bc=ocr0_tT(&sdata);
6557 IF_NOT_SURE bc=ocr0_sS(&sdata);
6558 IF_NOT_SURE bc=ocr0_gG(&sdata);
6559 IF_NOT_SURE bc=ocr0_xX(&sdata);
6560 IF_NOT_SURE bc=ocr0_yY(&sdata);
6561 IF_NOT_SURE bc=ocr0_zZ(&sdata);
6562 IF_NOT_SURE bc=ocr0_wW(&sdata);
6563 IF_NOT_SURE bc=ocr0_aA(&sdata);
6564 IF_NOT_SURE bc=ocr0_cC(&sdata);
6565 IF_NOT_SURE bc=ocr0_lL(&sdata);
6566 IF_NOT_SURE bc=ocr0_oO(&sdata);
6567 IF_NOT_SURE bc=ocr0_pP(&sdata);
6568 IF_NOT_SURE bc=ocr0_qQ(&sdata);
6569 IF_NOT_SURE bc=ocr0_iIjJ(&sdata);
6570 IF_NOT_SURE bc=ocr0_n(&sdata);
6571 IF_NOT_SURE bc=ocr0_M(&sdata);
6572 IF_NOT_SURE bc=ocr0_N(&sdata);
6573 IF_NOT_SURE bc=ocr0_h(&sdata);
6574 IF_NOT_SURE bc=ocr0_H(&sdata);
6575 IF_NOT_SURE bc=ocr0_k(&sdata);
6576 IF_NOT_SURE bc=ocr0_K(&sdata);
6577 IF_NOT_SURE bc=ocr0n(&sdata);
6578 IF_NOT_SURE bc=ocr0_brackets(&sdata);
6579 IF_NOT_SURE bc=ocr0p9(&sdata);
6580 IF_NOT_SURE bc=ocr0px(&sdata);
6583 if(box1->num_ac==0 && bc!=UNKNOWN) fprintf(stderr,"<!--ERROR 576-->");
6584 if(box1->num_ac>0 && box1->wac[0]>95) box1->c=bc=box1->tac[0];
6585 /* will be removed later, only fix old things */
6586 for (i=0;i<box1->num_ac;i++) if (box1->tac[i]==bc) { bc=box1->tac[0]; }