"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "xocr/Oocr.c" of archive xocr_5.german.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*******************************************************
    2 ***       Bildverarbeitungs- und OCR-Routinen        ***
    3 ***                                                  ***
    4 *******************************************************/
    5 
    6 /** includes **/
    7 #include <stdio.h>
    8 #include <stdlib.h>
    9 #include <math.h>
   10 #include <time.h>
   11 #include <dirent.h>
   12 #include <sys/stat.h>
   13 #include <unistd.h>
   14 #include "ocr.h"
   15 #include "baum.h"
   16 #include "semantik.h"
   17 #include "main.h"
   18 
   19 /** defines **/
   20 #define MAXDIFFERENZ 64
   21 #define Segment_X 128
   22 #define Segment_Y 180
   23 #define Segment_Bytes 16
   24 #define MAXSTACK 30000
   25 #define MAXWINKEL 0.2094395102
   26 
   27 #define MAXANZAHL 60
   28 
   29 /************ Globale Variablen  *****************/
   30 extern short int Wsa[];
   31 extern long Quadrat[];
   32 extern struct Parameter ParaAktuell;
   33 
   34 struct LearndListe *ZeichenListeStart[35][16][16];
   35 
   36 unsigned char Bits[8]        = {128, 64, 32, 16,  8,  4,  2,  1};
   37 unsigned char RandRechts[8]  = {  1,  3,  7, 15, 31, 63,127,254};
   38 unsigned char RandLinks[8]   = {128,192,224,240,248,252,254,255};
   39 
   40 struct BitBlockListe  *BitBlockListeStartPtr        = NULL;
   41 struct BitBlockListe  *SegmentBitBlockListeStartPtr = NULL;
   42 struct BitBlockListe  *KopierePtr                   = NULL;
   43 
   44 long Page_x,Page_y,Page_Bytes_pro_Zeile;
   45 long Max_x,Min_x,Min_y,Max_y;
   46 long maxcount,rek_x,rek_y,xx,yy,offset_x,offset_y;
   47 
   48 unsigned char *OrginalBildPuffer,*ArbeitsPuffer,*HilfsPtr;
   49 unsigned char Value,Value1;
   50 unsigned char *rek_y_zeile;
   51 
   52 unsigned short int PunkteInByte[256];
   53 unsigned short int ByteIstGespiegelt[256];
   54 
   55 float faktorx,faktory;
   56 long durch_dx, durch_dy;
   57 
   58 /******** Sonstiges/Deklarationen  *************/
   59 
   60 void SucheBitBloecke();
   61 void SucheSegmenteBitBloecke();
   62 
   63 /***************************************************************
   64 Procedure        : void Spiegle()
   65 
   66 Uebergabe        : short int
   67 Rueckgabe        : short int
   68 Zugriffe/Global  : Keine
   69 Autor            : Martin Bauer
   70 Letzte Aenderung : 1.6.1995
   71 
   72 Getestet         : JA , Resultat: fehlerfrei (1.6.1995)
   73 
   74 Aufgabe:
   75          Es soll der Eingabeparameter (8-Bit) einfach gespiegelt
   76          werden. Die muss nicht effizient geloest sein !
   77 
   78 ****************************************************************
   79    Arithmetic is being able to count up to twenty without
   80    taking off your shoes.
   81 ****************************************************************/
   82 
   83 unsigned short int Spiegle(wert)
   84 unsigned long wert;
   85 {
   86   long l,r,t;
   87   unsigned short int wert_1;
   88   l=128;
   89   r=1;
   90   wert_1=0;
   91 for (t=0;t<4;t++)
   92 {
   93  if (l & wert) wert_1 = wert_1 | r;
   94  if (r & wert) wert_1 = wert_1 | l;
   95  l=l>>1;
   96  r=r<<1;
   97 }
   98 return(wert_1);
   99 }
  100 
  101 
  102 /***************************************************************
  103 Procedure        : void ZaehlePunkte()
  104 
  105 Uebergabe        : short int
  106 Rueckgabe        : short int
  107 Zugriffe/Global  : Keine
  108 Autor            : Martin Bauer
  109 Letzte Aenderung : 1.6.1995
  110 
  111 Getestet         : JA , Resultat: fehlerfrei (1.6.1995)
  112 
  113 Aufgabe:
  114          Es sollen alle im Eingabeparameter (8-Bit) gesetzten Bits
  115          gezaehlt werden. Die muss nicht effizient geloest sein !
  116 
  117 *****************************************************************/
  118 /* Remember:  Silly is a state of Mind, Stupid is a way of Life.*/
  119 /****************************************************************/
  120 unsigned short int ZaehlePunkte(wert)
  121 unsigned long wert;
  122 {
  123  unsigned long l,t;
  124  unsigned char wert_1;
  125  l=1;
  126  wert_1=0;
  127  for (t=0;t<8;t++)
  128  {
  129   if (l & wert) wert_1++;
  130   l=l<<1;
  131  }
  132  return(wert_1);
  133 }
  134 
  135 
  136 /***************************************************************
  137 Procedure        : MemoryError()
  138 
  139 Uebergabe        : Nichts
  140 Rueckgabe        : Nichts
  141 Autor            : Martin Bauer
  142 Letzte Aenderung : 3.6.1995
  143 
  144 Getestet         : JA , Resultat: fehlerfrei
  145 
  146 
  147 Aufgabe:
  148             Bei zuwenig Speicher soll ein Fehler ausgegeben werden.
  149 ****************************************************************/
  150 void MemoryError()
  151 {
  152  /* "Heisenberg may have slept here" */
  153  fprintf(stderr,"        -------> FEHLER <-------           \n");
  154  fprintf(stderr,"                                           \n");
  155  fprintf(stderr,"- Das System hat den angefordeten Speicher \n");
  156  fprintf(stderr,"      nicht zur verfuegung gestellt !      \n");
  157  fprintf(stderr,"                                           \n");
  158  fprintf(stderr,"- Behebung des Fehlers:                    \n");
  159  fprintf(stderr,"                                           \n");
  160  fprintf(stderr,"  1. Swapspace erhoehen                    \n");
  161  fprintf(stderr,"  2. Mehr Arbeitsspeicher kaufen           \n");
  162  fprintf(stderr,"  3. Andere Applikationen schliessen       \n");
  163  fprintf(stderr,"                                           \n");
  164  fflush(stderr);
  165  exit(-1);
  166 }
  167 
  168 
  169 /***************************************************************
  170 Procedure        : OcrInit()
  171 
  172 Uebergabe        : Nichts
  173 Rueckgabe        : Nichts
  174 Autor            : Martin Bauer
  175 Letzte Aenderung : 3.6.1995
  176 
  177 Getestet         : JA , Resultat: fehlerfrei
  178 
  179 
  180 Aufgabe:
  181             Es werden diverse Initialisierungen und Berechnungen
  182             vorgenommen .
  183 ****************************************************************/
  184 void LadeGelernteZeichen();
  185 
  186 void OcrInit()
  187 {
  188  unsigned long t,t1,t2;
  189  for (t=0;t<256;t++)
  190  {
  191   PunkteInByte[t]=ZaehlePunkte(t);
  192   ByteIstGespiegelt[t]=Spiegle(t);
  193  }
  194  /* init der Zeichenliste */
  195  for (t=0;t<35;t++) for (t1=0;t1<16;t1++) for (t2=0;t2<16;t2++) ZeichenListeStart[t][t1][t2]=NULL;
  196  LadeGelernteZeichen();
  197 }
  198 
  199 
  200 /***************************************************************
  201 Procedure        : void LoescheBildFeld(x,y,dx,dy)
  202 
  203 Uebergabe        : Kordinaten x,y,dx,dy
  204 Rueckgabe        : Nichts
  205 Zugriffe/Global  : OrginalBildPuffer,Page_Bytes_Pro_Zeile
  206 Autor            : Martin Bauer
  207 Letzte Aenderung : 1.6.1995
  208 
  209 Getestet         : JA , Resultat: fehlerfrei
  210 
  211 
  212 Aufgabe:
  213            Es soll in dem Bild ein Bereich beginnend bei
  214            x,y mit der Groesse dx,dy geloescht werden.
  215 
  216 ****************************************************************/
  217 void LoescheBildFeld(x,y,dx,dy)
  218 long x,y,dx,dy;
  219 {
  220  char *P;
  221  long xx,yy,x1,y1,beginx,endex;
  222  x--;
  223  dx++;
  224  xx=x+dx;
  225  yy=y+dy+1;
  226  if (xx>=Page_x) xx=Page_x-1;
  227  if (yy>=Page_y) yy=Page_y-1;
  228 
  229 
  230  endex=(xx>>3);
  231  beginx=(x>>3);
  232 
  233  for (y1=y;y1<yy;y1++)
  234  {
  235   P=OrginalBildPuffer+Page_Bytes_pro_Zeile*y1+beginx;
  236   *P=*P & RandLinks[x&7];
  237   P++;
  238   for (x1=beginx;x1<endex;x1++)
  239   {
  240    *P=0; P++;
  241   }
  242   *P=*P & RandRechts[xx&7];
  243  }
  244 }
  245 
  246 /***************************************************************
  247 Procedure        : void SetzeBildFeld(x,y,dx,dy)
  248 
  249 Uebergabe        : Kordinaten x,y,dx,dy
  250 Rueckgabe        : Nichts
  251 Zugriffe/Global  : OrginalBildPuffer,Page_Bytes_Pro_Zeile
  252 Autor            : Martin Bauer
  253 Letzte Aenderung : 1.6.1995
  254 
  255 Getestet         : JA , Resultat: fehlerfrei
  256 
  257 
  258 Aufgabe:
  259            Es soll in dem Bild ein Bereich beginnend bei
  260            x,y mit der Groesse dx,dy gesetzt werden.
  261 
  262 ****************************************************************/
  263 void SetzeBildFeld(Puffer,max,x,y,dx,dy)
  264 unsigned char *Puffer;
  265 long max,x,y,dx,dy;
  266 {
  267  unsigned char *P;
  268  long xx,yy,x1,y1,beginx,endex;
  269  xx=(--x)+(++dx);
  270  yy=y+dy+1;
  271  if (xx>=Page_x) xx=Page_x-1;
  272  if (yy>=Page_y) yy=Page_y-1;
  273 
  274 
  275  endex=(xx>>3);
  276  beginx=(x>>3);
  277  x &= 7;
  278  xx &= 7;
  279  for (y1=y;y1<yy;y1++)
  280  {
  281   P=Puffer+max*y1+beginx;
  282   *P++ |= ~RandLinks[x];
  283   for (x1=beginx;x1<endex;x1++) *P++=255;
  284   *P |= ~RandRechts[xx];
  285  }
  286 }
  287 
  288 
  289 /***************************************************************
  290 Procedure        : void KopiereRekursiv
  291 
  292 Uebergabe        : Nichts
  293 Rueckgabe        : Nichts
  294 Zugriffe/Global  : maxcount,offset_x,offset_y, y_zeile,faktory,
  295                    KopierePtr,Page_y,Page_x,Value1,Value,HilfsPtr;
  296 Autor            : Martin Bauer
  297 Letzte Aenderung : 1.6.1995
  298 
  299 Getestet         : JA , Resultat: fehlerfrei (1.6.1995)
  300 
  301 
  302 Aufgabe:
  303           Es wurde aus Performance- und Stackminimierungsgruenden
  304           auf lokale Variablen und Parameter verzichtet !
  305           Es sollen zusammenhaengende Punkte aus dem Ur-Bild wegkopiert
  306           und mittels dem Wert von faktory auf ein 16x16 grosses Bild
  307           Kopiert werden. Das Ziel-Bild ist: KopierePtr->Bilddaten.
  308           Das Ur-Bild (y_zeile zeigt darauf) wird dabei VERNICHTET !
  309 
  310 ****************************************************************/
  311 void KopiereRekursiv()
  312 {
  313   maxcount++;
  314   if (maxcount>MAXSTACK) { maxcount--; return; }   /* notfall-rek. abbruch */
  315   if ((rek_x<0) || (Page_x<rek_x) || (rek_y<0) || (Page_y<rek_y)) { maxcount--; return; }
  316   HilfsPtr=(rek_y_zeile+(rek_x >> 3));
  317   Value=*HilfsPtr;
  318   Value1=Value &  (~(128>>(rek_x&7)));
  319   if ( Value!=Value1 )
  320   {
  321    *HilfsPtr=Value1;
  322    {
  323     long x,y;
  324     x=((rek_x-KopierePtr->x)*faktory) ;
  325     y=((rek_y-KopierePtr->y)*faktory) ;
  326     x=x+offset_x;
  327     y=y+offset_y;
  328     if (y>15) y=15;
  329     if (x>15) x=15;
  330     HilfsPtr=(KopierePtr->BildDaten+y+y+(x>>3));
  331     *HilfsPtr=*HilfsPtr | (128>>(x&7));
  332     }
  333    if (Min_x>rek_x) Min_x=rek_x; if (Min_y>rek_y) Min_y=rek_y;
  334    if (Max_x<rek_x) Max_x=rek_x; if (Max_y<rek_y) Max_y=rek_y;
  335    rek_x--;
  336    KopiereRekursiv();
  337    rek_x+=2;
  338    KopiereRekursiv();
  339    rek_x--;
  340    rek_y--;
  341    rek_y_zeile-=Page_Bytes_pro_Zeile;
  342    KopiereRekursiv();
  343    rek_y+=2;
  344    rek_y_zeile=rek_y_zeile+Page_Bytes_pro_Zeile+Page_Bytes_pro_Zeile;
  345    KopiereRekursiv();
  346    rek_y--;
  347    rek_y_zeile-=Page_Bytes_pro_Zeile;
  348   }
  349   maxcount--;
  350 }
  351 
  352 
  353 /***************************************************************
  354 Procedure        : void Finde_Bloecke()
  355 
  356 Uebergabe        : Nichts
  357 Rueckgabe        : Nichts
  358 Autor            : Martin Bauer
  359 Letzte Aenderung : 1.6.1995
  360 
  361 Getestet         : JA , Resultat: fehlerfrei (1.6.1995)
  362 
  363 Aufgabe:
  364          Es sollen in einem Bild (*OrginalBildPuffer) der Groesse
  365          Page_x,Page_y (Page_Bytes_pro_Zeile) einzelne zusammen-
  366          haengende Punkte gefunden werden. Diese Bloecke sollen
  367          dann in eine Liste eingehaengt werden. Der Startzeiger dieser
  368          Liste ist: *BitBlockListeStartPtr.
  369          Die Elemente dieser Liste sind vo Typ: struct BitBlockListe
  370 
  371 ****************************************************************/
  372 void Finde_Bloecke()
  373 {
  374  char *ArbeitsPtr,*P1,*P2;
  375  long t,x,y,dx,dy,y_zeile;
  376  long n_dx,n_dy,anzahl;
  377  struct BitBlockListe *Ptr,*Ptr1;
  378 
  379  /* Init der lokalen Variablen */
  380  t=0; x=0; y=0; dx=0; dy=0; y_zeile=0; n_dx=0;
  381  n_dy=0; anzahl=0; Ptr=NULL; Ptr1=NULL; P1=NULL; P2=NULL;
  382 
  383  /* Kopiere Orginaldaten in einen Arbeitspuffer */
  384  x=Page_y*Page_Bytes_pro_Zeile; ArbeitsPtr=malloc(x+1000);
  385  if (ArbeitsPtr==NULL) { MemoryError(); }
  386  P1=ArbeitsPtr; P2=OrginalBildPuffer;
  387  for (t=0;t<x;t++) { *P1=*P2; P1++; P2++; }
  388 
  389  /* untersuche nach Bloecken */
  390  y_zeile=-Page_Bytes_pro_Zeile-Page_Bytes_pro_Zeile;
  391  for (y=0;y<Page_y;y+=2)
  392  {
  393   y_zeile=y_zeile+Page_Bytes_pro_Zeile+Page_Bytes_pro_Zeile;
  394   ArbeitsPuffer=ArbeitsPtr;
  395   /* gehe alle 2 x-Spalten voran */
  396   for (x=0;x<Page_x;x+=2)
  397   {
  398    /* Punkt im Bild gesetzt ? */
  399    if (Bits[(x&7)] & (*(ArbeitsPuffer+y_zeile+(x>>3))))
  400    {
  401     /* Pixel im ArbeitsBild gesetzt ! */
  402     Min_x=x; Max_x=x; Min_y=y; Max_y=y; maxcount=0;
  403     rek_x=x; rek_y=y; rek_y_zeile=y_zeile+ArbeitsPuffer;
  404     /* suche nun den groessten Block */
  405     SucheBitBloecke();
  406     dx=Max_x-Min_x; dy=Max_y-Min_y;
  407     if ((dx>0) && (dy>0))
  408     {
  409      /* erstelle Datenelement */
  410      anzahl++; n_dx+=dx; n_dy+=dy;
  411      Ptr=calloc(1,sizeof(struct BitBlockListe));
  412      if (Ptr==NULL) { MemoryError(); }
  413      Ptr->Bytes_pro_Zeile=t;
  414      Ptr->x=Min_x;
  415      Ptr->y=Min_y;
  416      Ptr->Startx=x;
  417      Ptr->Starty=y;
  418      Ptr->Geloescht=0;
  419      Ptr->SpaltenNummer=0;
  420      Ptr->SegmentNummer=0;
  421      Ptr->XSpiegel=0;
  422      Ptr->YSpiegel=0;
  423      Ptr->Untere_Zeile=-1;
  424      Ptr->Obere_Zeile=-1;
  425      Ptr->Bild=0;
  426      Ptr->dx=dx;
  427      Ptr->Elemente=1;
  428      Ptr->dy=dy;
  429      Ptr->xx=Min_x+dx;
  430      Ptr->yy=Min_y+dy;
  431      Ptr->NextPtrInZeile=NULL;
  432      Ptr->NextSegmentBlockPtr=NULL;
  433      Ptr->NextPtrInSegment=NULL;
  434      Ptr->NextPtr=BitBlockListeStartPtr;
  435      BitBlockListeStartPtr=Ptr;
  436     }
  437    x=x+dx-1;
  438    }  /* punkt gesetzt */
  439   }  /* x loop */
  440  } /* y loop */
  441  if (anzahl!=0)
  442  { /* es gab also Bitbloecke */
  443    long schnittx,schnitty;
  444    schnittx=(n_dx / (anzahl+0.0))*15;
  445    schnitty=(n_dy / (anzahl+0.0))*15;
  446    for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  447    {
  448     if (Ptr->dx>schnittx) { Ptr->Bild=1; }
  449     if (Ptr->dy>schnitty) { Ptr->Bild=1; }
  450    }
  451    /* suche nach bilder die sich ueberschneiden */
  452    for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  453    {
  454     if ((Ptr->Geloescht==0) && (Ptr->Bild==1))
  455     {
  456      for (Ptr1=BitBlockListeStartPtr;Ptr1!=NULL;Ptr1=Ptr1->NextPtr)
  457      {
  458       if ((Ptr1!=Ptr) && (Ptr1->Geloescht==0))
  459       {
  460        if (Ptr->x>Ptr1->x) { x=Ptr->x; } else { x=Ptr1->x; }
  461        if (Ptr->y>Ptr1->y) { y=Ptr->y; } else { y=Ptr1->y; }
  462        if (Ptr->xx<Ptr1->xx) { xx=Ptr->xx; } else { xx=Ptr1->xx; }
  463        if (Ptr->yy<Ptr1->yy) { yy=Ptr->yy; } else { yy=Ptr1->yy; }
  464        if (((xx-x)>=0) && ((yy-y)>=0))
  465        { /* verschmelzen ! */
  466         if (Ptr->x>Ptr1->x) { x=Ptr1->x; } else { x=Ptr->x; }
  467         if (Ptr->y>Ptr1->y) { y=Ptr1->y; } else { y=Ptr->y; }
  468         if (Ptr->xx<Ptr1->xx) { xx=Ptr1->xx; } else { xx=Ptr->xx; }
  469         if (Ptr->yy<Ptr1->yy) { yy=Ptr1->yy; } else { yy=Ptr->yy; }
  470         Ptr1->Geloescht=0;
  471         Ptr1->Bild=1;
  472         Ptr->x=x;
  473         Ptr->Bild=1;
  474         Ptr->Geloescht=0;
  475         Ptr->y=y;
  476         Ptr->xx=xx;
  477         Ptr->yy=yy;
  478         Ptr->dx=xx-x;
  479         Ptr->dy=yy-y;
  480        } /* diff x,y */
  481       }
  482      }
  483     }
  484    }
  485   /* und loesche alle Bilder aus dem Orginal-Bild ! */
  486    for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  487    {
  488     if (Ptr->Bild==1)
  489     {
  490      Ptr->Geloescht=1;
  491      LoescheBildFeld(Ptr->x,Ptr->y,Ptr->dx,Ptr->dy);
  492     }
  493    }
  494   }
  495   /* Jetzt werden alle erkannten Bloecke aus dem Bild kopiert */
  496   /* resturiere ArbeitsBild */
  497   x=Page_y*Page_Bytes_pro_Zeile; P1=ArbeitsPtr; P2=OrginalBildPuffer;
  498   for (t=0;t<x;t++) { *P1=*P2; P1++; P2++; }
  499   for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  500   {
  501    if ((Ptr->Bild==0) && (Ptr->Geloescht==0))
  502    {
  503     for (t=0;t<32;t++) Ptr->BildDaten[t]=0; /* loesche bild */
  504     offset_x=0; offset_y=0;
  505     if (Ptr->dx>Ptr->dy) { faktory=16/(Ptr->dx+0.0); offset_y=(16-(faktory*Ptr->dy))/2; }
  506     else                 { faktory=16/(Ptr->dy+0.0); offset_x=(16-(faktory*Ptr->dx))/2; }
  507     if ((Ptr->dx<16) && (Ptr->dy<16)) {  faktory=1.0; offset_y=(16-Ptr->dy)>>1; offset_x=(16-Ptr->dx)>>1; }
  508     KopierePtr=Ptr;
  509     rek_x=Ptr->Startx;
  510     rek_y=Ptr->Starty;
  511     maxcount=0;
  512     rek_y_zeile=ArbeitsPtr+rek_y*Page_Bytes_pro_Zeile;
  513     KopiereRekursiv();
  514    }
  515   }
  516   free(ArbeitsPtr);
  517 }
  518 
  519 
  520 /***************************************************************
  521 Procedure        : void Finde_SegmentBloecke()
  522 
  523 Uebergabe        : Nichts
  524 Rueckgabe        : Nichts
  525 Autor            : Martin Bauer
  526 Letzte Aenderung : 1.6.1995
  527 
  528 Getestet         : JA , Resultat: fehlerfrei (1.6.1995)
  529 
  530 Aufgabe:
  531          Es sollen in einem Bild (*OrginalBildPuffer) der Groesse
  532          Page_x,Page_y (Page_Bytes_pro_Zeile) alle "Segmente", d.h.
  533          alle rechteckigen Bloecke zusammengefasst werden die nach
  534          einem Verkleinerungszoom des Orginalbildes sich gebildet haben.
  535          Dadurch kann man einzelne Text-Bloecke gut herausfinden.
  536          Diese gefundenen Bloecke werden in eine Liste eingetragen.
  537          Der StartPointer der Liste ist: SegmentBitBlockListeStartPtr
  538          Die Elemente der Liste haben den Typ: BitBlockListe.
  539          Der Zeiger auf das naechste Segment ist: NextPtrInSegment
  540          Es sollen weiterhin alle Segmente in Spalten sortiert werden.
  541          Dabei gilt: Spalten von links nach rechts, Segmente in den
  542          Spalten vun oben nach unten.
  543 
  544 ****************************************************************/
  545 void Finde_SegmentBloecke()
  546 {
  547  long t,x,y,dx,dy,y1,xx,yy,y_zeile;
  548  struct BitBlockListe *Ptr,*P1,*P2,*P3,*P4,*P0;
  549  unsigned char *HilfsPuffer,*P,*Pc1;
  550  long SegmentNummer,x11,y11,k,min,max,Anzahl,Summe;
  551  float deltax,deltay;
  552 
  553  /* Init der lokalen Variablen */
  554  t=0; x=0; y=0; dx=0; dy=0; xx=0; yy=0; y_zeile=0;
  555  SegmentNummer=0; x11=0; y11=0; k=0; min=0; max=0;
  556  Summe=0; Anzahl=0; y1=0;
  557  P1=NULL; P2=NULL; P3=NULL; P4=NULL; P0=NULL;
  558  P=NULL; HilfsPuffer=NULL; deltax=0.0; deltay=0.0;
  559 
  560  /* lege platz fuer segment-kopie an ! */
  561  k=Page_Bytes_pro_Zeile*Page_y;
  562  HilfsPuffer=calloc(1,k);
  563  if (HilfsPuffer==NULL) { MemoryError(); }
  564  Pc1=HilfsPuffer;
  565  for (t=0;t<k;t++) { *Pc1=0; Pc1++; }
  566  dx=0;
  567  dy=0;
  568  Anzahl=0;
  569 
  570  /* kopiere jetzt schwarz bloecke rein ! */
  571    for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  572    {
  573     if ((Ptr->Bild==0) && (Ptr->Geloescht==0))
  574     {
  575      dx=dx+Ptr->dx;
  576      dy=dy+Ptr->dy;
  577      Anzahl++;
  578     }
  579    }
  580  x11=0;
  581  y11=0;
  582  if (Anzahl!=0)
  583  {
  584   x11=((dx+0.0)/Anzahl)*2;
  585   y11=((dy+0.0)/Anzahl)*3;
  586  }
  587  for (Ptr=BitBlockListeStartPtr;Ptr!=NULL;Ptr=Ptr->NextPtr)
  588    {
  589     if ((Ptr->Bild==0) && (Ptr->Geloescht==0))
  590     {
  591     if (x11>Ptr->dx) { x=x11; } else { x=Ptr->dx*1.5; }
  592     if (y11>Ptr->dy) { y=y11; } else { y=Ptr->dy*1.5; }
  593      SetzeBildFeld(HilfsPuffer,Page_Bytes_pro_Zeile,Ptr->x,Ptr->y,x,y);
  594     }
  595    }
  596 
  597  /* Jetzt wird nach den Bloecken im schwarzen bloecke Bild gesucht */
  598  y_zeile=0-Page_Bytes_pro_Zeile;
  599  for (y=0;y<Page_y;y+=1)
  600  {
  601   y_zeile=y_zeile+Page_Bytes_pro_Zeile;
  602   for (x=0;x<Page_x;x+=1)
  603   {
  604    /* Punkt gesetzt ? */
  605    if (Bits[(x&7)]&(*(HilfsPuffer+y_zeile+(x >> 3))))
  606    {
  607     /* Pixel im ArbeitsBild gesetzt ! */
  608     Min_x=x; Max_x=x;
  609     Min_y=y; Max_y=y;
  610     maxcount=0;
  611     ArbeitsPuffer=HilfsPuffer;
  612     rek_x=x; rek_y=y; rek_y_zeile=y_zeile+ArbeitsPuffer;
  613     SucheBitBloecke();
  614     dx=Max_x-Min_x+1;
  615     dy=Max_y-Min_y+1;
  616     if ((dx>3) && (dy>3))
  617     {
  618      /* erstelle Datenelement */
  619      Ptr=calloc(1,sizeof(struct BitBlockListe));
  620      if (Ptr==NULL) { MemoryError(); }
  621      Ptr->Bytes_pro_Zeile=0;
  622      Ptr->x=Min_x;
  623      Ptr->y=Min_y;
  624      Ptr->Startx=x;
  625      Ptr->Starty=y;
  626      Ptr->Bild=0;
  627      Ptr->SegmentNummer=-1;
  628      Ptr->SpaltenNummer=-1;
  629      Ptr->XSpiegel=0;
  630      Ptr->YSpiegel=0;
  631      Ptr->Untere_Zeile=-1;
  632      Ptr->Obere_Zeile=-1;
  633      Ptr->Geloescht=0;
  634      Ptr->dx=dx;
  635      Ptr->dy=dy;
  636      Ptr->xx=Min_x+dx;
  637      Ptr->yy=Min_y+dy;
  638      Ptr->NextPtrInZeile=NULL;
  639      Ptr->NextSegmentBlockPtr=NULL;
  640      Ptr->NextPtrInSegment=NULL;
  641      Ptr->NextPtr=SegmentBitBlockListeStartPtr;
  642      SegmentBitBlockListeStartPtr=Ptr;
  643     } /* min. 2 pixel */
  644     x=x+dx-1;
  645    }  /* punkt gesetzt */
  646   }  /* x loop */
  647  }  /* y loop */
  648  free(HilfsPuffer);
  649  /* Wenn nun wegen max-rekursion abgebrochen wurde, muessen */
  650  /* wir noch zusammenhaengende Segmente zusammenfuegen !    */
  651  for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  652  {
  653   if (P1->Geloescht==0)
  654   {
  655    for (P2=SegmentBitBlockListeStartPtr;P2!=NULL;P2=P2->NextPtr)
  656    {
  657     if ((P2->Geloescht==0) && (P1!=P2))
  658     {
  659      if (P1->x>P2->x) { x=P1->x; } else { x=P2->x; }
  660      if (P1->y>P2->y) { y=P1->y; } else { y=P2->y; }
  661      if (P1->xx<P2->xx) { xx=P1->xx; } else { xx=P2->xx; }
  662      if (P1->yy<P2->yy) { yy=P1->yy; } else { yy=P2->yy; }
  663      if (((xx-x)>=0) && ((yy-y)>=0))
  664      { /* verschmelzen ! */
  665       if (P1->x>P2->x) { x=P2->x; } else { x=P1->x; }
  666       if (P1->y>P2->y) { y=P2->y; } else { y=P1->y; }
  667       if (P1->xx<P2->xx) { xx=P2->xx; } else { xx=P1->xx; }
  668       if (P1->yy<P2->yy) { yy=P2->yy; } else { yy=P1->yy; }
  669       P2->Geloescht=1;
  670       P1->x=x;
  671       P1->y=y;
  672       P1->xx=xx;
  673       P1->yy=yy;
  674       P1->dx=xx-x;
  675       P1->dy=yy-y;
  676      } /* diff x,y */
  677     } /* p1!=p2 */
  678    } /* for P2 */
  679   } /* if */
  680   if (((P1->xx-P1->x)<2) && ((P1->yy-P1->y)<3)) P1->Geloescht=1;
  681  } /* for P1 */
  682 
  683  /* Berechne nun die Spalten / Segmentreihenfolge */
  684  min=9999999; max=0; Summe=0; Anzahl=0; P2=NULL;
  685  for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  686  {
  687   if (P1->Geloescht==0)
  688   {
  689    if (P1->x<min) { min=P1->x; P2=P1; }
  690    if (P1->xx>max) { max=P1->xx; }
  691    Anzahl++;
  692    Summe=Summe+P1->xx-P1->x;
  693   } /* if not killed */
  694  } /* for */
  695  if(Anzahl!=0)
  696  {
  697   float Schnitt,aha;
  698   long SpaltenAnzahl,x1,SpaltenNummer;
  699   Schnitt=Summe/(Anzahl+0.0);
  700   SpaltenNummer=0;
  701   SpaltenAnzahl=(0.5+((max-min) / Schnitt));
  702   aha=((max-min) / SpaltenAnzahl)*0.7 ;
  703 
  704  for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  705   {
  706 
  707     if ((P1->dx<aha) )
  708     {
  709      dx=P1->dx+x11;
  710      xx=dx+P1->x;
  711      P1->dx=dx;
  712      P1->xx=xx;
  713    }
  714   }
  715 
  716 
  717  min=9999999; max=0; Summe=0; Anzahl=0; P2=NULL;
  718  for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  719  {
  720   if (P1->Geloescht==0)
  721   {
  722    if (P1->x<min) { min=P1->x; P2=P1; }
  723    if (P1->xx>max) { max=P1->xx; }
  724    Anzahl++;
  725    Summe=Summe+P1->xx-P1->x;
  726   } /* if not killed */
  727  } /* for */
  728 
  729  Schnitt=Summe/(Anzahl+0.0);
  730  SpaltenNummer=0;
  731  SpaltenAnzahl=(0.5+((max-min) / Schnitt));
  732 
  733 
  734  /* */
  735   for (SpaltenNummer=0;SpaltenNummer<=SpaltenAnzahl;)
  736   {
  737    x1=min+Schnitt;
  738    for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  739    {
  740     if ((P1->Geloescht==0) && (P1->SpaltenNummer==-1) && (P1->x<x1))
  741     {
  742      P1->SpaltenNummer=SpaltenNummer;
  743     } /* if not killed */
  744    } /* for */
  745    SpaltenNummer++;
  746    min=max+1;
  747    for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  748    {
  749     if ((P1->Geloescht==0) && (P1->SpaltenNummer==-1) && (P1->x<min))
  750     {
  751      min=P1->x;
  752     } /* if */
  753    } /* for */
  754   } /* for spaltennummer */
  755   P3=NULL; P4=NULL;
  756   SegmentNummer=0;
  757   min=9999999;
  758   for (SpaltenNummer=0;SpaltenNummer<=SpaltenAnzahl;SpaltenNummer++)
  759   {
  760    P2=SegmentBitBlockListeStartPtr;
  761    for (;P2!=NULL;)
  762    {
  763     P2=NULL; min=88888888;
  764     for (P1=SegmentBitBlockListeStartPtr;P1!=NULL;P1=P1->NextPtr)
  765     {
  766      if ((P1->Geloescht==0) && (P1->SpaltenNummer==SpaltenNummer) && (P1->SegmentNummer==-1))
  767      {
  768       if (P1->y<min) { min=P1->y; P2=P1; }
  769      } /* if */
  770     }  /* for */
  771     if (P2!=NULL)
  772     {
  773      if (P3==NULL) P4=P2; /* start */
  774      if (P3!=NULL) P3->NextSegmentBlockPtr=P2;
  775      P3=P2;
  776      P2->SegmentNummer=SegmentNummer;
  777      SegmentNummer++;
  778     }
  779    } /* P2!=NULL */
  780   } /* for spaltennummer */
  781   P0=NULL;
  782   if (P4!=NULL)
  783   {
  784    for (P1=P4;P1!=NULL;P1=P1->NextSegmentBlockPtr)
  785    {
  786     if (P1->NextSegmentBlockPtr!=NULL)
  787     {
  788      P2=P1->NextSegmentBlockPtr;
  789      if (P1->y>P2->y) { y=P1->y; } else { y=P2->y; }
  790      if (P1->yy<P2->yy) { yy=P1->yy; } else { yy