gocr-ruby 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +21 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +49 -0
  8. data/ext/gocr/Makefile +141 -0
  9. data/ext/gocr/Makefile.in +140 -0
  10. data/ext/gocr/amiga.h +31 -0
  11. data/ext/gocr/barcode.c +2108 -0
  12. data/ext/gocr/barcode.h +11 -0
  13. data/ext/gocr/box.c +496 -0
  14. data/ext/gocr/config.h +37 -0
  15. data/ext/gocr/config.h.in +36 -0
  16. data/ext/gocr/database.c +468 -0
  17. data/ext/gocr/detect.c +1003 -0
  18. data/ext/gocr/extconf.rb +6 -0
  19. data/ext/gocr/gocr.c +436 -0
  20. data/ext/gocr/gocr.h +290 -0
  21. data/ext/gocr/jconv.c +168 -0
  22. data/ext/gocr/job.c +92 -0
  23. data/ext/gocr/lines.c +364 -0
  24. data/ext/gocr/list.c +334 -0
  25. data/ext/gocr/list.h +91 -0
  26. data/ext/gocr/ocr0.c +7312 -0
  27. data/ext/gocr/ocr0.h +63 -0
  28. data/ext/gocr/ocr0n.c +1527 -0
  29. data/ext/gocr/ocr1.c +85 -0
  30. data/ext/gocr/ocr1.h +3 -0
  31. data/ext/gocr/otsu.c +310 -0
  32. data/ext/gocr/otsu.h +23 -0
  33. data/ext/gocr/output.c +291 -0
  34. data/ext/gocr/output.h +37 -0
  35. data/ext/gocr/pcx.c +153 -0
  36. data/ext/gocr/pcx.h +9 -0
  37. data/ext/gocr/pgm2asc.c +3259 -0
  38. data/ext/gocr/pgm2asc.h +105 -0
  39. data/ext/gocr/pixel.c +538 -0
  40. data/ext/gocr/pnm.c +538 -0
  41. data/ext/gocr/pnm.h +35 -0
  42. data/ext/gocr/progress.c +87 -0
  43. data/ext/gocr/progress.h +42 -0
  44. data/ext/gocr/remove.c +715 -0
  45. data/ext/gocr/tga.c +87 -0
  46. data/ext/gocr/tga.h +6 -0
  47. data/ext/gocr/unicode.c +1318 -0
  48. data/ext/gocr/unicode.h +62 -0
  49. data/ext/gocr/unicode_defs.h +1245 -0
  50. data/ext/gocr/version.h +2 -0
  51. data/gocr-ruby.gemspec +28 -0
  52. data/image.png +0 -0
  53. data/lib/gocr.rb +6 -0
  54. data/lib/gocr/image.rb +8 -0
  55. data/lib/gocr/version.rb +3 -0
  56. metadata +156 -0
@@ -0,0 +1,63 @@
1
+ #ifndef _OCR0_H
2
+ #define _OCR0_H
3
+ #include "pgm2asc.h"
4
+
5
+ /* ----------------------------------------------------------------
6
+ - functions with thousand of lines make the compilation very slow
7
+ therefore the ocr0-function is splitted in subfunctions
8
+ - shared data used often in ocr0-subroutines are stored
9
+ in ocr0_shared structure.
10
+ * ------------------------------------------------------------ */
11
+
12
+ typedef struct ocr0_shared { /* shared variables and properties */
13
+
14
+ struct box *box1; /* box in whole image */
15
+ pix *bp; /* extracted temporarly box, cleaned */
16
+ int cs; /* global threshold value (gray level) */
17
+
18
+ /* ToDo: or MACROS: X0 = box1->x0 */
19
+ int x0, x1, y0, y1; /* box coordinates related to box1 */
20
+ int dx, dy; /* size of box */
21
+ int hchar, gchar; /* relation to m1..m4 */
22
+ int aa[4][4]; /* corner points, see xX (x,y,dist^2,vector_idx) v0.41 */
23
+ holes_t holes; /* list of holes (max MAX_HOLES) */
24
+
25
+ } ocr0_shared_t;
26
+
27
+ /* tests for umlaut */
28
+ int testumlaut(struct box *box1, int cs, int m, wchar_t *modifier);
29
+ /* detect chars */
30
+ wchar_t ocr0(struct box *box1, pix *b, int cs);
31
+ /* detect numbers */
32
+ wchar_t ocr0n(ocr0_shared_t *sdata);
33
+
34
+ static inline int sq(int x) { return x*x; } /* square */
35
+
36
+ /*
37
+ * go from vector j1 to vector j2 and measure maximum deviation of
38
+ * the steps from the line connecting j1 and j2
39
+ * return the squared maximum distance
40
+ * in units of the box size times 1024
41
+ */
42
+ int line_deviation( struct box *box1, int j1, int j2 );
43
+
44
+ /*
45
+ * search vectors between j1 and j2 for nearest point a to point r
46
+ * example:
47
+ *
48
+ * r-> $$...$$ $ - mark vectors
49
+ * @@$..@@ @ - black pixels
50
+ * @@$..@@ . - white pixels
51
+ * @@@@.$@
52
+ * a-> @@$@$@@
53
+ * @$.@@@@
54
+ * @@..$@@
55
+ * @@..$@@
56
+ * j1 --> $$...$$ <-- j2
57
+ *
58
+ * ToDo: vector aa[5] = {rx,ry,x,y,d^2,idx} statt rx,ry?
59
+ * j1 and j2 must be in the same frame
60
+ * return aa?
61
+ */
62
+ int nearest_frame_vector( struct box *box1, int j1, int j2, int rx, int ry);
63
+ #endif
@@ -0,0 +1,1527 @@
1
+ /* ocr-engine numbers only */
2
+ /*
3
+ This is a Optical-Character-Recognition program
4
+ Copyright (C) 2000-2010 Joerg Schulenburg
5
+
6
+ This program is free software; you can redistribute it and/or
7
+ modify it under the terms of the GNU General Public License
8
+ as published by the Free Software Foundation; either version 2
9
+ of the License, or (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program; if not, write to the Free Software
18
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+
20
+ see README for EMAIL-address
21
+
22
+ OCR engine (c) Joerg Schulenburg
23
+ first engine: rule based --- numbers 0..9
24
+
25
+ */
26
+
27
+ #include <stdlib.h>
28
+ #include <stdio.h>
29
+ /* #include "pgm2asc.h" */
30
+ #include "ocr0.h"
31
+ #include "ocr1.h"
32
+ #include "amiga.h"
33
+ #include "pnm.h"
34
+ #include "gocr.h"
35
+ #include "unicode_defs.h"
36
+
37
+ /* only for debugging and development */
38
+ #define IFV if(OCR_JOB->cfg.verbose&4)
39
+ #define MM {IFV fprintf(stderr,"\nDBG %c L%04d (%d,%d): ",(char)c_ask,__LINE__,box1->x0,box1->y0);}
40
+
41
+ /* the old debug mode (0.40) was only for a special char, for another char
42
+ * code must be recompiled with C_ASK='char'
43
+ * new debug mode (0.41) explains why char is declined or accepted as ABC...
44
+ * the output can be filtered by external scripts
45
+ * ToDo: we could reduce output to filter string
46
+ */
47
+ #ifndef DO_DEBUG /* can be defined outside */
48
+ #define DO_DEBUG 0 /* 0 is the default */
49
+ #endif
50
+
51
+ /* this macro is for debugging output: "if char is declined, why?" */
52
+ #if DO_DEBUG /* 0=Work mode, 1=debugging mode */
53
+ // Setac: output, that char is choosen with a probability
54
+ // Break: output, why the char is not choosen
55
+ // MSG: debugging functions for char C_ASK, mostly messages
56
+ // DBG: definitions usefull only for debugging
57
+ #define Setac(box1,ac,ad) { MM;IFV fprintf(stderr,"setac %d",ad);setac(box1,ac,ad); }
58
+ #define Break { MM;IFV fprintf(stderr,"break"); break; }
59
+ #define MSG(x) { MM;IFV x }
60
+ #define DBG(x) x
61
+ #else
62
+ #define Setac(box1,ac,ad) setac(box1,ac,ad)
63
+ #define Break break
64
+ #define MSG(x)
65
+ #define DBG(x)
66
+ #endif
67
+
68
+ /* extern "C"{ */
69
+
70
+ // OCR engine ;)
71
+ wchar_t ocr0n(ocr0_shared_t *sdata){
72
+ struct box *box1=sdata->box1;
73
+ pix *bp=sdata->bp;
74
+ int d,x,y,x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
75
+ int dx=x1-x0+1,dy=y1-y0+1,cs=sdata->cs; // size
76
+ int xa,xb,ya,yb, /* tmp-vars */
77
+ i1,i2,i3,i4,i,j;
78
+ int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
79
+ wchar_t bc=UNKNOWN; // best char
80
+ int ad=0; // propability 0..100
81
+ int hchar=sdata->hchar; // char is higher than 'e'
82
+ int gchar=sdata->gchar; // char has ink lower than m3
83
+ int dots=box1->dots;
84
+ // --- test 5 near S ---------------------------------------------------
85
+ for(ad=d=100;dx>2 && dy>4;){ // min 3x4
86
+ DBG( char c_ask='5'; )
87
+ if (sdata->holes.num > 1) Break; /* be tolerant */
88
+ if( num_cross( dx/2, dx/2,0,dy-1,bp,cs)!=3
89
+ && num_cross(6*dx/8,2*dx/8,0,dy-1,bp,cs)!=3 ) Break; // 2010-09-25 6x7
90
+
91
+ i1=loop(bp,dx-1,dy-1,dx,cs,0,LE);
92
+ i2=loop(bp,dx-1,dy-2,dx,cs,0,LE);
93
+ if (i2-i1 >= dx/4) Break; // ~{ 5x7font
94
+ // i1, i2 unused now
95
+
96
+ if (dx<13 && dy<17) { // oebb_teletext S5 Aug10
97
+ i1=loop(bp, 0,0,dx,cs,0,RI);
98
+ i2=loop(bp, 0,1,dx,cs,0,RI);
99
+ i3=loop(bp,dx-1,0,dx,cs,0,LE);
100
+ if (i1>i2 && i3>0) ad=98*ad/100;
101
+ }
102
+ // i1, i2, i3 unused now
103
+
104
+ // get the upper and lower hole koords, y around dy/4 ???
105
+ x=5*dx/8;
106
+ y =loop(bp,x,0,dy,cs,0,DO); if(y>dy/8) Break;
107
+ y +=loop(bp,x,y,dy,cs,1,DO); if(y>(dy+2)/4) Break; // 6x7 2010-09-25
108
+ i1 =loop(bp,x,y,dy,cs,0,DO)+y; if(i1>5*dy/8) Break;
109
+ i3=y=(y+i1)/2; // upper end can be shifted to the right for italic
110
+ x =loop(bp,0,y,dx,cs,0,RI); if(x>4*dx/8) Break;
111
+ x +=loop(bp,x,y,dx,cs,1,RI); if(x>5*dx/8) Break;
112
+ i1 =loop(bp,x,y,dx,cs,0,RI); i1=(i1+2*x)/2; // upper center (i1,i3)
113
+ y=11*dy/16;
114
+ x =loop(bp,dx-1 ,y,dx,cs,0,LE); if(x>dx/4) Break;
115
+ x +=loop(bp,dx-1-x,y,dx,cs,1,LE); if(x>dx/2) Break;
116
+ i2 =loop(bp,dx-1-x,y,dx,cs,0,LE); i2=dx-1-(i2+2*x)/2; // lower center x
117
+
118
+ MSG( fprintf(stderr,"i1,i3=%d,%d i2,y=%d,%d (upper+lower center)",i1,i3,i2,y);)
119
+
120
+ y =loop(bp,i1,0,dy,cs,0,DO);
121
+ y +=loop(bp,i1,y,dy,cs,1,DO);
122
+ y =(3*y+i3)/4;
123
+ if( num_cross( i1, dx-1, y, y,bp,cs)>0 ){ /* S or serif5 ? */
124
+ y =loop(bp,i1 ,i3,dy,cs,0,DO);
125
+ i =loop(bp,i1-1,i3,dy,cs,0,DO);
126
+ if (y>i ) ad=99*ad/100; /* looks like S */
127
+ y =loop(bp,i1 ,i3,dy,cs,0,UP);
128
+ i =loop(bp,i1+1,i3,dy,cs,0,UP);
129
+ if (i<y ) ad=99*ad/100; /* looks like S */
130
+ x =loop(bp,dx-1,0,dx,cs,0,LE);
131
+ i =loop(bp,dx-1,1,dx,cs,0,LE);
132
+ if (x>i ) ad=99*ad/100; /* looks like S */
133
+ if( num_cross( 0, dx/2, dy-1, dy-1,bp,cs)>1
134
+ && num_cross( dx/2,dx-1, 0, 0,bp,cs)>1 ) ad=98*ad/100; /* serifs */
135
+ if (loop(bp,0,dy-1,dx,cs,0,RI)==0) ad=98*ad/100; /* S or 7segment */
136
+ ad=99*ad/100;
137
+ }
138
+
139
+ for(y=dy/5;y<3*dy/4;y++) // right gap?
140
+ if( num_cross(i1,dx-1,y,y,bp,cs)==0 ) break;
141
+ if( y==3*dy/4 ) Break;
142
+
143
+ for(y=dy/4;y<=11*dy/16;y++) // left gap?
144
+ if( num_cross(0,i2,y,y,bp,cs)==0 ) break;
145
+ if( y>11*dy/16 ) Break;
146
+
147
+ // if( num_hole( x0, x1, y0, y1, box1->p,cs,NULL) > 0 ) break;
148
+ if (sdata->holes.num>0) Break;
149
+
150
+ // sS5 \sl z left upper v-bow ?
151
+ for(x=dx,i=y=dy/4;y<dy/2;y++){
152
+ j=loop(bp,0,y,dx,cs,0,RI); if(j<x) { x=j; i=y; }
153
+ } y=i; /* get smalles left gap and its y position */
154
+ i1=loop(bp,0, dy/16 ,dx,cs,0,RI); /* left gap at top */
155
+ i2=loop(bp,0,(y+dy/16)/2 ,dx,cs,0,RI); /* left gap below top */
156
+ i =loop(bp,0,(y+dy/16)/2+1,dx,cs,0,RI); if( i>i2 ) i2=i;
157
+ i3=loop(bp,0, y ,dx,cs,0,RI); /* left gap at y */
158
+ i =loop(bp,0, y-1,dx,cs,0,RI); if( i<i3 ) i3=i;
159
+ if( 2*i2+ dx/16 < i1+i3 ) ad=99*ad/100; /* 5S oebb_teletext */
160
+ if( 2*i2+1+dx/16 < i1+i3 ) Break; /* break if bow */
161
+
162
+ if( dy>=20 && dx<16 ) /* tall S */
163
+ if( loop(bp,0, dy/5 ,dx,cs,0,RI)
164
+ ==loop(bp,0, dy/4 ,dx,cs,0,RI)
165
+ &&
166
+ loop(bp,0, dy/10 ,dx,cs,0,RI)
167
+ >loop(bp,0, dy/4 ,dx,cs,0,RI)
168
+ &&
169
+ loop(bp,0, 1 ,dx,cs,0,RI)
170
+ >loop(bp,0, dy/4 ,dx,cs,0,RI)+1
171
+ &&
172
+ loop(bp,dx-1, 0 ,dx,cs,0,LE)
173
+ >loop(bp,dx-1, 1 ,dx,cs,0,LE) ) Break;
174
+
175
+ if( dy>=30 && dx>15 ) /* large S */
176
+ if( loop(bp,dx/4,3*dy/10,dy,cs,1,DO)>0 ) // check start
177
+ if( loop(bp,dx-2,3*dy/4 ,dy,cs,1,UP)>0 ) // check end
178
+ if( num_cross(dx/4,dx-2,3*dy/10,3*dy/4,bp,cs)==1 ) Break; // connected?
179
+ MSG(fprintf(stderr,"~S ad=%d",ad);)
180
+
181
+ // small fat s is very similar to rounded serif 5
182
+ // but has a fat diagonal arrea (Oct08 JS)
183
+ if ( num_cross(dx/8,dx-1-dx/8,3*dy/10,3*dy/4,bp,cs)==1 ) ad=98*ad/100;
184
+ MSG(fprintf(stderr,"~S ad=%d",ad);)
185
+
186
+ if( dy>17 && dx>9 ) /* S */
187
+ if( loop(bp, 0,dy/2 ,dx,cs,0,RI)<dx/2
188
+ || loop(bp, 0,dy/2-1 ,dx,cs,0,RI)<dx/2 )
189
+ if( loop(bp,dx/4,3*dy/10,dy,cs,1,DO)>0 ) // check start
190
+ if( loop(bp,dx-2,2*dy/3 ,dy,cs,1,UP)>0 ) // check end
191
+ if( loop(bp, 0, dy/16,dx,cs,0,RI)
192
+ >= loop(bp,dx-1, dy-1-dy/16,dx,cs,0,LE) ) ad=ad*98/100;
193
+ MSG(fprintf(stderr,"~S ad=%d",ad);)
194
+ if( loop(bp,3*dx/4 , 0,dy,cs,1,DO) // ToDo: improve!
195
+ < loop(bp, dx/4 ,dy-1,dy,cs,1,UP)
196
+ && loop(bp,3*dx/4-1, 0,dy,cs,0,DO)
197
+ < loop(bp, dx/4+1,dy-1,dy,cs,0,UP) ) ad=ad*98/100;
198
+ MSG(fprintf(stderr,"~S ad=%d",ad);)
199
+
200
+ if ( gchar) ad=99*ad/100;
201
+ if (!hchar) ad=98*ad/100; // ~s 6x7 font tmp08/gocr0801_bad5.jpg
202
+ if (box1->m2 && y0>=box1->m2 && ad<100 && ad>96) {ad=96;MSG({})} // s
203
+ Setac(box1,(wchar_t)'5',ad);
204
+ if (ad==100) return '5';
205
+ break;
206
+
207
+ }
208
+ // --- test 1 ---------------------------------------------------
209
+ for(ad=d=100;dy>4 && dy>dx && 2*dy>box1->m3-box1->m2;){ // min 3x4
210
+ DBG( char c_ask='1'; )
211
+ if( dots==1 ) Break;
212
+ if (sdata->holes.num > 1) Break; /* be tolerant */
213
+
214
+ if( num_cross(0, dx-1, 0 , 0 ,bp,cs) != 1
215
+ && num_cross(0, dx-1, 1 , 1 ,bp,cs) != 1 ) Break;
216
+ if( num_cross(0, dx-1,dy/2,dy/2,bp,cs) != 1 ) Break;
217
+ if( num_cross(0, dx-1,dy-1,dy-1,bp,cs) != 1
218
+ && num_cross(0, dx-1,dy-2,dy-2,bp,cs) != 1 ) Break;
219
+ /* 5x7 micr ocr-a 6x10 6x9 bad 6x9
220
+ mozilla
221
+ 3x6 5x7 5x7 ..@@..<-
222
+ .@@@.. @@@...<- @@@...<-
223
+ ..@@.. @.@... ..@...
224
+ ooo @@@.. ..@@..< ..@... ..@...
225
+ .$. ooo ..@.. ..@@.. ..@...< ..@...<
226
+ $@. oo ..@.. ..@@.. ..@... ..@...
227
+ .$. oo ..@.. ..@@.. ..@... ..@...
228
+ .@. ooooo ..@.@ ..@@.. ..@... ..@...
229
+ .$. ooooo ..@.@ ..@@.. ..@... ..@...
230
+ $@$ ooooo @@@@@ @@@@@@<- @@@@@@<- @@@@@@<-
231
+ gocr0801_bad5
232
+ */
233
+ i4=0; // human font
234
+ if (num_cross(0, dx-1,3*dy/4,3*dy/4,bp,cs) != 2 ) { // except ocr-a
235
+ for (y=1; y<dy/2; y++) {
236
+ if (num_cross(0, dx-1, y , y ,bp,cs) == 2 ) break;
237
+ } if (y>=dy/2) {
238
+ if (dx>6) ad=98*ad/100;
239
+ else ad=99*ad/100; MSG(fprintf(stderr,"ad= %d",ad);) }
240
+ for( i=dy/8,y=7*dy/16;y<dy-1 && i;y++ ){
241
+ if( num_cross(0, dx-1, y , y ,bp,cs) != 1 ) i--;
242
+ } if( dy>8 && !i ) Break;
243
+ } else { // ocr-a-1
244
+ i= loop(bp,dx/2,0,dy,cs,0,DO);
245
+ if (loop(bp,dx/2,i,dy,cs,1,DO)<dy-1) Break;
246
+ i= loop(bp,dx -1,dy-1-dy/16,dx,cs,0,LE);
247
+ if (loop(bp,dx-i-1,dy-1-dy/16,dx,cs,1,LE)<dx-1) Break;
248
+ i= loop(bp,0,dy/16,dx,cs,0,RI);
249
+ if (loop(bp,i,dy/16,dx,cs,1,RI)<dx/2) Break;
250
+ i4=1;
251
+ MSG(fprintf(stderr,"ocr-a-1 detected ad= %d", ad);)
252
+ }
253
+
254
+ if( num_cross(0, dx-1, 0 , 0 ,bp,cs) > 1
255
+ && num_cross(0, dx-1, 1 , 1 ,bp,cs) > 1 ) Break; // ~/it_7
256
+
257
+ // calculate upper and lower mass center (without lower serif)
258
+
259
+ x =loop(bp,0,7*dy/8-1,dx,cs,0,RI); i2=x;
260
+ x+=loop(bp,x,7*dy/8-1,dx,cs,1,RI)-1; i2=(i2+x)/2;
261
+
262
+ i1=loop(bp,dx-1 ,1+0* dy/4,dx,cs,0,LE); i1=dx-1-i1-(x-i2)/2;
263
+
264
+ x =(i1-i2+4)/8; i1+=x; i2-=x;
265
+
266
+ if( get_line2(i1,0,i2,dy-1,bp,cs,100)<95 ) { // dont work for ocr-a-1
267
+ i1=loop(bp,dx-1 ,1+0* dy/4,dx,cs,0,LE); i1=dx-1-i1;
268
+ if( get_line2(i1,0,i2,dy-1,bp,cs,100)<95 ) Break;
269
+ }
270
+ // upper and lower width
271
+ x =loop(bp,(i1+i2)/2,dy/2,dx,cs,1,RI); i=x; i3=0;
272
+ for (y=0;y<7*dy/8;y++)
273
+ if ( loop(bp,i1+y*(i2-i1)/dy, y,dx,cs,1,RI)-i > 1+dx/8 ) break;
274
+ if (y<7*dy/8) { ad=98*ad/100; // serif or ocr-a-1 ?
275
+ MSG(fprintf(stderr,"i12 %d %d ad= %d", i1,i2,ad);) }
276
+ if (y<6*dy/8) { ad=99*ad/100; /* MICR E-13B font Jan07 */
277
+ MSG(fprintf(stderr,"i12 %d %d ad= %d", i1,i2,ad);) }
278
+ if (y<4*dy/8) Break;
279
+ MSG(fprintf(stderr,"i12 %d %d ad= %d", i1,i2,ad);)
280
+ // out_x(box1); printf(" i12=%d %d\n",i1,i2);
281
+ x =loop(bp,i2,dy-1,dx,cs,1,LE); j=x;
282
+ x =loop(bp,i2,dy-2,dx,cs,1,LE); if(x>j)j=x; i=j;
283
+ x =loop(bp,i2,dy-1,dx,cs,1,RI); j=x;
284
+ x =loop(bp,i2,dy-2,dx,cs,1,RI); if(x>j)j=x;
285
+ if(abs(i-j)>1+dx/8) i3|=1;
286
+ if(i3) Break;
287
+ // out_x(box1);printf(" 11 i=%d j=%d i2=%d dx=%d\n",i,j,i1,dx);
288
+ MSG(fprintf(stderr,"ad= %d", ad);)
289
+ // get most left upper point (i,j)
290
+ for(i=dx,j=y=0;y<7*dy/16;y++){
291
+ x =loop(bp,0,y,dx,cs,0,RI); if(x<i) { i=x;j=y; }
292
+ }
293
+ if ( i1-i<7*dx/16 ) { ad=ad*98/100;
294
+ MSG(fprintf(stderr,"i1i %d %d ad= %d", i1,i,ad);) }
295
+ if ( i1-i<6*dx/16 ) { ad=ad*98/100; // 4*dx/8 => 7*dx/16 MICR E-13B font
296
+ MSG(fprintf(stderr,"i1i %d %d ad= %d", i1,i,ad);) }
297
+ if ( i1-i<4*dx/16 ) Break;
298
+ MSG(fprintf(stderr,"i12 %d %d ad= %d", i1,i2,ad);)
299
+ x =loop(bp,0,dy/2,dx,cs,0,RI); // right distance
300
+ j =loop(bp,x,dy/2,dx,cs,1,RI); // thickness
301
+ if( j>x+(dy+16)/32 ) ad=98*ad/100; // ~l but MICR E-13B font
302
+ x =loop(bp,0,0,dx,cs,0,RI); // straight line ???
303
+ j =loop(bp,0,1,dx,cs,0,RI);
304
+ if (j>x) {
305
+ if (dy>9) { Break; }
306
+ else { if (ad>99) ad=ad*99/100; MSG({}) } // ~l but gocr0801_bad5
307
+ }
308
+ if (x==j) j =loop(bp,0,dy/8,dx,cs,0,RI);
309
+ if (j>x && y>9 && !i4) { Break; }
310
+ else if (j>x && !i4 && ad>99) { ad=ad*99/100; MSG({}) }
311
+ if (x==j) if(loop(bp,0,dy/4,dx,cs,0,RI)>x) { // ~l
312
+ // check micr-1 first before taken as 'l'
313
+ if (loop(bp,dx-1,dy/8,dx,cs,0,LE)<=dx/4
314
+ && loop(bp, 0,3*dy/4,dx,cs,1,RI)< dx-1) ad=97*ad/100;
315
+ }
316
+ MSG(fprintf(stderr,"1l check ad= %d", ad);)
317
+ x=j;
318
+ // j =loop(bp,0,2,dx,cs,0,RI); if( j>=x ) Break; x=j; // ~l
319
+ // j =loop(bp,0, 0,dx,cs,0,DO); if( !j ) Break; // ~7
320
+ if( !hchar ) // ~ right part of n
321
+ /* look for upper right side, not going from nw to se */
322
+ if( loop(bp,dx-1, 1,dx,cs,0,LE)-dy/6
323
+ > loop(bp,dx-1,dy/4,dx,cs,0,LE)
324
+ // failes on small fonts with 1 point spaces between chars
325
+ // also do not know what the purpose of this line was (JS Oct08)
326
+ // || get_bw(x1+1,x1+2,y0,y0+dy/8,box1->p,cs,1)==1
327
+ ) Break; // Mai00
328
+ if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE) > dx/2
329
+ && get_bw(x1-dx/4,x1,y1-1,y1,box1->p,cs,1)==1 ) Break; // ~z Jun00
330
+
331
+ i=loop(bp, dx/8,0,dy,cs,0,DO);
332
+ for (y=dy,x=dx/2;x<3*dx/4;x++){ /* get upper end y */
333
+ j=loop(bp,x,0,dy,cs,0,DO); if (j<y) { y=j; }
334
+ }
335
+ if(y<dy/2 && y+dy/16>=i) ad=98*ad/100; // ~\tt l ??? ocr-a_1
336
+ MSG(fprintf(stderr,"1l check i= %d y= %d ad= %d", i, y, ad);)
337
+
338
+ if( loop(bp, 0, dy/8,dx,cs,0,RI)
339
+ -(dx-loop(bp,dx-1,7*dy/8,dx,cs,0,LE)) > dx/4 ) Break; // ~/
340
+
341
+ i= loop(bp, 0, 0,dy,cs,0,DO); // horizontal line?
342
+ if(dy>=12 && i>dy/8 && i<dy/2){
343
+ if( loop(bp,dx-1,3*dy/16,dx,cs,0,LE)-dx/8
344
+ >loop(bp,dx-1, i,dx,cs,0,LE)
345
+ || loop(bp,dx-1,3*dy/16,dx,cs,0,LE)-dx/8
346
+ >loop(bp,dx-1, i+1,dx,cs,0,LE) ) Break; // ~t,~f
347
+ i= loop(bp, 0,dy-1-dy/32,dx,cs,0,RI);
348
+ x= loop(bp, 0,dy-2-dy/32,dx,cs,0,RI); if (i<x) x=i;
349
+ if( x-loop(bp, 0, 3*dy/4,dx,cs,0,RI)>dx/8
350
+ && loop(bp,dx-1, 3*dy/4,dx,cs,0,LE)-dx/8
351
+ >loop(bp,dx-1,dy-1-dy/32,dx,cs,0,LE) ) Break; // ~t
352
+ if( loop(bp, 0,i-1,dx,cs,0,RI)>1 && dx<6) {
353
+ ad=99*ad/100;
354
+ if ( loop(bp,dx-1,i-1,dx,cs,0,LE)>1 ) Break; // ~t
355
+ }
356
+ }
357
+
358
+ if (dx>8){
359
+ if (loop(bp,0,3*dy/4,dx,cs,0,RI)-
360
+ loop(bp,0,dy/2-1,dx,cs,0,RI)>dx/4) ad=95*ad/100; // ~3
361
+ if (loop(bp,dx-1,dy/2-1,dx,cs,0,LE)-
362
+ loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/8) ad=99*ad/100; // ~3 ocr-a?
363
+ if (loop(bp,dx-1, dy/4 ,dx,cs,0,LE)<dx/3 // 2010-09-25 6x9
364
+ && loop(bp,dx-1, dy/16,dx,cs,0,LE)-
365
+ loop(bp,dx-1, dy/4,dx,cs,0,LE)>dx/8) ad=95*ad/100; // ~23
366
+ MSG(fprintf(stderr,"23 check ad= %d", ad);)
367
+ }
368
+ /* font 5x9 "2" recognized as "1" */
369
+ i=loop(bp,dx-1-dx/8,dy-1,dy,cs,0,UP);
370
+ if (i<=dy/4) {
371
+ i+=loop(bp,dx-1-dx/8,dy-1-i,dy,cs,1,UP);
372
+ if (i<=dy/4) {
373
+ i=loop(bp,dx-1-dx/8,dy-1-i,dx,cs,0,LE);
374
+ if (loop(bp,dx-1,dy/4,dx,cs,0,LE)<dx/2) // 2010-09-25 6x9 1
375
+ if (2*i>=dx && loop(bp,dx/4,0,dy,cs,0,DO)<dy/2) {
376
+ if (dx<17) ad=98*ad/100;
377
+ if (dx<9) ad=97*ad/100;
378
+ MSG(fprintf(stderr,"5x9 2 check ad= %d", ad);)
379
+ }
380
+ }
381
+ }
382
+
383
+ // 2010-10-01 sample tmp10/barcode_code128_145
384
+ if (dx<3 && dy>7 && box1->m4==0) ad=ad*96/100; // just a vertical line?
385
+
386
+ // looking for ###
387
+ // ..# pattern (its important, we dont want perp. lines as 1)
388
+ // ToDo: better check that we have exact one on top
389
+ for (i2=0,i=dx,y=0;y<dy/2;y++) {
390
+ j=loop(bp,0,y,dx,cs,0,RI); if (j<i) i=j;
391
+ if (j>i+dx/8) { break; }
392
+ } if (y>=dy/2) ad=95*ad/100; // Feb07 care plates, right black border
393
+ MSG(fprintf(stderr,"ad= %d", ad);)
394
+
395
+ if (sdata->holes.num > 0) Break; // mini holes should be filtered
396
+ if (!box1->m3 && ad>98) ad=98; else {
397
+ if (!hchar) ad=99*ad/100;
398
+ if (box1->y0>box1->m2) ad=98*ad/100;
399
+ if (box1->y1<(1*box1->m2+3*box1->m3)/4) ad=98*ad/100;
400
+ if (box1->y1-box1->y0<(box1->m3-box1->m1)/2) ad=98*ad/100;
401
+ if ( gchar) ad=99*ad/100;
402
+ }
403
+
404
+ Setac(box1,(wchar_t)'1',ad);
405
+ break;
406
+ }
407
+ // --- test 2 old pixelbased - remove! -----------------------------
408
+ #ifdef Old_pixel_based
409
+ for(ad=d=100;dx>2 && dy>4;){ // min 3x4
410
+ DBG( char c_ask='2'; )
411
+ if (sdata->holes.num > 1) Break; /* be tolerant */
412
+ if( get_bw(x0+dx/2, x0+dx/2 , y1-dy/5, y1 ,box1->p,cs,1) != 1 ) Break;
413
+ if( get_bw(x0+dx/2, x0+dx/2 , y0 , y0+dy/5,box1->p,cs,1) != 1 ) Break;
414
+ if( get_bw(x0+dx/8, x1-dx/3 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
415
+
416
+ if( get_bw(x1-dx/3, x1 , y0+dy/3 , y0+dy/3,box1->p,cs,1) != 1 ) Break;
417
+ if( get_bw(x0 , x0+dx/ 8, y1-dy/16, y1 ,box1->p,cs,1) != 1 ) Break;
418
+ if( num_cross(x0, x1-dx/8, y0+dy/2, y0+dy/2,box1->p,cs) != 1 ) Break;
419
+ if( get_bw(x0, x0+dx/9 , y0 , y0 ,box1->p,cs,1) == 1
420
+ && get_bw(x0, x0+dx/2 ,y0+3*dy/16,y0+3*dy/16,box1->p,cs,1) == 1 ) Break;
421
+ if( get_bw(x0, x0+dx/9 , y0 , y0 ,box1->p,cs,1)
422
+ != get_bw(x1-dx/9, x1 , y0 , y0 ,box1->p,cs,1) )
423
+ { if (dx<6 && dy<9) ad=99*ad/100; else Break; }
424
+ // out_x(box1);
425
+
426
+ for( x=x0+dx/4;x<x1-dx/6;x++ ) // C
427
+ if( num_cross( x, x, y0, y0+dy/2,box1->p,cs) == 2 ) break;
428
+ if( x>=x1-dx/6 ) Break;
429
+
430
+ for( x=x0+dx/4;x<x1-dx/6;x++ ) // C, but acr-a
431
+ if( num_cross( x, x, y0+3*dy/8,y1,box1->p,cs) == 2 ) break;
432
+ if( x>=x1-dx/6 ) Break;
433
+
434
+ for(i=1,y=y0;y<y0+dy/2;y++ )
435
+ if( num_cross( x0, x1, y, y,box1->p,cs) == 2 ) i=0;
436
+ if( i ) ad=99*ad/100; // ToDo: ocr-a-2 should have 100%
437
+
438
+ for(i=1,y=y0+dy/5;y<y0+3*dy/4;y++ )
439
+ if( get_bw( x0, x0+dx/3, y, y,box1->p,cs,1) == 0 ) i=0;
440
+ if( i ) Break;
441
+
442
+ x=x1-dx/3,y=y1; /* center bottom */
443
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( y<y1-dy/5 ) Break;
444
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,UP); if( y<y1-dy/4 ) ad=99*ad/100;
445
+ if( y<y1-dy/3 ) Break;
446
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( y<y0+dy/3 ) Break; y++;
447
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,ST);
448
+ if( x<x1 ){ x--; // hmm thick font and serifs
449
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( y<y0+dy/2 ) Break; y++;
450
+ turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,ST);
451
+ if( x<x1 ) Break;
452
+ }
453
+
454
+ // test ob rechte Kante ansteigend
455
+ for(x=0,y=dy/18;y<=dy/3;y++){ // rechts abfallende Kante/Rund?
456
+ i=loop(box1->p,x1,y0+y,dx,cs,0,LE); // use p (not b) for broken chars
457
+ if( i<x ) break; // rund
458
+ if( i>x ) x=i;
459
+ }
460
+ if (y>dy/3 ) Break; // z
461
+
462
+ // hole is only allowed in beauty fonts
463
+ // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) > 0 ) // there is no hole
464
+ // if( num_hole( x0, x0+dx/2, y0, y0+dy/2,box1->p,cs,NULL) == 0 ) // except in some beauty fonts
465
+ if (sdata->holes.num>0)
466
+ if (sdata->holes.hole[0].x1 >= dx/2 || sdata->holes.hole[0].y1 >= dy/2)
467
+ Break;
468
+
469
+ if (loop(bp,dx-1, 0,dx,cs,0,LE)
470
+ <loop(bp,dx-1,dy/4,dx,cs,0,LE)-dx/8) Break; // 5x7,5x8 z Jul09
471
+ i1=loop(bp,dx-1-dx/16,0,dy,cs,0,DO); // Jul00
472
+ i2=loop(bp, dx/ 2,0,dy,cs,0,DO); if( i2+dy/32>=i1 ) Break; // ~z
473
+ i1=loop(bp,dx-1,dy-3*dy/16,dx,cs,0,LE);
474
+ i2=loop(bp, 0,dy-3*dy/16,dx,cs,0,RI); if( i2>i1 ) ad=98*ad/100; // ~i
475
+ if (dots) ad=98*ad/100; // i
476
+ if (loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/4) ad=96*ad/100; // \it i
477
+
478
+ if ((!hchar) && box1->m4!=0) ad=80*ad/100;
479
+ Setac(box1,(wchar_t)'2',ad);
480
+ if (ad==100) return '2';
481
+ break;
482
+ }
483
+ #endif
484
+ // --- test 2 new edge based v0.44 --------------------------------------
485
+ for(ad=d=100;dx>2 && dy>4;){ // min 3x4
486
+ // rewritten for vectors 0.42
487
+ int ld, i1, i2, i3, i4, i5, i6, i7; // line derivation + corners
488
+ DBG( wchar_t c_ask='2'; )
489
+ if (sdata->holes.num > 0) Break; /* no hole */
490
+ /* half distance to the center */
491
+ d=2*sq(128/4);
492
+ /* now we check for the lower ends, must be near to the corner */
493
+ if (aa[1][2]>d/4) Break; /* [2] = distance, ~7... */
494
+ if (aa[2][2]>d/2) Break; /* [2] = distance, ~r... */
495
+ if (aa[0][2]>d/1) Break; /* [2] = distance, ~d... */
496
+ if (aa[3][2]>d/1) Break; /* [2] = distance, ~bhk... */
497
+ /* searching for 4 notches between neighbouring ends */
498
+
499
+ /*
500
+ type A B
501
+
502
+ 1OOO OO
503
+ 2 1 2 <- 6
504
+ 7-> OOOO O
505
+ O O <- 5
506
+ 3OO4 3OO4
507
+ */
508
+
509
+ // ToDo: replace by vector code (get point on line at dy/4)
510
+ if (loop(bp,dx-1, 0,dx,cs,0,LE)
511
+ <loop(bp,dx-1,dy/4,dx,cs,0,LE)-dx/8) Break; // 5x7,5x8 z Jul09
512
+
513
+ /* get a point on the inner low left side of the J */
514
+ i =box1->num_frame_vectors[0] - 1;
515
+ /* rightmost point on upper left side */
516
+ i2=nearest_frame_vector(box1, aa[0][3], aa[1][3], x1+dx, y0+dy/4);
517
+ /* upper leftmost vector */
518
+ i1=nearest_frame_vector(box1, aa[0][3], i2, x0-dx, (y0+y1)/2);
519
+ i3=aa[1][3];
520
+ /* low leftmost vector */
521
+ i5=nearest_frame_vector(box1, aa[2][3], aa[3][3], x0, y1);
522
+ /* low mostright vector */
523
+ i4=nearest_frame_vector(box1, aa[1][3], i5, x1+dx, y1);
524
+ /* next local max_x-point after i5 */
525
+ i6=i5;
526
+ for (i=i5;i!=aa[0][3];i=(i+1)%box1->num_frame_vectors[0]) {
527
+ if (box1->frame_vector[ i][0]
528
+ >box1->frame_vector[i6][0]) i6=i; // get next maximum
529
+ if (box1->frame_vector[ i][0]<x0+dx/3
530
+ && box1->frame_vector[ i][1]<y0+dy/3
531
+ && box1->frame_vector[i6][0]>x0+dx/2) break; // 5
532
+ }
533
+ /* which type? ToDo: have a more sure algorithm */
534
+ i7=nearest_frame_vector(box1, i2, i3, x0-dx/8, (y0+y1)/2);
535
+ if (box1->frame_vector[i7][0]<=x0+ dx/4
536
+ && box1->frame_vector[i7][1]<=y0+2*dy/3) {
537
+ MSG(fprintf(stderr,"7-segment-type");)
538
+ } else { /* regular-book-type */
539
+ MSG( fprintf(stderr,"upper bow not z-like? ad %d", ad); )
540
+ if (aa[3][0]>=x1-dx/8 // x of upper right point
541
+ && aa[3][1]< y0+dy/8) ad=99*ad/100; // y of upper right point
542
+ if (aa[0][0]<=x0+dx/8 // x of upper left point
543
+ && aa[0][1]< y0+dy/8) ad=99*ad/100; // y of upper left point
544
+ if (aa[3][2]<=aa[1][2]) ad=97*ad/100; // dist to (maxx,0) <= (0,maxy)
545
+ }
546
+ // ToDo: output no=(x,y)
547
+ MSG( fprintf(stderr,"i1-7 %d %d %d %d %d %d %d ad %d",
548
+ i1,i2,i3,i4,i5,i6,i7,ad); )
549
+ if (i5==i6) Break; // ~+
550
+
551
+ if (box1->frame_vector[i5][1]
552
+ -box1->frame_vector[i6][1]<dy/4) Break; // ~5
553
+ if (box1->frame_vector[i1][1]>y0+dy/2) Break; // not to low
554
+ if (box1->frame_vector[i1][0]>x0+dx/8+dx/16) Break; // slanted ?
555
+ if (box1->frame_vector[i2][1]>(y0+ y1)/2) Break;
556
+ if (box1->frame_vector[i2][1]>(5*y0+3*y1)/8) ad=99*ad/100;
557
+ MSG( fprintf(stderr,"ad %d", ad); )
558
+ if (box1->frame_vector[i2][0]<(x0+x1+1)/2) Break; // fat tiny fonts?
559
+ if (box1->frame_vector[i2][0]<(x0+2*x1)/3) ad=99*ad/100;
560
+ MSG( fprintf(stderr,"ad %d", ad); )
561
+ if (box1->frame_vector[i3][0]>(3*x0+x1)/4) Break;
562
+ if (box1->frame_vector[i3][0]>(7*x0+x1)/8) ad=99*ad/100;
563
+ MSG( fprintf(stderr,"ad %d", ad); )
564
+ /* check lowest left point */
565
+ if (box1->frame_vector[i3][1]<(y0+3*y1)/4) Break;
566
+ if (box1->frame_vector[i3][1]<(y0+7*y1)/8) ad=99*ad/100;
567
+ MSG( fprintf(stderr,"ad %d", ad); )
568
+ /* check lower leftmost point from right side */
569
+ if (box1->frame_vector[i5][0]>(x0+2*x1)/3) Break;
570
+ if (box1->frame_vector[i5][0]>(x0+ x1)/2) ad=98*ad/100;
571
+ if (box1->frame_vector[i5][0]>(2*x0+2+x1)/3) ad=99*ad/100; /* 9x10 2 */
572
+ MSG( fprintf(stderr,"ad %d", ad); )
573
+ if (box1->frame_vector[i5][1]<(3*y0+5*y1)/8) Break;
574
+ if (box1->frame_vector[i5][1]<(y0+3*y1)/4) ad=99*ad/100;
575
+ MSG( fprintf(stderr,"ad %d", ad); )
576
+ if (box1->frame_vector[i6][1]>(y0+2*y1)/3) Break;
577
+ if (box1->frame_vector[i6][1]>(y0+ y1)/2) ad=99*ad/100;
578
+ MSG( fprintf(stderr,"ad %d", ad); )
579
+ if (box1->frame_vector[i6][0]<(x0+3*x1)/4) Break;
580
+ if (box1->frame_vector[i6][0]<(x0+7*x1)/8) ad=99*ad/100;
581
+
582
+ /* check for zZ */
583
+
584
+ /* check if lower left and right points are joined directly */
585
+ ld=line_deviation(box1, i3, i4);
586
+ MSG(fprintf(stderr,"i1-i2 %d %d dist= %d/%d",i1,i2,ld,2*sq(1024/4));)
587
+ if (ld >2*sq(1024/4)) Break;
588
+ if (ld > sq(1024/4)) ad=99*ad/100;
589
+
590
+ if (box1->m3) {
591
+ if(!hchar){ ad=99*ad/100; }
592
+ if( gchar){ ad=99*ad/100; }
593
+ } else { if (ad==100) ad=99; } /* not 100% sure */
594
+ Setac(box1,'2',ad);
595
+ if (ad==100) return '2';
596
+ break;
597
+ }
598
+ // --- test 3 -------
599
+ for(ad=d=100;dx>3 && dy>4;){ // dy<=dx nicht perfekt! besser mittleres
600
+ // min-suchen fuer m
601
+ int i1, i2, i3, i4, i5, i6, i7, i8; // line derivation + corners
602
+ DBG( char c_ask='3'; )
603
+ if (sdata->holes.num > 1) Break; /* be tolerant */
604
+ if (sdata->holes.num > 0) ad=98*ad/100; /* be tolerant */
605
+ if (4*dx<dy) ad=98*ad/100; // to tall 1:2 - 1:3 is usual
606
+ // --- vector based code ---
607
+ /* half distance to the center */
608
+ d=2*sq(128/4);
609
+ /* now we check for the lower ends, must be near to the corner */
610
+ if (aa[1][2]>d/1) Break; /* [2] = distance, ~7... */
611
+ if (aa[2][2]>d/1) Break; /* [2] = distance, ~r... */
612
+ if (aa[0][2]>d/1) Break; /* [2] = distance, ~d... */
613
+ if (aa[3][2]>d/1) Break; /* [2] = distance, ~bhk... */
614
+ /*
615
+ type A B C
616
+
617
+ 1OO8 1OO 1OO8
618
+ O 8 2 <- 7,8
619
+ 2 2 7
620
+ 1-5-> 3OO7 37 3OO
621
+ 4 4 4
622
+ O 6 6 <- 6
623
+ 5OO6 5OO 5OO
624
+ */
625
+ /* rightmost point on upper left side */
626
+ i2=nearest_frame_vector(box1, aa[0][3], aa[1][3], x1, y0+3*dy/16);
627
+ /* rightmost point on lower left side */
628
+ i4=nearest_frame_vector(box1, aa[0][3], aa[1][3], x1, y1-dy/4);
629
+ /* leftmost point on middle left side */
630
+ i3=nearest_frame_vector(box1, i2, i4, x0, y0+dy/2);
631
+ /* upper leftmost vector */
632
+ i1=nearest_frame_vector(box1, aa[0][3], i2, x0-dx, (y0+y1)/2);
633
+ i5=aa[1][3]; // points to vector point in point list
634
+ i6=aa[2][3];
635
+ i8=aa[3][3];
636
+ /* leftmost point on middle right side */
637
+ i7=nearest_frame_vector(box1, i6, i8, x0 , y0+dy/2);
638
+ /* which type? ToDo: have a more sure algorithm */
639
+ if (box1->frame_vector[i7][0]>=x1- dx/4
640
+ && box1->frame_vector[i6][0]>=x1- dx/8 // ToDo: ...
641
+ && box1->frame_vector[i6][1]>=y1- dy/8) {
642
+ MSG(fprintf(stderr,"7-segment-type");)
643
+ } else { /* regular-book-type */
644
+ }
645
+ // ToDo: output no=(x,y)
646
+ MSG(fprintf(stderr,"i1-8 %d %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7,i8);)
647
+ // if (i5==i6) Break; // ~+
648
+
649
+ // i2 = upper left gap ) , i3 = middle left <
650
+ if (box1->frame_vector[i2][0]
651
+ -box1->frame_vector[i3][0]<dx/4) Break; // video samples
652
+ if (box1->frame_vector[i4][0]
653
+ -box1->frame_vector[i3][0]<dx/4) Break; // video samples
654
+ if (box1->frame_vector[i4][0]
655
+ -box1->frame_vector[i5][0]<dx/2) Break; // video samples
656
+ if (box1->frame_vector[i2][0]
657
+ -box1->frame_vector[i1][0]<dx/2) Break; // video samples
658
+ if (box1->frame_vector[i1][1]>y0+dy/2) Break; // not to low
659
+ if (box1->frame_vector[i1][0]>x0+dx/4+dx/16) Break; // slanted?
660
+ if (box1->frame_vector[i5][1]<y1-dy/2) Break; // not to high
661
+ if (box1->frame_vector[i5][0]>x0+dx/4) Break;
662
+ // ToDo ....
663
+
664
+ // --- pixel based old code ---
665
+ // if( get_bw(x0+dx/2,x0+dx/2,y0,y0+dy/4,box1->p,cs,1) == 0 ) Break; // ~4
666
+ // if( get_bw(x0+dx/2,x0+dx/2,y1-dy/8,y1,box1->p,cs,1) == 0 ) Break; // ~4
667
+ // if( num_cross(x0+dx/2,x0+dx/2,y0 ,y1,box1->p,cs) < 2 ) Break;
668
+ // if( num_cross(x0+dx/4,x0+dx/4,y1-dy/2,y1,box1->p,cs) == 0 ) Break;
669
+ if( get_bw(dx/2,dx/2, 0,dy/6,bp,cs,1) == 0 ) Break; // ~4
670
+ if( get_bw(dx/2,dx-1, dy/6,dy/6,bp,cs,1) == 0 ) Break; // ~j
671
+ if( get_bw(dx/2,dx/2,dy-1-dy/8,dy-1,bp,cs,1) == 0 ) Break; // ~4
672
+ if( num_cross(dx/2,dx/2,0 ,dy-1,bp,cs) < 2 // normal
673
+ && num_cross(dx/3,dx/3,0 ,dy-1,bp,cs) < 2 ) Break; // fat LCD
674
+ if( num_cross(dx/4,dx/4,dy-1-dy/2,dy-1,bp,cs) == 0 ) Break;
675
+ if( loop(bp,dx/2, 0 ,dy,cs,0,DO)>dy/4 ) Break;
676
+ if( loop(bp,dx/2, dy-1,dy,cs,0,UP)>dy/4 ) Break;
677
+ if( loop(bp,dx-1, dy/3,dy,cs,0,LE)>dy/4 /* 3 with upper bow */
678
+ && loop(bp,dx-1, dy/8,dy,cs,0,LE)>dy/4 /* 3 with horizontal line */
679
+ && loop(bp,dx/4, dy/8,dy,cs,1,RI)<dy/2 ) Break;
680
+ if( loop(bp,dx-1,2*dy/3,dy,cs,0,LE)>dy/4 ) Break;
681
+ if( loop(bp,dx-1,3*dy/4,dy,cs,0,LE)>dy/2 ) Break; // ~2 Feb06
682
+ if( loop(bp,dx-1,7*dy/8,dy,cs,0,LE)>dy/2 ) Break; // ~2 Feb06
683
+ // search upper right half circle (may fail on 4x5 font)
684
+ for( i3=x=0,i1=y=dy/5;y<dy/2;y++ ){
685
+ i=loop(bp,0,y,dx,cs,0,RI);
686
+ if (i>x) { i3=x=i; i1=y; }
687
+ } i3--;
688
+ if( loop(bp,i3,i1,1,cs,0,UP)==1 ) { // find hidden gap in tiny fonts
689
+ i1--; i3+=loop(bp,i3,i1,dx,cs,0,RI)-1;
690
+ }
691
+ if (i3<dx/3 && i3+1+loop(bp,i3+1,i1,dx,cs,1,RI)<3*dx/4) Break;
692
+ if (loop(bp,dx-1,i1,dx,cs,0,LE)>1+dx/8) ad=ad*99/100; // ~1 with a pixel
693
+ // search lower right half circle
694
+ for( i4=x=0,i2=y=dy-1-dy/8;y>=dy/2;y-- ){
695
+ i=loop(bp,0,y,dx,cs,0,RI);
696
+ if( i>x ) { i4=x=i;i2=y; }
697
+ } i4--; if(i4<dx/3 && i4+1+loop(bp,i4+1,i2,dx,cs,1,RI)<3*dx/4) Break;
698
+ if (loop(bp,dx-1,i2,dx,cs,0,LE)>1+dx/8) ad=ad*99/100; // ~1 with a pixel
699
+
700
+ for( x=xa=0,ya=y=dy/4;y<3*dy/4;y++ ){ // right gap, not on LCD-font
701
+ i=loop(bp,dx-1,y,dx,cs,0,LE);
702
+ if (i>=xa) { xa=i;ya=y;x=xa+loop(bp,dx-1-xa,y,dx,cs,1,LE); }
703
+ } if (dy>3*dx) if (xa<2 && x-xa<dx/2) Break; // ~]
704
+ if (xa>1+dx/8 // noLCD
705
+ && xa<=loop(bp,dx-1,i2,dx,cs,0,LE)) ad=ad*99/100; // ~1 with a pixel
706
+ if (xa>1+dx/8 // noLCD
707
+ && xa<=loop(bp,dx-1,i1,dx,cs,0,LE)) ad=ad*99/100; // ~1 with a pixel
708
+
709
+ // upper left gap = (i3,i1)
710
+ // lower left gap = (i4,i2)
711
+ MSG(fprintf(stderr,"left white gaps (%d,%d) (%d,%d)",i3,i1,i4,i2);)
712
+ if( get_bw(i3,i3,i1,i2 ,bp,cs,1) != 1 ) Break; // no hor. middle line?
713
+ if( get_bw(i4,i4,i1,i2 ,bp,cs,1) != 1 ) Break;
714
+ if( get_bw(i3,i3,0 ,i1 ,bp,cs,1) != 1 ) Break; // no upper bow?
715
+ if( get_bw(i4,i4,i2,dy-1,bp,cs,1) != 1 ) Break; // no lower bow?
716
+ // hole is only allowed in beauty fonts
717
+ // if( num_hole( x0, x1, y0, y1,box1->p,cs,NULL) > 0 ) // there is no hole
718
+ // if( num_hole( x0, x0+dx/2, y0, y0+dy/2,box1->p,cs,NULL) == 0 ) // except in some beauty fonts
719
+ if (sdata->holes.num>0)
720
+ if (sdata->holes.hole[0].x1 >= dx/2 || sdata->holes.hole[0].y1 >= dy/2)
721
+ Break;
722
+ Setac(box1,(wchar_t)'3',ad);
723
+ if (ad==100) return '3';
724
+ break;
725
+ }
726
+ // --- test 4 --------------------------------------------------- 25Nov06
727
+ for(ad=d=100;dy>3 && dx>2;){ // min 3x4 ~<gA',
728
+ // rewritten for vectors 0.42
729
+ int ld, i1, i2, i3, i4, i5, i6, i7, i2up; // line derivation + corners
730
+ DBG( wchar_t c_ask='4'; )
731
+ if (sdata->holes.num > 1) Break; /* no or one hole */
732
+ /* half distance to the center */
733
+ d=2*sq(128/4); /* 2048 */
734
+ /* now we check for the lower left end, must be far away */
735
+ /* lowest is 144 for 9x10 screen font (Apr2009) */
736
+ if (aa[1][2]<d/16) { /* Apr09: d/8=256 to d/16=128 */
737
+ MSG( fprintf(stderr," low-left-dist= %d < max= %d", aa[1][2], d); )
738
+ Break; /* [2] = distance, ~ABDEF... */
739
+ }
740
+ /* searching for 4 notches between neighbouring ends */
741
+
742
+ /* 5x8 2010-10
743
+ type A B C D ...@.<-
744
+ ..@@.
745
+ 1 5 1 1 1 .@.@.<
746
+ O O O O5 O5 @..@. left=i2up
747
+ 2OO3 O 5 O O O O <- 7 6 @..@.
748
+ O 2O3O 2OO3 2OO3O @@@@@
749
+ 4 4 4 4 ...@.
750
+ ...@.<-
751
+
752
+
753
+ y4-y3 should be significant (bigger y3-y6)?
754
+ */
755
+
756
+ /* Warning: aa0 can be left upper or left lower point for type B */
757
+ /* get a point on the inner low left side of the J */
758
+ i =box1->num_frame_vectors[0] - 1;
759
+ /* leftmost upper point */
760
+ i1=nearest_frame_vector(box1, 0, i, x0, y0-dy);
761
+ /* lowest from leftmost vector can be very low (20/23) */
762
+ i2=nearest_frame_vector(box1, 0, i, x0-2*dx, (y0+7*y1)/8);
763
+ i2up=
764
+ nearest_frame_vector(box1, 0, i, x0-2*dx, (5*y0+3*y1)/8);
765
+ /* lowest vector */
766
+ i4=nearest_frame_vector(box1, 0, i, (x0+2*x1)/3, y1+dy);
767
+ /* right center crossing point */
768
+ i3=nearest_frame_vector(box1, i2, i4, x1, (3*y0+y1)/4);
769
+ /* get a point on the outer right side below top serif */
770
+ /* next local max_y-point after i4 */
771
+ i5=i4;
772
+ for (i=i4;i!=i2;i=(i+1)%box1->num_frame_vectors[0]) {
773
+ if (box1->frame_vector[ i][1]
774
+ <box1->frame_vector[i5][1]) i5=i; // get next maximum
775
+ if (box1->frame_vector[ i][1]
776
+ >box1->frame_vector[i5][1]+1) break; // break after maximum
777
+ if (box1->frame_vector[ i][0]<x0+dx/4) break; // type A B
778
+ }
779
+ if (box1->num_frames>1) { // type C D
780
+ i = box1->num_frame_vectors[0] - 1; // end outer loop
781
+ j = box1->num_frame_vectors[1] - 1; // end inner loop
782
+ if (box1->num_frames>2) { // see font2.png, 2nd one pixel hole
783
+ j = box1->num_frame_vectors[2] - 1; // end inner loop
784
+ ad=99*ad/100; // little bit unsure
785
+ }
786
+ i6=nearest_frame_vector(box1, i+1, j, x1, y1);
787
+ i7=nearest_frame_vector(box1, i+1, j, x0, y1);
788
+ if (box1->frame_vector[i1][0]
789
+ -box1->frame_vector[i2][0]<dx/4+1) ad=96*ad/100; // ~4x6q
790
+ i =nearest_frame_vector(box1, i+1, j, x0, y0); // top left
791
+ MSG(fprintf(stderr,"triangle type top-left i=%d",i);)
792
+ if (box1->frame_vector[i ][0]-x0<dx/4+1
793
+ && box1->frame_vector[i ][1]-y0<dy/4+1
794
+ && dx>7) ad=97*ad/100; // q
795
+
796
+ } else { // type A B
797
+ i6=nearest_frame_vector(box1, i5, i1, (x0+3*x1)/4, y1-dy/8);
798
+ i7=nearest_frame_vector(box1, i5, i1, x0 , y1-dy/8);
799
+ MSG(fprintf(stderr,"open type");)
800
+ if (box1->frame_vector[i6][1]-y0>3*dy/4
801
+ || box1->frame_vector[i7][1]-y0>3*dy/4) ad=96*ad/100; // ~uU
802
+ }
803
+ // ToDo: output no=(x,y)
804
+ MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d 2up %d",i1,i2,i3,i4,i5,i6,i7,i2up);)
805
+ if (i5==i6) Break; // ~+
806
+
807
+ if (box1->frame_vector[i1][1]>y0+dy/8) Break; // not to low
808
+ if (box1->frame_vector[i2][1]
809
+ -box1->frame_vector[i1][1]<dy/2) Break;
810
+ if (box1->frame_vector[i3][0]
811
+ -box1->frame_vector[i2][0]<dx/4) Break;
812
+ if (abs(box1->frame_vector[i3][1]
813
+ -box1->frame_vector[i2][1])>dy/4) Break;
814
+ if (box1->frame_vector[i2][0]>x0+dx/8) Break;
815
+ if (box1->frame_vector[i2][1]>y1-dy/8) Break;
816
+ if (box1->frame_vector[i4][1]
817
+ -box1->frame_vector[i2][1]<dy/8) Break;
818
+ if (box1->frame_vector[i4][1]
819
+ -box1->frame_vector[i2][1]<dy/6) ad=99*ad/100;
820
+ /* min. distance of the horizontal bar to the ground */
821
+ /* y4-y3 should be significant (bigger y3-y6)? */
822
+ if (box1->frame_vector[i4][1]
823
+ -box1->frame_vector[i3][1]<1+dy/16) Break;
824
+ if ((box1->frame_vector[i4][1]
825
+ -box1->frame_vector[i3][1])*2<=
826
+ (box1->frame_vector[i3][1]
827
+ -box1->frame_vector[i6][1])) Break; // 090728 gas_meter (flat-ulike)
828
+ if ((box1->frame_vector[i4][1]
829
+ -box1->frame_vector[i3][1])<
830
+ (box1->frame_vector[i3][1]
831
+ -box1->frame_vector[i6][1])) ad=99*ad/100;
832
+ if (box1->frame_vector[i4][1]
833
+ -box1->frame_vector[i3][1]<dy/6) ad=99*ad/100; /* tall chars */
834
+ if (box1->frame_vector[i4][1]
835
+ -box1->frame_vector[i3][1]<dy/8) ad=99*ad/100;
836
+ if (box1->frame_vector[i4][1]<y1-1-dy/8) Break;
837
+ if (box1->frame_vector[i3][0]<x0+dx/4) Break;
838
+ if (box1->frame_vector[i3][0]<x0+dx/2) ad=98*ad/100;
839
+ /* on very tall chars the i3 point can be near to the groundline */
840
+ if (box1->frame_vector[i3][1]>y1-1) Break;
841
+ if (box1->frame_vector[i3][1]>y1-dy/16) Break;
842
+ if (box1->frame_vector[i3][1]>=y1) Break; // ~5x5#
843
+ if (box1->frame_vector[i5][0]<x0+dx/3) Break;
844
+ /* upper end of right vertical line */
845
+ if (box1->frame_vector[i5][1]>y0+2*dy/3) Break;
846
+ if (box1->frame_vector[i6][1]
847
+ -box1->frame_vector[i5][1]<1+dy/16) Break;
848
+ if (box1->frame_vector[i6][0]<x0+dx/3) Break;
849
+ if (box1->frame_vector[i7][0]>x0+dx/2) Break;
850
+ if (box1->frame_vector[i7][0]>x0+dx/3) ad=ad*99/100;
851
+ if (box1->frame_vector[i6][1]<y0+dy/3) Break;
852
+ if (box1->frame_vector[i6][0]<x0+dx/2) ad=96*ad/100; // ~ 42
853
+ if (box1->frame_vector[i6][0]<aa[2][0]-dx/2
854
+ && aa[2][1]>=y1-1-dy/8) ad=96*ad/100; // ~ 42
855
+ if (box1->frame_vector[i7][1]<y0+dy/3) Break;
856
+ if (abs(box1->frame_vector[i3][1]
857
+ -box1->frame_vector[i2][1])>dy/4) Break;
858
+
859
+ /* check if upper left and lower left points are joined directly */
860
+ ld=line_deviation(box1, i1, i2up);
861
+ MSG(fprintf(stderr,"i1-i2up %d %d dist= %d/%d",i1,i2up,ld,2*sq(1024/4));)
862
+ if (ld >2*sq(1024/4)) Break;
863
+ if (i2!=i2up) ld=line_deviation(box1, i2up, i2); else ld=0;
864
+ MSG(fprintf(stderr,"i2up-i2 %d %d dist= %d/%d",i2up,i2,ld,2*sq(1024/4));)
865
+ if (ld >2*sq(1024/4)) Break;
866
+ /* check if lower right and upper right points are joined directly */
867
+ ld=line_deviation(box1, i2, i3);
868
+ MSG(fprintf(stderr,"i2-i3 %d %d dist= %d/%d",i2,i3,ld,2*sq(1024/4));)
869
+ if (ld > sq(1024/4)) Break;
870
+ /* check if lower right and upper right points are joined directly */
871
+ ld=line_deviation(box1, i3, i4);
872
+ MSG(fprintf(stderr,"i3-i4 %d %d dist= %d/%d",i3,i4,ld,2*sq(1024/4));)
873
+ if (ld > sq(1024/4)) Break;
874
+ /* check if lower right and upper right points are joined directly */
875
+ ld=line_deviation(box1, i6, i7);
876
+ MSG(fprintf(stderr,"i6-i7 %d %d dist= %d/%d",i6,i7,ld,2*sq(1024/4));)
877
+ if (ld >2*sq(1024/4)) Break;
878
+
879
+ // handwritten a i1=(9,0) i5=(21,1) Aug2010
880
+ if (sdata->holes.num == 1 // type C and D against italic a, alpha
881
+ && // expect no distance between 1 and 5
882
+ box1->frame_vector[i5][0]
883
+ - box1->frame_vector[i1][0] > dx/4 ) Break;
884
+
885
+ // 4 exists as gchar and ~gchar
886
+ if(!hchar){ ad=99*ad/100; }
887
+ Setac(box1,'4',ad);
888
+ break;
889
+ }
890
+ #ifdef Old_pixel_based
891
+ // --- old test 4 pixelbased ------- remove!
892
+ for(ad=d=100;dx>3 && dy>5;){ // dy>dx, min 4x6 font
893
+ DBG( char c_ask='4'; )
894
+ if (sdata->holes.num > 2) Break; /* be tolerant */
895
+ if (sdata->holes.num > 1) ad=97*ad/100;
896
+ // upper raising or vertical line
897
+ if( loop(bp,0 ,3*dy/16,dx,cs,0,RI)
898
+ < loop(bp,0 ,2*dy/4 ,dx,cs,0,RI)-dx/8 ) Break;
899
+ // search for a vertical line on lower end
900
+ for (y=0;y<dy/4;y++)
901
+ if( loop(bp,0 ,dy-1-y,dx,cs,0,RI)
902
+ + loop(bp,dx-1,dy-1-y,dx,cs,0,LE) >= dx/2 ) break;
903
+ if (y>=dy/4) Break;
904
+ if( loop(bp,0 ,dy-1-dy/8,dx,cs,0,RI) < dx/4 ) Break;
905
+ // --- follow line from (1,0) to (0,.7)
906
+ y=0; x=loop(bp,0,0,dx,cs,0,RI);
907
+ if (x<=dx/4) { // ocr-a-4
908
+ i=loop(bp,0,dy/4,dx,cs,0,RI); if (i>dx/4) Break;
909
+ i=loop(bp,i,dy/4,dx,cs,1,RI); if (i>dx/2) Break;
910
+ j=loop(bp,i,dy/4,dy,cs,0,DO)+dy/4; if (j>7*dy/8) Break;
911
+ }
912
+ turmite(bp,&x,&y,0,dx-1,0,dy-1,cs,DO,LE); if( x>=0 ) Break;
913
+
914
+ y=loop(bp,0,0,dy,cs,0,DO);
915
+ if( (y+loop(bp,0,y,dy,cs,1,DO)) < dy/2 ) Break;
916
+ if( get_bw(x0 , x0+3*dx/8, y1-dy/7, y1-dy/7,box1->p,cs,1) == 1 ) Break;
917
+ if( get_bw(x0+dx/2, x1 , y1-dy/3, y1-dy/3,box1->p,cs,1) != 1 ) Break;
918
+ if( get_bw(x0+dx/2, x0+dx/2, y0+dy/3, y1-dy/5,box1->p,cs,1) != 1 ) Break;
919
+ i=loop(bp,bp->x-1, bp->y/4,dx,cs,0,LE);
920
+ if( i > loop(bp,bp->x-1,2*bp->y/4,dx,cs,0,LE)+1
921
+ && i > loop(bp,bp->x-1,3*bp->y/8,dx,cs,0,LE)+1 ) Break;
922
+ if (loop(bp,0,0,dx,cs,0,RI)>dx/4) {
923
+ for(i=dx/8+1,x=0;x<dx && i;x++){
924
+ if( num_cross(x ,x ,0 ,dy-1, bp,cs) == 2 ) i--;
925
+ } if( i ) Break;
926
+ }
927
+ for(i=dy/6+1,y=dy/4;y<dy && i;y++){
928
+ if( num_cross(0 ,dx-1,y ,y , bp,cs) == 2 ) i--;
929
+ } if( dy>15 && i ) Break;
930
+ for(i=dy/10+1,y=dy-1-dy/4;y<dy && i;y++){
931
+ if( num_cross(0 ,dx-1,y ,y , bp,cs) == 1 )
932
+ if( num_cross(dx/2,dx-1,y ,y , bp,cs) == 1 ) i--;
933
+ } if( i ) Break;
934
+ // i4 = num_hole ( x0, x1, y0, y1,box1->p,cs,NULL);
935
+ // ToDo:
936
+ // - get start and endpoint of left edge of left vert. line
937
+ // and check if that is an streight line
938
+ // - check the right edge of the inner hole (if there) too
939
+ i4 = sdata->holes.num;
940
+ if (sdata->holes.num >0) { // ~q
941
+ i = loop(bp,0,dy/16,dx,cs,0,RI);
942
+ if (i < dx/3) Break;
943
+ if (i < dx/2) ad=98*ad/100; // hole?
944
+ if ( loop(bp, 0,dy-1,dy,cs,0,UP)
945
+ -loop(bp,dx/8+1,dy-1,dy,cs,0,UP)>dy/16) ad=97*ad/100;
946
+ }
947
+ // thickness of left vertical line
948
+ for (j=y=0;y<dy/6;y++) {
949
+ i=loop(bp,dx-1 ,y,dx,cs,0,LE);
950
+ i=loop(bp,dx-1-i,y,dx,cs,1,LE); if (i>j) j=i;
951
+ }
952
+ if (j>=dx/2) ad=98*ad/100; // ~q handwritten a (or very thinn 4)
953
+ // ToDo: check y of masscenter of the hole q4
954
+
955
+ if( i4 ) if( dx > 15 )
956
+ if( loop(bp, dx/2, 0,dy,cs,0,DO)<dy/16
957
+ && loop(bp, dx/4, 0,dy,cs,0,DO)<dy/8
958
+ && loop(bp,3*dx/4, 0,dy,cs,0,DO)<dy/8
959
+ && loop(bp, dx/4,dy-1,dy,cs,0,UP)<dy/8
960
+ && loop(bp, dx/2,dy-1,dy,cs,0,UP)<dy/8
961
+ && loop(bp,3*dx/4,dy-1,dy,cs,0,UP)<dy/4 ) Break; // ~9
962
+
963
+ i =loop(bp,dx-1 ,dy-1,dx,cs,0,LE); // ~9
964
+ i+=loop(bp,dx-1-i,dy-1,dx,cs,1,LE);
965
+ if( i>3*dx/4
966
+ && i-loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE)>dx/4 ) Break;
967
+
968
+ i =loop(bp,dx-1-dx/4,dy-1,dx,cs,0,UP);
969
+ if (i> dy/2) ad=97*ad/100;
970
+ if (i>3*dy/4) ad=97*ad/100; /* handwritten n */
971
+
972
+ if( num_cross(0 ,dx-1,dy/16 ,dy/16 , bp,cs) == 2 // ~9
973
+ && loop(bp,dx-1,dy/16 ,dx,cs,0,LE)>
974
+ loop(bp,dx-1,dy/16+1+dy/32,dx,cs,0,LE) ) Break;
975
+ if ( !hchar) ad=99*ad/100;
976
+ if (gchar && !hchar) ad=98*ad/100; // ~q
977
+ Setac(box1,(wchar_t)'4',ad);
978
+ if (ad>99) bc='4';
979
+ break;
980
+ }
981
+ #endif
982
+ // --- test 6 ------- ocr-a-6 looks like a b :(
983
+ for(ad=d=100;dx>3 && dy>4;){ // dy>dx
984
+ DBG( char c_ask='6'; )
985
+ if (sdata->holes.num > 2) Break; /* be tolerant */
986
+ if( loop(bp, 0, dy/4,dx,cs,0,RI)>dx/2 // ocr-a=6
987
+ && loop(bp,dx-1, 0,dy,cs,0,DO)>dy/4 ) Break; // italic-6
988
+ if( loop(bp, 0, dy/2,dx,cs,0,RI)>dx/4 ) Break;
989
+ if( loop(bp, 0,3*dy/4,dx,cs,0,RI)>dx/4 ) Break;
990
+ if( loop(bp,dx-1,3*dy/4,dx,cs,0,LE)>dx/2 ) Break;
991
+ if( num_cross(x0+ dx/2,x0+ dx/2,y0 ,y1 ,box1->p,cs) != 3
992
+ && num_cross(x0+5*dx/8,x0+5*dx/8,y0 ,y1 ,box1->p,cs) != 3 ) {
993
+ if( num_cross(x0+ dx/2,x0+ dx/2,y0+dy/4,y1 ,box1->p,cs) != 2
994
+ && num_cross(x0+5*dx/8,x0+5*dx/8,y0+dy/4,y1 ,box1->p,cs) != 2 ) Break;
995
+ // here we have the problem to decide between ocr-a-6 and b
996
+ if ( loop(box1->p,(x0+x1)/2,y0,dy,cs,0,DO)<dy/2 ) Break;
997
+ ad=99*ad/100;
998
+ } else {
999
+ if (loop(box1->p,x0+dx/2,y0,dx,cs,0,DO)>dy/8
1000
+ && loop(box1->p,x1-dx/4,y0,dx,cs,0,DO)>dy/8 ) Break;
1001
+ }
1002
+ if( num_cross(x0 ,x1 ,y1-dy/4,y1-dy/4,box1->p,cs) != 2 ) Break;
1003
+ for( y=y0+dy/6;y<y0+dy/2;y++ ){
1004
+ x =loop(box1->p,x1 ,y ,dx,cs,0,LE); if( x>dx/2 ) break;
1005
+ x+=loop(box1->p,x1-x+1,y-1,dx,cs,0,LE); if( x>dx/2 ) break;
1006
+ } if( y>=y0+dy/2 ) Break;
1007
+ if (loop(box1->p,x0,y1-dy/3,dx,cs,0,RI)>dx/4 ) Break;
1008
+ if (loop(box1->p,x1,y1-dy/3,dx,cs,0,LE)>dx/4 ) Break;
1009
+
1010
+ if (sdata->holes.num != 1) Break;
1011
+ if (sdata->holes.hole[0].y1 < dy/2) ad=95*ad/100; // whats good for?
1012
+ if (sdata->holes.hole[0].y0 < dy/4) Break;
1013
+ MSG( fprintf(stderr,"hole[0].x0,x1 %d %d", sdata->holes.hole[0].x0,
1014
+ sdata->holes.hole[0].x1); )
1015
+ if (sdata->holes.hole[0].x0<1
1016
+ && dx-1-sdata->holes.hole[0].x1>2) ad=ad*99/100; // melted serif sS ?
1017
+ if (loop(box1->p,x0,y0+dy/2,dx,cs,0,RI)>0
1018
+ && loop(box1->p,x0,y0+dy/4,dx,cs,0,RI)==0
1019
+ && loop(box1->p,x0,y1-dy/4,dx,cs,0,RI)==0) ad=97*ad/100; // molten serif sS
1020
+ // if( num_hole ( x0, x1, y0, y0+dy/2,box1->p,cs,NULL) > 0 ) ad=95*ad/100;
1021
+ // if( num_hole ( x0, x1, y0+dy/4, y1,box1->p,cs,NULL) != 1 ) Break;
1022
+ // if( num_hole ( x0, x1, y0 , y1,box1->p,cs,NULL) != 1 ) Break;
1023
+ // out_x(box1); printf(" x0 y0 %d %d\n",x0,y0);
1024
+ /* check left vertical bow */
1025
+ i1=loop(bp,0,dy/8 ,dx,cs,0,RI);
1026
+ i3=loop(bp,0,dy-1-dy/8,dx,cs,0,RI);
1027
+ i2=loop(bp,0,dy/2 ,dx,cs,0,RI);
1028
+ if(i1+i3-2*i2<-2-dx/16 && i1+i2+i3>0) Break; // convex from left
1029
+ if(i1+i3-2*i2<1 && i1+i2+i3>0) ad=99*ad/100; // 7-segment-font
1030
+ for( x=dx,y=0;y<dy/4;y++ ){ // ~ b (serife?)
1031
+ i1=loop(bp, 0,y,dx,cs,0,RI);
1032
+ i2=loop(bp,i1,y,dx,cs,1,RI);
1033
+ if (i2+i1>dx/2 && i2>dx/4) break; /* its a 6 (example: 7-segment) */
1034
+ if (i1<x) x=i1; else if (i1>x) break; /* may be serifen b */
1035
+ } if (y<dy/4 && i1+i2<=dx/2) Break;
1036
+ // ~& (with open upper loop)
1037
+ for( i=0,y=dy/2;y<dy;y++){
1038
+ if( num_cross(dx/2,dx-1,y,y,bp,cs) > 1 ) i++; if( i>dy/8 ) break;
1039
+ } if( y<dy ) Break;
1040
+ if ( gchar) ad=99*ad/100;
1041
+ if (!hchar) ad=98*ad/100;
1042
+ if ( box1->dots ) ad=98*ad/100;
1043
+ Setac(box1,(wchar_t)'6',ad);
1044
+ bc='6';
1045
+ break;
1046
+ }
1047
+ // --- test 7 ---------------------------------------------------
1048
+ for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx
1049
+ DBG( char c_ask='7'; )
1050
+ if (sdata->holes.num > 1) Break; /* be tolerant */
1051
+ if( loop(bp,dx/2,0,dy,cs,0,DO)>dy/8 ) Break;
1052
+ if( num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs) != 1 ) Break; // preselect
1053
+ for( yb=xb=y=0;y<dy/2;y++){ // upper h-line and gap
1054
+ j=loop(bp,0,y,dx,cs,0,RI);if(xb>0 && j>dx/4) break; // gap after h-line
1055
+ j=loop(bp,j,y,dx,cs,1,RI);if(j>xb){ xb=j;yb=y; } // h-line
1056
+ } if( xb<dx/4 || y==dy/2 ) Break;
1057
+ j=loop(bp,0,dy/2,dx,cs,0,RI);
1058
+ j=loop(bp,j,dy/2,dx,cs,1,RI); if(xb<2*j) Break; // minimum thickness
1059
+ for(x=0,y+=dy/16;y<dy;y++){ // one v-line?
1060
+ if( num_cross(0,dx-1,y,y,bp,cs) != 1 ) break;
1061
+ j=loop(bp,dx-1,y,dx,cs,0,LE); if( j<x ) break; if( j-1>x ) x=j-1;
1062
+ } if( y<dy || x<dx/3 ) {
1063
+ MSG( fprintf(stderr,"xy= %d %d",x,y); )
1064
+ Break;
1065
+ }
1066
+ j =loop(bp,dx-1,0,dy,cs,0,DO); // ~T
1067
+ j+=loop(bp,dx-1,j,dy,cs,1,DO)+dy/16;
1068
+ i =loop(bp,dx-1,j,dx,cs,0,LE); if(j<dy/2) {
1069
+ if (i>j) Break;
1070
+ j=loop(bp, 0,j,dx,cs,0,RI);
1071
+ if(j>dx/4 && j<=i+dx/16) Break; // tall T
1072
+ }
1073
+
1074
+ MSG( fprintf(stderr,"7: ad= %d",ad); )
1075
+ if( loop(bp, 0,3*dy/8,dx,cs,0,RI)
1076
+ <=loop(bp,dx-1,3*dy/8,dx,cs,0,LE)+dx/8 ) ad=ad*98/100; // l
1077
+ MSG( fprintf(stderr,"7: ad= %d",ad); )
1078
+ if( num_cross(0,dx-1,dy/4,dy/4,bp,cs) == 1
1079
+ && loop(bp,0,dy/4,dx,cs,0,RI) < dx/2 ) ad=ad*96/100; // J
1080
+ MSG( fprintf(stderr,"7: ad= %d",ad); )
1081
+
1082
+ if (box1->m3 && dy<box1->m3-box1->m2) ad=99*ad/100; // too small
1083
+ if (box1->m3 && 2*dy<box1->m3-box1->m2) ad=96*ad/100; // too small
1084
+ if (dy>3*dx) ad=99*ad/100; // )
1085
+ if ( gchar) ad=99*ad/100; // J
1086
+ if (!hchar) ad=99*ad/100;
1087
+ Setac(box1,(wchar_t)'7',ad);
1088
+ break;
1089
+ }
1090
+ // --- test 8 ---------------------------------------------------
1091
+ // last change: May15th,2000 JS
1092
+ for(ad=d=100;dx>2 && dy>4;){ // or we need large height
1093
+ DBG( char c_ask='8'; )
1094
+ if (sdata->holes.num != 2) Break;
1095
+ if( num_cross(x0,x1,y0 +dy/4,y0 +dy/4,box1->p,cs) != 2 ) Break; // ~gr (glued)
1096
+ if( num_cross(x0,x1,y1 -dy/4,y1 -dy/4,box1->p,cs) != 2
1097
+ && num_cross(x0,x1,y1-3*dy/8,y1-3*dy/8,box1->p,cs) != 2 ) Break;
1098
+ if( get_bw(x0,x0+dx/4,y1-dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break; // ~9
1099
+ if( get_bw(x0,x0+dx/2,y0+dy/4,y0+dy/4,box1->p,cs,1) == 0 ) Break;
1100
+ if( get_bw(x0+dx/2,x0+dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break; // ~0
1101
+ // MSG( printf(" x0 y0 %d %d\n",x0,y0); )
1102
+ for( i2=i1=x=0,i=y=y0+dy/3;y<=y1-dy/3;y++){ // check left middle nick
1103
+ j=loop(box1->p,x0,y,dx,cs,0,RI);
1104
+ if (j>x || (abs(j-x)<=dx/8 /* care about MICR E-13B font */
1105
+ && (i1=loop(box1->p,x0+j,y,dx,cs,1,RI))>dx/2)) {
1106
+ if (j>x) x=j; i=y; if (i1>i2) i2=i1; }
1107
+ } if(i>=y1-dy/3 || (x<dx/8 && i2<=dx/2) || x>dx/2) Break; // no gB
1108
+ if (x< dx/4) ad=99*ad/100; // no B
1109
+ if (x<=dx/8) ad=98*ad/100; // no B
1110
+ j = loop(box1->p,x1,y1- dy/4,dx,cs,0,LE);
1111
+ if( j>loop(box1->p,x1,y1- dy/5,dx,cs,0,LE)
1112
+ && j>loop(box1->p,x1,y1-2*dy/5,dx,cs,0,LE) ) Break; // &
1113
+ // check for upper hole
1114
+ for (j=0;j<sdata->holes.num;j++) {
1115
+ if (sdata->holes.hole[j].y1 < i-y0+1 ) break;
1116
+ if (sdata->holes.hole[j].y1 < i-y0+dy/8) break;
1117
+ } if (j==sdata->holes.num) Break; // not found
1118
+ // if( num_hole(x0,x1,y0,i+1 ,box1->p,cs,NULL)!=1 )
1119
+ // if( num_hole(x0,x1,y0,i+dy/8,box1->p,cs,NULL)!=1 ) Break; // upper hole
1120
+ // check for lower hole
1121
+ for (j=0;j<sdata->holes.num;j++) {
1122
+ if (sdata->holes.hole[j].y0 > i-y0-1 ) break;
1123
+ } if (j==sdata->holes.num) Break; // not found
1124
+ // if( num_hole(x0,x1,i-1,y1,box1->p,cs,NULL)!=1 ) Break;
1125
+ i1=i; // left middle nick
1126
+ /* find the middle right nick */
1127
+ for( x=0,i2=i=y=y0+dy/3;y<=y1-dy/3;y++){
1128
+ j=loop(box1->p,x1,y,dx,cs,0,LE); if( j>=x ) i2=y;
1129
+ /* we care also for 7-segment and unusual fonts */
1130
+ if (j>x || (abs(j-x)<=(dx+4)/8
1131
+ && loop(box1->p,x1-j,y,dx,cs,1,LE)>dx/2)){
1132
+ if (j>x) x=j; i=y; }
1133
+ // MSG(fprintf(stderr," yjix %d %d %d %d %d %d",y-y0,j,i-y0,x,loop(box1->p,x1-j,y,dx,cs,1,LE),dx/2);)
1134
+ }
1135
+ if( i>y0+dy/2+dy/10 ) Break;
1136
+ // if( x<dx/8 ) Break;
1137
+ if( x>dx/2 ) Break;
1138
+ MSG(fprintf(stderr,"center bar at y= %d %d x=%d+%d i1=%d",i-y0,i2-y0,x,j,i1);)
1139
+ if( num_cross(x0,x1, i , i ,box1->p,cs) != 1
1140
+ && num_cross(x0,x1, i+1 , i+1 ,box1->p,cs) != 1
1141
+ && num_cross(x0,x1,(i+i2)/2,(i+i2)/2,box1->p,cs) != 1 ) Break; // no g
1142
+ if(abs(i1-i)>(dy+5)/10) ad=99*ad/100; // y-distance right-left-nick
1143
+ if(abs(i1-i)>(dy+4)/8) ad=99*ad/100; // y-distance right-left-nick
1144
+ if(abs(i1-i)>(dy+2)/4) Break;
1145
+ // ~B ff
1146
+ for(i=dx,y=0;y<dy/8+2;y++){
1147
+ j=loop(bp,0,y,dx,cs,0,RI); if( j<i ) i=j; if( j>i+dx/16 ) break;
1148
+ } if( y<dy/8+2 ) Break;
1149
+ for(i=dx,y=0;y<dy/8+2;y++){
1150
+ j=loop(bp,0,dy-1-y,dx,cs,0,RI);
1151
+ if( j<i ) i=j; if( j>i+dx/16 ) break;
1152
+ } if( y<dy/8+2 ) Break;
1153
+ if( dy>16 && num_cross(0,dx-1,dy-1,dy-1,bp,cs) > 1
1154
+ && loop(bp,0,dy-1,dx,cs,0,RI) <dx/8+1 ) Break; // no fat serif S
1155
+ for( i=0,y=dy/2;y<dy;y++){
1156
+ if( num_cross(0,dx-1,y,y,bp,cs) > 2 ) i++; if( i>dy/8 ) break;
1157
+ } if( y<dy ) Break;
1158
+ if ( loop(bp,dx-1,0,dx,cs,0,LE)==0 ) ad=99*ad/100;
1159
+ if (num_cross( 0,dx-1,dy-1,dy-1,bp,cs) > 1) ad=98*ad/100; // &
1160
+ if (num_cross(dx-1,dx-1,dy/2,dy-1,bp,cs) > 1) ad=98*ad/100; // &
1161
+ if (num_cross( 0,dx-1, 0, 0,bp,cs) > 1) ad=98*ad/100;
1162
+ if (dy>15)
1163
+ if (num_cross( 0,dx-1, 1, 1,bp,cs) > 1) ad=98*ad/100;
1164
+ /* if m1..4 is unsure ignore hchar and gchar ~ga */
1165
+ if (!hchar) {
1166
+ if ((box1->m2-box1->y0)*8>=dy) ad=98*ad/100;
1167
+ else ad=99*ad/100;
1168
+ }
1169
+ if ( gchar
1170
+ && (box1->y1-box1->m3)*8>=dy) ad=99*ad/100;
1171
+ Setac(box1,(wchar_t)'8',ad);
1172
+ break;
1173
+ }
1174
+ // --- test 9 \it g ---------------------------------------------------
1175
+ /*
1176
+ *
1177
+ * lcd micr round
1178
+ * ooo ooo ooo
1179
+ * o o o o o o
1180
+ * ooo ooo ooo
1181
+ * o o o
1182
+ * ooo o o
1183
+ */
1184
+ for(ad=d=100;dx>2 && dy>4;){ // dx>1 dy>2*dx
1185
+ DBG( char c_ask='9'; )
1186
+ if (sdata->holes.num > 1) Break;
1187
+ if( num_cross(x0+ dx/2,x0+ dx/2,y0,y1-dy/4,box1->p,cs) != 2 // pre select
1188
+ && num_cross(x0+ dx/2,x0+ dx/2,y0, y1,box1->p,cs) != 3 // pre select
1189
+ && num_cross(x0+3*dx/8,x0+3*dx/8,y0,y1,box1->p,cs) != 3
1190
+ && num_cross(x0+ dx/4,x1 -dx/4,y0,y1,box1->p,cs) != 3 ) Break;
1191
+ if( num_cross(x0+ dx/2,x0 +dx/2,y0,y0+dy/4,box1->p,cs) < 1 ) Break;
1192
+ if( num_cross(x0+ dx/2,x1, y0+dy/2 ,y0+dy/2,box1->p,cs) < 1 ) Break;
1193
+ if( num_cross(x0,x1, y0+ dy/4 ,y0+ dy/4,box1->p,cs) != 2
1194
+ && num_cross(x0,x1, y0+3*dy/8 ,y0+3*dy/8,box1->p,cs) != 2 ) Break;
1195
+ if( num_cross(x1-dx/8,x1,y0+dy/4,y0+dy/4,box1->p,cs) == 0) ad=ad*97/100; // ~4
1196
+ for( x=0,i=y=y0+dy/2;y<=y1-dy/4;y++){ // find notch (suche kerbe)
1197
+ j=loop(box1->p,x0,y,dx,cs,0,RI);
1198
+ if( j>x ) { x=j; i=y; }
1199
+ } if (x<1 || x<dx/8) Break; y=i;
1200
+ // fprintf(stderr," debug 9: %d %d\n",x,i-y0);
1201
+ if( x<dx/2 ) { /* big bow? */
1202
+ j=loop(box1->p,x0+x-1,y,dy/8+1,cs,0,DO)/2; y=i=y+j;
1203
+ j=loop(box1->p,x0+x-1,y,dx/2 ,cs,0,RI); x+=j;
1204
+ if (x<dx/2) Break;
1205
+ }
1206
+ // check for the right lower bow
1207
+ MSG( fprintf(stderr,"bow-y0= %d",i-y0); )
1208
+ if (dx>5)
1209
+ if( num_cross(x0+dx/2,x1,i,y1 ,box1->p,cs) != 1 /* fails on 5x8 */
1210
+ && num_cross(x0+dx/2,x1,i,y1-dy/8,box1->p,cs) != 1 ) Break;
1211
+ if( num_cross(x0+dx/2,x0+dx/2,i,y1,box1->p,cs) > 1 ) Break;
1212
+ if( num_cross(x0+dx/2,x1 ,i, i,box1->p,cs) != 1 ) Break;
1213
+
1214
+ if (sdata->holes.num < 1) { /* happens for 5x7 font */
1215
+ if (dx<8) ad=98*ad/100; else Break; }
1216
+ else {
1217
+ if (sdata->holes.hole[0].y1 >= i+1) Break;
1218
+ if (sdata->holes.hole[0].y0 > i-1) Break;
1219
+ if (sdata->holes.num > 1)
1220
+ if (sdata->holes.hole[1].y0 > i-1) Break;
1221
+ // if( num_hole(x0,x1,y0,i+1,box1->p,cs,NULL)!=1 ) Break;
1222
+ // if( num_hole(x0,x1,i-1,y1,box1->p,cs,NULL)!=0 ) Break;
1223
+ }
1224
+ if( loop(box1->p,x0,y1 ,dy,cs,0,RI)>dx/3 &&
1225
+ loop(box1->p,x0,y1-1,dy,cs,0,RI)>dx/3
1226
+ && (box1->m3==0 || (box1->m3!=0 && (!hchar || gchar)))) ad=98*ad/100; // no q OR ocr-a-9
1227
+ for( x=0,i=y=y0+dy/3;y<=y1-dy/3;y++){ // suche kerbe
1228
+ j=loop(box1->p,x1,y,dx,cs,0,LE);
1229
+ if( j>x ) { x=j; i=y; }
1230
+ } if( x>dx/2 ) Break; // no g
1231
+ i1=loop(bp,dx-1,dy/8 ,dx,cs,0,LE); if(i1>dx/2) Break;
1232
+ i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE);
1233
+ i2=loop(bp,dx-1,dy/2 ,dx,cs,0,LE); if(i1+i3-2*i2<-1-dx/16) Break; // konvex
1234
+ i1=loop(bp,dx-1,dy/4 ,dx,cs,0,LE); if(i1>dx/2) Break;
1235
+ i3=loop(bp,dx-1,dy-1-dy/8,dx,cs,0,LE);
1236
+ for(y=dy/4;y<dy-1-dy/4;y++){ // may fail on type=round
1237
+ i2=loop(bp,dx-1,y,dx,cs,0,LE);
1238
+ // konvex from right ~g ~3 Jul09
1239
+ if(i2>i1+(i3-i1)*(2*y-dy/2)/dy+dx/16) break;
1240
+ // MSG(fprintf(stderr," y i2 %d %d %d",y,i2,i1+(i3-i1)*(2*y-dy/2)/dy);)
1241
+ } if(y<dy-1-dy/4) Break;
1242
+ x=loop(bp,dx -1,6*dy/8,dx,cs,0,LE); if(x>0){
1243
+ x--; // robust
1244
+ y=loop(bp,dx-x-1, dy-1,dy,cs,0,UP);
1245
+ if(y<dy/8) Break; // ~q (serif!)
1246
+ }
1247
+ // check for agglutinated serif y
1248
+ if (dy>=16 && dx>9
1249
+ && loop(bp, 0,dy/ 4,dx,cs,0,RI)
1250
+ -loop(bp, 0,dy/16,dx,cs,0,RI)>dx/6
1251
+ && loop(bp,dx-1,dy/ 4,dx,cs,0,LE)
1252
+ -loop(bp,dx-1,dy/16,dx,cs,0,LE)>dx/6) Break; // ~ serif yY
1253
+
1254
+ if (box1->m3) {
1255
+ if ( gchar) ad=99*ad/100; /* unsure (italic g)? */
1256
+ if (box1->m2 && (!gchar) && y1 > box1->m3){
1257
+ ad=99*ad/100;
1258
+ if (box1->m4-box1->m3<3) ad=99*ad/100;
1259
+ // if (!hchar) ad = 99*ad/100;
1260
+ }
1261
+ if (!hchar) ad=99*ad/100; /* unsure */
1262
+ } else { if (ad==100) ad=99; } /* not 100% sure */
1263
+ Setac(box1,(wchar_t)'9',ad);
1264
+ break;
1265
+ }
1266
+ // 0 is same as O !?
1267
+ // --- test 0 (with one big hole in it ) -----------------------------
1268
+ for(d=ad=100;dx>2 && dy>3;){ // min 3x4
1269
+ DBG( char c_ask='0'; )
1270
+ if (sdata->holes.num > 1) Break; /* be tolerant */
1271
+ if( get_bw(x0 , x0+dx/3,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1272
+ if( get_bw(x1-dx/3 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1273
+ /* could be an O, unless we find a dot in the center */
1274
+ if( get_bw(x0 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 3 ) ad=99;
1275
+ if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/3 , y1,box1->p,cs,1) != 1 ) Break;
1276
+ if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/3,box1->p,cs,1) != 1 ) Break;
1277
+ /* accept 0 with dot in center, accept \/0 too ... */
1278
+ if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 0 ) Break;
1279
+
1280
+ if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 2 ) Break;
1281
+ if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND
1282
+ if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
1283
+ if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen"
1284
+ if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 1 ) Break;
1285
+ if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1286
+ if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1287
+ if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1288
+ if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1289
+ // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 1 ) Break;
1290
+ if (sdata->holes.num != 1) Break;
1291
+
1292
+ i= loop(bp,0 ,0 ,x1-x0,cs,0,RI)-
1293
+ loop(bp,0 ,2 ,x1-x0,cs,0,RI);
1294
+ if (i<0) Break;
1295
+ if (i==0) {
1296
+ if (loop(bp,dx-1,0 ,x1-x0,cs,0,LE)>
1297
+ loop(bp,dx-1,2 ,x1-x0,cs,0,LE) ) ad=98*ad/100;
1298
+ ad=99*ad/100; /* LCD-type? */
1299
+ }
1300
+
1301
+ x=loop(bp,dx-1,dy-1-dy/3,x1-x0,cs,0,LE); // should be minimum
1302
+ for (y=dy-1-dy/3;y<dy;y++){
1303
+ i=loop(bp,dx-1,y,x1-x0,cs,0,LE);
1304
+ if (i<x-dx/16-1) break; if (i>x) x=i;
1305
+ }
1306
+ if( y<dy ) Break;
1307
+
1308
+ // ~D (but ocr-a-font)
1309
+ i= loop(bp, 0, dy/16,dx,cs,0,RI)
1310
+ + loop(bp, 0,dy-1-dy/16,dx,cs,0,RI)
1311
+ - 2*loop(bp, 0, dy/2 ,dx,cs,0,RI);
1312
+ j= loop(bp,dx-1, dy/16,dx,cs,0,LE)
1313
+ + loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)
1314
+ <= 2*loop(bp,dx-1, dy/2 ,dx,cs,0,LE);
1315
+ if (i<-dx/8 || i+dx/8<j) Break; // not konvex
1316
+
1317
+ if( loop(bp,dx-1, dy/16,dx,cs,0,LE)>dx/8 )
1318
+ if( loop(bp,0 , dy/16,dx,cs,0,RI)<dx/16 ) Break;
1319
+ if( loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/8 )
1320
+ if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)<dx/16 ) Break;
1321
+ if( get_bw(x1-dx/32,x1,y0,y0+dy/32,box1->p,cs,1) == 0
1322
+ && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0
1323
+ && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1
1324
+ || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) {
1325
+ if (dx<32) ad=ad*99/100; else Break; // ~D
1326
+ }
1327
+
1328
+ // search lowest inner white point
1329
+ for(y=dy,j=x=0;x<dx;x++) {
1330
+ i =loop(bp,x,dy-1 ,y1-y0,cs,0,UP);
1331
+ i+=loop(bp,x,dy-1-i,y1-y0,cs,1,UP);
1332
+ if (i<=y) { y=i; j=x; }
1333
+ } i=y;
1334
+ // italic a
1335
+ for(y=dy-1-i;y<dy-1;y++)
1336
+ if( num_cross(j,dx-1,y,y,bp,cs) > 1 ) ad=99*ad/100; // ~a \it a
1337
+
1338
+ if (loop(bp, 0, 0,x1-x0,cs,0,RI)>=dx/8) { // round, notLCD
1339
+ if (loop(bp,dx-1,dy-1,x1-x0,cs,0,LE)<dx/8) ad=98*ad/100; // \it a
1340
+ if (loop(bp,dx-1, 0,x1-x0,cs,0,LE)<dx/8) ad=98*ad/100; // \it a
1341
+ }
1342
+
1343
+ if (abs(loop(bp,dx/2, 0,dy,cs,0,DO)
1344
+ -loop(bp,dx/2,dy-1,dy,cs,0,UP))>dy/8
1345
+ || num_cross(0,dx-1, 0, 0,bp,cs) > 1
1346
+ || num_cross(0,dx-1,dy-1,dy-1,bp,cs) > 1
1347
+ ) ad=98*ad/100; // ~bq
1348
+
1349
+ if (box1->m3) {
1350
+ if (!hchar) ad=98*ad/100; else // ~o
1351
+ if ( gchar) ad=99*ad/100; // wrong line detection?
1352
+ } else { if (ad==100) ad=99; } /* not 100% sure */
1353
+ if (ad>98) ad=98; /* we can never be sure having a O, (2010-10 98%)
1354
+ let context correction decide, see below! */
1355
+ Setac(box1,(wchar_t)'0',ad);
1356
+ break;
1357
+ }
1358
+ // --- test 0 with a straight line in it -------------------
1359
+ for(ad=100;dx>4 && dy>5;){ /* v0.3.1+ */
1360
+ DBG( char c_ask='0'; )
1361
+ if (sdata->holes.num > 3) Break; /* be tolerant */
1362
+ if (sdata->holes.num < 1) Break;
1363
+ if (sdata->holes.num != 2) ad=95*ad/100;
1364
+ if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1365
+ if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1366
+ if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/2 , y1,box1->p,cs,1) != 1 ) Break;
1367
+ if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1368
+ if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 1 ) Break;
1369
+ // out_x(box1); printf(" x0 y0 %d %d\n",x0,y0);
1370
+ if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 3 ) Break;
1371
+ if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND
1372
+ if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
1373
+ if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen"
1374
+ if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 1 ) Break;
1375
+ if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1376
+ if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1377
+ if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1378
+ if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1379
+ // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 2 ) Break;
1380
+ if (sdata->holes.num != 2) ad=85*ad/100;
1381
+
1382
+ if( loop(bp,0 , 0,x1-x0,cs,0,RI)<=
1383
+ loop(bp,0 , 2+dy/32,x1-x0,cs,0,RI) ) Break;
1384
+ x= loop(bp,0 ,dy/2 ,x1-x0,cs,0,RI);
1385
+ i= loop(bp,0 ,dy/2-1,x1-x0,cs,0,RI); if (i>x) x=i;
1386
+ i= loop(bp,0 ,dy/2-2,x1-x0,cs,0,RI); if (i>x && dy>8) x=i;
1387
+ if( loop(bp,0 , dy/4,x1-x0,cs,0,RI)<x ) Break; // ~8
1388
+ x= loop(bp,dx-1,dy/2 ,x1-x0,cs,0,LE);
1389
+ i= loop(bp,dx-1,dy/2-1,x1-x0,cs,0,LE); if(i>x) x=i;
1390
+ i= loop(bp,dx-1,dy/2-1,x1-x0,cs,0,LE); if(i>x && dy>8) x=i;
1391
+ if( loop(bp,dx-1,3*dy/4,x1-x0,cs,0,LE)<x) Break; // ~8
1392
+
1393
+ x=loop(bp,dx-1,dy-1-dy/3,x1-x0,cs,0,LE); // should be minimum
1394
+ for( y=dy-1-dy/3;y<dy;y++ ){
1395
+ i=loop(bp,dx-1,y,x1-x0,cs,0,LE);
1396
+ if (i<x-dx/16) break;
1397
+ if (i>x) x=i;
1398
+ }
1399
+ if( y<dy ) Break;
1400
+
1401
+ /* test for straight line */
1402
+ y =loop(bp,dx/2,dy-1 ,y1-y0,cs,0,UP); if(y>dy/4) Break;
1403
+ y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,1,UP); if(y>dy/3) Break; if (y>dy/4) ad=ad*99/100;
1404
+ y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,0,UP); if(3*y>2*dy) Break;
1405
+ x =loop(bp,dx/2,dy-y,dx/2,cs,0,RI); if(x==0) Break;
1406
+ // MM; fprintf(stderr," y=%d x=%d\n",y-1,x);
1407
+ if( loop(bp,dx/2+x-1-dx/16,dy-y,y1-y0,cs,0,UP)==0 ) Break;
1408
+ // $
1409
+ for(i=0,y=dy/4;y<dy-dy/4-1;y++)
1410
+ if( loop(bp, 0,y,dx-1,cs,0,RI) > dx/4
1411
+ || loop(bp,dx-1,y,dx-1,cs,0,LE) > dx/4 ) break;
1412
+ if( y<dy-dy/4-1 ) Break;
1413
+
1414
+ // ~D
1415
+ if( loop(bp,0, dy/16,dx,cs,0,RI)
1416
+ + loop(bp,0,dy-1-dy/16,dx,cs,0,RI)
1417
+ <= 2*loop(bp,0, dy/2 ,dx,cs,0,RI)+dx/8 ) Break; // not konvex
1418
+
1419
+ if( loop(bp,dx-1, dy/16,dx,cs,0,LE)>dx/8 )
1420
+ if( loop(bp,0 , dy/16,dx,cs,0,RI)<dx/16 ) Break;
1421
+ if( loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/8 )
1422
+ if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)<dx/16 ) Break;
1423
+ if( get_bw(x1-dx/32,x1,y0,y0+dy/32,box1->p,cs,1) == 0
1424
+ && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0
1425
+ && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1
1426
+ || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) Break; // ~D
1427
+
1428
+ /* 5x9 font "9" is like "0" */
1429
+ if (dx<16)
1430
+ if ( num_cross(x0,x0,y0,y1,box1->p,cs) != 1 ) ad=98*ad/100;
1431
+
1432
+ // italic a
1433
+ for(i=0,y=6*dy/8;y<dy-dy/16;y++)
1434
+ if( num_cross(0,dx-1,y,y,bp,cs) > 2 ) i++; else i--;
1435
+ if(i>0) ad=ad*98/100; // ~'a' \it a
1436
+ if( !hchar ) ad=90*ad/100;
1437
+ Setac(box1,(wchar_t)'0',ad);
1438
+ break;
1439
+ }
1440
+ // --- test 0 with a dot in it -------------------
1441
+ for(ad=100;dx>4 && dy>5;){ /* v0.46+ */
1442
+ DBG( char c_ask='0'; )
1443
+ if (sdata->holes.num != 1) Break; /* do not be tolerant */
1444
+ // 8x10 font 2-pixel line width has 3 frames
1445
+ if (sdata->box1->num_frames != 3) ad=85*ad/100; // 2010-09-24
1446
+ // MSG(fprintf(stderr,"ad=%d",ad);)
1447
+ if( get_bw(x0 , x0+dx/2,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1448
+ if( get_bw(x1-dx/2 , x1 ,y0+dy/2 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1449
+ if( get_bw(x0+dx/2 , x0+dx/2,y1-dy/2 , y1,box1->p,cs,1) != 1 ) Break;
1450
+ if( get_bw(x0+dx/2 , x0+dx/2,y0 , y0+dy/2,box1->p,cs,1) != 1 ) Break;
1451
+ if( get_bw(x0+dx/2 , x0+dx/2,y0+dy/3 , y1-dy/3,box1->p,cs,1) != 1 ) Break;
1452
+ // out_x(box1); printf(" x0 y0 %d %d\n",x0,y0);
1453
+ if( num_cross(x0+dx/2,x0+dx/2,y0 , y1 ,box1->p,cs) != 3 ) Break;
1454
+ if( num_cross(x0+dx/3,x1-dx/3,y0 , y0 ,box1->p,cs) != 1 ) // AND
1455
+ if( num_cross(x0+dx/3,x1-dx/3,y0+1 , y0+1 ,box1->p,cs) != 1 ) Break;
1456
+ if( num_cross(x0+dx/3,x1-dx/3,y1 , y1 ,box1->p,cs) != 1 ) // against "rauschen"
1457
+ if( num_cross(x0+dx/3,x1-dx/3,y1-1 , y1-1 ,box1->p,cs) != 1 ) Break;
1458
+ if( num_cross(x0 ,x0 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1459
+ if( num_cross(x0+1 ,x0+1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1460
+ if( num_cross(x1 ,x1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 )
1461
+ if( num_cross(x1-1 ,x1-1 ,y0+dy/3 , y1-dy/3,box1->p,cs) != 1 ) Break;
1462
+ // if( num_hole(x0,x1,y0,y1,box1->p,cs,NULL) != 2 ) Break;
1463
+ // MSG(fprintf(stderr,"ad=%d",ad);)
1464
+
1465
+ if( loop(bp,0 , 0,x1-x0,cs,0,RI)<=
1466
+ loop(bp,0 , 2+dy/32,x1-x0,cs,0,RI) ) Break;
1467
+ x= loop(bp,0 ,dy/2 ,x1-x0,cs,0,RI);
1468
+ i= loop(bp,0 ,dy/2-1,x1-x0,cs,0,RI); if (i>x) x=i;
1469
+ i= loop(bp,0 ,dy/2-2,x1-x0,cs,0,RI); if (i>x && dy>8) x=i;
1470
+ if( loop(bp,0 , dy/4,x1-x0,cs,0,RI)<x ) Break; // ~8
1471
+ x= loop(bp,dx-1,dy/2 ,x1-x0,cs,0,LE);
1472
+ i= loop(bp,dx-1,dy/2-1,x1-x0,cs,0,LE); if(i>x) x=i;
1473
+ i= loop(bp,dx-1,dy/2-1,x1-x0,cs,0,LE); if(i>x && dy>8) x=i;
1474
+ if( loop(bp,dx-1,3*dy/4,x1-x0,cs,0,LE)<x) Break; // ~8
1475
+
1476
+ x=loop(bp,dx-1,dy-1-dy/3,x1-x0,cs,0,LE); // should be minimum
1477
+ for( y=dy-1-dy/3;y<dy;y++ ){
1478
+ i=loop(bp,dx-1,y,x1-x0,cs,0,LE);
1479
+ if (i<x-dx/16) break;
1480
+ if (i>x) x=i;
1481
+ }
1482
+ if( y<dy ) Break;
1483
+
1484
+ /* test for straight line */
1485
+ y =loop(bp,dx/2,dy-1 ,y1-y0,cs,0,UP); if(y>dy/4) Break;
1486
+ y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,1,UP); if(y>dy/3) Break;
1487
+ if (y>dy/4) { ad=ad*99/100;MSG(fprintf(stderr,"ad=%d",ad);) }
1488
+ y+=loop(bp,dx/2,dy-1-y,y1-y0,cs,0,UP); if(3*y>2*dy) Break;
1489
+ x =loop(bp,dx/2,dy-y,dx/2,cs,0,RI); if(x==0) Break;
1490
+ // MM; fprintf(stderr," y=%d x=%d\n",y-1,x);
1491
+ if( loop(bp,dx/2+x-1-dx/16,dy-y,y1-y0,cs,0,UP)==0 ) Break;
1492
+ // $
1493
+ for(i=0,y=dy/4;y<dy-dy/4-1;y++)
1494
+ if( loop(bp, 0,y,dx-1,cs,0,RI) > dx/4
1495
+ || loop(bp,dx-1,y,dx-1,cs,0,LE) > dx/4 ) break;
1496
+ if( y<dy-dy/4-1 ) Break;
1497
+
1498
+ // ~D
1499
+ if( loop(bp,0, dy/16,dx,cs,0,RI)
1500
+ + loop(bp,0,dy-1-dy/16,dx,cs,0,RI)
1501
+ <= 2*loop(bp,0, dy/2 ,dx,cs,0,RI)+dx/8 ) Break; // not konvex
1502
+
1503
+ if( loop(bp,dx-1, dy/16,dx,cs,0,LE)>dx/8 )
1504
+ if( loop(bp,0 , dy/16,dx,cs,0,RI)<dx/16 ) Break;
1505
+ if( loop(bp,dx-1,dy-1-dy/16,dx,cs,0,LE)>dx/8 )
1506
+ if( loop(bp,0 ,dy-1-dy/16,dx,cs,0,RI)<dx/16 ) Break;
1507
+ if( get_bw(x1-dx/32,x1,y0,y0+dy/32,box1->p,cs,1) == 0
1508
+ && get_bw(x1-dx/32,x1,y1-dy/32,y1,box1->p,cs,1) == 0
1509
+ && ( get_bw(x0,x0+dx/32,y0,y0+dy/32,box1->p,cs,1) == 1
1510
+ || get_bw(x0,x0+dx/32,y1-dy/32,y1,box1->p,cs,1) == 1 ) ) Break; // ~D
1511
+
1512
+ /* 5x9 font "9" is like "0" */
1513
+ if (dx<16)
1514
+ if (num_cross(x0,x0,y0,y1,box1->p,cs) != 1) {
1515
+ ad=98*ad/100;MSG(fprintf(stderr,"ad=%d",ad);) }
1516
+
1517
+ // italic a
1518
+ for(i=0,y=6*dy/8;y<dy-dy/16;y++)
1519
+ if (num_cross(0,dx-1,y,y,bp,cs) > 2) i++; else i--;
1520
+ if (i>0) { ad=ad*98/100; MSG(fprintf(stderr,"i=%d ad=%d",i,ad);) }
1521
+
1522
+ if (!hchar) ad=90*ad/100;
1523
+ Setac(box1,(wchar_t)'0',ad);
1524
+ break;
1525
+ }
1526
+ return box1->c;
1527
+ }