# include "bitmapConfig.h" # include # include # include "bmintern.h" # include # define y0 math_y0 # define y1 math_y1 # include # undef y0 # undef y1 # include # ifndef M_PI # define M_PI 3.14159265358979323846 # endif /************************************************************************/ /* */ /* Flip a scan line consisting of 1 bit pixels */ /* */ /************************************************************************/ static unsigned char bmFlipLeft[256]; static unsigned char bmFlipRight[256]; static void bmFlip1Init( int n ) { int i; int rshift= n % 8; int lshift= 8- rshift; for ( i= 0; i < 256; i++ ) { unsigned char value= ( i & 0x01 ) << 7 | ( i & 0x02 ) << 5 | ( i & 0x04 ) << 3 | ( i & 0x08 ) << 1 | ( i & 0x10 ) >> 1 | ( i & 0x20 ) >> 3 | ( i & 0x40 ) >> 5 | ( i & 0x80 ) >> 7 ; bmFlipLeft[i]= value << lshift; bmFlipRight[i]= value >> rshift; } } static void bmFlip2Init( int n ) { int i; int rshift= 2* ( n % 4 ); int lshift= 8- rshift; for ( i= 0; i < 256; i++ ) { unsigned char value= ( i & 0x03 ) << 6 | ( i & 0x0c ) << 2 | ( i & 0x30 ) >> 2 | ( i & 0xc0 ) >> 6 ; bmFlipLeft[i]= value << lshift; bmFlipRight[i]= value >> rshift; } } static void bmFlip4Init( int n ) { int i; int rshift= 4* ( n % 2 ); int lshift= 8- rshift; for ( i= 0; i < 256; i++ ) { unsigned char value= ( i & 0x0f ) << 4 | ( i & 0xf0 ) >> 4 ; bmFlipLeft[i]= value << lshift; bmFlipRight[i]= value >> rshift; } } /************************************************************************/ /* */ /* Flip the bytes in a scan line. */ /* */ /************************************************************************/ int bmFlipBytes( unsigned char * buffer, int byteCount, int bitsPerPixel ) { switch( bitsPerPixel ) { case 1: case 2: case 4: bmFlip1Init( 8/bitsPerPixel ); break; case 8: return 0; case 24: default: LDEB(bitsPerPixel); return -1; } while( byteCount-- > 0 ) { *buffer= bmFlipRight[*buffer]; buffer++; } return 0; } /************************************************************************/ /* */ /* Flip a scan line consisting of 1 bit pixels */ /* */ /************************************************************************/ static void bmFlipBits( unsigned char * to, const unsigned char * from, int pixelsWide, int pixelsPerByte ) { int i; int count; count= pixelsWide/ pixelsPerByte; to += count; if ( pixelsWide % pixelsPerByte ) { *(to)= bmFlipLeft[*from]; to--; for ( i= count; i; i-- ) { *to= bmFlipRight[*(from++)]; *(to--) |= bmFlipLeft [* from ]; } } else{ for ( i= count; i; i-- ) { *(--to)= bmFlipRight[*(from++)]; } } } /************************************************************************/ /* */ /* Flip a scan line consisting of 8 bit pixels */ /* */ /************************************************************************/ static void bmFlip8Bits( unsigned char * to, const unsigned char * from, int pixelsWide, int ignored ) { int i; to += pixelsWide- 1; for ( i= pixelsWide; i; i-- ) { *(to--)= *(from++); } } /************************************************************************/ /* */ /* Flip a scan line consisting of 24 bit pixels */ /* */ /************************************************************************/ static void bmFlip24Bits( unsigned char * to, const unsigned char * from, int pixelsWide, int ignored ) { int i; to += 3*pixelsWide- 3; for ( i= pixelsWide; i; i-- ) { to[0]= from[0]; to[1]= from[1]; to[2]= from[2]; to -= 3; from += 3; } } /************************************************************************/ /* */ /* Mirror bitmap images: Flip over horizontal axis. */ /* */ /************************************************************************/ int bmVerticalFlip( BitmapDescription * bdOut, const BitmapDescription * bdIn, unsigned char ** pBufOut, const unsigned char * bufIn, int ignoredInt ) { const unsigned char * from; unsigned char * to; unsigned int row; unsigned char * bufOut; bufOut= (unsigned char *)malloc( bdIn->bdBufferLength ); if ( ! bufOut ) { LLDEB(bdIn->bdBufferLength,bufOut); return -1; } for ( row= 0; row < bdIn->bdPixelsHigh; row++ ) { from= bufIn+ row* bdIn->bdBytesPerRow; to= bufOut+ ( bdIn->bdPixelsHigh- row -1 )* bdIn->bdBytesPerRow; memcpy( to, from, bdIn->bdBytesPerRow ); } bmCopyDescription( bdOut, bdIn ); *pBufOut= bufOut; return 0; } /************************************************************************/ /* */ /* Mirror bitmap images: Rotate 180 degrees. */ /* */ /************************************************************************/ int bmUpsideDown( BitmapDescription * bdOut, const BitmapDescription * bdIn, unsigned char ** pBufOut, const unsigned char * bufIn, int ignoredInt ) { const unsigned char * from; unsigned char * to; unsigned int row; int pixelsPerByte= 8/ bdIn->bdBitsPerPixel; unsigned char * bufOut; void (*flip)( unsigned char *, const unsigned char *, int, int ); bufOut= (unsigned char *)malloc( bdIn->bdBufferLength ); if ( ! bufOut ) { LLDEB(bdIn->bdBufferLength,bufOut); return -1; } switch( bdIn->bdBitsPerPixel ) { case 1: flip= bmFlipBits; bmFlip1Init( bdIn->bdPixelsWide ); break; case 2: flip= bmFlipBits; bmFlip2Init( bdIn->bdPixelsWide ); break; case 4: flip= bmFlipBits; bmFlip4Init( bdIn->bdPixelsWide ); break; case 8: flip= bmFlip8Bits; break; case 24: flip= bmFlip24Bits; break; default: LDEB(bdIn->bdBitsPerPixel); return -1; } for ( row= 0; row < bdIn->bdPixelsHigh; row++ ) { from= bufIn+ row* bdIn->bdBytesPerRow; to= bufOut+ ( bdIn->bdPixelsHigh- row -1 )* bdIn->bdBytesPerRow; (*flip)( to, from, bdIn->bdPixelsWide, pixelsPerByte ); } bmCopyDescription( bdOut, bdIn ); *pBufOut= bufOut; return 0; } /************************************************************************/ /* */ /* Mirror bitmap images: Flip over vertical axis. */ /* */ /************************************************************************/ int bmHorizontalFlip( BitmapDescription * bdOut, const BitmapDescription * bdIn, unsigned char ** pBufOut, const unsigned char * bufIn, int ignoredInt ) { const unsigned char * from; unsigned char * to; unsigned int row; int pixelsPerByte= 8/ bdIn->bdBitsPerPixel; unsigned char * bufOut; void (*flip)( unsigned char *, const unsigned char *, int, int ); bufOut= (unsigned char *)malloc( bdIn->bdBufferLength ); if ( ! bufOut ) { LLDEB(bdIn->bdBufferLength,bufOut); return -1; } switch( bdIn->bdBitsPerPixel ) { case 1: flip= bmFlipBits; bmFlip1Init( bdIn->bdPixelsWide ); break; case 2: flip= bmFlipBits; bmFlip2Init( bdIn->bdPixelsWide ); break; case 4: flip= bmFlipBits; bmFlip4Init( bdIn->bdPixelsWide ); break; case 8: flip= bmFlip8Bits; break; case 24: flip= bmFlip24Bits; break; default: LDEB(bdIn->bdBitsPerPixel); return -1; } for ( row= 0; row < bdIn->bdPixelsHigh; row++ ) { from= bufIn+ row* bdIn->bdBytesPerRow; to= bufOut+ row* bdIn->bdBytesPerRow; (*flip)( to, from, bdIn->bdPixelsWide, pixelsPerByte ); } bmCopyDescription( bdOut, bdIn ); *pBufOut= bufOut; return 0; } /************************************************************************/ /* */ /* Rotate a bitmap by 0,90,180,270 degrees. */ /* */ /************************************************************************/ int bmRotate90( BitmapDescription * bdOut, const BitmapDescription * bdIn, unsigned char ** pBufOut, const unsigned char * bufIn, int angle ) { const unsigned char * from; unsigned char * to; unsigned int row, col; unsigned char * bufOut; BitmapDescription bd; int s; int shift; unsigned char m= 0; unsigned char mr; int step; switch( angle ) { case 0: if ( bmCopyDescription( &bd, bdIn ) ) { LDEB(1); return -1; } bufOut= (unsigned char *)malloc( bd.bdBufferLength ); if ( ! bufOut ) { LLDEB(bd.bdBufferLength,bufOut); return -1; } memcpy( bufOut, bufIn, bd.bdBufferLength ); *bdOut= bd; *pBufOut= bufOut; return 0; case 180: return bmUpsideDown( bdOut, bdIn, pBufOut, bufIn, angle ); case 270: case 90: break; default: LDEB(angle); return -1; } bmCopyDescription( &bd, bdIn ); bd.bdPixelsWide= bdIn->bdPixelsHigh; bd.bdPixelsHigh= bdIn->bdPixelsWide; bd.bdBytesPerRow= ( bd.bdPixelsWide* bdIn->bdBitsPerPixel+ 7 )/ 8; bd.bdBufferLength= bd.bdPixelsHigh* bd.bdBytesPerRow; bufOut= (unsigned char *)malloc( bd.bdBufferLength ); if ( ! bufOut ) { LLDEB(bd.bdBufferLength,bufOut); return -1; } switch( bdIn->bdBitsPerPixel ) { case 4: m |= 0x30; /*FALLTHROUGH*/ case 2: m |= 0x40; /*FALLTHROUGH*/ case 1: m |= 0x80; memset( bufOut, 0, bd.bdBufferLength ); step= 8/ bdIn->bdBitsPerPixel; if ( angle == 90 ) { for ( row= 0; row < bd.bdPixelsHigh; row++ ) { int toRow= bd.bdPixelsHigh- row- 1; mr= m >> bdIn->bdBitsPerPixel* ( row % step ); for ( s= 0; s < row % step; s++ ) { to= bufOut+ toRow* bd.bdBytesPerRow; from= bufIn+ row/step+ s* bdIn->bdBytesPerRow; shift= row % step- s; shift *= bdIn->bdBitsPerPixel; for ( col= s; col < bd.bdPixelsWide; col += step ) { *(to++) |= ( *from & mr ) << shift; from += step* bdIn->bdBytesPerRow; } } for ( s= row % step; s < step; s++ ) { to= bufOut+ toRow* bd.bdBytesPerRow; from= bufIn+ row/step+ s* bdIn->bdBytesPerRow; shift= s- row % step; shift *= bdIn->bdBitsPerPixel; for ( col= s; col < bd.bdPixelsWide; col += step ) { *(to++) |= ( *from & mr ) >> shift; from += step* bdIn->bdBytesPerRow; } } } } else{ /*270*/ for ( row= 0; row < bd.bdPixelsHigh; row++ ) { mr= m >> bdIn->bdBitsPerPixel* ( row % step ); for ( s= 0; s < row % step; s++ ) { int ri= bdIn->bdPixelsHigh- 1; to= bufOut+ row* bd.bdBytesPerRow; from= bufIn+ ( bdIn->bdPixelsHigh- 1 )* bdIn->bdBytesPerRow; from -= s* bdIn->bdBytesPerRow; ri -= s; from += row/ step; shift= row % step- s; shift *= bdIn->bdBitsPerPixel; for ( col= 0; col < bd.bdPixelsWide; col += step ) { if ( ri < 0 ) { break; } *(to++) |= ( *from & mr ) << shift; from -= step* bdIn->bdBytesPerRow; ri -= step; } } for ( s= row % step; s < step; s++ ) { int ri= bdIn->bdPixelsHigh- 1; to= bufOut+ row* bd.bdBytesPerRow; from= bufIn+ ( bdIn->bdPixelsHigh- 1 )* bdIn->bdBytesPerRow; from -= s* bdIn->bdBytesPerRow; ri -= s; from += row/ step; shift= s- row % step; shift *= bdIn->bdBitsPerPixel; for ( col= 0; col < bd.bdPixelsWide; col += step ) { if ( ri < 0 ) { break; } *(to++) |= ( *from & mr ) >> shift; from -= step* bdIn->bdBytesPerRow; ri -= step; } } } } break; case 8: if ( angle == 90 ) { for ( row= 0; row < bd.bdPixelsHigh; row++ ) { from= bufIn+ row; to= bufOut+ ( bd.bdPixelsHigh- row- 1 )* bd.bdBytesPerRow; for ( col= 0; col < bd.bdPixelsWide; col++ ) { *(to++)= *from; from += bdIn->bdBytesPerRow; } } } else{ /*270*/ for ( row= 0; row < bd.bdPixelsHigh; row++ ) { from= bufIn+ row; to= bufOut+ ( row+ 1 )* bd.bdBytesPerRow- 1; for ( col= 0; col < bd.bdPixelsWide; col++ ) { *(to--)= *from; from += bdIn->bdBytesPerRow; } } } break; case 24: if ( angle == 90 ) { for ( row= 0; row < bd.bdPixelsHigh; row++ ) { from= bufIn+ 3* row; to= bufOut+ ( bd.bdPixelsHigh- row- 1 )* bd.bdBytesPerRow; for ( col= 0; col < bd.bdPixelsWide; col++ ) { *(to++)= from[0]; *(to++)= from[1]; *(to++)= from[2]; from += bdIn->bdBytesPerRow; } } } else{ for ( row= 0; row < bd.bdPixelsHigh; row++ ) { from= bufIn+ 3* row; to= bufOut+ ( row+ 1 )* bd.bdBytesPerRow- 3; for ( col= 0; col < bd.bdPixelsWide; col++ ) { to[0]= from[0]; to[1]= from[1]; to[2]= from[2]; to -= 3; from += bdIn->bdBytesPerRow; } } } break; default: LDEB(bdIn->bdBitsPerPixel); return -1; } *bdOut= bd; *pBufOut= bufOut; return 0; } /************************************************************************/ /* */ /* Shear operations. */ /* */ /************************************************************************/ typedef void (*ShearRow)( unsigned char * rowBufOut, const unsigned char * rowBufIn, const BitmapDescription * bdIn, const BitmapDescription * bdOut, int colShift, int fl ); typedef void (*ShearCol)( unsigned char * imgBufOut, const unsigned char * imgBufIn, const BitmapDescription * bdIn, const BitmapDescription * bdOut, int col, int rowShift, int fl ); static void bmShearRow8Bit( unsigned char * rowBufOut, const unsigned char * rowBufIn, const BitmapDescription * bdIn, const BitmapDescription * bdOut, int colShift, int fl ) { int fr= 255- fl; int spp= bdIn->bdSamplesPerPixel; int i; int colIn0; int colIn1; int colIn; int colTo0; int prev[5]; /* 1 */ colIn0= 0; colIn1= bdIn->bdPixelsWide- 1; if ( colShift < 0 ) { colIn0= -colShift; } colTo0= colIn0+ colShift; if ( colIn1+ colShift >= bdOut->bdPixelsWide ) { colIn1= bdOut->bdPixelsWide- colShift- 1; } rowBufOut += spp* colShift; for ( i= 0; i < spp; i++ ) { prev[i]= rowBufIn[i]; } for ( colIn= colIn0; colIn <= colIn1; colIn++ ) { const unsigned char * f= rowBufIn; unsigned char * t= rowBufOut; for ( i= 0; i < spp; i++ ) { t[0]= ( ( fl* prev[i] )+ ( fr* f[0] ) )/ 255; prev[i]= f[0]; f++; t++; } rowBufOut += spp; rowBufIn += spp; } return; } /************************************************************************/ /* */ /* Shear one column in a one byte per sample image. */ /* */ /* 1) For all rows of the input image. */ /* */ /************************************************************************/ static void bmShearCol8Bit( unsigned char * imgBufOut, const unsigned char * imgBufIn, const BitmapDescription * bdIn, const BitmapDescription * bdOut, int col, int rowShift, int fl ) { int fr= 255- fl; int spp= bdIn->bdSamplesPerPixel; int i; int rowIn0; int rowIn1; int rowIn; int rowTo0; int prev[5]; const unsigned char * from; unsigned char * to; for ( i= 0; i < spp; i++ ) { prev[i]= 0; } /* 1 */ rowIn0= 0; rowIn1= bdIn->bdPixelsHigh- 1; if ( rowShift < 0 ) { rowIn0= -rowShift; } rowTo0= rowIn0+ rowShift; if ( rowIn1+ rowShift >= bdOut->bdPixelsHigh ) { rowIn1= bdOut->bdPixelsHigh- rowShift- 1; } from= imgBufIn+ rowIn0* bdIn->bdBytesPerRow+ spp* col; to= imgBufOut+ rowTo0* bdOut->bdBytesPerRow+ spp* col; /* 1 */ for ( rowIn= rowIn0; rowIn <= rowIn1; rowIn++ ) { const unsigned char * f= from; unsigned char * t= to; for ( i= 0; i < spp; i++ ) { t[0]= ( ( fl* prev[i] )+ ( fr* f[0] ) )/ 255; prev[i]= f[0]; f++; t++; } from += bdIn->bdBytesPerRow; to += bdOut->bdBytesPerRow; } return; } static int bmShearRows( unsigned char * bufOut, const BitmapDescription * bdOut, int shear, const DocumentRectangle * drOut, const BitmapDescription * bdIn, const unsigned char * bufIn, ShearRow shearRow ) { int row; int fl; int colShift; unsigned char * rowBufOut; const unsigned char * rowBufIn; if ( bdOut->bdPixelsHigh != bdIn->bdPixelsHigh ) { LLDEB(bdOut->bdPixelsHigh,bdIn->bdPixelsHigh); return -1; } for ( row= 0; row < bdIn->bdPixelsHigh; row++ ) { rowBufOut= bufOut+ row* bdOut->bdBytesPerRow; rowBufIn= bufIn+ row* bdIn->bdBytesPerRow; fl= ( 255* shear* row )/ (int)bdIn->bdPixelsHigh; colShift= ( shear* row )/ (int)bdIn->bdPixelsHigh; if ( fl >= 0 ) { fl -= 255* colShift; } else{ fl -= 255* colShift; fl += 255; } colShift -= drOut->drX0; (*shearRow)( rowBufOut, rowBufIn, bdIn, bdOut, colShift, fl ); } return 0; } static int bmShearCols( unsigned char * bufOut, const BitmapDescription * bdOut, int shear, const DocumentRectangle * drOut, const BitmapDescription * bdIn, const unsigned char * bufIn, ShearCol shearCol ) { int col; int fl; int rowShift; if ( bdOut->bdPixelsWide != bdIn->bdPixelsWide ) { LLDEB(bdOut->bdPixelsWide,bdIn->bdPixelsWide); return -1; } for ( col= 0; col < bdIn->bdPixelsWide; col++ ) { fl= ( 255* shear* col )/ (int)bdIn->bdPixelsWide; rowShift= ( shear* col )/ (int)bdIn->bdPixelsWide; if ( fl >= 0 ) { fl -= 255* rowShift; } else{ fl -= 255* rowShift; fl += 255; } rowShift -= drOut->drY0; (*shearCol)( bufOut, bufIn, bdIn, bdOut, col, rowShift, fl ); } return 0; } /************************************************************************/ /* */ /* Apply an affine transform to the rectangle from the original image. */ /* */ /* The routine used to determine the smallest rectangle that encloses */ /* the result of an intermediate result in the rotation of an image. */ /* */ /************************************************************************/ static void bmTransformRectangle( BitmapDescription * bd, Point2DI to[4], DocumentRectangle * drTo, const AffineTransform2D * at, const Point2DI from[4], const DocumentRectangle * drFrom ) { int i; for ( i= 0; i < 4; i++ ) { to[i].p2diX= AT2_X( from[i].p2diX- drFrom->drX0, from[i].p2diY- drFrom->drY0, at ); to[i].p2diY= AT2_Y( from[i].p2diX- drFrom->drX0, from[i].p2diY- drFrom->drY0, at ); } drTo->drX0= drTo->drX1= to[0].p2diX; drTo->drY0= drTo->drY1= to[0].p2diY; for ( i= 1; i < 4; i++ ) { if ( drTo->drX0 > to[i].p2diX ) { drTo->drX0= to[i].p2diX; } if ( drTo->drY0 > to[i].p2diY ) { drTo->drY0= to[i].p2diY; } if ( drTo->drX1 < to[i].p2diX ) { drTo->drX1= to[i].p2diX; } if ( drTo->drY1 < to[i].p2diY ) { drTo->drY1= to[i].p2diY; } } bd->bdPixelsWide= drTo->drX1- drTo->drX0+ 1; bd->bdPixelsHigh= drTo->drY1- drTo->drY0+ 1; bmCalculateSizes( bd ); return; } /************************************************************************/ /* */ /* Rotate a pixmap image over an arbitrary angle. */ /* */ /* Use the algorithm outlined in: */ /* PAETH, Alan: "A Fast Algorithm for General Raster Rotation" pp 179- */ /* 195 in: GLASSNER, Andrew S: "Graphics Gems", Academic Press, */ /* Boston, 1990. */ /* */ /* The two main advantages of the algorithm are fast and easy anti- */ /* aliassing and the simple continuous loops that prevent holes in the */ /* rendering. */ /* */ /* Counterclockwise rotation of (x,y) onto (x',y') by an angle theta */ /* is a multiplication of the vector my the matrix: */ /* [ cos(theta) -sin(theta) ] */ /* [ sin(theta) cos(theta) ] */ /* The matrix is orhogonal: the inverse is the transpose: */ /* [ cos(theta) sin(theta) ] */ /* [ -sin(theta) cos(theta) ] */ /* It can be written as the product of three shears: */ /* [ 1 a ] [ 1 0 ] [ 1 c ] [ cos(theta) -sin(theta) ] */ /* [ 0 1 ] [ b 1 ] [ 0 1 ] = [ sin(theta) cos(theta) ] */ /* Where: */ /* a= -tan( theta/ 2 ). */ /* b= sin( theta ). */ /* c= -tan( theta/ 2 ). */ /* */ /* 1) Find a theta <= 45 degrees. */ /* 2) Initial X Shear. */ /* 3) Subsequent Y Shear. */ /* 4) Final X Shear. */ /* */ /************************************************************************/ int bmRotate( BitmapDescription * bdOut, const BitmapDescription * bdIn, unsigned char ** pBufOut, const unsigned char * bufIn, double theta ) { int rval= 0; int rot90; double a; double b; double c; AffineTransform2D C; AffineTransform2D B; AffineTransform2D A; Point2DI rectIn[4]; Point2DI rectC[4]; Point2DI rectB[4]; Point2DI rectA[4]; DocumentRectangle drIn; DocumentRectangle drC; DocumentRectangle drB; DocumentRectangle drA; int shearC; int shearB; int shearA; BitmapDescription bdC; BitmapDescription bdB; BitmapDescription bdA; unsigned char * bufC= (unsigned char *)0; unsigned char * bufB= (unsigned char *)0; unsigned char * bufA= (unsigned char *)0; ShearRow shearRow= (ShearRow)0; ShearCol shearCol= (ShearCol)0; switch( bdIn->bdColorEncoding ) { case BMcoBLACKWHITE: case BMcoWHITEBLACK: switch( bdIn->bdBitsPerPixel ) { case 8: shearRow= bmShearRow8Bit; shearCol= bmShearCol8Bit; break; default: LLDEB(bdIn->bdColorEncoding,bdIn->bdBitsPerPixel); return -1; } break; case BMcoRGB: switch( bdIn->bdBitsPerSample ) { case 8: shearRow= bmShearRow8Bit; shearCol= bmShearCol8Bit; break; default: LLDEB(bdIn->bdColorEncoding,bdIn->bdBitsPerPixel); return -1; } break; case BMcoRGB8PALETTE: LDEB(bdIn->bdColorEncoding); return -1; break; default: LDEB(bdIn->bdColorEncoding); return -1; } bmInitDescription( &bdC ); bmInitDescription( &bdB ); bmInitDescription( &bdA ); utilIdentityAffineTransform2D( &C ); utilIdentityAffineTransform2D( &B ); utilIdentityAffineTransform2D( &A ); /*********/ /* 0 1 */ /* 3 2 */ /*********/ drIn.drX0= 0; drIn.drX1= bdIn->bdPixelsWide- 1; drIn.drY0= 0; drIn.drY1= bdIn->bdPixelsHigh- 1; rectIn[0].p2diX= 0; rectIn[0].p2diY= 0; rectIn[1].p2diX= drIn.drX1; rectIn[1].p2diY= 0; rectIn[2].p2diX= drIn.drX1; rectIn[2].p2diY= drIn.drY1; rectIn[3].p2diX= 0; rectIn[3].p2diY= drIn.drY1; /* 1 */ while( theta < -M_PI/4 ) { theta += 2* M_PI; } for ( rot90= 0; theta > M_PI/4; rot90++ ) { theta -= M_PI/2; } rot90= rot90 % 4; c= -tan( theta/ 2.0 ); b= sin( theta ); a= -tan( theta/ 2.0 ); C.at2Ayx= c; B.at2Axy= b; A.at2Ayx= a; /* 2 */ bmCopyDescription( &bdC, bdIn ); bmTransformRectangle( &bdC, rectC, &drC, &C, rectIn, &drIn ); shearC= c* bdIn->bdPixelsHigh; bufC= malloc( bdC.bdBufferLength ); if ( ! bufC ) { LLDEB(bdC.bdBufferLength,bufC); } memset( bufC, 0, bdC.bdBufferLength ); if ( bmShearRows( bufC, &bdC, shearC, &drC, bdIn, bufIn, shearRow ) ) { LDEB(1); rval= -1; goto ready; } # define RET_C 0 # if RET_C bmCopyDescription( bdOut, &bdC ); *pBufOut= bufC; bufC= (unsigned char *)0; goto ready; # endif # define NO_C 0 # if NO_C bmCopyDescription(&bdC,bdIn); memcpy( bufC, bufIn, bdIn->bdBufferLength ); # endif /* 3 */ bmCopyDescription( &bdB, &bdC ); bmTransformRectangle( &bdB, rectB, &drB, &B, rectC, &drC ); shearB= b* bdC.bdPixelsWide; bufB= malloc( bdB.bdBufferLength ); if ( ! bufB ) { LLDEB(bdB.bdBufferLength,bufB); } memset( bufB, 0, bdB.bdBufferLength ); if ( bmShearCols( bufB, &bdB, shearB, &drB, &bdC, bufC, shearCol ) ) { LDEB(1); rval= -1; goto ready; } free( bufC ); bufC= (unsigned char *)0; # define RET_B 0 # if RET_B bmCopyDescription( bdOut, &bdB ); *pBufOut= bufB; bufB= (unsigned char *)0; goto ready; # endif # define NO_B 0 # if NO_B bmCopyDescription(&bdB,&bdC); memcpy( bufB, bufC, bdC.bdBufferLength ); # endif /* 4 */ bmCopyDescription( &bdA, &bdB ); bmTransformRectangle( &bdA, rectA, &drA, &A, rectB, &drB ); shearA= a* bdB.bdPixelsHigh; bufA= malloc( bdA.bdBufferLength ); if ( ! bufA ) { LLDEB(bdA.bdBufferLength,bufA); } memset( bufA, 0, bdA.bdBufferLength ); if ( bmShearRows( bufA, &bdA, shearA, &drA, &bdB, bufB, shearRow ) ) { LDEB(1); rval= -1; goto ready; } free( bufB ); bufB= (unsigned char *)0; if ( rot90 != 0 ) { if ( bmRotate90( bdOut, &bdA, pBufOut, bufA, 90* rot90 ) ) { LDEB(rot90); rval= -1; goto ready; } } else{ /* steal */ bmCopyDescription( bdOut, &bdA ); *pBufOut= bufA; bufA= (unsigned char *)0; } ready: if ( bufC ) { free( bufC ); } if ( bufB ) { free( bufB ); } if ( bufA ) { free( bufA ); } bmCleanDescription( &bdC ); bmCleanDescription( &bdB ); bmCleanDescription( &bdA ); return rval; }