# include "bitmapConfig.h" # include # include "bmSegments.h" # include "bmintern.h" # include /************************************************************************/ /* */ /* Build an administration of the 'segments' in an image. */ /* */ /* All pixels in a segment have the same color, and the segment is */ /* connected. */ /* */ /************************************************************************/ typedef struct LookUp { int luX0; int luXp; SegmentEdge * lu_edge; SegmentNode * lu_node; int lu_use; int lu_compid; } LookUp; typedef struct CompIndex { BitmapSegment * ci_compo; int ci_count; } CompIndex; # define LU_UNSPEC 1 # define LU_ENDED 2 # define LU_EXTENDED 3 # define LU_MERGED 4 /************************************************************************/ /* */ /* Insert a node in the administration of a segment. */ /* */ /************************************************************************/ static int bmRememberSegmentNode( BitmapSegment * bs, SegmentNode * sn ) { SegmentNode ** nw; int row= sn->snY0; nw= (SegmentNode **)realloc( bs->bsNodes, ( bs->bsNodeCount+ 1 )* sizeof(SegmentNode *) ); if ( ! nw ) { XDEB(nw); return -1; } bs->bsNodes= nw; nw[bs->bsNodeCount++]= sn; if ( bs->bsNodeCount <= 1 ) { bs->bsY0= bs->bsY1= row; } else{ if ( bs->bsY0 > row ) { bs->bsY0 = row; } if ( bs->bsY1 < row ) { bs->bsY1 = row; } } return 0; } /************************************************************************/ /* */ /* Insert an edge in the administration of a segment. */ /* */ /************************************************************************/ static int bmRememberSegmentEdge( BitmapSegment * bs, SegmentEdge * se ) { SegmentEdge ** nw; int i; DataRun * dr; nw= (SegmentEdge **)realloc( bs->bsEdges, ( bs->bsEdgeCount+ 1 )* sizeof(SegmentEdge *) ); if ( ! nw ) { XDEB(nw); return -1; } bs->bsEdges= nw; nw[bs->bsEdgeCount++]= se; dr= se->seRuns; if ( bs->bsEdgeCount <= 1 ) { bs->bsX0= dr->drX0; bs->bsX1= dr->drXp- 1; } for ( i= 0; i < se->seRunCount; dr++, i++ ) { if ( bs->bsX0 > dr->drX0 ) { bs->bsX0 = dr->drX0; } if ( bs->bsX1 < dr->drXp- 1 ) { bs->bsX1 = dr->drXp- 1; } } /* appDebug( "........ [%4d..%4d x %4d..%4d]\n", bs->bsX0, bs->bsX1, bs->bsY0, bs->bsY1 ); */ return 0; } /************************************************************************/ /* */ /* Allocate a fresh node. */ /* */ /************************************************************************/ static SegmentNode * bmSegmentNode( BitmapSegment * bs, int row ) { SegmentNode * sn; sn= (SegmentNode *)malloc( sizeof(SegmentNode) ); if ( ! sn ) { XDEB(sn); return sn; } sn->snDownEdges= (SegmentEdge **)0; sn->snUpEdges= (SegmentEdge **)0; sn->snUpEdgeCount= 0; sn->snDownEdgeCount= 0; sn->snY0= row; if ( bs && bmRememberSegmentNode( bs, sn ) ) { free( sn ); return (SegmentNode *)0; } return sn; } /************************************************************************/ /* */ /* Insert a new edge into a node. */ /* */ /************************************************************************/ static int bmConnectSegmentEdgeToNode( SegmentNode * sn, SegmentEdge * se, int up ) { short int * pcount; SegmentEdge *** pold; unsigned int sz; SegmentEdge ** nw; if ( up ) { pcount= &sn->snUpEdgeCount; pold= &sn->snUpEdges; } else{ pcount= &sn->snDownEdgeCount; pold= &sn->snDownEdges; } sz= ( *pcount+ 1 )* sizeof(SegmentEdge *); nw= (SegmentEdge **)realloc( *pold, sz ); if ( ! nw ) { XDEB(nw); return -1; } *pold= nw; nw[(*pcount)++]= se; if ( up ) { se->seTo= sn; } else{ se->seFrom= sn; } return 0; } /************************************************************************/ /* */ /* Allocate an edge. Insert the first run. */ /* */ /* 1) To help subsequent realloc()s a little, more space than needed */ /* is claimed for the runs. */ /* */ /************************************************************************/ static SegmentEdge * bmSegmentEdge( BitmapSegment * bs, SegmentNode * from, int x0, int xp ) { SegmentEdge * se; se= (SegmentEdge *)malloc( sizeof(SegmentEdge) ); if ( ! se ) { XDEB(se); return se; } se->seRuns= (DataRun *)malloc( 5* sizeof(DataRun) ); if ( ! se->seRuns ) { free( se ); return (SegmentEdge *)0; } se->seRuns->drX0= x0; se->seRuns->drXp= xp; se->seRuns->drRepeatCount= 1; se->seRunCount= 1; se->seFrom= from; se->seTo= (SegmentNode *)0; if ( bmRememberSegmentEdge( bs, se ) ) { free( se->seRuns ); free( se ); return (SegmentEdge *)0; } if ( from && bmConnectSegmentEdgeToNode( from, se, 0 ) ) { free( se->seRuns ); free( se ); if ( bs ) { bs->bsEdgeCount--; } return (SegmentEdge *)0; } return se; } /************************************************************************/ /* */ /* Insert a run into an edge. */ /* */ /* NOTE */ /* 1) That the first run has been inserted at creation time, so no */ /* initial allocation of the array of runs is necessary. */ /* 2) To help subsequent realloc()s a little, more space than needed */ /* is claimed for the runs. */ /* */ /************************************************************************/ static int bmAddRunToSegmentEdge( BitmapSegment * bs, SegmentEdge * se, int x0, int xp ) { DataRun * dr; int nrun; unsigned sz; if ( se->seRunCount > 0 ) { dr= se->seRuns+ se->seRunCount- 1; if ( dr->drX0 == x0 && dr->drXp == xp ) { dr->drRepeatCount++; return 0; } } if ( se->seRunCount % 5 ) { nrun= se->seRunCount+ 1; } else{ nrun= se->seRunCount+ 5; } /* 2 */ sz= nrun* sizeof(DataRun); dr= (DataRun *)realloc( se->seRuns, sz ); if ( ! dr ) { LDEB(dr); return -1; } se->seRuns= dr; dr += se->seRunCount++; dr->drX0= x0; dr->drXp= xp; dr->drRepeatCount= 1; if ( bs->bsX0 > x0 ) { bs->bsX0 = x0; } if ( bs->bsX1 < xp- 1 ) { bs->bsX1 = xp- 1; } /* appDebug( "........ [%4d..%4d x %4d..%4d]\n", bs->bsX0, bs->bsX1, bs->bsY0, bs->bsY1 ); */ return 0; } /************************************************************************/ /* */ /* Destroy a segemnt. */ /* */ /************************************************************************/ static void bmFreeEdge( SegmentEdge * se ) { if ( se->seRuns ) { free( se->seRuns ); } free( se ); } static void bmFreeNode( SegmentNode * sn ) { if ( sn->snUpEdges ) { free( sn->snUpEdges ); } if ( sn->snDownEdges ) { free( sn->snDownEdges ); } free( sn ); } void bmFreeSegment( BitmapSegment * bs ) { int i; for ( i= 0; i < bs->bsEdgeCount; i++ ) { if ( bs->bsEdges[i] ) { bmFreeEdge( bs->bsEdges[i] ); } } for ( i= 0; i < bs->bsNodeCount; i++ ) { if ( bs->bsNodes[i] ) { bmFreeNode( bs->bsNodes[i] ); } } if ( bs->bsEdges ) { free( bs->bsEdges ); } if ( bs->bsNodes ) { free( bs->bsNodes ); } free( bs ); return; } /************************************************************************/ /* */ /* Construct a new component. */ /* */ /************************************************************************/ static BitmapSegment * bmNewSegment( void ) { BitmapSegment * bs; bs= (BitmapSegment *)malloc( sizeof(BitmapSegment) ); if ( ! bs ) { XDEB(bs); return bs; } bs->bsEdges= (SegmentEdge **) malloc( sizeof(SegmentEdge *) ); bs->bsNodes= (SegmentNode **) malloc( sizeof(SegmentNode *) ); if ( ! bs->bsNodes || ! bs->bsEdges ) { XXDEB(bs->bsEdges,bs->bsNodes); bmFreeSegment( bs ); return (BitmapSegment *)0; } bs->bsX0= bs->bsX1= bs->bsY0= bs->bsY1= -1; bs->bsNodeCount= bs->bsEdgeCount= 0; return bs; } /************************************************************************/ /* */ /* Copy everything in one component to another one. */ /* */ /************************************************************************/ static int bmMoveComponentContents( BitmapSegment * to, BitmapSegment * from ) { int i; for ( i= 0; i < from->bsNodeCount; i++ ) { if ( bmRememberSegmentNode( to, from->bsNodes[i] ) ) { LDEB(i); return -1; } from->bsNodes[i]= (SegmentNode *)0; } for ( i= 0; i < from->bsEdgeCount; i++ ) { if ( bmRememberSegmentEdge( to, from->bsEdges[i] ) ) { LDEB(i); return -1; } from->bsEdges[i]= (SegmentEdge *)0; } bmFreeSegment( from ); return 0; } /************************************************************************/ /* */ /* 1) Find the first '0' pixel on of after position 'col' in a row */ /* 2) Find the first '1' pixel on of after position 'col' in a row */ /* */ /************************************************************************/ /* 1 */ static int bmc0Run( const unsigned char * buf, int bytesPerRow, int xsz, const int col, int nfret ) { int colbyte= col/ 8; int bit= col- 8* colbyte; int c; while( colbyte < bytesPerRow ) { if ( ( c= buf[colbyte] ) != 0xff ) { while( bit < 8 ) { if ( ! ( c & Bmc1Masks[bit] ) ) { int rval= 8* colbyte+ bit; if ( rval >= xsz ) { return nfret; } else{ return rval; } } bit++; } } colbyte++; bit= 0; } return nfret; } /* 2 */ static int bmc1Run( const unsigned char * buf, int bytesPerRow, int xsz, const int col, int nfret ) { int colbyte= col/ 8; int bit= col- 8* colbyte; int c; while( colbyte < bytesPerRow ) { if ( ( c= buf[colbyte] ) != 0x00 ) { while( bit < 8 ) { if ( c & Bmc1Masks[bit] ) { int rval= 8* colbyte+ bit; if ( rval >= xsz ) { return nfret; } else{ return rval; } } bit++; } } colbyte++; bit= 0; } return nfret; } /************************************************************************/ /* */ /* Make 'sn' the terminating branch node */ /* */ /* 1) Make the new edge that branches off. */ /* 2) Insert the old edge as an up going edge in the node. */ /* 3) ? */ /* 4) Remove one run from the edge that came from above. */ /* 5) The new edge continues down at this location. */ /* */ /************************************************************************/ static int bcBranch( CompIndex * ci, LookUp * lu, SegmentNode * sn ) { SegmentEdge * se; DataRun * dr; /* 1 */ se= bmSegmentEdge( ci->ci_compo, sn, lu->luX0, lu->luXp ); if ( ! se ) { XDEB(se); return -1; } /* 2 */ if ( bmConnectSegmentEdgeToNode( sn, lu->lu_edge, 1 ) ) { LDEB(1); return -1; } /* 3 */ ci->ci_count++; /* 4 */ dr= lu->lu_edge->seRuns+ lu->lu_edge->seRunCount- 1; if ( dr->drRepeatCount > 1 ) { dr->drRepeatCount--; } else{ lu->lu_edge->seRunCount--; } /* 5 */ lu->lu_edge= se; return 0; } /************************************************************************/ /* */ /* Create a new component. */ /* */ /* Memory management of the components is rudimentary. I think it will */ /* do for this application. */ /* */ /************************************************************************/ static int bmStartNewSegment( int * pnco, int * pmco, CompIndex ** pcomps, SegmentEdge ** pse, int x0, int xp, int row ) { int nco= *pnco; int mco= *pmco; CompIndex * comps= *pcomps; BitmapSegment * bs; SegmentNode * sn; SegmentEdge * se; bs= bmNewSegment(); if ( ! bs ) { XDEB(bs); return -1; } if ( nco >= mco ) { mco= ( 3* mco )/2+ 1; comps= (CompIndex *)realloc( comps, mco* sizeof(CompIndex) ); if ( ! comps ) { return -1; } } comps[nco].ci_compo= bs; comps[nco].ci_count= 1; sn= bmSegmentNode( bs, row ); if ( ! sn ) { XDEB(sn); return -1; } se= bmSegmentEdge( bs, sn, x0, xp ); if ( ! se ) { XDEB(se); return -1; } *pcomps= comps; *pnco= nco+ 1; *pmco= mco; *pse= se; return nco; } /************************************************************************/ /* */ /* Get rid of a component because it has been merged with another one. */ /* Memory management of the components is rudimentary. I think it will */ /* do for this application. */ /* */ /************************************************************************/ static int bcMergeComp( CompIndex * comps, int * pnco, int newcomp, int oldcomp, LookUp * olu, int oLuCount, LookUp * nlu, int nLuCount ) { int nco= *pnco; if ( oldcomp == newcomp ) { comps[oldcomp].ci_count--; return 0; } if ( comps[oldcomp].ci_compo ) { if ( bmMoveComponentContents( comps[newcomp].ci_compo, comps[oldcomp].ci_compo ) ) { LDEB(1); return -1; } comps[oldcomp].ci_compo= (BitmapSegment *)0; comps[oldcomp].ci_count= 0; while( nco > 0 && ! comps[nco- 1].ci_compo ) { nco--; } *pnco= nco; while( --oLuCount >= 0 ) { if ( olu->lu_compid == oldcomp ) { olu->lu_compid= newcomp; } olu++; } while( --nLuCount >= 0 ) { if ( nlu->lu_compid == oldcomp ) { nlu->lu_compid= newcomp; } nlu++; } } return 0; } /************************************************************************/ /* */ /* Refresh the count of newcomp */ /* */ /************************************************************************/ static void bcCountComp( CompIndex * comps, int newcomp, LookUp * olu, int oLuCount, LookUp * nlu, int nLuCount ) { comps[newcomp].ci_count= 0; while( --oLuCount >= 0 ) { if ( olu->lu_use != LU_ENDED && olu->lu_compid == newcomp ) { comps[newcomp].ci_count++; } olu++; } while( --nLuCount >= 0 ) { if ( nlu->lu_compid == newcomp ) { comps[newcomp].ci_count++; } nlu++; } return; } /************************************************************************/ /* */ /* Terminate an edge with a node. */ /* This destroys one reference to the component. */ /* */ /* 1) Make the end node. */ /* 2) Attach the edge to it. */ /* */ /************************************************************************/ static int bcTerminate( CompIndex * ci, LookUp * plu, int row ) { SegmentNode * sn; /* 1 */ sn= bmSegmentNode( ci->ci_compo, row ); if ( ! sn ) { XDEB(sn); return -1; } /* 2 */ if ( bmConnectSegmentEdgeToNode( sn, plu->lu_edge, 1 ) ) { LDEB(1); return -1; } plu->lu_use= LU_ENDED; plu->lu_node= sn; ci->ci_count--; return 0; } /************************************************************************/ /* */ /* If any segments from the previous row are found, continue/merge */ /* them. */ /* */ /* 1) If more than one run touch the current run, merge them in a */ /* node. */ /* 2) If the last one was already continued.. It is a split. */ /* */ /************************************************************************/ static int bcContinueSegments( int * pNLuCount, int * pNCo, LookUp * olu, const int oLuCount, LookUp * nlu, int nLuCount, int nco, CompIndex * comps, const int row, const int x0, const int xp, int beg, int end ) { int compid; compid= olu[beg].lu_compid; /* 1 */ if ( beg < end- 1 ) { SegmentNode * sn; SegmentEdge * se; sn= bmSegmentNode( comps[compid].ci_compo, row ); if ( ! sn ) { XDEB(sn); return -1; } while( beg < end- 1 ) { /* appDebug( "-- %4d: MERGE\n", beg ); */ if ( bcMergeComp( comps, &nco, compid, olu[beg+1].lu_compid, olu+ beg, oLuCount- beg, nlu, nLuCount ) ) { LDEB(1); return -1; } if ( bmConnectSegmentEdgeToNode( sn, olu[beg].lu_edge, 1 ) ) { LDEB(1); return -1; } olu[beg].lu_use= LU_MERGED; olu[beg].lu_node= sn; olu[beg].lu_compid= compid; beg++; } bcCountComp( comps, compid, olu+beg, oLuCount-beg, nlu, nLuCount ); if ( bmConnectSegmentEdgeToNode( sn, olu[beg].lu_edge, 1 ) ) { LDEB(1); return -1; } se= bmSegmentEdge( comps[compid].ci_compo, sn, x0, xp ); if ( ! se ) { XDEB(se); return -1; } se->seRunCount= 0; /* Oups, against an extra row */ olu[beg].lu_node= sn; olu[beg].lu_edge= se; olu[beg].lu_compid= compid; /* appDebug( "-- %4d: BELOW\n", beg ); */ } /* 2 */ if ( olu[beg].lu_use != LU_UNSPEC ) { SegmentNode * sn; SegmentEdge * se; /* appDebug( "-- %4d: SPLIT\n", beg ); */ sn= nlu[nLuCount-1].lu_node; if ( ! sn ) { sn= bmSegmentNode( comps[compid].ci_compo, row ); if ( ! sn ) { XDEB(sn); return -1; } if ( bcBranch( comps+compid, nlu+ nLuCount- 1, sn ) ) { LDEB(1); return -1; } nlu[nLuCount-1].lu_node= sn; } else{ comps[compid].ci_count++; } se= bmSegmentEdge( comps[compid].ci_compo, sn, x0, xp ); if ( ! se ) { XDEB(se); return -1; } /* olu[beg].lu_use= LU_EXTENDED; see above */ nlu[nLuCount].luX0= x0; nlu[nLuCount].luXp= xp; nlu[nLuCount].lu_edge= se; nlu[nLuCount].lu_compid= compid; nlu[nLuCount].lu_use= LU_UNSPEC; nlu[nLuCount].lu_node= sn; nLuCount++; } else{ /* 3 */ /* appDebug( "-- %4d: CONT \n", beg ); */ compid= olu[beg].lu_compid; if ( bmAddRunToSegmentEdge( comps[compid].ci_compo, olu[beg].lu_edge, x0, xp ) ) { LDEB(1); return -1; } olu[beg].lu_use= LU_EXTENDED; nlu[nLuCount].luX0= x0; nlu[nLuCount].luXp= xp; nlu[nLuCount].lu_edge= olu[beg].lu_edge; nlu[nLuCount].lu_compid= compid; nlu[nLuCount].lu_use= LU_UNSPEC; nlu[nLuCount].lu_node= (SegmentNode *)0; nLuCount++; } *pNLuCount= nLuCount; *pNCo= nco; return 0; } /************************************************************************/ /* */ /* Find the different black connected components on a page. */ /* For every successive scanline, the relationships of the runs of */ /* black with those on the previous one are determined. */ /* */ /* 3) For all rows in the image. */ /* 4) Loop over all runs of 'black' pixels. */ /* 5) Skip all segments from the previous row that end before the */ /* black run. Terminate them if necessary. */ /* 6) Find the first segment that begins after the black run. */ /* 7) If any segments from the previous row are found, continue/merge */ /* them. */ /* */ /************************************************************************/ int bcComponents( BitmapSegment *** pSegments, int * pCount, const unsigned char * buffer, const BitmapDescription * bd ) { int row; int pixelsWide= bd->bdPixelsWide; int oLuCount; int nLuCount; int beg, end; LookUp * lu1= (LookUp *)malloc( pixelsWide* sizeof(LookUp) ); LookUp * lu2= (LookUp *)malloc( pixelsWide* sizeof(LookUp) ); LookUp * olu= lu1; LookUp * nlu= lu2; LookUp * swap; int x0, xp; int nco= 0, mco= 30; CompIndex * comps= (CompIndex *)malloc( mco* sizeof(CompIndex) ); int compid; BitmapSegment ** retcomps= (BitmapSegment **)0; int diagonals= 1; int (*whiteRun)( const unsigned char * _buf, int bytesPerRow, int xsz, const int col, int nfret ); int (*blackRun)( const unsigned char * _buf, int bytesPerRow, int xsz, const int col, int nfret ); if ( ! lu1 || ! lu2 || ! comps ) { XXDEB(lu1,lu2); XDEB(comps); goto failure; } switch( bd->bdColorEncoding ) { case BMcoBLACKWHITE: if ( bd->bdBitsPerPixel != 1 ) { LLDEB(bd->bdColorEncoding,bd->bdBitsPerPixel); goto failure; } whiteRun= bmc1Run; blackRun= bmc0Run; break; case BMcoWHITEBLACK: if ( bd->bdBitsPerPixel != 1 ) { LLDEB(bd->bdColorEncoding,bd->bdBitsPerPixel); goto failure; } whiteRun= bmc0Run; blackRun= bmc1Run; break; default: LDEB(bd->bdColorEncoding); goto failure; } oLuCount= 0; /* 3 */ for ( row= 0; row < bd->bdPixelsHigh; row++ ) { x0= 0; nLuCount= 0; beg= end= 0; /* appDebug( "======== ROW %4d\n", row ); */ /* 4 */ for (;;) { x0= (*whiteRun)( buffer+ row* bd->bdBytesPerRow, bd->bdBytesPerRow, bd->bdPixelsWide, x0, -1 ); if ( x0 < 0 ) { break; } xp= (*blackRun)( buffer+ row* bd->bdBytesPerRow, bd->bdBytesPerRow, bd->bdPixelsWide, x0+ 1, bd->bdPixelsWide ); /* appDebug( "++ %4d: FOUND %5d -| %5d\n", nLuCount, x0, xp ); */ /************************************************************/ /* Identify what kind of a run we found. */ /* 2) First one that does begin after x1. */ /************************************************************/ /* 5 */ while( beg < oLuCount ) { compid= olu[beg].lu_compid; if ( olu[beg].luXp > x0- diagonals ) { break; } if ( olu[beg].lu_use == LU_UNSPEC ) { if ( bcTerminate( comps+ compid, olu+ beg, row- 1 ) ) { goto failure; } /* appDebug( "-- %4d: TERM \n", beg ); */ } else{ /* appDebug( "-- %4d: CONT \n", beg ); */ } beg++; } end= beg; /* 6 */ while( end < oLuCount ) { if ( olu[end].luX0 >= xp+ diagonals ) { break; } /* appDebug( "-- %4d: PREV \n", end ); */ end++; } /* 7 */ if ( end > beg ) { if ( bcContinueSegments( &nLuCount, &nco, olu, oLuCount, nlu, nLuCount, nco, comps, row, x0, xp, beg, end ) ) { LDEB(1); goto failure; } beg= end- 1; } else{ SegmentEdge * se; compid= bmStartNewSegment( &nco, &mco, &comps, &se, x0, xp, row ); if ( compid < 0 ) { LDEB(compid); goto failure; } nlu[nLuCount].lu_compid= compid; nlu[nLuCount].luX0= x0; nlu[nLuCount].luXp= xp; nlu[nLuCount].lu_edge= se; nlu[nLuCount].lu_node= (SegmentNode *)0; nlu[nLuCount].lu_use= LU_UNSPEC; nLuCount++; /* appDebug( "-- %4d: NEW \n", nLuCount- 1 ); */ } x0= xp+ 1; } while( beg < oLuCount ) { compid= olu[beg].lu_compid; if ( olu[beg].lu_use == LU_UNSPEC ) { if ( bcTerminate( comps+ compid, olu+ beg, row- 1 ) ) { goto failure; } /* appDebug( "-- %4d: TERM \n", beg ); */ } else{ /* appDebug( "-- %4d: READY\n", beg ); */ } beg++; } swap= nlu; nlu= olu; olu= swap; oLuCount= nLuCount; } /* APP_DEB(appDebug( "%-5d ROWS:\n", row )); */ beg= 0; while( beg < oLuCount ) { compid= olu[beg].lu_compid; if ( olu[beg].lu_use == LU_UNSPEC ) { if ( bcTerminate( comps+ compid, olu+ beg, row- 1 ) ) { goto failure; } /* appDebug( "-- %4d: BOTTM\n", beg ); */ } else{ /* appDebug( "-- %4d: ERROR\n", beg ); */ goto failure; } beg++; } retcomps= (BitmapSegment **)malloc( nco* sizeof(BitmapSegment *) ); if ( ! retcomps ) { goto failure; } end= nco; nco= 0; for ( beg= 0; beg < end; beg++ ) { double wide; double high; int rejected= 0; if ( ! comps[beg].ci_compo ) { continue; } wide= comps[beg].ci_compo->bsX1- comps[beg].ci_compo->bsX0+ 1; high= comps[beg].ci_compo->bsY1- comps[beg].ci_compo->bsY0+ 1; if ( wide < 5 && high < 5 ) { rejected= 1; } if ( wide >= bd->bdPixelsWide/ 10 || high >= bd->bdPixelsHigh/ 10 ) { rejected= 1; } if ( wide > 15* high || high > 15* wide ) { rejected= 1; } if ( rejected ) { bmFreeSegment( comps[beg].ci_compo ); continue; } retcomps[nco++]= comps[beg].ci_compo; } if ( lu1 ) { free( lu1 ); } if ( lu2 ) { free( lu2 ); } if ( comps ) { free( comps ); } *pCount= nco; *pSegments= retcomps; return 0; failure: for ( beg= 0; beg < nco; beg++ ) { bmFreeSegment( comps[beg].ci_compo ); } if ( lu1 ) { free( lu1 ); } if ( lu2 ) { free( lu2 ); } if ( comps ) { free( comps ); } return -1; } int bmcDrawComponent( const BitmapSegment * bs, unsigned char * buffer, int col0, int row0, int bytesPerRow, int colorEncoding ) { SegmentEdge ** se; int i, j; # if 0 bmDrawBox( buffer, bd, bs->bsX0- col0, row0, bs->bsX1- col0, row0+ bs->bsY1- bs->bsY0, 1, colorEncoding ); bmDrawLine( buffer, bd, bs->bsX0- col0, row0, bs->bsX1- col0, row0+ bs->bsY1- bs->bsY0, 2 ); bmDrawLine( buffer, bd, bs->bsX0- col0, row0+ bs->bsY1- bs->bsY0, bs->bsX1- col0, row0, 2 ); return 0; # endif se= bs->bsEdges; for ( i= 0; i < bs->bsEdgeCount; i++, se++ ) { int row= se[0]->seFrom->snY0- bs->bsY0+ row0; DataRun * dr= se[0]->seRuns; for ( j= 0; j < se[0]->seRunCount; j++, dr++ ) { bmFillBlock( buffer, dr->drX0- col0, row, dr->drXp- col0, row+ dr->drRepeatCount, bytesPerRow ); row += dr->drRepeatCount; } } return 0; } /************************************************************************/ /* */ /* Return information on a component. If a buffer pointer is given, */ /* a bitmap for the component is returned. */ /* */ /************************************************************************/ int bmComponentBitmap( unsigned char ** pBuffer, BitmapDescription * bdout, BitmapSelection * bsel, const BitmapDescription * bdin, const void * voidbs ) { const BitmapSegment * bs= (const BitmapSegment *)voidbs; BitmapDescription resbd= *bdin; int byte= 8* resbd.bdBitsPerPixel; unsigned char * buffer; int colorEncoding= bdin->bdColorEncoding; resbd.bdPixelsWide= bs->bsX1- bs->bsX0+ 1; resbd.bdPixelsWide= ( ( resbd.bdPixelsWide+ byte- 1 )/ byte ) * byte; resbd.bdPixelsHigh= bs->bsY1- bs->bsY0+ 1; resbd.bdBytesPerRow= resbd.bdPixelsWide/ byte; resbd.bdBufferLength= resbd.bdBytesPerRow* resbd.bdPixelsHigh; if ( pBuffer ) { buffer= bmBackgroundBuffer( resbd.bdBufferLength, colorEncoding ); if ( ! buffer ) { LLDEB(resbd.bdBufferLength,buffer); return -1; } if ( bmcDrawComponent( bs, buffer, bs->bsX0, 0, resbd.bdBytesPerRow, colorEncoding ) ) { free( buffer ); return -1; } *pBuffer= buffer; } *bdout= resbd; bsel->bsX0= bs->bsX0; bsel->bsY0= bs->bsY0; bsel->bsPixelsWide= resbd.bdPixelsWide; bsel->bsPixelsHigh= resbd.bdPixelsHigh; return 0; } /************************************************************************/ /* */ /* Return information on the geometry of a component. */ /* */ /************************************************************************/ void bmcStatistics( const BitmapSegment * bs, int * pN, float * pSx, float * pSy, float * pSxx, float * pSyy, float * pSxy ) { SegmentEdge ** se; int i, j; *pN= 0; *pSx= 0; *pSy= 0; *pSxx= 0; *pSyy= 0; *pSxy= 0; se= bs->bsEdges; for ( i= 0; i < bs->bsEdgeCount; i++, se++ ) { DataRun * dr; int y0= se[0]->seFrom->snY0; dr= se[0]->seRuns; for ( j= 0; j < se[0]->seRunCount; j++, dr++ ) { int x0= dr->drX0; int x1= dr->drXp+ 1; int xx0= x0* ( x0+ 1 ); int xx1= x1* ( x1+ 1 ); int sxx= xx1/2- xx0/2; double xxx0= xx0* ( 2.0* x0+ 1.0 ); double xxx1= xx1* ( 2.0* x1+ 1.0 ); int y1= y0+ dr->drRepeatCount; int yy0= y0* ( y0+ 1 ); int yy1= y1* ( y1+ 1 ); int syy= yy1/2- yy0/2; double yyy0= yy0* ( 2.0* y0+ 1.0 ); double yyy1= yy1* ( 2.0* y1+ 1.0 ); *pN += dr->drRepeatCount* ( x1- x0 ); *pSx += dr->drRepeatCount* sxx; *pSy += ( x1- x0 )* syy; *pSxx += dr->drRepeatCount* ( xxx1/6- xxx0/6 ); *pSyy += ( x1- x0 )* ( yyy1/6- yyy0/6 ); *pSxy += sxx* syy; y0 += dr->drRepeatCount; } } return; }