PageRenderTime 64ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 1ms

/Spikes/GocrDemo/ocr0.c

http://stp-iphone.googlecode.com/
C | 6756 lines | 5455 code | 438 blank | 863 comment | 4512 complexity | ffa277b2d87e6c78c5649170766ee916 MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  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-2009 Joerg Schulenburg
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. see README for email address
  19. >>> DO NOT EDIT THIS FILE IF YOU NOT REALLY KNOW WHAT YOU ARE DOING! <<<
  20. I have invested lot of time, to write this part of the program.
  21. This engine should recognize chars allways right or return UNKNOWN.
  22. If you change something, test all other example files too,
  23. to be sure that all things work better. (JoergS)
  24. This engine was pixelbased until 0.40 which was not successfull enough.
  25. Also code changes always hade side effects. The vectorisation of the code
  26. starts from version 0.41 with the chars XNz and seems to be much better
  27. to handle. Vectorization means we frame each character by a chain of
  28. vectors and dont care about pixels anymore. Unfortunatly I have to
  29. replace all the pixel codes, which is a long process. Old code will be lost.
  30. (JorgS)
  31. ToDo:
  32. - if box1->p and b differ, reduce probability
  33. - probability makes life much easier here
  34. - use only one box!?, may be bits have usefull infos
  35. - divide this file, suggestion: classify chars:
  36. high=ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhklt, low=acegijmnopqrsuvwxyz
  37. or
  38. often_used=etianmsurwdkgo rarely_used=hvjcflpqxyz.,:
  39. or
  40. every char (large overhead)
  41. - two-pass version (first pass without tolerance)
  42. 2nd pass with tolerance (ex: one tiny more in sdata->holes)
  43. general feature extraction:
  44. - white holes at middle, upper, lower position (cost much time)
  45. - test lines and triangles insteat of rectangles
  46. char is removed, wchar_t is used (better code)
  47. making a static global variable-set x.x0,x.x1, and call test_a,
  48. test_b ... (faster compilation, but not reentrant!)
  49. - adding slant-angle (if detected) to distinguish between l and / ?
  50. - ac (alternate chars) as string add_ac(box1,"/") => box1->ac="Il/";
  51. for better context correction or output: "Ha[lI][lI]o!"
  52. */
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. // #include "pgm2asc.h"
  56. #include "ocr0.h"
  57. // #include "ocr1.h"
  58. #include "amiga.h"
  59. #include "pnm.h"
  60. #include "gocr.h"
  61. #define IFV if(JOB->cfg.verbose&4)
  62. #define MM {IFV fprintf(stderr,"\nDBG %c L%04d (%d,%d): ",(char)c_ask,__LINE__,box1->x0,box1->y0);}
  63. // the old debug mode (0.40) was only for a special char, for another char
  64. // code must be recompiled with C_ASK='char'
  65. // new debug mode (0.41) explains why char is declined or accepted as ABC...
  66. // the output can be filtered by external scripts
  67. // ToDo: we could reduce output to filter string
  68. #ifndef DO_DEBUG /* can be defined outside (configure --with-debug) */
  69. #define DO_DEBUG 0 /* 0 is the default */
  70. #endif
  71. /* this macro is for debugging output: "if char is declined, why?" */
  72. #if DO_DEBUG /* 0=Work mode, 1=debugging mode */
  73. // Setac: output, that char is choosen with a probability
  74. // Break: output, why the char is not choosen
  75. // MSG: debugging functions for char C_ASK, mostly messages
  76. // DBG: definitions usefull only for debugging
  77. #define Setac(box1,ac,ad) { MM;IFV fprintf(stderr,"setac %d",ad);setac(box1,ac,ad); }
  78. #define Break { MM;IFV fprintf(stderr,"break"); break; }
  79. #define MSG(x) { MM;IFV x }
  80. #define DBG(x) x
  81. #else
  82. #define Setac(box1,ac,ad) setac(box1,ac,ad)
  83. #define Break break
  84. #define MSG(x)
  85. #define DBG(x)
  86. #endif
  87. /* extern "C"{ */
  88. // static inline int sq(int x) { return x*x; } /* square */
  89. /*
  90. * go from vector j1 to vector j2 and measure maximum deviation of
  91. * the steps from the line connecting j1 and j2
  92. * return the squared maximum distance
  93. * in units of the box size times 1024
  94. * ToDo: 1) better give back max-dx and max-dy ???
  95. * errors if j1 and j2 are in different frames or belong to
  96. * more then one frame?
  97. * 2) Better get deviation from a complete vector graphic?
  98. * The vectorgraphic is the ideal test char adapted to the
  99. * extrem vertices of the real char.
  100. */
  101. int line_deviation( struct box *box1, int j1, int j2 ) {
  102. int r1x, r1y, r2x, r2y, r3x, r3y, i, x, y, d, dist, maxdist=0, frame, l2;
  103. r1x=box1->frame_vector[j1][0];
  104. r1y=box1->frame_vector[j1][1];
  105. r2x=box1->frame_vector[j2][0];
  106. r2y=box1->frame_vector[j2][1];
  107. if (!box1->num_frames) return(-1);
  108. if (j1<0 || j1>box1->num_frame_vectors[box1->num_frames-1] ||
  109. j2<0 || j2>box1->num_frame_vectors[box1->num_frames-1]) {
  110. fprintf(stderr,"Error in "__FILE__" L%d: idx out of range",__LINE__);
  111. return(-1);
  112. }
  113. /* get the frame the endvector belongs to */
  114. for (i=0;i<box1->num_frames;i++)
  115. if (j2<box1->num_frame_vectors[i]) break;
  116. frame=i;
  117. /* frame(j1)<=frame(j2) possible */
  118. for (i=j1;;i++) { // do it for each vector between j1 and j2
  119. if (i >= box1->num_frame_vectors[frame])
  120. i=((frame)?box1->num_frame_vectors[frame-1]:0); /* go around */
  121. if (i==j2) break;
  122. // for (i=j1;i!=j2;i=(i+1)%box1->num_frame_vectors[0]) {~}
  123. r3x=box1->frame_vector[i][0];
  124. r3y=box1->frame_vector[i][1];
  125. // Language=german
  126. // german: Abstand Punkt von Strecke, Laenge Lotrechte
  127. // germ.Strecke : l1=(r1+r2)/2+d*(r2-r1)/2 for d=-1..1
  128. // germ.Lotrechte: l2=r3+b*[-(r2-r1).y,(r2-r1).x]
  129. // Schnittpunkt : l1=l2,
  130. // eq1x: (r1x+r2x)/2-r3x+d*(r2x-r1x)/2+b*(r2y-r1y)=0
  131. // eq1y: (r1y+r2y)/2-r3y+d*(r2y-r1y)/2-b*(r2x-r1x)=0
  132. // eq2x: b*(r2x-r1x)*(r2y-r1y)=-((r1x+r2x)/2-r3x+d*(r2x-r1x)/2)*(r2x-r1x)
  133. // eq2y: b*(r2x-r1x)*(r2y-r1y)= ((r1y+r2y)/2-r3y+d*(r2y-r1y)/2)*(r2y-r1y)
  134. // eq2y-eq2x: ... in units of 1024 (fast integer rounded correctly)
  135. l2=sq(r2x-r1x)+sq(r2y-r1y); // square of distance r2-r1
  136. if (l2==0) {
  137. // fprintf(stderr,"ocr0 L%d: r1==r2 r1= %d %d",__LINE__, r1x, r1y); // debugging
  138. d=-1024;
  139. } else
  140. d=-( ((r1x+r2x)-2*r3x)*(r2x-r1x)
  141. +((r1y+r2y)-2*r3y)*(r2y-r1y))*1024/l2; // ..-1024..+1024..
  142. if (d<=-1024) { x=r1x; y=r1y; } // starting point
  143. else {
  144. if (d>=1024) { x=r2x; y=r2y; } // end point
  145. else {
  146. x=((r1x+r2x)+1)/2+(d*(r2x-r1x))/2048;
  147. y=((r1y+r2y)+1)/2+(d*(r2y-r1y))/2048;
  148. /* we have the crossing point x,y now */
  149. }
  150. }
  151. dist=sq((x-r3x)*1024/(box1->x1-box1->x0+1))
  152. +sq((y-r3y)*1024/(box1->y1-box1->y0+1)); // 0..2*sq(1024)
  153. if (dist>maxdist) maxdist=dist;
  154. // for debugging:
  155. // fprintf(stderr,"\nDBG dev: %d-%d-%d dist=%5d max=%5d d=%d %d,%d-%d,%d"
  156. // " vector= %d %d crosspoint= %d %d ",
  157. // j1,i,j2,dist,maxdist,d,r1x,r1y,r2x,r2y,r3x,r3y,x,y);
  158. }
  159. return maxdist;
  160. }
  161. /*
  162. * search vectors between j1 and j2 for nearest point a to point r
  163. * example:
  164. *
  165. * r-> $$...$$ $ - mark vectors
  166. * @@$..@@ @ - black pixels
  167. * @@$..@@ . - white pixels
  168. * @@@@.$@
  169. * a-> @@$@$@@
  170. * @$.@@@@
  171. * @@..$@@
  172. * @@..$@@
  173. * j1 --> $$...$$ <-- j2
  174. *
  175. * ToDo: vector aa[5] = {rx,ry,x,y,d^2,idx} statt rx,ry?
  176. * j1 and j2 must be in the same frame
  177. * return aa?
  178. * 2009-07:
  179. * - change from normalized (dx=128,dy=128) to absolute distance
  180. * - simpler and no squeeze effect (problem getting right i2 for "3")
  181. */
  182. int nearest_frame_vector( struct box *box1, int j1, int j2, int rx, int ry) {
  183. int x,y,d,i,aa[4]; /* x,y,normalized_distance^2,vector_index */
  184. int frame=0;
  185. // int x0=box1->x0, y0=box1->y0,
  186. // x1=box1->x1, y1=box1->y1;
  187. // int dx=box1->x1-x0+1, dy=box1->y1-y0+1;
  188. if (!box1->num_frames) return(-1);
  189. if (j1<0 || j1>box1->num_frame_vectors[box1->num_frames-1] ||
  190. j2<0 || j2>box1->num_frame_vectors[box1->num_frames-1]) {
  191. fprintf(stderr,"Error in "__FILE__" L%d: idx %d-%d out of range\n",__LINE__,j1,j2);
  192. out_x(box1);
  193. return(-1);
  194. }
  195. aa[0]=x=box1->frame_vector[j2][0]; /* x */
  196. aa[1]=y=box1->frame_vector[j2][1]; /* y */
  197. /* maximum is (distance*128)^2 if r is inside the box */
  198. // aa[2]=d=2*sq(128)+sq((rx-(x0+x1)/2)*128/dx)+sq((ry-(y0+y1)/2)*128/dy);
  199. aa[2]=d=2*(sq(x-rx)+sq(y-ry)); /* must be greater than min. dist, Jul09 */
  200. aa[3]=j2; /* vector index */
  201. /* get the frame the endvector belongs to */
  202. for (i=0;i<box1->num_frames;i++)
  203. if (j2<box1->num_frame_vectors[i]) break;
  204. frame=i;
  205. /* frame(j1)<=frame(j2) possible */
  206. for (i=j1;;i++) {
  207. if (i >= box1->num_frame_vectors[frame])
  208. i=((frame)?box1->num_frame_vectors[frame-1]:0); /* go around */
  209. x=box1->frame_vector[i][0]; /* take a vector */
  210. y=box1->frame_vector[i][1];
  211. /* distance to upper left end, normalized to 128 */
  212. // d=sq((x-rx)*128/dx)+sq((y-ry)*128/dy); // old 2009-07
  213. d=sq(x-rx)+sq(y-ry);
  214. if (d<aa[2]) { aa[0]=x; aa[1]=y; aa[2]=d; aa[3]=i; }
  215. if (i==j2) break;
  216. }
  217. return aa[3];
  218. }
  219. // test for umlauts, if ret>0 and m==1 box1 is changed
  220. // m>0 modify box1->dots
  221. // m==2 modify box1->y0
  222. // called by pgm2asc + ocr0(?)
  223. int testumlaut(struct box *box1, int cs, int m, wchar_t *modifier){
  224. // pix p=*(box1->p);
  225. int r,y,x,x0,x1,y0,y1,dx,dy,m1,m2,m3,
  226. xl,xr,yu,yl; // left, right, upper and lower border of dots
  227. wchar_t mod='\0'; /* (TeX-) modifier ~"'` for compose() */
  228. DBG( wchar_t c_ask='"'; )
  229. r=0;
  230. x0=box1->x0; x1=box1->x1; dx=x1-x0+1;
  231. y0=box1->y0; y1=box1->y1; dy=y1-y0+1;
  232. m1=box1->m1; m2=box1->m2; m3=box1->m3;
  233. xl=x0; xr=x1; yu=yl=y0;
  234. if( dy < 5 || 4*y0 > 3*m2+m3 ) return 0; // no low chars: .,-=
  235. /* modifier in box included? */
  236. if( 2*y1 > m1+m2 ){
  237. /* modifier in box included? */
  238. for(y=y0;2*y<y0+y1;y++)if( get_bw(xl,xr,y,y,box1->p,cs,1)==0 ) break;
  239. if( 2*y<y0+y1 ){ /* yes => extract */
  240. yl=y;
  241. while( get_bw(xl,xr,y,y,box1->p,cs,1)==0 && 2*y<=y0+y1) y++;
  242. if( m&2 ) box1->y0=y; /* set new upper bond */
  243. }
  244. }
  245. if( yu>=yl ) { if(m) box1->dots=0; return 0; } /* nothing found */
  246. if( get_bw(xl-1,xl-1,yu,yl-1,box1->p,cs,1)==1 ) // neighbour overlap?
  247. while( get_bw(xl ,xl ,yu,yl-1,box1->p,cs,1)==1 && 2*xl<x0+x1) xl++;
  248. for(;xl<x1;xl++)if( get_bw(xl,xl,yu,yl,box1->p,cs,1)==1 ) break;
  249. for(;xr>xl;xr--)if( get_bw(xr,xr,yu,yl,box1->p,cs,1)==1 ) break;
  250. if ( yl-1>yu ) { // tall box ij"a"o"u
  251. #if 0
  252. x=box1->y0; box1->y0=m1; out_x(box1); box1->y0=x;
  253. fprintf(stderr,"\n#testumlaut x= %d %d m1=%d m2=%d",x0,y0,m1-y0,m2-y0);
  254. fprintf(stderr," yu=%d yl=%d xl=%d xr=%d",yu-y0,yl-y0,xl-x0,xr-x0);
  255. #define DEBUG 1
  256. #endif
  257. {
  258. x=xl;y=yu;
  259. if( get_bw(xl,x1+1,yu,yl-1,box1->p,cs,1)==0 ) r=0; // neighbour overlap?
  260. else
  261. if( get_bw(xl ,xl ,yu,yl-1,box1->p,cs,1)==0
  262. || get_bw(xl-1,xl-1,yu,yl-1,box1->p,cs,1)==0 ) // be sure there are gap to neighbours
  263. if( get_bw(xr ,xr ,yu,yl-1,box1->p,cs,1)==0
  264. || get_bw(xr+1,xr+1,yu,yl-1,box1->p,cs,1)==0 )
  265. { int i,j,x;
  266. r=1;
  267. // ...@@@.... RING_ABOVE // ..@@@..@@. TILDE
  268. // ..@...@... // @@.@@@@@..
  269. // ..@...@... // @.........
  270. // ..@..@@...
  271. // ...@@@....
  272. for (i=yu;i<yl;i++) if (get_bw(xl,xr,i,i,box1->p,cs,1)==1) break;
  273. for ( ;i<yl;i++) if (get_bw(xl,xr,i,i,box1->p,cs,1)==0) break;
  274. for (j=xl;j<xr;j++) if (get_bw(j,j,yu,i,box1->p,cs,1)==1) break;
  275. for ( ;j<xr;j++) if (get_bw(j,j,yu,i,box1->p,cs,1)==0) break;
  276. for ( x=j;x<xr;x++) if (get_bw(x,x,yu,i,box1->p,cs,1)==1) break;
  277. // vert. gap detected
  278. if( j<xr && x<xr && j<x && xr-xl>2
  279. && num_obj(xl,xr,yu,yl-1,box1->p,cs)>=2 // not best!!!
  280. && num_cross(xl,xr,yu +(yl-yu)/4,yu+ (yl-yu)/4,box1->p,cs) == 2
  281. && num_cross(xl,xr,yl-1-(yl-yu)/2,yl-1-(yl-yu)/2,box1->p,cs) == 2
  282. ){ // may be the following lines are not quite ok
  283. while( get_bw(xl,xr,yl,yl,box1->p,cs,1)==0 && 2*yl<y0+y1) yl++;
  284. r=2;
  285. // 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);
  286. mod = DIAERESIS;
  287. }
  288. if( m&2 ) box1->y0=yl;
  289. /* if( m&2 ) box1->y0= ( (r==1) ? yu : yl ); */
  290. // out_x(box1);
  291. }
  292. if(r==0){ // divided fr != fi
  293. while( get_bw(x0,x1,yu,yu,box1->p,cs,1)==0 && 2*yu<y0+y1) yu++;
  294. if(m)box1->y0=yu;
  295. }
  296. if( r==1 ){ yl--;
  297. // .@@@. ..@@.
  298. // .@@.. .@@..
  299. // .@... .@@..
  300. //
  301. // if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
  302. // > loop(box1->p,xl,yl,xr-xl,cs,0,RI) // +dx/8
  303. // && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
  304. // < loop(box1->p,xr,yl,xr-xl,cs,0,LE)) // -dx/8 ) // &eacute; Nov03
  305. if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
  306. - loop(box1->p,xr,yu,xr-xl,cs,0,LE)
  307. > loop(box1->p,xl,yl,xr-xl,cs,0,RI) // +dx/8
  308. - loop(box1->p,xr,yl,xr-xl,cs,0,LE)+1) // -dx/8 ) // &eacute; Nov03
  309. mod = ACUTE_ACCENT; // '
  310. if( xr-xl+1 > 3*(yl-yu+1)
  311. && get_bw(xl,xr,yu,yl,box1->p,cs,2)==0 )
  312. mod = MACRON; // "-" above
  313. // .@@@. .@@..
  314. // ..@@. ..@@.
  315. // ...@. ..@@.
  316. //
  317. // if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
  318. // < loop(box1->p,xl,yl,xr-xl,cs,0,RI) // -dx/8
  319. // && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
  320. // > loop(box1->p,xr,yl,xr-xl,cs,0,LE) ) // +dx/8 ) &agrave; Nov03
  321. if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
  322. - loop(box1->p,xr,yu,xr-xl,cs,0,LE)
  323. < loop(box1->p,xl,yl,xr-xl,cs,0,RI) // -dx/8
  324. - loop(box1->p,xr,yl,xr-xl,cs,0,LE) -1 ) // +dx/8 ) &agrave; Nov03
  325. mod = GRAVE_ACCENT; // `
  326. #ifdef DEBUG
  327. fprintf(stderr,"\n#testumlaut x= %d %d m1=%d m2=%d",x0,y0,m1-y0,m2-y0);
  328. fprintf(stderr," yu=%d yl=%d xl=%d xr=%d",yu-y0,yl-y0,xl-x0,xr-x0);
  329. #endif
  330. if( (xr-xl+1) < 2*(yl-yu+1)+2
  331. && 2*(xr-xl+1)+2 > (yl-yu+1) ) {
  332. int i,i1,i2,i3,i4;
  333. i1=loop(box1->p,xl ,(yu+yl)/2,xr-xl+1,cs,0,RI);
  334. i1=loop(box1->p,xl+i1,(yu+yl)/2,xr-xl+1,cs,1,RI);
  335. i2=loop(box1->p,(xl+xr)/2,yu ,yl-yu+1,cs,0,DO);
  336. i2=loop(box1->p,(xl+xr)/2,yu+i2,yl-yu+1,cs,1,DO);
  337. for (i=0;i<xr-xl+1 && i<yl-yu+1;i++)
  338. if (getpixel(box1->p,xl+i,yu+i)< cs) break; i3=i;
  339. for ( ;i<xr-xl+1 && i<yl-yu+1;i++)
  340. if (getpixel(box1->p,xl+i,yu+i)>=cs) break; i3=i-i3;
  341. for (i=0;i<xr-xl+1 && i<yl-yu+1;i++)
  342. if (getpixel(box1->p,xr-i,yu+i)< cs) break; i4=i;
  343. for ( ;i<xr-xl+1 && i<yl-yu+1;i++)
  344. if (getpixel(box1->p,xr-i,yu+i)>=cs) break; i4=i-i4;
  345. #ifdef DEBUG
  346. fprintf(stderr,"\n#DEBUG DOT_ABOVE %d %d %d %d",i1,i2,i3,i4);
  347. #endif
  348. if ( (xr-xl<5 && yl-yu<8) /* to small */
  349. || (i1>=(xr-xl+1)/2+2 && i2>=(yl-yu+1)/2+2 /* symmetrical */
  350. && abs(i3-i4)<=i1/4+2 && abs(i1-i2)<=i1/4+2
  351. && abs(i3-i1)<=i1/4+4 && abs(i4-i2)<=i1/4+4)
  352. )
  353. mod = DOT_ABOVE; // "." above, ToDo: improve it!
  354. }
  355. if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
  356. > loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/8
  357. || loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
  358. > loop(box1->p,xl,yl-1,xr-xl,cs,0,RI)-dx/8 )
  359. && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
  360. > loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/8
  361. || loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
  362. > loop(box1->p,xr,yl-1,xr-xl,cs,0,LE)-dx/8 )
  363. && num_cross(xl,xr,yu ,yu ,box1->p,cs) == 1
  364. && ( num_cross(xl,xr,yl ,yl ,box1->p,cs) == 2
  365. || num_cross(xl,xr,yl-1,yl-1,box1->p,cs) == 2 ))
  366. mod = CIRCUMFLEX_ACCENT; // "^"
  367. if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
  368. < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10
  369. || loop(box1->p,xl,yu+1,xr-xl,cs,0,RI)
  370. < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10 )
  371. && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
  372. < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10
  373. || loop(box1->p,xr,yu+1,xr-xl,cs,0,LE)
  374. < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10 )
  375. && ( num_cross(xl,xr,yu ,yu ,box1->p,cs) == 2
  376. || num_cross(xl,xr,yu+1,yu+1,box1->p,cs) == 2 )
  377. && num_cross(xl,xr,yl ,yl ,box1->p,cs) == 1 )
  378. mod = CARON; // "v" above
  379. if( /* test for bow (new0.3.6) */
  380. loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
  381. + loop(box1->p,xl,yl ,xr-xl,cs,0,RI)
  382. - 2*loop(box1->p,xl,(yl+yu)/2,xr-xl,cs,0,RI) > dx/16+1
  383. && xr-xl>10)
  384. if( ( loop(box1->p,xl,yu ,xr-xl,cs,0,RI)
  385. < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10
  386. || loop(box1->p,xl,yu+1,xr-xl,cs,0,RI)
  387. < loop(box1->p,xl,yl ,xr-xl,cs,0,RI)-dx/10 )
  388. && ( loop(box1->p,xr,yu ,xr-xl,cs,0,LE)
  389. < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10
  390. || loop(box1->p,xr,yu+1,xr-xl,cs,0,LE)
  391. < loop(box1->p,xr,yl ,xr-xl,cs,0,LE)-dx/10 )
  392. && ( num_cross(xl,xr,yu ,yu ,box1->p,cs) == 2
  393. || num_cross(xl,xr,yu+1,yu+1,box1->p,cs) == 2 )
  394. && num_cross(xl,xr,yl ,yl ,box1->p,cs) == 1 )
  395. mod = BREVE; // round "u" above
  396. if( xr-xl>3 && yl-yu>1 )
  397. if( loop(box1->p,xl,yu,xr-xl,cs,0,RI)
  398. > loop(box1->p,xl,yl,xr-xl,cs,0,RI)
  399. && loop(box1->p,xr,yu,xr-xl,cs,0,LE)
  400. < loop(box1->p,xr,yl,xr-xl,cs,0,LE)
  401. && num_cross(xl,xr,yu,yu,box1->p,cs) == 2
  402. && num_cross(xl,xr,yl,yl,box1->p,cs) == 2 )
  403. mod = TILDE;
  404. if( xr-xl>2 && yl-yu>2)
  405. if( num_cross(xl,xr,(yu+yl)/2,(yu+yl)/2,box1->p,cs) >1 )
  406. if( num_cross((xl+xr)/2,(xl+xr)/2,yu,yl,box1->p,cs) >1 )
  407. if( num_hole(xl,xr,yu,yl,box1->p,cs,NULL) == 1 )
  408. mod = RING_ABOVE;
  409. #ifdef DEBUG
  410. printf("\n#DEBUG umlaut mod=0x%04x x=%d..%d y=%d..%d r=%d %s",
  411. (int)mod,yu-box1->y0,yl-box1->y0,
  412. xl-box1->x0,xr-box1->x0,r,((mod==CARON)?"CARON":
  413. ((mod==ACUTE_ACCENT)?"ACUTE":
  414. ((mod==TILDE)?"TILDE":"?"))));
  415. out_x(box1);
  416. #endif
  417. }
  418. }
  419. if (m) box1->dots=r; // set to 0 also possible after division
  420. if (m) box1->modifier=mod; /* should be resetted after compose ??? */
  421. MSG(fprintf(stderr,"umlaut mod=%s dots=%d y0o=%d",decode(mod,ASCII),r,y0);)
  422. }
  423. // printf(" modifier=%c",mod);
  424. if (modifier) *modifier=mod; /* set modifier */
  425. return r;
  426. }
  427. static wchar_t ocr0_eE(ocr0_shared_t *sdata){
  428. struct box *box1=sdata->box1;
  429. int i,i1,i2,j,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,bad_e=0,
  430. x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
  431. int dx=x1-x0+1,dy=y1-y0+1, /* size */
  432. ad; /* tmp-vars */
  433. int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
  434. // --- most frequent letter e first!!!
  435. // --- test e ---------------------------------------------------
  436. for(ad=d=100;dx>2 && dy>3;){ // min 3x4 (smallest seen is 5x6)
  437. DBG( wchar_t c_ask='e'; )
  438. if (sdata->holes.num > 2) Break; /* tolerant against a tiny hole */
  439. if (sdata->holes.num != 1) ad=97*ad/100;
  440. /* ToDo: may be a two pass version intolerant/tolerant is better */
  441. if( loop(box1->p,x0,y0+dy/2,x1-x0,cs,0,RI)>dx/3 ) Break; // rough test
  442. if( loop(box1->p,x0+dx/2,y0,y1-y0,cs,0,DO)>dy/3 ) Break;
  443. if( loop(box1->p,x0+dx/2,y1,y1-y0,cs,0,UP)>dy/3 ) Break;
  444. if( num_cross(x0,x1,y0+dy/4 ,y0+dy/4 ,box1->p,cs) > 2
  445. && num_cross(x0,x1,y0+dy/4+1,y0+dy/4+1,box1->p,cs) > 2 ) Break; // gt
  446. x=(x0+x1)/2;i= num_cross(x,x,y0,y1,box1->p,cs); // v0.40
  447. if (i!=3) { x=(x0+2*x1)/3;i= num_cross(x,x,y0,y1,box1->p,cs); }
  448. if (i!=3) { x=(x0+3*x1)/4;i= num_cross(x,x,y0,y1,box1->p,cs); }
  449. if (i!=3) { i= num_cross((x0+2*x1)/3,(x0+x1)/2,y0,y1,box1->p,cs); }
  450. i=loop(box1->p,x0,y0+dy/2,x1-x0,cs,0,RI); if( i>dx/2 ) Break;
  451. j=loop(box1->p,x0,y0 ,x1-x0,cs,0,RI); if( j<i ) Break;
  452. j=loop(box1->p,x0,y1 ,x1-x0,cs,0,RI); if( j<i ) Break;
  453. i=loop(box1->p,x0+dx/2,y0,y1-y0,cs,0,DO); if( i>dx/2 ) Break;
  454. j=loop(box1->p,x1-dx/3,y0,y1-y0,cs,0,DO); if( j<i ) i=j;
  455. j=loop(box1->p,x0 ,y0,y1-y0,cs,0,DO); if( j<i ) Break;
  456. j=loop(box1->p,x1 ,y0,y1-y0,cs,0,DO); if( j<i ) Break;
  457. i=loop(box1->p,x0+dx/2,y1,y1-y0,cs,0,UP); if( i>dx/2 ) Break;
  458. j=loop(box1->p,x0 ,y1,y1-y0,cs,0,UP); if( j<i ) Break;
  459. j=loop(box1->p,x1 ,y1,y1-y0,cs,0,UP); if( j<i ) Break;
  460. j=2*loop(box1->p,x0, (y0+y1)/2,x1-x0,cs,0,RI)
  461. -loop(box1->p,x0,(3*y0+y1)/4,x1-x0,cs,0,RI)
  462. -loop(box1->p,x0,(y0+3*y1)/4,x1-x0,cs,0,RI);
  463. if (dx>3 && j>=dx/4) Break; // ~g 4x6font
  464. for(y=1;y<dy/2;y++) if( num_cross(x0,x1,y0+y,y0+y,box1->p,cs) == 2 ) break;
  465. if( y==dy/2 ) Break; // v0.2.5 ~ bad_t
  466. for(i=0,j=x0+dx/4;j<=x1-dx/4 && i<=dx/4;j++)
  467. if( num_cross(j,j,y0,y1,box1->p,cs) == 3 ) i++;
  468. if( dx>4 && dy>5 && (i<dx/4-1 || i==0) ) Break; // ~g but 4x6-e
  469. // look for horizontal white line (right gap) => set x,y
  470. for(x=0,y=i=y0+dy/3;i<y1-dy/6;i++){
  471. j=loop(box1->p,x1,i,y1-y0,cs,0,LE);
  472. if(j>=x) { x=j;y=i; }
  473. }
  474. if (x<dx/2){ // no gap found, fat font???
  475. // check smallest thickness left > 2* smallest thickness right
  476. for(i1=dx,i=y0+dy/3;i<y1-dy/6;i++){
  477. j =loop(box1->p,x0 ,i,y1-y0,cs,0,RI); if (j>dx/2) break;
  478. j =loop(box1->p,x0+j,i,y1-y0,cs,1,RI);
  479. if (j<i1) i1=j; // smallest thickness on left bow
  480. }
  481. for(i2=dx,y=i=y0+dy/3;i<y1-dy/6;i++){
  482. j =loop(box1->p,x1 ,i,y1-y0,cs,0,LE);
  483. j =loop(box1->p,x1-j,i,y1-y0,cs,1,LE);
  484. if(j<i2) { i2=j;y=i; }
  485. } if (3*i2>2*i1) Break; // not accepted, if right line is not very thinn
  486. x =loop(box1->p,x1 ,y,y1-y0,cs,0,LE);
  487. x+=loop(box1->p,x1-x,y,y1-y0,cs,1,LE);
  488. x+=loop(box1->p,x1-x,y,y1-y0,cs,0,LE);
  489. if (3*i2>i1) ad=99*ad/100;
  490. if (2*i2>i1) ad=99*ad/100;
  491. bad_e=60; // used later?
  492. }
  493. if (x<dx/2) Break;
  494. for(i=1,j=x0+dx/6;j<x1-dx/6 && i;j++)
  495. if( num_cross(j,j,y0,y,box1->p,cs) > 1 ) i=0;
  496. if( i ) Break;
  497. // ..@@@@...<-
  498. // .@@@@@@;.
  499. // @@,...@@.
  500. // @@.....@,
  501. // @@@@@@@@@
  502. // @@.,;.@,. <- problem (y) == bad_e>50
  503. // @@.....@.
  504. // @@,...@@.
  505. // .@@@,@@@.
  506. // ..@@@@;..<-
  507. if (dy>11 && bad_e<50)
  508. if ( num_cross(x0,x1,y,y,box1->p,cs) != 1 ) Break; // except "geschwungenem e"
  509. if ( num_cross(x0,x1-dx/3,y ,y ,box1->p,cs) != 1
  510. && num_cross(x0,x1-dx/3,y+1,y+1,box1->p,cs) != 1 ) Break;
  511. // if( num_hole(x0, x1, y0 , y ,box1->p,cs,NULL) < 1 ){
  512. if( sdata->holes.num == 0 || sdata->holes.hole[0].y1 >= y-y0){
  513. if( sdata->hchar ) Break; // ~ \it t
  514. // look if thinn font (may be h-line is broken) Mai00
  515. for(j=0,i=x0+dx/8;i<x1-1;i++)
  516. if( get_bw(i,i,y0+dy/4,y,box1->p,cs,1) == 1 ) j++;
  517. if(j<2*dx/4) Break;
  518. }
  519. if( sdata->holes.num>0 && sdata->holes.hole[0].y0 > y-y0) Break;
  520. if( sdata->holes.num>1 && sdata->holes.hole[1].y0 > y-y0) Break;
  521. if( sdata->holes.num==1 && sdata->holes.hole[0].x0 >= dx/2) {
  522. ad=95*ad/100; } /* 8*10 @ (=at) is not an e */
  523. // look for horizontal gap
  524. for(x=0,y=i=y0+dy/4;i<y1-dy/4;i++){
  525. j=loop(box1->p,x0,i,x1-x0,cs,0,RI);
  526. if(j>=x) { x=j;y=i; }
  527. }
  528. if (y>y0+dy/4 && y<y1-dy/4 && x>dx/2) Break; // s
  529. if (x>dx/4) ad=99*ad/100;
  530. if( num_cross(x0+dx/2,x1 ,y1-dy/4,y1 ,box1->p,cs) == 0
  531. && num_cross(x0+dx/2,x1-1,y1-dy/4,y1 ,box1->p,cs) == 0
  532. && num_cross(x0+dx/2,x1 ,y1-dy/4,y1-1,box1->p,cs) == 0 ) {
  533. if (sdata->gchar) Break; // ~p
  534. ad=99*ad/100;
  535. }
  536. /* upper case is for 5x6 box */
  537. if( sdata->hchar // broken B ? should also work when linedetection fails
  538. && loop(box1->p,x1,y1-dy/3,dx,cs,0,LE)<=dx/8 ) {
  539. x = loop(box1->p,x0,y0+dy/2,dx,cs,0,RI);
  540. if( loop(box1->p,x0,y0+dy/4,dx,cs,0,RI)<=x
  541. && loop(box1->p,x0,y0+dy/8,dx,cs,0,RI)<=x ) Break;
  542. if( loop(box1->p,x0,y1-dy/4,dx,cs,0,RI)<=x
  543. && loop(box1->p,x0,y1-dy/8,dx,cs,0,RI)<=x ) Break;
  544. }
  545. x = loop(sdata->bp,0,dy-2 ,dx,cs,0,RI);
  546. if( loop(sdata->bp,0,dy-1-dy/8,dx,cs,0,RI)>x && dy>16) Break; // some Q
  547. if (box1->m2) {
  548. if (sdata->gchar) ad=99*ad/100;
  549. if (sdata->hchar) ad=99*ad/100;
  550. } else ad=99*ad/100;
  551. Setac(box1,(wchar_t)'e',ad);
  552. if (ad>=100) return 'e';
  553. break;
  554. }
  555. // --- test E ---------------------------------------------------
  556. for(ad=d=100;dx>2 && dy>4 ;){ // min 3x4
  557. // rewritten for vectors 0.43
  558. int i1, i2, i3, i4, i5; // line derivation + corners
  559. DBG( wchar_t c_ask='E'; )
  560. if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
  561. /* half distance to the center */
  562. d=2*sq(128/4);
  563. /* now we check for the upper right end of the h */
  564. if (aa[3][2]>d/2) Break; /* [2] = distance, ~dj... */
  565. if (aa[0][2]>d/2) Break; /* upper left end */
  566. if (aa[1][2]>d/2) Break; /* lower left end */
  567. if (aa[2][2]>d/2) Break; /* lowerright end */
  568. /*
  569. E f near E
  570. OOOOOOOO OOOO
  571. O5 O O
  572. O4 O
  573. OOOO3 OOOOOO
  574. O2 O
  575. O O
  576. O1 O O
  577. OOOOOOOO OOOOOO
  578. */
  579. // check the bow from below
  580. for (i=aa[1][3];i!=aa[2][3];i=(i+1)%box1->num_frame_vectors[0]) {
  581. if (y1-box1->frame_vector[ i][1]>dy/4) break; // fatal!
  582. } if (i!=aa[2][3]) Break; // ~AHKMNRX
  583. // search most left+down between bottom right and top right
  584. i1=nearest_frame_vector(box1, aa[2][3],aa[3][3], x0, y1);
  585. i5=nearest_frame_vector(box1, i1,aa[3][3], x0, y0);
  586. i3=nearest_frame_vector(box1, i1, i5, x1, (y0+y1)/2);
  587. i2=nearest_frame_vector(box1, i1, i3, x0, (2*y0+y1)/3);
  588. i4=nearest_frame_vector(box1, i3, i5, x0, (y0+2*y1)/3);
  589. i =nearest_frame_vector(box1, aa[0][3],aa[1][3], x0-dx/4, (y0+y1)/2);
  590. if (2*box1->frame_vector[i][0] < aa[0][0]+aa[1][0]-1-dx/16) Break;
  591. if (2*box1->frame_vector[i][0] < aa[0][0]+aa[1][0]) ad=99*ad/100; // f
  592. MSG(fprintf(stderr,"i1-5 %d %d %d %d %d",i1,i2,i3,i4,i5);)
  593. // holes right open?
  594. for( i=1,y=y0; y<y0+dy/4 && i; y++ ) // long black line
  595. if( get_bw(x0+dx/3,x1-dx/6,y,y,box1->p,cs,2) == 0 ) i=0;
  596. if( i ) Break;
  597. for( i=1,y=y1; y>y1-dy/4 && i; y-- ) // long black line
  598. if( get_bw(x0+dx/6,x1-dx/4,y,y,box1->p,cs,2) == 0 ) i=0;
  599. if( i ) Break;
  600. for( i=1,y=y0+dy/3; y<y1-dy/3 && i; y++ ){ // black line
  601. j=loop(box1->p,x0 ,y,dx,cs,0,RI);
  602. j=loop(box1->p,x0+j,y,dx,cs,1,RI); if( j>dx/3 ) i=0;
  603. } if( i ) Break;
  604. x=x1-dx/3; y=y0; // von oben durchbohren!
  605. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y0+dy/4 ) Break;
  606. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,DO); if( y>y0+dy/3 ) Break;
  607. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,DO); if( x<=x1 || y>y0+dy/2 ) Break;
  608. x=x1-dx/3; y=y1; // von unten durchbohren!
  609. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,UP,ST); if( y<y1-dy/4 ) Break;
  610. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,UP); if( y<y0-dy/3 ) Break;
  611. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,RI,UP); if( x<=x1 || y<y0+dy/2 ) Break;
  612. x=x1-dx/3; y=y0; // von oben durchbohren!
  613. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y0+dy/4 ) Break;
  614. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,ST,DO); if( y>y0+dy/3 ) Break;
  615. y+=dy/15;
  616. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,LE,ST); if( x<x0 ) Break;
  617. if (dx>15 && x==x0) ad=99*ad/100; // to thin
  618. x+=dx/15+1;
  619. turmite(box1->p,&x,&y,x0,x1,y0,y1,cs,DO,ST); if( y>y1-dy/3 ) Break;
  620. // if( num_hole(x0, x1, y0 , y1 ,box1->p,cs,NULL) > 0 ) Break;
  621. if (sdata->holes.num > 0) Break;
  622. i=loop(box1->p,x0,y0+dy/4,dx,cs,0,RI); if(i>dx/2) Break;
  623. j=loop(box1->p,x0,y0+dy/2,dx,cs,0,RI); if(j<i-dx/4 || j>i+dx/8) Break; i=j;
  624. j=loop(box1->p,x0,y1-dy/4,dx,cs,0,RI); if(j<i-dx/4 || j>i+dx/8) Break;
  625. j=loop(box1->p,x1,y1-dy/4,dx,cs,0,LE);
  626. for( x=dx,y=y0+dy/6; y<y1-dy/9; y++ ) // left border straight
  627. { i=loop(box1->p,x0,y,dx,cs,0,RI);
  628. if (i>j/2 && ad>98) ad=99*ad/100;
  629. if (i>dx/4) break;
  630. if(i<x) x=i;
  631. } if( y<y1-dy/9 ) Break; // t
  632. if(dy>3*dx) // ~[
  633. if( get_bw(x0+dx/2,x0+dx/2,y0+dy/4,y1-dy/4,box1->p,cs,1) == 0 ) Break;
  634. if (box1->m2) {
  635. if (!hchar) ad=ad*99/100;
  636. if ( gchar) ad=ad*99/100;
  637. }
  638. Setac(box1,(wchar_t)'E',ad);
  639. if (ad>=100) return 'E';
  640. break;
  641. }
  642. return box1->c;
  643. }
  644. static wchar_t ocr0_n(ocr0_shared_t *sdata){
  645. struct box *box1=sdata->box1;
  646. int i,j,d,x,y,i1,i2,i3,handwritten=0,
  647. x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
  648. int dx=x1-x0+1,dy=y1-y0+1, /* size */
  649. ad; /* tmp-vars */
  650. // --- test n ---------------------------------------------------
  651. // glued rm is very similar to glued nn -> thickness of h-line should grow
  652. // may02: tested for 8x12 font
  653. for(ad=d=100;dx>2 && dy>3;){ // min 3x4
  654. DBG( wchar_t c_ask='n'; )
  655. if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
  656. i= num_cross( 0,dx-1,dy/4,dy/4,sdata->bp,cs);
  657. j= num_cross( 0,dx-1,dy/2,dy/2,sdata->bp,cs);
  658. if( (i<2 || i>3) && j!=2 ) Break;
  659. if( loop(sdata->bp,dx/2,0,dy,cs,0,DO) > dy/8 && sdata->hchar ) Break; /* tt */
  660. y=5*dy/8; /* also for handwritten n, where first bow goes not down enough */
  661. if( num_cross( 0,dx/2,y ,y ,sdata->bp,cs) != 1
  662. && num_cross( 0,dx/2,y-1,y-1,sdata->bp,cs) != 1
  663. && num_cross(dx/2,dx-1,y ,y ,sdata->bp,cs) < 1 ) Break; // n rr
  664. // ~thick_w
  665. y=loop(sdata->bp,dx-1-dx/4,0,dy,cs,0,DO); if(y>dy/2) Break;
  666. if(y>1)if( get_bw(dx-1-dx/4,dx-1,0,y-2,sdata->bp,cs,1) == 1 ) Break;
  667. y=3*dy/4;
  668. if( num_cross(0, dx/2,y ,y ,sdata->bp,cs) == 1
  669. && num_cross(dx/2,dx-1,y ,y ,sdata->bp,cs) == 0 ) Break; // ~p
  670. y=dy/2;
  671. if( num_cross(0,dx-1,dy/2-dy/8,dy/2-dy/8,sdata->bp,cs) == 2
  672. && num_cross(0,dx-1,dy/2, dy/2 ,sdata->bp,cs) == 2 ) { // n rr
  673. /* printed n */
  674. x =loop(sdata->bp,0,y,dx ,cs,0,RI); if(x> dx/4) Break; // search 1st v-line
  675. x+=loop(sdata->bp,x,y,dx-x,cs,1,RI); if(x> dx/2) Break; i1=x; // 1st gap
  676. x+=loop(sdata->bp,x,y,dx-x,cs,0,RI); if(x< dx/2) Break; i2=x; // 2nd v-line
  677. x+=loop(sdata->bp,x,y,dx-x,cs,1,RI); if(x<3*dx/4) Break; i3=x; // 2nd gap
  678. i=dy/4; y=13*dy/16;
  679. if( num_cross(dx/2,dx-1,y,y,sdata->bp,cs)==2 ) i=3*dy/8; // \it n
  680. if (i<2 && i<dy/2) i++; // correct for small fonts like 8x12
  681. // the same game for the lower part =>l1 l2 l3 l4 ???
  682. for(x=i1;x<i2;x++) if( loop(sdata->bp,x, 0,dy,cs,0,DO)>=i ) break;
  683. if(x <i2) Break; // gap detected
  684. for(x=i1;x<i2;x++) if( loop(sdata->bp,x,dy-1,dy,cs,0,UP) >dy/4 ) break;
  685. if(x==i2) Break; // no gap detected (glued serifs ??? )
  686. // glued rm as nn ???
  687. for(y=0,x=(i1+i2)/2;x<i2;x++){
  688. i=loop(sdata->bp,x,0,dy,cs,0,DO);
  689. i=loop(sdata->bp,x,i,dy,cs,1,DO); // measure thickness
  690. if( i>y ) y=i; if( i<y/2 ) break;
  691. }
  692. if(x <i2) Break; // unusual property for n
  693. if( dy>7 )
  694. if( loop(sdata->bp,dx-1,dy-1-dy/8,dx,cs,0,LE)
  695. +loop(sdata->bp, 0,dy-1-dy/8,dx,cs,0,RI)-dx/8-1
  696. > loop(sdata->bp,dx-1,dy-1-dy/2,dx,cs,0,LE)
  697. +loop(sdata->bp, 0,dy-1-dy/2,dx,cs,0,RI) ) ad=90*ad/100; // broken o
  698. if( dy>7 && dx>7 )
  699. if( loop(sdata->bp,dx-1, dy/2,dx,cs,0,LE)==0
  700. && loop(sdata->bp,dx-1,dy-1-dy/8,dx,cs,0,RI)>dx/8 ) ad=98*ad/100; // broken o
  701. } else { /* check handwritten n */
  702. if( num_cross(0,dx-1,dy/2, dy/2 ,sdata->bp,cs) != 3
  703. && num_cross(0,dx-1,dy/2-dy/8,dy/2-dy/8,sdata->bp,cs) != 3 ) Break;
  704. i =loop(sdata->bp,0,dy/2-dy/8,dx,cs,0,RI); if (i>dx/4) Break;
  705. i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,1,RI); if (i>dx/2) Break;
  706. i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,0,RI);
  707. if( num_cross(i,i, 0,dy/2-2*dy/8,sdata->bp,cs) != 0 ) Break;
  708. i+=loop(sdata->bp,i,dy/2-dy/8,dx,cs,1,RI);
  709. if( num_cross(i,i,dy/2+1, dy-1,sdata->bp,cs) != 0 ) Break;
  710. handwritten=80;
  711. }
  712. i= loop(sdata->bp,dx-1 ,dy/2,dx,cs,0,LE); if(i>5)
  713. if( get_bw(dx-1-i/2,dx-1-i/2,0,dy/2,sdata->bp,cs,1) == 1 ) Break; // ~rr
  714. i+=loop(sdata->bp,dx-1-i,dy/2,dx,cs,1,LE);
  715. if( get_bw(dx-1-i ,dx-1-i ,0,dy/2,sdata->bp,cs,1) == 0 ) Break; // ~rv
  716. if( get_bw(dx/2,dx/2,dy/4,dy/4,sdata->bp,cs,1) == 0
  717. && get_bw(dx/2,dx-1,dy-2,dy-2,sdata->bp,cs,1) == 0
  718. && get_bw(dx/2,dx/2,dy/4,dy-2,sdata->bp,cs,1) == 1 ) Break; // ~P
  719. // glued ri ???
  720. if( box1->dots>0 && box1->m1 )
  721. if( get_bw((x1+x0)/2,x1,box1->m1,y0-1,box1->p,cs,1) == 1 )
  722. if( num_cross( 0,dx-1,0 ,0 ,sdata->bp,cs) >2
  723. || num_cross( 0,dx-1,1 ,1 ,sdata->bp,cs) >2 ) Break;
  724. i=loop(sdata->bp,dx-1, dy-1,dx,cs,0,LE); if (i>dx/2)
  725. i=loop(sdata->bp,dx-1, dy-2,dx,cs,0,LE);
  726. x=loop(sdata->bp,dx-1,dy-1-dy/4,dx,cs,0,LE);
  727. if (sdata->hchar && i-x>1) Break; // &szlig;
  728. x=loop(sdata->bp, 0,dy-1,dx,cs,0,LE); // check for serifs
  729. i=loop(sdata->bp, 0,dy-2,dx,cs,0,LE); if (i<x) x=i;
  730. i=loop(sdata->bp, 0, 1,dx,cs,0,LE); if (i<x) x=i;
  731. i=loop(sdata->bp, 0, 2,dx,cs,0,LE); if (i<x) x=i;
  732. if (sdata->hchar && x>0) Break; // fl
  733. if (num_cross( 0,dx-1,dy/4,dy/4,sdata->bp,cs)>=3) ad=98*ad/100; // small M
  734. if (sdata->hchar || 2*y0<box1->m1+box1->m2) ad=96*ad/100;
  735. if (sdata->gchar) ad=96*ad/100; // &szlig; fl
  736. if (dx<5) { // for small fonts no middle line is possible for m
  737. ad=99*ad/100; // 4x6 m
  738. if (num_cross(0,dx-1,dy/8,dy/8,sdata->bp,cs)>=2) {
  739. ad=97*ad/100; // ~m
  740. if (dy<=4) Setac(box1,'m',97); // only for 4x6 font!
  741. }
  742. }
  743. Setac(box1,'n',ad);
  744. break;
  745. }
  746. return box1->c;
  747. }
  748. static wchar_t ocr0_M(ocr0_shared_t *sdata){
  749. struct box *box1=sdata->box1;
  750. pix *bp=sdata->bp;
  751. int d,x,y,i0,i1,i2,i3,t1,hchar=sdata->hchar,gchar=sdata->gchar,
  752. x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
  753. int dx=x1-x0+1,dy=y1-y0+1, /* size */
  754. ad; /* tmp-vars */
  755. // ------------------ test M ---------------------------
  756. for(ad=d=100;dx>3 && dy>3;){ // dy<=dx nicht perfekt! besser mittleres
  757. // min-suchen fuer m
  758. DBG( wchar_t c_ask='M'; )
  759. if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
  760. for (y=dy/4;y<=3*dy/4;y++)
  761. if (num_cross(0,dx-1,y,y,bp,cs)>=3) break;
  762. if (y>3*dy/4 && dx>4) Break;
  763. if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)<2
  764. && num_cross(0,dx-1, dy/8, dy/8,bp,cs)<2 ) Break; /* fat M */
  765. if( num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)<2 ) Break;
  766. x = loop(bp,dx-1 ,dy-1,dx,cs,0,LE); // ~ melted kl
  767. x = loop(bp,dx-1-x,dy-1,dx,cs,1,LE); if( x>dx/2 ) Break;
  768. if( loop(bp, 0,7*dy/16,dx,cs,0,RI)
  769. + loop(bp,dx-1,7*dy/16,dx,cs,0,LE) > dx/2 ) Break; // ~K
  770. if( dy>8 /* following lines should be extend to range check */
  771. && loop(bp, dx/4,dy-1, dy,cs,0,UP)<dy/4
  772. && loop(bp,3*dx/8,dy-1, dy,cs,0,UP)<dy/4 )
  773. if( loop(bp, 0,dy-1-dy/ 8,dx,cs,0,RI)
  774. < loop(bp, 0,dy-1-dy/16,dx,cs,0,RI)-dx/32 ) Break; // ~it_u
  775. if( num_cross(0,dx-1, dy/2, dy/2,bp,cs)==2
  776. && num_cross(0,dx-1, dy/4, dy/4,bp,cs)> 2
  777. && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)> 2 ) Break; // ~it_u
  778. if( num_cross(0 ,dx-1,3*dy/4,3*dy/4,bp,cs)==2
  779. && num_cross(dx/2,dx/2,3*dy/4, dy-1,bp,cs)> 0 ) Break; // ~it_v
  780. if( loop(bp,3*dx/4, 0,dy,cs,0,DO)
  781. > loop(bp,2*dx/4, 0,dy,cs,0,DO)
  782. && loop(bp,3*dx/4,dy-1,dy,cs,0,UP)
  783. < loop(bp,2*dx/4,dy-1,dy,cs,0,UP) ) Break; // ~N
  784. if( loop(bp,3*dx/4, dy/8,dy,cs,0,DO)
  785. > loop(bp,2*dx/4, dy/8,dy,cs,0,DO)
  786. && loop(bp,3*dx/4,dy-1-dy/8,dy,cs,0,UP)
  787. < loop(bp,2*dx/4,dy-1-dy/8,dy,cs,0,UP) ) Break; // ~serif_N
  788. // i0 is lower end of upper serifen (widest gap? )
  789. i0=0;
  790. if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)!=4 ){ // Is it a N ?
  791. if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)==3 ){
  792. for(y=dy/2+1;y<dy;y++){
  793. if( num_cross(0,dx-1,y,y,bp,cs)<3 ) break;
  794. }
  795. if( num_cross(0,dx-1,y,y,bp,cs)==2 ){
  796. x =loop(bp,dx-1 ,y-1,dx,cs,0,LE);
  797. x+=loop(bp,dx-1-x,y-1,dx,cs,1,LE);
  798. x+=loop(bp,dx-1-x,y-1,dx,cs,0,LE);
  799. if( loop(bp,dx-x,y-1,dy,cs,0,UP)>y-2 ) Break; // ~N
  800. }
  801. }
  802. }
  803. // MNWK
  804. for(i2=0,i1=x=dx/2;x<dx-dx/4;x++){ // lowest pixel
  805. y=loop(bp,x,0,dy,cs,0,DO); if(y>i2) {i2=y;i1=x;} else break; }
  806. i3=i2+loop(bp,i1,i2,dy-i2,cs,1,DO);
  807. if(i2<dy/4) {
  808. if (!sdata->hchar) Break; // rm
  809. ad=99*ad/100;
  810. }
  811. if (i2==0 && dx>8 && dy>12) Break; // glued and bad splitted serifen-MN
  812. // if( num_hole(x0, x1, y0 , y1 ,box1->p,cs,NULL) != 0 ) Break; // small A
  813. if (sdata->holes.num != 0) Break;
  814. t1=loop(bp,0 ,3*dy/4,dx,cs,0,RI);
  815. t1=loop(bp,t1,3*dy/4,dx,cs,1,RI); // thickness of line?
  816. if( 7*(t1+1)<dx )
  817. if( num_cross(i1,dx-1,i2-1,i2-1,bp,cs)!=2
  818. || num_cross(0 ,i1 ,i2-1,i2-1,bp,cs)!=2 ) Break; // too hard ???
  819. // ~u_n-pair
  820. if( num_cross(0,dx-1,0,0,bp,cs)!=2
  821. && num_cross(0,dx-1,1,1,bp,cs)!=2
  822. && num_cross(0,dx-1,2,2,bp,cs)!=2 ) Break;
  823. // ~nn v0.2.4a3
  824. if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)==4
  825. && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)==4 ){
  826. i1 =loop(bp, 0, dy/4,dx,cs,0,RI);
  827. i1+=loop(bp,i1, dy/4,dx,cs,1,RI);
  828. i1+=loop(bp,i1, dy/4,dx,cs,0,RI);
  829. i2 =loop(bp, 0,3*dy/4,dx,cs,0,RI);
  830. i2+=loop(bp,i2,3*dy/4,dx,cs,1,RI);
  831. i2+=loop(bp,i2,3*dy/4,dx,cs,0,RI);
  832. if( i1>=i2 ) Break; // no good M
  833. i1+=loop(bp,i1, dy/4,dx,cs,1,RI);
  834. i2+=loop(bp,i2,3*dy/4,dx,cs,1,RI);
  835. if( i1>=i2 ) Break; // no good M
  836. i1+=loop(bp,i1, dy/4,dx,cs,0,RI);
  837. i2+=loop(bp,i2,3*dy/4,dx,cs,0,RI);
  838. if( i1<=i2 ) Break; // no good M
  839. }
  840. if( num_cross(0,dx-1,dy/2,dy/2,bp,cs)==2
  841. && num_cross(0,dx-1,dy/4,dy/4,bp,cs)==2 && !hchar ) Break; // ~ \it u
  842. if (dy<17)
  843. if( num_cross(0,dx-1, 0, 0,bp,cs)<2 ) ad=99*ad/100;
  844. if (dx>5) /* 4x6 font has only 1 cross at y=1 */
  845. if( num_cross(0,dx-1, 1, 1,bp,cs)<2 ) ad=96*ad/100; // kt
  846. if( num_cross(dx/2,dx/2, 0, dy-1,bp,cs)!=1) ad=98*ad/100; // kt
  847. if (dx<5 && loop(bp,dx/2,0,dy,cs,0,DO)>=3*dy/8) ad=96*ad/100; // 4x6 H
  848. if( num_cross(0,dx-1, dy/4, dy/4,bp,cs)<=2
  849. && num_cross(0,dx-1,3*dy/4,3*dy/4,bp,cs)<=2
  850. && dx>8 && dy>12 ){
  851. ad=98*ad/100;
  852. for(y=5*dy/16;y<5*dy/8;y++) // look for H-line
  853. if( num_cross(0,dx-1,y ,y ,bp,cs)==1 ) break;
  854. if( y<5*dy/8 ) ad=95*ad/100;
  855. if( y<5*dy/8 )
  856. if( num_cross(2+dx/6,dx-3-dx/6,y-2,y-2,bp,cs)==0
  857. || num_cross(2+dx/6,dx-3-dx/6,y-1,y-1,bp,cs)==0 ) Break; // ~H bad!
  858. }
  859. if( loop(bp,3*dx/8, 0,dy,cs,0,DO) >dy/2
  860. && loop(bp,5*dx/8,dy-1,dy,cs,0,UP) >dy/2 ) ad=95*ad/100;
  861. if(!hchar){
  862. ad=98*ad/100; /* not sure */
  863. if( loop(bp,0, dy/4,dx,cs,0,RI)
  864. < loop(bp,0,dy-1-dy/8,dx,cs,0,RI)-dx/16 ) Break; // ~wi glued
  865. }
  866. if( gchar ) ad=98*ad/100;
  867. if (ad>99 && dx<8) ad=99*ad/100; /* give 5x8 N a chance */
  868. Setac(box1,'M',ad);
  869. break;
  870. }
  871. return box1->c;
  872. }
  873. static wchar_t ocr0_N(ocr0_shared_t *sdata){
  874. struct box *box1=sdata->box1;
  875. int d,x,y,i1,i2,i3,hchar=sdata->hchar,gchar=sdata->gchar,
  876. x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1;
  877. int dx=x1-x0+1,dy=y1-y0+1, /* size */
  878. (*aa)[4]=sdata->aa, /* corner-points, (x,y,dist^2,vector_idx) */
  879. dbg[9],
  880. ad; /* tmp-vars */
  881. // --- test N ------- +hchar -gchar
  882. for(ad=d=100;dx>3 && dy>3;){ // 4x6font
  883. int j;
  884. DBG( wchar_t c_ask='N'; )
  885. if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
  886. if (sdata->holes.num > 0) ad=98*ad/100; /* # */
  887. if (dx<6) ad=99*ad/100;
  888. if (dx<5) ad=99*ad/100;
  889. /* half distance to the center */
  890. d=2*sq(128/4);
  891. /* now we check for the 4 ends of the x */
  892. if (aa[0][2]>d) Break;
  893. if (aa[1][2]>d) Break;
  894. if (aa[2][2]>d) Break;
  895. if (aa[3][2]>d) Break;
  896. if (aa[3][0]-aa[0][0]<dx/2) Break;
  897. if (aa[2][0]-aa[1][0]<dx/2) Break;
  898. if (aa[1][1]-aa[0][1]<dy/2) Break;
  899. if (aa[2][1]-aa[3][1]<dy/2) Break;
  900. if (aa[3][0]-aa[0][0]<4-1) Break; /* to small to hold an N */
  901. if (aa[2][0]-aa[1][0]<4-1) Break; /* to small */
  902. if (abs(aa[3][1]-aa[0][1])>(dy+2)/5) Break; /* glued tu */
  903. if (abs(aa[3][1]-aa[0][1])>(dy+4)/8) ad=98*ad/100; /* glued tu */
  904. /* left and right vertical line */
  905. d=line_deviation(box1, aa[0][3], aa[1][3]); if (d>2*sq(1024/4)) Break;
  906. ad=(100-(d-sq(1024)/2)/sq(1024)/4)*ad/100;
  907. d=line_deviation(box1, aa[2][3], aa[3][3]); if (d>2*sq(1024/4)) Break;
  908. /* i1: uppermost left ^ from bottom (near 0,0) */
  909. i1=nearest_frame_vector(box1,aa[1][3],aa[2][3], x0+dx/8, y0);
  910. x=box1->frame_vector[i1][0];
  911. y=box1->frame_vector[i1][1];
  912. MSG( fprintf(stderr,"i1= %d (%d,%d) left ^ from below", i1,x-x0,y-y0);)
  913. if (y-y0 > 5*dy/8) Break;
  914. if (x-x0 > 5*dx/8) Break;
  915. /* i3: uppermost right ^ ~H */
  916. i3=nearest_frame_vector(box1,aa[1][3],aa[2][3], x1, y0);
  917. MSG( fprintf(stderr,"i3= %d (%d,%d) right ^ (ad=%d)",\
  918. i3, box1->frame_vector[i3][0]-x0,box1->frame_vector[i3][1]-y0,ad);)
  919. /* check lower border of diagonal line, may fail on fonts where
  920. * line ends on middle of right vertical line (screen font) */
  921. dbg[0]=d=line_deviation(box1,i1, aa[2][3]);
  922. /* check right border of left vertical line */
  923. /* but split to possible lower left serif + vert. line */
  924. j=nearest_frame_vector(box1,aa[1][3],i1, x0+dx/2, y1+dy/2);
  925. dbg[1]=d=line_deviation(box1, aa[1][3],j );
  926. +line_deviation(box1, j,i1);
  927. MSG(fprintf(stderr," i1-a2 %d a1_serif-i1 %d ad=%d",dbg[0],dbg[1],ad);)
  928. if (dbg[0] > sq(1024/4)) Break;
  929. if (dx>4 && dbg[1] > sq(1024/4)) ad=97*ad/100; // d=0..2*sq(1024)
  930. if (dx>4 && dbg[1] > sq(1024/3)) Break; // d=0..2*sq(1024)
  931. // serif N has d=sq(1024/3)=116508
  932. MSG( fprintf(stderr,"ad %d", ad); )
  933. /* i2: lowest right v from top, same frame? N-tilde etc.? */
  934. i2=nearest_frame_vector(box1,aa[3][3],aa[0][3], x1, y1-dy/8);
  935. x=box1->frame_vector[i2][0];
  936. y=box1->frame_vector[i2][1];
  937. MSG( fprintf(stderr,"i2= %d (%d,%d) lowest right v from top",\
  938. i2, box1->frame_vector[i2][0]-x0,box1->frame_vector[i2][1]-y0);)
  939. if (y-y0 < 3*dy/8) Break;
  940. if (x-x0 < 3*dx/8) Break;
  941. // test H
  942. if ( box1->frame_vector[i3][0]-box1->frame_vector[i1][0]> dx/4
  943. && box1->frame_vector[i3][1]-box1->frame_vector[i1][1]<=dy/8
  944. && y<=box1->frame_vector[i1][1]) Break;
  945. /* check if upper left and lower right point are joined directly */
  946. /* but split to possible upper right serif + down line */
  947. j=nearest_frame_vector(box1,i2,aa[0][3], x0+dx/2, y0-dy/2);
  948. dbg[2]=d=line_deviation(box1,i2, j)
  949. +line_deviation(box1, j, aa[0][3]);
  950. /* check if upper right and lower right point are joined directly */
  951. /* but split to possible upper right serif + vert. line */
  952. j=nearest_frame_vector(box1,aa[3][3],i2, x0+dx/2, y0-dy/2);
  953. dbg[3]=d=line_deviation(box1, aa[3][3],j)
  954. +line_deviation(box1, j,i2); // ToDo: split once more?
  955. MSG( fprintf(stderr," i2-a0 %d a3-i2 %d ad %d",dbg[2],dbg[3], ad); )
  956. if (dbg[2] > sq(1024/4)) Break;
  957. // serif N, ToDo: do it better
  958. if (dbg[3] > sq(1024/4)) ad=97*ad/100;
  959. if (dbg[3] > sq(1024/3)) Break;
  960. MSG( fprintf(stderr,"ad %d", ad); )
  961. MSG( fprintf(stderr,"check against melted tu"); )
  962. // i1 = left ^ from below, i2 = lowest right v from top
  963. // sample gocr_Device*: 3-8,dy=27
  964. if ( (box1->frame_vector[i1][1]-y0)
  965. -(y1-box1->frame_vector[i2][1])>dy/8) ad=99*ad/100; /* ~ tu */
  966. MSG( fprintf(stderr,"tu ad %d", ad); )
  967. if (box1->frame_vector[i2][0]
  968. -box1->frame_vector[i1][0]<=dx/8) Break; /* nonsignificant distance */
  969. MSG( fprintf(stderr,"i2-i1<=dx/8 ad %d", ad); )
  970. /* i1: uppermost left ^ from bottom (near 0,0) */
  971. /* i2: lowest right v from top, same frame? N-tilde etc.? */
  972. if (box1->frame_vector[i2][1]
  973. -box1->frame_vector[i1][1]<=dy/8) {
  974. // may happen on screen fonts 7x10
  975. if (dx>8) ad=97*ad/100; /* too flat (ff,H) */
  976. }
  977. MSG( fprintf(stderr,"i2-i1<=dy/8 ad %d", ad); )
  978. if (box1->frame_vector[i2][1]
  979. -box1->frame_vector[i1][1]<=dy/2) ad=99*ad/100;
  980. MSG( \
  981. fprintf(stderr,"^v %d %d %d %d line dev %d %d %d %d max %d %d ad %d",\
  982. box1->frame_vector[i1][0]-x0,box1->frame_vector[i1][1]-y0,\
  983. box1->frame_vector[i2][0]-x0,box1->frame_vector[i2][1]-y0,\
  984. dbg[0],dbg[1],dbg[2],dbg[3],sq(1024/4),sq(1024),ad);)
  985. ad=(100-(dbg[0]-sq(1024)/2)/sq(1024)/4)*ad/100;
  986. MSG( fprintf(stderr,"ad %d", ad); )
  987. ad=(100-(dbg[1]-sq(1024)/2)/sq(1024)/4)*ad/100;
  988. MSG( fprintf(stderr,"ad %d", ad); )
  989. ad=(100-(dbg[2]-sq(1024)/2)/sq(1024)/4)*ad/100;
  990. MSG( fprintf(stderr,"ad %d", ad); )
  991. ad=(100-(dbg[3]-sq(1024)/2)/sq(1024)/4)*ad/100;
  992. MSG( fprintf(stderr,"ad %d", ad); )
  993. if (!hchar) ad=99*ad/100;
  994. if ( gchar) ad=98*ad/100; // \sc N
  995. Setac(box1,'N',ad);
  996. break;
  997. }
  998. return box1->c;
  999. }
  1000. static wchar_t ocr0_h(ocr0_shared_t *sdata){
  1001. struct box *box1=sdata->box1;
  1002. pix *bp=sdata->bp;
  1003. int i,d,x,y,hchar=sdata->hchar,gchar=sdata->gchar,
  1004. x0=box1->x0,x1=box1->x1,y0=box1->y0,y1=box1->y1,cs=sdata->cs;
  1005. int dx=x1-x0+1,dy=y1-y0+1, /* size */
  1006. ad; /* tmp-vars */
  1007. int (*aa)[4]=sdata->aa; /* corner-points, (x,y,dist^2,vector_idx) */
  1008. // --- test h ---------------------------------------------------
  1009. for(ad=d=100;dx>2 && dy>3;){ // min 3x4
  1010. // rewritten for vectors 0.42
  1011. int i1, i2, i3, i4, i5, i6, i7, i8; // line derivation + corners
  1012. DBG( wchar_t c_ask='h'; )
  1013. if (sdata->holes.num > 1) Break; /* tolerant against a tiny hole */
  1014. /* half distance to the center */
  1015. d=2*sq(128/4);
  1016. /* now we check for the upper right end of the h */
  1017. if (aa[3][2]<d/4) Break; /* [2] = distance, ~BCDEF... */
  1018. if (aa[0][2]>d/2) Break; /* upper left end */
  1019. if (aa[1][2]>d/2) Break; /* lower left end */
  1020. if (aa[2][2]>d/2) Break; /* lowerright end */
  1021. /*
  1022. type A B=italic ???
  1023. 18 OOO
  1024. O O O
  1025. O O
  1026. O7OOO OOOO
  1027. O4 O O O
  1028. O O O O
  1029. O O O O O
  1030. 2O3 5O6 O OOO
  1031. */
  1032. i1=i8=aa[0][3];
  1033. i2=i3=aa[1][3];
  1034. i5=i6=aa[2][3];
  1035. // check the bow from below (fails on melted serifs)
  1036. for (i4=i=i2;i!=i5;i=(i+1)%box1->num_frame_vectors[0]) {
  1037. if (box1->frame_vector[ i][1]
  1038. <box1->frame_vector[i4][1]) i4=i; // get next maximum
  1039. if (box1->frame_vector[ i][1]<=y0) break; // fatal!
  1040. }
  1041. if (box1->frame_vector[i4][1]-y0<dy/4) Break; // ~MN
  1042. if (y1-box1->frame_vector[i4][1]<dy/4) Break; // ~BCDEGIJLOQSUYZ
  1043. // two steps for i7 to go around pitfalls on italic h
  1044. i7=nearest_frame_vector(box1, i6, i8, (x0+x1)/2, (y0+y1)/2);
  1045. i7=nearest_frame_vector(box1, i6, i7, x0, (y0+y1)/2);
  1046. i3=nearest_frame_vector(box1, i2, i4, (x0+x1)/2, y1);
  1047. i5=nearest_frame_vector(box1, i4, i6, (x0+x1)/2, y1);
  1048. MSG(fprintf(stderr,"i1-7 %d %d %d %d %d %d %d",i1,i2,i3,i4,i5,i6,i7);)
  1049. /* ... new part /// old obsolete part ... */
  1050. if( get_bw(0 ,dx/2,dy/8 ,dy/8 ,bp,cs,1) != 1 ) Break;
  1051. if( get_bw(0 ,dx/2,dy/2 ,dy/2 ,bp,cs,1) != 1 ) Break;
  1052. if( get_bw(dx/2 ,dx-1,dy-1-dy/3,dy-1-dy/3,bp,cs,1) != 1 ) Break;
  1053. if( get_bw(dx/2 ,dx/2,dy/5 ,dy-1-dy/3,bp,cs,1) != 1 ) Break;
  1054. if( get_bw(dx-1-dx/3,dx-1,0 ,1 ,bp,cs,1) == 1 ) Break;
  1055. if( get_bw(dx-1-dx/3,dx-1,1 ,dy/6 ,bp,cs,1) == 1 ) Break;
  1056. if( dy>18 )
  1057. if( get_bw(dx-1-dx/3,dx-1,dy/6 ,dy/5 ,bp,cs,1) == 1 ) Break;
  1058. if( get_bw(dx-1-dx/3,dx-1,dy-1-dy/4,dy-1 ,bp,cs,1) == 0 ) Break; // s-
  1059. for( x=x0+dx/3;x<x1-dx/3;x++)
  1060. if( get_bw(x, x,y1-dy/4, y1, box1->p,cs,1) == 0 ) break;
  1061. if( x>=x1-dx/3 ) Break;
  1062. for(i=dy/4,y=y0+dy/3;y<=y1 && i;y++){

Large files files are truncated, but you can click here to view the full file