replaced libart with new polygon code
[swftools.git] / lib / gocr / ocr0.c
1 /*
2   rule based OCR engine, partly rewritten for edges (old=pixel)
3  */ 
4 /*
5 This is a Optical-Character-Recognition program
6 Copyright (C) 2000-2007 Joerg Schulenburg
7
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.
12
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.
17
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.
21
22  see README for email address
23
24  >>>  DO NOT EDIT THIS FILE IF YOU NOT REALLY KNOW WHAT YOU ARE DOING! <<<
25   
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)
30   
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.
37   (JorgS)
38
39
40 ToDo:
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
46       or
47       often_used=etianmsurwdkgo     rarely_used=hvjcflpqxyz.,:
48       or
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)
52
53   general feature extraction:
54    - white holes at middle, upper, lower position (cost much time)
55    - test lines and triangles insteat of rectangles
56    
57    char is removed, wchar_t is used  (better code)
58    
59    making a static global variable-set x.x0,x.x1, and call test_a,
60       test_b ... (faster compilation, but not reentrant!)
61       
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!"
65
66 */
67
68 #include <stdlib.h>
69 #include <stdio.h>
70 // #include "pgm2asc.h"
71 #include "ocr0.h"
72 // #include "ocr1.h"
73 #include "pnm.h"
74 #include "gocr.h"
75
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);}
78
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 */
86 #endif
87
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 }
97 #define DBG(x) x
98 #else
99 #define Setac(box1,ac,ad)  setac(box1,ac,ad)
100 #define Break break
101 #define MSG(x)
102 #define DBG(x)
103 #endif
104
105 /* extern "C"{ */
106
107 // static inline int sq(int x) { return x*x; } /* square */
108
109 /*
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.
120  */ 
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__);
131       return(-1);
132   }
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;
136   frame=i;
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 */
141      if (i==j2) break;
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];
145     // Language=german
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
156     if (l2==0) { 
157       // fprintf(stderr,"ocr0 L%d: r1==r2 r1= %d %d",__LINE__, r1x, r1y); // debugging
158       d=-1024;
159     } else 
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
163       else {
164         if (d>=1024) { x=r2x; y=r2y; }  // end point
165           else {
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 */
169           }
170       }
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;
174     // for debugging:
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);
178   }
179   return maxdist;
180 }
181
182 /*
183  * search vectors between j1 and j2 for nearest point a to point r 
184  * example:
185  * 
186  *     r-> $$...$$   $ - mark vectors
187  *         @@$..@@   @ - black pixels
188  *         @@$..@@   . - white pixels
189  *         @@@@.$@
190  *     a-> @@$@$@@
191  *         @$.@@@@
192  *         @@..$@@
193  *         @@..$@@
194  *  j1 --> $$...$$ <-- j2
195  *     
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
198  *          return aa?
199  */
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);
209       //out_x(box1);
210       return(-1);
211    }
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;
220    frame=i;
221    /* frame(j1)<=frame(j2) possible */
222    for (i=j1;;i++) {
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; }
230      if (i==j2) break;
231    }
232    return aa[3];
233 }
234
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){
240    // pix p=*(box1->p);
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='"'; )
245    r=0;
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? */
252    if( 2*y1 > m1+m2 ){
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 */
256       yl=y;
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 */
259     } 
260    }
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;
266
267    if ( yl-1>yu ) {  // tall box ij"a"o"u
268 #if 0
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);
272 #define DEBUG 1
273 #endif
274      {
275
276        x=xl;y=yu;
277        if( get_bw(xl,x1+1,yu,yl-1,box1->p,cs,1)==0 ) r=0; // neighbour overlap?
278        else
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 )
283        { int i,j,x;
284          r=1;
285          //  ...@@@....  RING_ABOVE //  ..@@@..@@.  TILDE
286          //  ..@...@...             //  @@.@@@@@..
287          //  ..@...@...             //  @.........
288          //  ..@..@@...
289          //  ...@@@....
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++;
302            r=2; 
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);
304            mod = DIAERESIS;
305          }
306          if( m&2 ) box1->y0=yl;
307 /*         if( m&2 ) box1->y0= ( (r==1) ? yu : yl ); */
308          // out_x(box1);
309        }
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++;
312          if(m)box1->y0=yu;
313        }
314        if( r==1 ){ yl--;
315 //        .@@@.    ..@@.
316 //        .@@..    .@@..
317 //        .@...    .@@..
318 //
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 ) // &eacute; 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 ) // &eacute; Nov03 
327            mod = ACUTE_ACCENT; // '
328
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
332
333 //        .@@@.   .@@..
334 //        ..@@.   ..@@.
335 //        ...@.   ..@@.
336 //
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 ) &agrave; 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 ) &agrave; Nov03
345            mod = GRAVE_ACCENT; // ` 
346
347 #ifdef DEBUG
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);
350 #endif
351          if(    (xr-xl+1)   < 2*(yl-yu+1)+2
352            && 2*(xr-xl+1)+2 >   (yl-yu+1) )  {
353            int i,i1,i2,i3,i4;
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;
366 #ifdef DEBUG
367            fprintf(stderr,"\n#DEBUG DOT_ABOVE %d %d %d %d",i1,i2,i3,i4);
368 #endif
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)
373            )
374            mod = DOT_ABOVE; // "." above, ToDo: improve it!
375          }
376
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; // "^"
389          
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
402          
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
407            && xr-xl>10)
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
420          
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 ) 
428            mod = TILDE;
429
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 )
434            mod = RING_ABOVE;
435
436 #ifdef DEBUG
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":"?"))));
442         out_x(box1);
443 #endif
444
445        }
446      }
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);)
450    }
451 //   printf(" modifier=%c",mod);
452    if (modifier) *modifier=mod; /* set modifier */
453    return r;
454 }
455
456  
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 */
462         ad;     /* tmp-vars */
463    int (*aa)[4]=sdata->aa;    /* corner-points, (x,y,dist^2,vector_idx) */
464
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; }
504       }
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
511        }
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?
523       }
524       if (x<dx/2) Break;
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;
527       if( i ) Break;
528 // ..@@@@...<-
529 // .@@@@@@;.
530 // @@,...@@.
531 // @@.....@,
532 // @@@@@@@@@
533 // @@.,;.@,.  <- problem (y) == bad_e>50
534 // @@.....@.
535 // @@,...@@.
536 // .@@@,@@@.
537 // ..@@@@;..<-
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++;
548         if(j<2*dx/4) Break;
549       }
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; }
558       }
559       if (y>y0+dy/4 && y<y1-dy/4 && x>dx/2) Break; // s
560       if (x>dx/4) ad=99*ad/100;
561
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
566         ad=99*ad/100;
567       }
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;
576       }
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
579       if (box1->m2) {
580         if (sdata->gchar) ad=99*ad/100;
581         if (sdata->hchar) ad=99*ad/100;
582       } else              ad=99*ad/100;
583
584       Setac(box1,(wchar_t)'e',ad);
585       if (ad>=100) return 'e';
586       break;
587    }
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 */
595      d=2*sq(128/4);
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 */
601 /*
602            E            f near E 
603                   
604          OOOOOOOO         OOOO
605           O5    O        O
606           O4             O
607           OOOO3        OOOOOO
608           O2             O
609           O              O
610           O1    O        O
611          OOOOOOOO      OOOOOO
612 */
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
626
627      MSG(fprintf(stderr,"i1-5 %d %d %d %d %d",i1,i2,i3,i4,i5);)
628       // holes right open?
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;
631       if( i ) Break;
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;
634       if( i ) Break;
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;
638       } if( i ) Break;
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;
650       y+=dy/15;
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
653       x+=dx/15+1;
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;
664         if (i>dx/4) break;
665         if(i<x) x=i;
666       } if( y<y1-dy/9 ) Break;  // t
667       if(dy>3*dx)  // ~[
668       if( get_bw(x0+dx/2,x0+dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break;
669
670       if (box1->m2) {
671         if (!hchar) ad=ad*99/100;
672         if ( gchar) ad=ad*99/100;
673       }
674       Setac(box1,(wchar_t)'E',ad);
675       if (ad>=100) return 'E';
676       break;
677    }
678    return box1->c;
679 }
680
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 */
686         ad;     /* tmp-vars */
687
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
702       // ~thick_w
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;
705
706       y=3*dy/4;
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
709       y=dy/2;
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
712                 /* printed n */
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
717         i=dy/4; y=13*dy/16;
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;
730         }
731         if(x <i2) Break; // unusual property for n
732         if( dy>7 )
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
737         if( dy>7 && dx>7 )
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;
749         handwritten=80; 
750       }
751
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
756
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
760
761       // glued ri ???
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;
766
767
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; // &szlig;
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
777
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; // &szlig; 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) {
784           ad=97*ad/100; // ~m
785           if (dy<=4) Setac(box1,'m',97); // only for 4x6 font!
786         }
787       }
788       Setac(box1,'n',ad);
789       break;
790    }
791    return box1->c;
792 }
793
794 static wchar_t ocr0_M(ocr0_shared_t *sdata){
795    struct box *box1=sdata->box1;
796    pix *bp=sdata->bp;
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 */
800         ad;     /* tmp-vars */
801
802    // ------------------ test M ---------------------------
803    for(ad=d=100;dx>3 && dy>3;){ // dy<=dx nicht perfekt! besser mittleres
804                                 // min-suchen fuer m
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
811        && dx>4 ) Break;
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;
815       
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;
818
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
821
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
832
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 
841
842       // i0 is lower end of upper serifen (widest gap? )
843       i0=0;
844        
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;
849           }
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
855           }
856         }
857       }
858       // MNWK
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);
862       if(i2<dy/4) {
863         if (!sdata->hchar) Break;       // rm
864         ad=99*ad/100;
865       }
866       if (i2==0 && dx>8 && dy>12) Break; // glued and bad splitted serifen-MN
867
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?
872       if( 7*(t1+1)<dx )
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 ???
875
876       // ~u_n-pair
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;
880
881       // ~nn v0.2.4a3 
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
897       }
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
900
901       if (dy<17)
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
907       
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 
910        && dx>8 && dy>12 ){
911         ad=98*ad/100;
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;
915         if( y<5*dy/8 )
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!
918       }
919
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;
922
923       if(!hchar){
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
927       }
928       if( gchar ) ad=98*ad/100;
929       if (ad>99 && dx<8) ad=99*ad/100; /* give 5x8 N a chance */
930       Setac(box1,'M',ad);
931       break;
932    }
933    return box1->c;
934 }
935
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) */
942         dbg[9],
943         ad;     /* tmp-vars */
944
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 */
953       d=2*sq(128/4);
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;
971
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);)
983
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
993
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;
1002       // test H
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;
1014
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;
1025       MSG( \
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;
1034
1035       if (!hchar) ad=99*ad/100;
1036       if ( gchar) ad=98*ad/100; // \sc N
1037       Setac(box1,'N',ad);
1038       break;
1039    }
1040    return box1->c;
1041 }
1042
1043 static wchar_t ocr0_h(ocr0_shared_t *sdata){
1044    struct box *box1=sdata->box1;
1045    pix *bp=sdata->bp;
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 */
1049         ad;     /* tmp-vars */
1050    int (*aa)[4]=sdata->aa;    /* corner-points, (x,y,dist^2,vector_idx) */
1051    
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 */
1059      d=2*sq(128/4);
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 */
1065 /*
1066   type     A         B=italic ???
1067        18             OOO
1068         O            O  O
1069         O              O
1070         O7OOO          OOOO
1071         O4   O        O    O
1072         O    O       O    O
1073         O    O      O    O  O
1074        2O3  5O6    O     OOO
1075 */
1076      i1=i8=aa[0][3];
1077      i2=i3=aa[1][3];
1078      i5=i6=aa[2][3];
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!
1084      }
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);
1092
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;
1101       if( dy>18 )
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--;
1109       } if( i ) Break;
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--;
1112       } if( i ) Break;
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;
1127         if (ad<1) break;
1128       }
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);) }
1138
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);) }
1142       
1143       i=loop(bp,dx-1,1+dy/16,dx,cs,0,LE); if (i<dx/4) {
1144         ad=98*ad/100;
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) {
1150         ad=98*ad/100; // fi
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) {
1154         ad=98*ad/100; // li
1155         MSG(fprintf(stderr,"ad=%d",ad);) }
1156       
1157       
1158       if (sdata->holes.num > 0) ad=97*ad/100;
1159       if (box1->m2) {
1160         if ( gchar) ad=98*ad/100;
1161         if (!hchar) ad=97*ad/100;
1162       } else        ad=99*ad/100;
1163       Setac(box1,'h',ad);
1164       break;
1165    }
1166    return box1->c;
1167 }
1168
1169 static wchar_t ocr0_H(ocr0_shared_t *sdata){
1170    struct box *box1=sdata->box1;
1171    pix *bp=sdata->bp;
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 */
1175         ad;     /* tmp-vars */
1176
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; } 
1190       if( !i ) Break;
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;
1207       } if( i ) Break;
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;
1210       } if( i ) Break;
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;
1213       } if( i ) Break;
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;
1216       } if( i ) Break;
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;
1219       } if( i ) Break;
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;
1238       if( dx>8 )
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;
1247       Setac(box1,'H',ad);
1248       break;
1249    }
1250    return box1->c;
1251 }
1252
1253 static wchar_t ocr0_k(ocr0_shared_t *sdata){
1254    struct box *box1=sdata->box1;
1255    pix *bp=sdata->bp;
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 */
1259         ad;     /* tmp-vars */
1260    int (*aa)[4]=sdata->aa;    /* corner-points, (x,y,dist^2,vector_idx) */
1261
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 */
1269      d=2*sq(128/4);
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 */
1275 /*
1276   type     A         B=italic ???
1277        18             OOO
1278         O            O  O
1279         O    O6         O
1280         O7 OO          O   OO
1281         O4OO          OO OO
1282         O OO         O  O 
1283         O  OO       O    O  O
1284        2O3   O5    O     OOO
1285 */
1286      i1=i8=aa[0][3];
1287      i2=i3=aa[1][3];
1288      i5=   aa[2][3];
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!
1294      }
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;
1304
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;
1312       if( dx<8
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!
1333
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; 
1340       x=dx-1-x; y=j;
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; 
1345
1346       for(y=y0+dy/3;y<y1;y++) if( num_cross(x0,x1,y,y,box1->p,cs)==2 ) break;
1347       if( y==y1 ) Break;
1348       if(
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);
1358       if (i>dx/4
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
1362
1363       if( 2*y0>(box1->m1+box1->m2) ) ad=99*ad/100;
1364       
1365       if ( gchar) ad=98*ad/100;
1366       if (!hchar) ad=98*ad/100;
1367       Setac(box1,'k',ad);
1368       break;
1369    }
1370    return box1->c;
1371 }
1372
1373 static wchar_t ocr0_K(ocr0_shared_t *sdata){
1374    struct box *box1=sdata->box1;
1375    pix *bp=sdata->bp;
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 */
1380
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;
1393         }
1394         if(y>=dy/4) i=0; /* ok, found gap */
1395       } if( i ) Break;
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;
1405       } if( i ) Break;
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;
1408       } if( i ) Break;
1409       if( dx<10 ){
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;
1412         } if( i ) Break;
1413       }
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;
1416       } if( i ) Break;
1417       if( get_bw(x1-dx/3,x1,y0,y0+dy/8,box1->p,cs,1) != 1 ) Break; // ~k
1418       if( dy>16
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
1422
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
1429       //
1430       //  a   d   <= that are main points of K
1431       //  |  /
1432       //  b/e
1433       //  |  \    .
1434       //  c   f
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; }
1447 #endif
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; }
1452       }
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;
1458 #if 0
1459      MSG( \
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);\
1462        )
1463 #endif
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}
1472       } else {
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
1477       }
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
1483       }
1484       if(box1->m3 && !hchar) ad=99*ad/100;
1485       if(box1->m3 &&  gchar) ad=99*ad/100;
1486       // printf(" ok xe=%d",xe);
1487       Setac(box1,'K',ad);
1488       break;
1489    }
1490    return box1->c;
1491 }
1492
1493 static wchar_t ocr0_f(ocr0_shared_t *sdata){
1494    struct box *box1=sdata->box1;
1495    pix *bp=sdata->bp;
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) */
1501         ad;     /* tmp-vars */
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
1513     */
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 */
1521      d=2*sq(128/4);
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 */
1525 /*
1526           9 
1527          OOO 
1528         O 7 O8
1529         O6   
1530       1OOOO5
1531         O4
1532         O
1533        2O3
1534       OOOOO
1535 */
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);
1549
1550      MSG(fprintf(stderr,"i1-9 %d %d %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7,i8,i9);)
1551
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
1558
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
1567           ) break;
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;
1571       if( i>dy/8
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
1574
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; 
1579        
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
1590
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];
1597       ab[7][3]=i3;
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
1602
1603
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
1609
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
1615
1616       if( loop(bp,0,dy/2,dx,cs,0,RI)-1
1617          >loop(bp,0,   1,dx,cs,0,RI) ) Break; // ~X
1618
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 )
1631         { j=0;break; }
1632       }  if(j) ad=98*ad/100;  // not detected
1633
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;
1639       } 
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;
1643       if( dx>5 && !hchar)
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
1646       if( dx>8 )
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
1650
1651       if (!hchar)
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
1655
1656       if (dy>15)
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
1659       
1660       if( dx>4 )
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);) }
1672       }
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);) }
1678
1679       if( loop(bp,0,dy/4,dx  ,cs,0,RI)>1
1680        && loop(bp,0,   0,dy/4,cs,0,DO)<dy/4 ) {
1681         ad=95*ad/100; // ~I
1682         MSG(fprintf(stderr,"ad=%d",ad);) }
1683
1684       if (get_bw(x0+dx/16,x1-dx/16,y0,y0,box1->p,cs,2) == 0) { // white pixels?
1685         ad=98*ad/100; // F
1686         MSG(fprintf(stderr,"ad=%d",ad);) }
1687       
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++;
1691       Setac(box1,'f',ad);
1692       break;
1693    }
1694    return box1->c;
1695 }
1696
1697 static wchar_t ocr0_bB(ocr0_shared_t *sdata){
1698    struct box *box1=sdata->box1;
1699    pix *bp=sdata->bp;
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 */
1703         ad;     /* tmp-vars */
1704
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;
1711       if( !i ) Break;
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;
1714       if( !i ) Break;
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;
1730
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
1751       }
1752
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;
1760       // out_x(box1);
1761
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;
1764         if(i<x) x=i;
1765       } if( y<dy-dy/8 ) Break;  // ~8 bad_a
1766
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?)
1771
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!
1777
1778       if(!hchar){  // ~ fat_a
1779         ad=99*ad/100;
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;
1782       }
1783
1784       if ( (!hchar) && (dx<=10 || dy<=10) ) ad=97*ad/100; // hchar or good_quality
1785       if (gchar) ad=99*ad/100;
1786       Setac(box1,'B',ad);
1787       break;
1788    }
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 */
1793       for(y=y0;y<y1;y++)
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 )
1802       if( dy<16 ||
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;
1817       Setac(box1,'b',ad);
1818       if (ad>=100) return 'b';
1819       break;
1820    }
1821    return box1->c;
1822 }
1823
1824 static wchar_t ocr0_dD(ocr0_shared_t *sdata){
1825    struct box *box1=sdata->box1;
1826    pix *bp=sdata->bp;
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 */
1830         ad;     /* tmp-vars */
1831
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;
1852         if( i>x ) x=i;
1853       }
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;
1859         if( i<x ) x=i;
1860       }
1861       if (y<dy/3 ) 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;
1866         if( i<x ) x=i;
1867       }
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
1871
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
1875       }
1876
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
1880
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
1883
1884
1885       
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 
1889
1890       if(box1->dots) ad=ad*94/100;
1891       if ( gchar) ad=99*ad/100;
1892       if (!hchar) ad=99*ad/100;
1893       Setac(box1,'D',ad);
1894       break;
1895    }
1896    // --- test d ---------------------------------------------------
1897    for(d=100;dx>2 && dy>3;){     // min 3x4
1898       DBG( wchar_t c_ask='d'; )
1899       ad=100;
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;
1906       if(dy>19)
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--;
1915       } if( i ) Break;
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--;
1923       } if( i ) Break;
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;
1933       }
1934       if (!hchar) ad=98*ad/100;
1935       if ( gchar) ad=99*ad/100;
1936       Setac(box1,'d',ad);
1937       break;
1938    }
1939    return box1->c;
1940 }
1941
1942 static wchar_t ocr0_F(ocr0_shared_t *sdata){
1943    struct box *box1=sdata->box1;
1944    pix *bp=sdata->bp;
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 */
1948         ad;     /* tmp-vars */
1949
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;
1957
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
1960         if (j>x) x=j;
1961       } if (y<dy/4 || x<dx/2) Break;
1962
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; } 
1966       if( i ) Break;
1967
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; } 
1973       if( i ) Break;
1974
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; }
1980       }
1981       if( i ) Break;
1982
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;
1986       if( !i ) Break;
1987
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;
1990       if( !i ) Break;
1991
1992       i=loop(bp,dx-1,dy-1,dx,cs,0,LE); // serif or E ?
1993       if (i<=dx/3) {
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;
1996         ad=99*ad/100;
1997       }
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;
2000
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
2008
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;
2015
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;
2019
2020       // check for screen font P
2021       i= loop(bp,bp->x-1,bp->y/4,dx,cs,0,LE);
2022       if (i<1) {
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);
2025         if (j<=dy/2) {
2026           i=loop(bp,bp->x-1,0,dx,cs,0,LE);
2027           ad=ad*98/100;
2028           if (i>dx/8) Break;
2029           if (i) ad=98*ad/100;
2030         }
2031       }
2032
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
2035       }
2036       if (gchar) ad=99*ad/100;
2037       Setac(box1,'F',ad);
2038       break;
2039    }
2040    return box1->c;
2041 }
2042
2043 static wchar_t ocr0_uU(ocr0_shared_t *sdata){
2044    struct box *box1=sdata->box1;
2045    pix *bp=sdata->bp;
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 */
2049         ad;     /* tmp-vars */
2050    wchar_t bc=UNKNOWN;
2051
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;
2067
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; }
2073       } if( !i ) Break;
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--;
2078       } if( !i ) Break;
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;
2081       } if( i ) Break;
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--;
2084       } if( !i ) Break;
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;
2088       } if( !i ) Break;
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}
2091
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
2095       if(dy>15)
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)
2098       if( hchar && dy>7)
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
2105
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;
2110
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
2113
2114       if (ad==100) ad=99; // ToDo: only if lines.wt<100
2115       bc='u';
2116       if (gchar) ad=98*ad/100;
2117       if (hchar) bc='U';
2118       if (box1->dots>0) ad=99*ad/100;
2119       Setac(box1,bc,ad);
2120       break;
2121    }
2122    return box1->c;
2123 }
2124
2125 static wchar_t ocr0_micro(ocr0_shared_t *sdata){
2126    struct box *box1=sdata->box1;
2127    pix *bp=sdata->bp;
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 */
2131         ad;     /* tmp-vars */
2132
2133    // --- test \mu &micro; 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--;
2157       } if( !i ) break;
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--;
2162       } if( !i ) break;
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;
2165       } if( i ) break;
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--;
2168       } if( !i ) break;
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;
2173
2174       Setac(box1,MICRO_SIGN,ad);
2175       break;
2176    }
2177    return box1->c;
2178 }
2179
2180 static wchar_t ocr0_vV(ocr0_shared_t *sdata){
2181    struct box *box1=sdata->box1;
2182    pix *bp=sdata->bp;
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 */
2186         ad;     /* tmp-vars */
2187    wchar_t bc=UNKNOWN;
2188
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;
2201
2202       // UVW
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;
2208       // UV
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}
2227       
2228 #if 0
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
2235 #endif
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
2247       if( y0 < box1->m2 )
2248       if( i1-i2 > dx/32+2 
2249        && i3-i2 > dx/32+2 ) Break; // ~serif_Y 
2250       
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
2258       }
2259
2260       ad=99*ad/100; // be carefull (remove later)
2261       
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;
2264
2265       if (gchar) ad=99*ad/100;
2266       bc='v';
2267       if( hchar ) bc='V';
2268       Setac(box1, bc, ad);
2269       break;
2270    }
2271    return box1->c;
2272 }
2273
2274 static wchar_t ocr0_rR(ocr0_shared_t *sdata){
2275    struct box *box1=sdata->box1;
2276    pix *bp=sdata->bp;
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 */
2280         ad;     /* tmp-vars */
2281
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;
2290
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
2294       if( dx>4 )
2295       if( loop(bp,dx-1,dy/2,dx,cs,0,LE)<=dx/8+2 ) Break; // ~v Jun00
2296
2297       i=dy-(dy+20)/32;  // ignore dust on the ground
2298
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;
2303         if( (i1+(dx-i2
2304         -1))/2 >= 4*dx/8 ) break; // mass middle should be left
2305       }
2306       if (y<i) Break;
2307
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;
2311
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;
2314
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
2318
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)
2322         ad=98*ad/100;
2323       }
2324
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
2330
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
2335       if(y<dy-1) Break;
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
2340
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;
2344       Setac(box1,'r',ad);
2345       break; // not 100% sure!
2346    }
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
2355         && dy>=16 ) Break;
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;
2358       } if( !i ) Break;
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;
2361       } if( !i ) Break;
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;
2371       } if( i ) Break;
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;
2374       } if( i ) Break;
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;
2380       } if( i ) Break;
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
2387
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;
2391       if (dy>15)
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
2394       if (dy>7)
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)) {
2397         ad=98*ad/100; 
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 ??
2400       }
2401       j=sdata->holes.num;
2402       if (j != 1) {
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;
2407       }
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
2411
2412       if (!hchar) ad=98*ad/100;
2413       if ( gchar) ad=98*ad/100;
2414       Setac(box1,'R',ad);
2415       break;
2416    }
2417    return box1->c;
2418 }
2419
2420 static wchar_t ocr0_m(ocr0_shared_t *sdata){
2421    struct box *box1=sdata->box1;
2422    pix *bp=sdata->bp;
2423    int  i,d,x,y,i1,i2,i3,i4,i5,hchar=sdata->hchar,gchar=sdata->gchar,
2424         handwritten=0,
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 */
2427         ad;     /* tmp-vars */
2428
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
2435       y=dy/2;
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;
2443       } if (i>3) 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       /*  @@...............
2450           @@......,........
2451           @@,...@@@....@@@.
2452           @@,,.@@@@..@@@@@,
2453           @@@.@@@@@.@@@@@@,
2454           @@;@@@@@@@@@;,@@,
2455           @@@@@,.@@@@,,,@@@ <- i5
2456           ,@@@...;@@....@@@
2457           .@;...........,@@
2458           ...............@@
2459              i1  i2 i3 i4
2460       */
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;
2478       }
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;
2482       }
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;
2492        }
2493        if(x <i2) Break; // unusual property for m (see n)
2494       }
2495       if(gchar) ad=99*ad/100;
2496       if(hchar) ad=99*ad/100;
2497
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
2500
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
2504
2505       // {\it m}
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);
2509       
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;
2517           if (3*i>dy) Break;
2518         }
2519         if(x<i4) Break; // gap detected
2520       }
2521
2522       if (box1->dots) ad=99*ad/100;
2523       Setac(box1,'m',ad);
2524       if (ad>=100) return 'm';
2525       break;
2526
2527    }
2528    return box1->c;
2529 }
2530
2531 static wchar_t ocr0_tT(ocr0_shared_t *sdata){
2532    struct box *box1=sdata->box1;
2533    pix *bp=sdata->bp;
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 */
2537         ad;     /* tmp-vars */
2538
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;
2558       // center width
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
2564       // down width
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
2568       } if( y<dy ) Break;
2569
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;
2572
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
2585        
2586       Setac(box1,'T',ad);
2587       if (ad>=100) return 'T';
2588       break;
2589    }
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;
2602         if( y<11*dy/16
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
2605           ) break;
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
2611
2612       if (x<dx/2) ad=95*ad/100; // unusual small ?
2613       if (x>=dx && 9*dx>=8*dy) { ad=99*ad/100; } // +
2614
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;
2620       }
2621       if( y<dy/4 ) Break;  // ~f
2622
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;
2626       if( y==yb ) break;
2627
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;
2635
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 ???
2640
2641       j=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; }
2646       } if(!j) Break;
2647
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)
2650
2651       if( dy>= 16
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);
2664         if (x)
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;
2670       }
2671       if (dx>7)
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
2678       
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
2684       }
2685
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; /* ~\ */
2689
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 
2694
2695       // this happens quite often, do not be to strong
2696       if (!box1->m2) ad=99*ad/100;
2697       if (box1->m2) {
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 */
2701       }
2702       
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;
2706       Setac(box1,'t',ad);
2707       break;
2708    }
2709    return box1->c;
2710 }
2711
2712 static wchar_t ocr0_sS(ocr0_shared_t *sdata){
2713    struct box *box1=sdata->box1;
2714    pix *bp=sdata->bp;
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 */
2718         ad;     /* tmp-vars */
2719    wchar_t ac;
2720
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
2727        && dy>4 ) Break;
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
2731       y=dy/4;
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
2735       y=11*dy/16;
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;
2742       if( y<dy/2 ) 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
2746 //      }
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;
2749       }
2750       if(y==dy/2) Break;  // Mai00
2751
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;
2754
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;
2758
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
2762
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
2766
2767       // sS5 \sl z  left upper v-bow ?
2768
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
2772
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;
2778         // very small s?
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;
2783       }
2784       
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
2792       ac='s';
2793       if (gchar) { ad=98*ad/100; MSG({}) }
2794       if( hchar ){ // S but 5 is very similar! check it
2795         ac='S';
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
2800       }
2801       Setac(box1,ac,ad);
2802       break;
2803    }
2804    return box1->c;
2805 }
2806
2807 static wchar_t ocr0_gG(ocr0_shared_t *sdata){
2808    struct box *box1=sdata->box1;
2809    pix *bp=sdata->bp;
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 */
2813         ad;     /* tmp-vars */
2814
2815    // --- test g ---------------------------------------------------
2816    /* some g's have crotchet at upper right end, so hchar can be set */
2817    // ~italic g
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;
2824
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
2837       
2838       if (num_cross(x1, x1, (y0+y1)/2, y1, box1->p,cs)>1) {
2839         ad=98*ad/100; // ~&
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;
2842       }
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
2847       
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;
2853       }
2854       if( num_cross(0,dx-1,dy/2,dy/2,bp,cs) >2 ) ad=99*ad/100; // ~/o
2855
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 */
2860       
2861       if (box1->m4==0) ad=98*ad/100;
2862       if ( hchar) ad=96*ad/100;
2863       if (!gchar) ad=96*ad/100;
2864       ad=98*ad/100;
2865       Setac(box1,'g',ad);
2866       break;
2867    }
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
2879
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
2882
2883       x=x0; y=y1;
2884       turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST);      // left bow?
2885       if( y<y0+dy/4 ) Break;    // filter W
2886
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)
2892         x=x1; y=y1-dy/4;
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;
2896       }
2897       turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,UP);      // upper end right midle
2898       if( x<=x1     ) Break;
2899       if( y<y0+3*dy/8 ) Break;
2900       if( y>y1-dy/4 ) Break;
2901
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);)
2909       if( y>y0 ) Break;
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;
2918         if( i ) Break;
2919       }
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;
2922       if( i ) Break;
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;
2926         if( x>i ) i=x;
2927       } if( y<dy ) Break;
2928
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);)
2939
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; }
2947       }
2948       if(i) ad=95*ad/100;               // ~C
2949       if(!hchar) ad=98*ad/100;
2950       if( gchar) ad=98*ad/100;
2951
2952       Setac(box1,'G',ad);
2953       break;
2954    }
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; }
2966       }
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!)
2990       }
2991       // %
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;
2995       
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
3000       Setac(box1,'g',ad);
3001       break;
3002    }
3003    return box1->c;
3004 }
3005
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) */
3014         ad;                  /* tmp-vars */
3015    wchar_t bc=UNKNOWN;
3016
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 */
3024       d=2*sq(128/4);
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 */
3035       
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 */
3040       } if (j==i) Break;
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;
3060
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 */
3065       } if (j==i) Break;
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;
3080
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 */
3085       } if (j==i) Break;
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;
3105
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 */
3110       } if (j==i) Break;
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;
3125       
3126       // center crossing of diagonal lines is small?
3127       if (box1->frame_vector[i3][0] - box1->frame_vector[i1][0] > dx/2) Break;
3128
3129       if (gchar) ad=99*ad/100;
3130       bc='x'; if(hchar) bc='X';
3131       Setac(box1,bc,ad);
3132       break;
3133    }
3134    // --- test \it x ---------------------------------------------------
3135 #if 0
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;
3148       bc='x';
3149       Setac(box1,bc,ad);
3150       break;
3151    }
3152 #endif
3153    return box1->c;
3154 }
3155
3156 static wchar_t ocr0_yY(ocr0_shared_t *sdata){
3157    struct box *box1=sdata->box1;
3158    pix *bp=sdata->bp;
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 */
3163    wchar_t bc=UNKNOWN;
3164
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"
3189       "  /a   b \n"
3190       "   |  |  \n"
3191       "    -c/  \n"
3192       "  \e-d   \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;
3200       // printf("ok");
3201       bc='y';
3202       if(gchar && !hchar) bc='y'; else 
3203       if(hchar && (!gchar || dy<14)) bc='Y'; else ad=98*ad/100; // SMALL-CAPS ???
3204       Setac(box1,bc,ad);
3205       break;
3206    }
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;
3213       } else {
3214         if( get_bw(x0,x0+3*dx/8,y0+dy/8,y0+dy/8,box1->p,cs,1) != 1 ) Break;
3215       }
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; }
3232       }
3233       if(yb>dy/8) Break;
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; }
3239       } yc+=dy/16+1;
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 */
3248         if (j<x) x=j;
3249       } if (i<dy/4) xd-=loop(bp,xd,yd,dx,cs,1,LE)/2;
3250       MSG( fprintf(stderr," debug_yY: \n"
3251       "  a   b \n"
3252       "   \\ /  \n"
3253       "    c   \n"
3254       "   ed     ");)
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;
3267       }
3268       if( get_line2(xc,yc,xd,yd,bp,cs,100)<95 ) Break;
3269
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;
3282
3283       bc='y';
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; }
3287       // SMALL-CAPS ???
3288       Setac(box1,bc,ad);
3289       break;
3290    }
3291    return box1->c;
3292 }
3293
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) */
3301         ad;     /* tmp-vars */
3302    wchar_t bc=UNKNOWN;
3303
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 */
3310       d=2*sq(128/4);
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;
3325       MSG( \
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;
3333
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
3360             ..$@@$@@@$@@@@@... 
3361             ..@@@.....$$@@@@.. 
3362             ..@@.......@$@@@b. 
3363             ..$.........$@@@@. 
3364             .$$..........$@@@. 
3365             .$...........@@@@. 
3366             .............@@@@.< 
3367             .............$@@$. 
3368             ............$@@@.. 
3369             ............@@$... 
3370             ............$@$... 
3371               --- snip ----
3372        */
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;
3378        
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;
3383
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;
3397
3398       if (box1->frame_vector[i1][0]
3399          -box1->frame_vector[i2][0]<=dx/8) Break; /* nonsignificant distance */
3400       MSG( \
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;
3409
3410       if ( gchar) ad=98*ad/100;
3411       bc='z';
3412       if( hchar ) bc='Z';
3413       Setac(box1,bc,ad);
3414       break;
3415    }
3416    return box1->c;
3417 }
3418
3419 static wchar_t ocr0_wW(ocr0_shared_t *sdata){
3420    struct box *box1=sdata->box1;
3421    pix *bp=sdata->bp;
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 */
3426    wchar_t ac;
3427
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 */
3432       //   xa      xe
3433       //    \  xc  /  <=ya  connected xa-xb-xc-xd-xe
3434       //     xb  xd   <=yb
3435       // get two lowest points  i3,i4,ya
3436       // out_x(box1);
3437       // ~ul ~uf
3438       // out_x(box1);
3439       for(y=dy/8;y<  dy/2;y++) if( num_cross(0,dx-1,y,y,bp,cs)< 2 ) break;
3440       if(y<dy/2) Break;
3441       yb=dy-1;
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;
3446       }
3447       yb=y;
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);)
3463       }
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; 
3473       ya=dy-1-y; // flat
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;
3480       }
3481       ya-=y/2;
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
3486          xa=x+xa/4; 
3487       } else {
3488          xa=x+xa/2;
3489       }
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;
3508       // ~ur
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;
3513       } if( y<dy ) Break;
3514       MSG(fprintf(stderr,"ad=%d",ad);)
3515       ac=((hchar)?'W':'w');
3516       if (gchar) ad=98*ad/100;
3517       Setac(box1,ac,ad);
3518       break;
3519    }
3520    // --- test ~w {\it w} ohmega? also handwritten -------
3521    // italic
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 */
3525       // ~ul ~uf
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
3532       //   xa      xe
3533       //    \  xc  /  <=yb  connected xa-xb-xc-xd-xe
3534       //     xb  xd   
3535       for(y=dy/2;y<dy-1-dy/8;y++)
3536         if( num_cross(0,dx-1,y,y,bp,cs)==3 ) break;
3537       yb=y;
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;
3551       // ~ur
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;
3557       Setac(box1,ac,ad);
3558       Break;
3559    }
3560    return box1->c;
3561 }
3562
3563 static wchar_t ocr0_aA(ocr0_shared_t *sdata){
3564    struct box *box1=sdata->box1;
3565    pix *bp=sdata->bp;
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 */
3570
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. */
3579       if (box1->modifier)
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 */
3593
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;
3597       // hole (i2,i1)
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;
3602       
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;
3606       // out_x(box1);
3607       i3=0;i4=0;
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;
3611        if(i4==1) i3=x;
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);)
3614         Break;
3615       }
3616       if( get_bw(dx-1-dx/4, dx-1, dy-1-dy/4, dy-1, bp,cs,1) != 1 ) Break;
3617
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;
3623
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;
3629
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
3638       
3639       if (!hchar) ad=99*ad/100; // italic-a
3640       Setac(box1,'A',ad);
3641       break;
3642    }
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;
3662
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;
3667
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--;
3670       } if( i ) Break;
3671
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; 
3680       if( x==dx ) Break;
3681
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
3697       }
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 */
3702       
3703       if (hchar) ad=96*ad/100;
3704       if (gchar) ad=96*ad/100;
3705       Setac(box1,'a',ad);
3706       break;
3707    }
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;
3722
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;}
3735          else ad=98*ad/100;
3736       }
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
3739
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 )
3745       Break;
3746       if( num_hole(x0,x1  ,y0+dy/3,y1-1   ,box1->p,cs,NULL) != 0 ) Break;
3747
3748       if( loop(bp,0   ,0   ,x1-x0,cs,0,RI)<=
3749           loop(bp,0   ,2   ,x1-x0,cs,0,RI)  ) Break;
3750
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;
3753
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;
3756
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;
3761
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
3767
3768       if (hchar) ad=98*ad/100;
3769       if (gchar) ad=98*ad/100;
3770       // handwritten-a (alpha)
3771       Setac(box1,'a',ad);
3772       break;
3773    }
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 */
3792
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;
3796       // hole (i2,i1)
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;
3800       
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;
3803       // out_x(box1);
3804       i3=0;i4=0;
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;
3808        if(i4==1) i3=x;
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);)
3811         break;
3812       }
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;
3818
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;
3823
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;
3828
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;
3835       
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);
3839       break;
3840    }
3841    return box1->c;
3842 }
3843
3844 static wchar_t ocr0_cC(ocr0_shared_t *sdata){
3845    struct box *box1=sdata->box1;
3846    pix *bp=sdata->bp;
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 */
3851    wchar_t bc=UNKNOWN;
3852
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-[
3861
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
3865
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);
3869       if (t1>dx/2) Break;
3870
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
3875
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
3879
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
3888       
3889       i=1;
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; }
3896       }
3897       if(!i) ad=95*ad/100;              // ~G
3898
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
3902       // out_x(box1);
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;
3909       
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
3920       }
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;
3925         if( i>=x )
3926         if( num_cross(0,dx-1,dy/4,dy/4,bp,cs) < 2 ) Break;
3927        
3928       }
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; /* ~[ */
3933
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; // ~(
3943         
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 ){
3948         Setac(box1,'G',90);
3949         Break;
3950       }
3951
3952       if (hchar){
3953         i=1;
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; }
3960         }
3961         if (i) ad=98*ad/100;            // ~(
3962         if (dy>2*dx) ad=99*ad/100;
3963       }
3964       if( loop(bp,dx-1,dy/2,dx,cs,0,LE) < 6*dx/8 ) ad=98*ad/100;
3965       
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
3969
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; // <
3980
3981       if (gchar) ad=98*ad/100; // could happen for 5x7 font
3982       bc=((hchar)?'C':'c');
3983       Setac(box1,bc,ad);
3984       break;
3985    }
3986    return box1->c;
3987 }
3988
3989 static wchar_t ocr0_lL(ocr0_shared_t *sdata){
3990    struct box *box1=sdata->box1;
3991    pix *bp=sdata->bp;
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 */
3995         ad;     /* tmp-vars */
3996
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
4004
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;
4022       } if( !i ) Break;
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
4029
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
4033       Setac(box1,'L',ad);
4034       break;
4035    }
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;
4047       // mesure thickness
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
4053       }
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
4062       }
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
4066
4067       // detect serifs 
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 
4077
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;
4088       }
4089
4090       // if( get_bw(x0,x1,y0,y1,p,cs,2) == 0 ) Break; // unsure !I|
4091
4092       if(dx>3)
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;
4095
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;
4104
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;
4109
4110       if(dx>3){
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;
4113         if( y<dy-1 ) Break;
4114       }
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;
4119         if( i<x ) x=i;
4120       }
4121       if (y>=dy/5 ) Break; 
4122
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;
4127         if( i>x ) x=i;
4128       }
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);
4135       if( i>3 && j>3  )
4136       if( get_bw(dx-1-i/2,dx-1-i/2,0,dy/2,bp,cs,1) == 1 ) Break; // ~t
4137
4138       for(y=5*dy/8;y<dy;y++)
4139       if( num_cross(0,dx-1,y,y,bp,cs) == 2 ) break;
4140       if( y<dy ){
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
4146       }
4147       if ( dx>8
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
4152
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
4156       
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
4162       }
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;
4166       }
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 ){
4171          ad=98*ad/100; // ~]
4172         if ( loop(bp,dx-1,dy/2,dx,cs,0,LE)==0 ) Break;
4173       }
4174
4175       for(x=0;x<dx/2;x++)
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);
4183           if( x>i ) break;
4184         }
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
4190       }
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
4196       }
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; /* ~[ */
4208
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; // ~)
4219       
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
4243       }
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; // ~/
4251          
4252       if( get_bw(x0,x1,y0,y1,box1->p,cs,2) == 0 ) ad=99*ad/100;
4253
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
4263       }
4264
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:
4268             .@@@@.<-
4269             @@..@@
4270             ....@@
4271             ....@@<
4272             ...@@.
4273             ..@@@.
4274             ..@@..
4275             .@@...
4276             @@....
4277             @@@@@@<-
4278       */
4279       if(!hchar) ad=ad*99/100;
4280       if( gchar) ad=ad*99/100;
4281       Setac(box1,'l',ad);
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;
4286       break;
4287    }
4288    return box1->c;
4289 }
4290
4291 static wchar_t ocr0_oO(ocr0_shared_t *sdata){
4292    struct box *box1=sdata->box1;
4293    pix *bp=sdata->bp;
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 */
4297         ad;     /* tmp-vars */
4298    wchar_t bc=UNKNOWN;
4299
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; 
4311
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;
4322       
4323       if( loop(bp,0   ,0   ,x1-x0,cs,0,RI)<=
4324           loop(bp,0   ,2   ,x1-x0,cs,0,RI)  ) Break;
4325
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;
4330       }
4331       if( y<dy ) Break;
4332
4333       // ~D
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
4339
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
4349
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; }
4355       } i=y;
4356       // italic a
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
4369
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
4375
4376       if( hchar && 2*y0<box1->m1+box1->m2 ) i=1; else i=0;
4377       if (gchar) ad=99*ad/100;
4378       bc='o';  
4379       if( i ){ bc='O'; }
4380       if ( bc=='O' && ad>99) ad=99; /* we can never 100% sure, 0O */
4381       Setac(box1,bc,ad);
4382       if (bc=='O') Setac(box1,'0',ad);
4383       if (bc=='o') Setac(box1,'0',98*ad/100);
4384       break;
4385    }
4386    return box1->c;
4387 }
4388
4389 static wchar_t ocr0_pP(ocr0_shared_t *sdata){
4390    struct box *box1=sdata->box1;
4391    pix *bp=sdata->bp;
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 */
4395         ad;     /* tmp-vars */
4396    wchar_t bc=UNKNOWN;
4397
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;
4415
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;
4419
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;
4434
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);
4437       j=sdata->holes.num;
4438
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;
4443
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
4449
4450       if( ((!hchar) && (!gchar)) || (hchar && gchar)) ad=95*ad/100;
4451       bc='p';
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;
4455       
4456       Setac(box1,bc,ad);
4457       break;
4458    }
4459    return box1->c;
4460 }
4461
4462 static wchar_t ocr0_qQ(ocr0_shared_t *sdata){
4463    struct box *box1=sdata->box1;
4464    pix *bp=sdata->bp;
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 */
4468         ad;     /* tmp-vars */
4469
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);
4489       i=sdata->holes.num;
4490       if(!i) Break;
4491       if( i!=1 && (i!=2 || num_hole(x0,x1,y0+dy/2,y1,box1->p,cs,NULL)!=1) ) Break;
4492       x=x1;y=y1;
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
4500
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
4504
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
4511
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
4517
4518
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;
4524                else Break;
4525         }
4526       }
4527
4528        // italic a
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;
4532
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; }
4536         if (x-i>j) j=x-i;
4537         if( j>dx/16 ) Break;    // falling line detected
4538       }
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;
4543       Setac(box1,'Q',ad);
4544       break;
4545    }
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 ){
4565         ad=97*ad/100;
4566         if (hchar || !gchar) Break; // 4 
4567       }
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 ){
4570         ad=96*ad/100; // 4
4571       }
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; }
4582       // ~\it g
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
4588       Setac(box1,'q',ad);
4589       break;
4590    }
4591    return box1->c;
4592 }
4593
4594 static wchar_t ocr0_iIjJ(ocr0_shared_t *sdata){
4595    struct box *box1=sdata->box1;
4596    pix *bp=sdata->bp;
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) */
4603
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!
4610       /*
4611        *    o   <== ya
4612        *    o
4613        *
4614        *   ooo  <== yb
4615        *    o
4616        *    o
4617        *    o
4618        *   ooo
4619        */
4620       ya=y0;
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 )
4632         {
4633           Setac(box1,'i',ad);
4634           return 'i'; /* beleave me, thats an "i"! */
4635         } break;
4636       }
4637 //    if( box1->dots!=1 ) Break;
4638       if( box1->m2 && 2*y0>=box1->m2+box1->m1 ) ya=box1->m1;
4639
4640 //      out_x(box1);
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?
4643       ya=y;
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;
4648       yb=y;
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)
4653         ad=95*ad/100;
4654
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);
4657       // \sl ~f. !
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;
4661
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;
4671       if(yd>yc+2){
4672         xa=loop(bp,   0,yc-1,dx,cs,0,RI);
4673         xb=loop(bp,dx-1,yc-1,dx,cs,0,LE);
4674         if(
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);
4678           if(y>0){
4679             i=loop(bp,dx-xb-1,yc-1+y-1,dy,cs,0,DO);
4680             if( i>0 ) y+=i-1;
4681           }
4682           if( yc-1+y < yd-1 ) Break;
4683         } else { 
4684           y= loop(bp,11*xa/16,yc-1,dy,cs,0,DO);
4685           if( yc-1+y < yd-2 ) Break;
4686         }
4687       }
4688       if(yf<ye-2){
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);
4692         if( i>0 ) y+=i-1;
4693         if( ye+1-y > yf+1 ) Break;
4694       }
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;
4698
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;
4702
4703       // could be a broken + or similar thing?
4704       if( 3 * ya > box1->m1 + 2*box1->m2 ) ad=90*ad/100;
4705
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
4708
4709       // test for &eacute;
4710       if( dx>5 && num_cross(x0+dx/2,x0+dx/2, ya, y1 ,box1->p,cs) >= 3 )
4711         ad=95*ad/100;
4712
4713       Setac(box1,'i',ad);
4714       break;
4715    }
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 */
4721       ya=y0;
4722       if( box1->m2 && 2*y0>=box1->m2+box1->m1 ) ya=box1->m1;
4723
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
4726       ya=y;
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
4732       yb=y;
4733       if( loop(bp,dx-1,y+(y1-ya+1)/32,dx,cs,0,LE)>dx/2 ) Break; // unusual (right part of ouml)
4734
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);
4737       // \sl ~f. !
4738       for(y=(ya+y1)/2;y<=y1;y++) if( get_bw(x0,x1,y,y,box1->p,cs,1) != 1 ) break;
4739       if(y<=y1) Break;
4740
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;
4750       if(yd>yc+2){
4751         xa=loop(bp,   0,yc-1,dx,cs,0,RI);
4752         xb=loop(bp,dx-1,yc-1,dx,cs,0,LE);
4753         if(
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);
4757           if(y>0){
4758             i=loop(bp,dx-xb-1,yc-1+y-1,dy,cs,0,DO);
4759             if( i>0 ) y+=i-1;
4760           }
4761           if( yc-1+y < yd-1 ) Break;
4762         } else { 
4763           y= loop(bp,11*xa/16,yc-1,dy,cs,0,DO);
4764           if( yc-1+y < yd-2 ) Break;
4765         }
4766       }
4767       if(yf<ye-2){
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);
4771         if( i>0 ) y+=i-1;
4772         if( ye+1-y > yf+1 ) Break;
4773       }
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
4779
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;
4787
4788       Setac(box1,'j',ad);
4789
4790       break;
4791    }
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 */
4797
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;
4811       // out_x(box1);
4812
4813       // upper max width
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; }
4817       }
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; }
4821       }
4822       if( abs(i3-i1)>1+dx/8 ) Break;  // if i3>>i5 more sure!
4823       if( i1>i5 ){ // look for edges else *80%
4824       } 
4825       if(i1+1<i5 && !hchar) Break; // Jun00
4826
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;
4830
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;
4835
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;
4840
4841       // upper and lower width (what about serifs?)
4842       y=dy/8;
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;
4851
4852       if(dy>15)  // v024a4
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)
4855
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++;
4858       if( i>1 ) Break;
4859
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
4866       }
4867
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; /* ~] */
4872        
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; /* ~[ */
4876
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; // ~/
4893                                
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 )
4896       Break; // ~i
4897
4898       if(i1+1<i5 && !hchar){ ad=65*ad/100; MSG({}) } // ~ slanted I
4899
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);
4903       if (i3<2 || i4<2 
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)) {
4911           ad=96*ad/100;
4912         }
4913       }  // ~!
4914       //  a---b  
4915       //    I
4916       //    I
4917       //  c---e
4918       // check against Z
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; }
4922       }
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; }
4926       }
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
4935
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; // '
4939
4940       Setac(box1,'I',ad);
4941       break;
4942    }
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 */
4950       d=2*sq(128/4);
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 */
4954
4955 /*
4956     type A       B
4957       
4958        6OOOO     6O5
4959          7O5     7O
4960           O       O
4961           O       O
4962       2O 1O4     1O4
4963         OO     2OO
4964          3      3
4965 */
4966
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);)
4984       
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) { // ]?
5005         ad=99*ad/100;
5006         if (aa[1][2]==0) ad=98*ad/100;
5007         if (aa[2][2]<=aa[3][2]) ad=97*ad/100;
5008       }
5009       
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;
5037
5038       // J exists as gchar and ~gchar
5039       if(!hchar){ ad=99*ad/100; }
5040       Setac(box1,'J',ad);
5041       break;
5042    }
5043    return box1->c;
5044 }
5045
5046 static wchar_t ocr0_brackets(ocr0_shared_t *sdata){
5047    struct box *box1=sdata->box1;
5048    pix *bp=sdata->bp;
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 */
5054    wchar_t bc=UNKNOWN;
5055
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
5060       //    \           .
5061       //     \          .
5062       //    i1,i2
5063       //     /
5064       //    /
5065       //   1
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 */
5070       d=2*sq(128/4);
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 */
5076       
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;
5088       i1=j;
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);)
5099
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;
5112       i2=j;
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);)
5123       
5124       /*
5125            ToDo: calculate momentums or max derivations 
5126                  along lines to distinguish )]}>
5127                  i1,i2
5128        */
5129
5130       if (sdata->gchar) ad=98*ad/100;
5131       if (sdata->hchar) ad=99*ad/100;
5132       bc='>';
5133       Setac(box1,bc,ad);
5134       break;
5135    }
5136    // --- test /\\ ------------------------------------------------
5137 //   if(bc==UNKNOWN)
5138 //   if(!box1->dots)
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 */
5142 #if 1
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;
5147       }
5148       if( y<dy ) Break;
5149       if ( i>2 || (i>0 && dy<16)) Break;
5150 #endif
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;
5158
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;
5164       //  
5165       //  out_x(box1);printf("() %d %d %d %d %d %d %d\n",i,i1,i2,i3,i4,i5,i6);
5166
5167       // ~lI      
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;
5170       } if( y<dy ) Break;
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;
5173       } if( y<dy ) Break;
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; }
5176       Break;
5177    }
5178    // --- test ()<> ------------------------------------------------
5179 //   if(bc==UNKNOWN)
5180 //   if(!box1->dots)
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 */
5184 #if 1
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;
5189       }
5190       if( y<dy ) {Break;};
5191       if ( i>2 || (i>0 && dy<16)) {Break;};
5192 #endif
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; } 
5197       } y=(r1+r2)/2;
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);
5204       if(dx>dy){
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;}; }
5208       }
5209       if( dx > 2 && 9*dx>=5*dy ){  // 4x6 screen-font (3*5)
5210        ad=98;
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;}; 
5220        }
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;}; 
5227        }
5228 */
5229       }
5230       
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;
5238       //  
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;
5247         }
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;
5250         }
5251         if( y==(dy+2)/4 ) {Break;}; // ~l (left upper side must be convex) Jul00
5252         Setac(box1,(bc='('),ad); break;
5253       }
5254       Break;
5255    }
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;
5261       for(y=0;y<dy;y++){
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; }
5276       break;
5277    }
5278
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 */
5286       d=2*sq(128/16);
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;
5306
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;
5317
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;   
5322
5323       if (!hchar) ad=99*ad/100;
5324       if ( gchar) ad=98*ad/100; // \sc N
5325       ac=(wchar_t) ']';
5326       Setac(box1,ac,ad);
5327       if (ad>=100) return ac;
5328       break;
5329    }
5330 #endif
5331    //  --------- test ocr-a-[] --------------------------------
5332    if(bc==UNKNOWN)
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; }
5348       break;
5349    }
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; 
5355       for(y=0;y<dy;y++){
5356         if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
5357       } if (y<dy) 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;
5374    }
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; 
5378       for(y=0;y<dy;y++){
5379         if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
5380       } if (y<dy) 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;
5397    }
5398    return box1->c;
5399 }
5400
5401 #if 0
5402 /* ---------- empty prototype function for copy and expand ---------- */
5403 static wchar_t ocr0_XXX(ocr0_shared_t *sdata){
5404    struct box *box1=sdata->box1;
5405    pix *bp=sdata->bp;
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 */
5410
5411    // --- test XXX ---------------------------------------------------
5412    return box1->c;
5413 }
5414 #endif
5415
5416
5417 /* ----------------------- part9 -------------------------------- */
5418 static wchar_t ocr0p9(ocr0_shared_t *sdata){
5419    struct box *box1=sdata->box1;
5420    pix *bp=sdata->bp;
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 */
5426        ya,ad,cs=sdata->cs;
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;
5436    
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!
5444              a-\
5445              |  d
5446             b| /
5447              | \
5448             -c /
5449        */
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--;
5456         if( y<y1-5*dy/16 ) 
5457         if( get_bw(x1-dx/2,x1,y,y,box1->p,cs,1) == 0 ) i--;
5458       } if( i<=0 ) break;
5459       // out_x(box1);
5460
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;
5467
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;
5471
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;
5474       if( y>=y1 ) break;
5475
5476       for(y=y1-dy/3;y<y1-dy/8;y++){
5477         i=loop(box1->p,x1,y,dx,cs,0,LE);
5478         if( i>dx/4
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
5481
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
5485
5486
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;
5490
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;
5495
5496       x=x0+loop(bp,0,dy/4,dx,cs,0,RI);
5497       for(;x<x1-dx/3;x++)
5498         if( get_bw(x,x,y0,y0+dy/4,box1->p,cs,1) == 0 ) break;
5499       if( x<x1-dx/3 ) break;
5500
5501       if( !gchar )
5502       // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) != 0 ) break;
5503       if (sdata->holes.num != 0) break;
5504
5505       bc=LATIN_SMALL_LETTER_SHARP_S;
5506       Setac(box1,(wchar_t)bc,98);
5507       break;
5508    }
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;
5514       xb=(dx+1)/4;
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; }
5521       }
5522       if (3*dx<2*dy) ad=99*ad/100; // ~t
5523       if( !i ) Break;
5524       ac=(wchar_t) '+';
5525       Setac(box1,ac,ad);
5526       if (ad>=100) return ac;
5527       break;
5528    }
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;
5533       
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;
5554       if (ad<95) Break;
5555       ac=(wchar_t) '$';
5556       Setac(box1,ac,ad);
5557       if (ad>=100) return ac;
5558       break;
5559    }
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;
5570       if (i3>i1) Break;
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;
5573       }
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;
5583       }
5584       if (!hchar) ad=98*ad/100;
5585       bc=(wchar_t) '&';
5586       Setac(box1,bc,ad);
5587       if (ad>=100) return bc;
5588       break;
5589    }
5590    // --- test \it & like \epsilon\tau ------------------------------
5591    if(bc==UNKNOWN)
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;
5608       ac=(wchar_t) '&';
5609       Setac(box1,ac,ad);
5610       if (ad>=100) return ac;
5611       break;
5612    }
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;
5622       i1=y1;
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;
5625         i1=box1->m4;
5626         for(;i1>y1;i1--)        // new y1
5627           if( get_bw(x0, x1,i1,i1,box1->p,cs,1) == 1 ) break; // lower dot
5628       }
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;
5632       if (y==dy/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;
5637       if( y==i1 ) Break;
5638       for(      ;y<=i1;y++)
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
5642       bc='?';
5643       Setac(box1,(wchar_t)bc,98);
5644       return bc;
5645    }
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? */
5657      i1=y1;
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 ))  {
5661          i1=box1->m4;
5662          for(;i1>y1;i1--)       // new y1
5663            if( get_bw(x0, x1,i1,i1,box1->p,cs,1) == 1 ) break; // lower dot
5664        }
5665      } i2=i1;
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;
5670      
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
5673      
5674      if (!hchar) ad=96*ad/100;
5675      Setac(box1,(wchar_t)'!',ad);
5676      break; 
5677    }
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;
5691       /* horizontal */
5692       dbg[1]=i=get_line2(0,y,dx-1,y,bp,cs,100); if(i<95) Break;
5693       if (dy<8)
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;
5696       /* down (right) */
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;
5699       if(i<95) Break;
5700       /* down (left) */
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);
5708       break;
5709    }
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;
5722       if (dx>5) {
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;
5727       }
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);
5730       break;
5731    }
5732    // --- test @ - a popular char should be detectable! added in version v0.2.4a5
5733    if(bc==UNKNOWN)
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
5742          .@@..@@.
5743          @@....@@
5744          @@..@@@@<
5745          @@.@@.@@
5746          @@.@@.@@
5747          @@..@@@.
5748          @@......
5749          .@@...@@
5750          ..@@@@@.<- */
5751       x=6*dx/16;
5752       y=dy/2;
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;
5756       
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;
5768       if (dx>7) {
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;
5772       }
5773       Setac(box1,(wchar_t)'@',ad);
5774       break;
5775    }
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 
5792    }
5793
5794    return bc;
5795 }
5796
5797 /* ----------------------- partx -------------------------------- */
5798 static wchar_t ocr0px(ocr0_shared_t *sdata){
5799    struct box *box1=sdata->box1;
5800    pix *bp=sdata->bp;
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;
5814    
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
5818    if( bc==UNKNOWN )
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; } 
5832       if( !i ) break;
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;
5839         }
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;
5859       } if( !i ) break;
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;
5862       } if( i ) break;
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;
5865       } if( i ) break;
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;
5868       } if( i ) break;
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;
5871       } if( i ) break;
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;
5883       Setac(box1,ac,ad);
5884       break;
5885    }
5886    // --- test ae  ---------------------------------------------------
5887    if( bc==UNKNOWN )
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;
5913       Setac(box1,ac,ad);
5914       if (ad>=100) return ac;
5915       break;
5916
5917    }
5918    // --- test AE  ---------------------------------------------------
5919    if( bc==UNKNOWN )
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);
5934       if (i>j) j=i;
5935       if (x>dx/8) Break;
5936       if (j<dx/4) Break;
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;
5959       Setac(box1,ac,ad);
5960       if (ad>=100) return ac;
5961       break;
5962
5963    }
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;
5992
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;
5996       Setac(box1,ac,ad);
5997       if (ad>=100) return ac;
5998       break;
5999
6000    }
6001    // --- test /c /C C_WITH_STROKE CENT_SIGN --------------------------
6002    // here only the version with a continuously vertical line (not broken variant)
6003    if( bc==UNKNOWN )
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;
6021       for(y=0;y<dy;y++){
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;
6026       } if( y<dy ) 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;
6032
6033       ac=CENT_SIGN;
6034       Setac(box1,ac,ad);
6035       if (ad>=100) return ac;
6036       break;
6037
6038    }
6039    // --- test EURO_CURRENCY_SIGN -----------------------------------------
6040    if( bc==UNKNOWN )
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;
6058       Setac(box1,ac,ad);
6059       if (ad>=100) return ac;
6060       break;
6061    }
6062    // --- test LETTER_C_WITH_CEDILLA  ---------------------------------------------------
6063    if (bc==UNKNOWN)
6064    if (gchar)
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;
6089       Setac(box1,ac,ad);
6090       if (ad>=100) return ac;
6091       break;
6092
6093    }
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; }
6113       }
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;
6120
6121       ac=(wchar_t) '#';
6122       if( gchar ) {ad=99*ad/100;}
6123       Setac(box1,ac,ad);
6124       if (ad>=100) return ac;
6125       break;
6126    }
6127    // --- test bullet, full_box, grabbed cursor, ZapfDingBats_156
6128    if (bc==UNKNOWN)
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;
6132       ac=BULLET;
6133       if (gchar && !hchar) ad=80*ad/100;
6134       Setac(box1,ac,ad);
6135       if (ad>=100) return ac;
6136       break;
6137    }
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;
6152       ac='|';
6153       if (!hchar) ad=98*ad/100;
6154       Setac(box1,ac,ad);
6155       break;
6156    }
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;
6170
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;
6185       ac=(wchar_t) '%';
6186       Setac(box1,ac,ad);
6187       if (ad>=100) return ac;
6188       break;
6189    }
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;
6197
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;
6209       
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;
6216
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;
6221
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;
6226       }
6227       if( x>=3*dx/4 ) Break;
6228
6229       if( !hchar ) ad=60*ad/100;
6230       bc=GREEK_CAPITAL_LETTER_OMEGA;
6231       Setac(box1,bc,ad);
6232       break;
6233    }
6234
6235    return bc;
6236 }
6237
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
6251    
6252    sdata.box1=box1;
6253    sdata.bp=bp;
6254    sdata.cs=cs;
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;
6261
6262    sdata.hchar=hchar;
6263    sdata.gchar=gchar;
6264
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; }
6288    }
6289    for (i=0;i<16;i++) sdata.aa[i/4][i%4]=aa[i/4][i%4];
6290
6291    /* extract number position and size of holes and store in a table
6292     *   - hole coordinates are relative to box (x-x0,y-y0)
6293     */
6294    sdata.holes.num=0;
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);
6298
6299    /*
6300       after division of two glued chars, boundaries could be wrong,
6301       check this first (ToDo: only if a flag set?)
6302    */
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 ){
6310         /* be sure, ~_ */
6311         if (y>y0) y1=box1->y1=y;
6312       }
6313    }
6314
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)"
6318                            " d= %d %d %d %d",
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);)
6323
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;
6333       else {
6334        if (y1>=box1->m3) {
6335          if (  dx<2*dy) ad=98*ad/100;
6336          if (2*dx<3*dy) ad=98*ad/100;
6337          Setac(box1,'_',ad);
6338          break;
6339        }
6340       }
6341       Setac(box1,'-',ad); if (ad>=100) return '-';
6342       break;
6343    }
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);
6353       return '=';
6354    }
6355    // --- test dots : ---------------------------------
6356    for( ad=100; dy>2 && dy>=2*dx; ){     // max 3x3 (small font)
6357       
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);)
6367       
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 ':';
6379       break;
6380    }
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;
6393       if (i2<i1) break;
6394
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 */
6399
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 ';';
6404       break;
6405    }
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);
6418      }
6419      if(d==0)
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) )
6424      {
6425       bc='.'; if (box1->dots) { Setac(box1,':',ad); ad=98*ad/100; }
6426       Setac(box1,bc,ad);
6427      }
6428    }
6429    // --- first test small dots , ---------------------------------
6430    if( 3*dy<2*(box1->m4-box1->m1)
6431     && 2*y0>   box1->m2+box1->m3
6432     && (2*dx<3*dy 
6433      || get_bw(0,dx/2,dy/2,dy-1,bp,cs,1)==0) ){  // ocr-a-,
6434       DBG( wchar_t c_ask=','; )
6435       ad=100; bc=',';
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;
6449       }
6450       if(box1->dots==1) { Setac(box1,';',ad); ad=99*ad/100; }
6451       Setac(box1,bc,ad);
6452    }
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='\''; )
6458       ad=100; bc='\'';
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({}) }
6463       if (dx>4 
6464        && num_cross(x0,x1,y1,y1,box1->p,cs) == 2) { // " "
6465         bc='"';
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;
6468       } else {
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({}) }
6472       }
6473       if (2*y0 > box1->m1+box1->m2) ad=99*ad/100;
6474       Setac(box1,bc,ad);
6475       if (ad>=100) return bc;
6476    }
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='~'; )
6488         bc=TILDE;
6489         Setac(box1,bc,99);
6490       }
6491     }
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 )) {
6508         bc='^';
6509         Setac(box1,bc,99);
6510       }
6511     }
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)
6516       y=box1->m1;
6517       for(;y<y0+dy/2;y++)if( get_bw(x0+dx/4,x1,y,y,box1->p,cs,1)==1) break;
6518       { i1=y;
6519         if( y<y0+dy/4 )
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 ???
6523
6524         }
6525       }
6526    }
6527 #else
6528   um = box1->modifier;
6529 #endif
6530    if ( /* um==ACUTE_ACCENT || */ um==DIAERESIS){
6531       for(y=y1;y>y0;y--)
6532       if( get_bw(x0,x1,y,y,box1->p,cs,1)==0) { y0=y; dy=y1-y0+1; break; } // scan "a "o "u
6533    }
6534
6535    // --- test numbers 0..9 --- separated for faster compilation
6536    if( JOB->cfg.only_numbers ) return ocr0n(&sdata);
6537
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
6541
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)
6545
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);
6581
6582
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]; }
6587    
6588    return bc;
6589 }
6590
6591