1 #   include	"bitmapConfig.h"
2 
3 #   include	<geoAffineTransform.h>
4 #   include	<geo2DInteger.h>
5 
6 #   include	"bmintern.h"
7 
8 #   include	<string.h>
9 #   include	<stdlib.h>
10 
11 #   define	y0	math_y0
12 #   define	y1	math_y1
13 #   include	<math.h>
14 #   undef	y0
15 #   undef	y1
16 
17 #   include	<appDebugon.h>
18 
19 #   ifndef	M_PI
20 #	define	M_PI	3.14159265358979323846
21 #   endif
22 
23 /************************************************************************/
24 /*									*/
25 /*  Flip a scan line consisting of 1 bit pixels				*/
26 /*									*/
27 /************************************************************************/
28 
29 static unsigned char	bmFlipLeft[256];
30 static unsigned char	bmFlipRight[256];
31 
bmFlip1Init(int n)32 static void bmFlip1Init( int n )
33     {
34     int		i;
35     int		rshift= n % 8;
36     int		lshift= 8- rshift;
37 
38     for ( i= 0; i < 256; i++ )
39 	{
40 	unsigned char value=	( i & 0x01 ) << 7	|
41 				( i & 0x02 ) << 5	|
42 				( i & 0x04 ) << 3	|
43 				( i & 0x08 ) << 1	|
44 				( i & 0x10 ) >> 1	|
45 				( i & 0x20 ) >> 3	|
46 				( i & 0x40 ) >> 5	|
47 				( i & 0x80 ) >> 7	;
48 
49 	bmFlipLeft[i]=  value << lshift;
50 	bmFlipRight[i]= value >> rshift;
51 	}
52     }
53 
bmFlip2Init(int n)54 static void bmFlip2Init( int n )
55     {
56     int		i;
57     int		rshift= 2* ( n % 4 );
58     int		lshift= 8- rshift;
59 
60     for ( i= 0; i < 256; i++ )
61 	{
62 	unsigned char value=	( i & 0x03 ) << 6	|
63 				( i & 0x0c ) << 2	|
64 				( i & 0x30 ) >> 2	|
65 				( i & 0xc0 ) >> 6	;
66 
67 	bmFlipLeft[i]=  value << lshift;
68 	bmFlipRight[i]= value >> rshift;
69 	}
70     }
71 
bmFlip4Init(int n)72 static void bmFlip4Init( int n )
73     {
74     int		i;
75     int		rshift= 4* ( n % 2 );
76     int		lshift= 8- rshift;
77 
78     for ( i= 0; i < 256; i++ )
79 	{
80 	unsigned char value=	( i & 0x0f ) << 4	|
81 				( i & 0xf0 ) >> 4	;
82 
83 	bmFlipLeft[i]=  value << lshift;
84 	bmFlipRight[i]= value >> rshift;
85 	}
86     }
87 
88 /************************************************************************/
89 /*									*/
90 /*  Flip the bytes in a scan line.					*/
91 /*									*/
92 /************************************************************************/
93 
bmFlipBytes(unsigned char * buffer,int byteCount,int bitsPerPixel)94 int bmFlipBytes(		unsigned char *	buffer,
95 				int		byteCount,
96 				int		bitsPerPixel )
97     {
98     switch( bitsPerPixel )
99 	{
100 	case  1:
101 	case  2:
102 	case  4:
103 	    bmFlip1Init( 8/bitsPerPixel );
104 	    break;
105 
106 	case  8:
107 	    return 0;
108 
109 	case 24:
110 	default:
111 	    LDEB(bitsPerPixel); return -1;
112 	}
113 
114     while( byteCount-- > 0 )
115 	{ *buffer= bmFlipRight[*buffer]; buffer++;	}
116 
117     return 0;
118     }
119 
120 
121 /************************************************************************/
122 /*									*/
123 /*  Flip a scan line consisting of 1 bit pixels				*/
124 /*									*/
125 /************************************************************************/
126 
bmFlipBits(unsigned char * to,const unsigned char * from,int pixelsWide,int pixelsPerByte)127 static void bmFlipBits(	unsigned char *		to,
128 			const unsigned char *	from,
129 			int			pixelsWide,
130 			int			pixelsPerByte )
131     {
132     int			i;
133     int			count;
134 
135     count= pixelsWide/ pixelsPerByte;
136     to += count;
137 
138     if  ( pixelsWide % pixelsPerByte )
139 	{
140 	*(to)= bmFlipLeft[*from];
141 	to--;
142 
143 	for ( i= count; i; i-- )
144 	    {
145 	    *to=       bmFlipRight[*(from++)];
146 	    *(to--) |= bmFlipLeft [* from   ];
147 	    }
148 	}
149     else{
150 	for ( i= count; i; i-- )
151 	    { *(--to)= bmFlipRight[*(from++)];	}
152 	}
153     }
154 
155 /************************************************************************/
156 /*									*/
157 /*  Flip a scan line consisting of 8 bit pixels				*/
158 /*									*/
159 /************************************************************************/
160 
bmFlip8Bits(unsigned char * to,const unsigned char * from,int pixelsWide,int ignored)161 static void bmFlip8Bits(	unsigned char *		to,
162 				const unsigned char *	from,
163 				int			pixelsWide,
164 				int			ignored	)
165     {
166     int			i;
167 
168     to += pixelsWide- 1;
169 
170     for ( i= pixelsWide; i; i-- )
171 	{ *(to--)= *(from++); }
172     }
173 
174 /************************************************************************/
175 /*									*/
176 /*  Flip a scan line consisting of 24 bit pixels			*/
177 /*									*/
178 /************************************************************************/
179 
bmFlip24Bits(unsigned char * to,const unsigned char * from,int pixelsWide,int ignored)180 static void bmFlip24Bits(	unsigned char *		to,
181 				const unsigned char *	from,
182 				int			pixelsWide,
183 				int			ignored	)
184     {
185     int			i;
186 
187     to += 3*pixelsWide- 3;
188 
189     for ( i= pixelsWide; i; i-- )
190 	{
191 	to[0]= from[0]; to[1]= from[1]; to[2]= from[2];
192 	to -= 3; from += 3;
193 	}
194     }
195 
196 /************************************************************************/
197 /*									*/
198 /*  Mirror bitmap images: Flip over horizontal axis.			*/
199 /*									*/
200 /************************************************************************/
201 
bmVerticalFlip(RasterImage * riOut,const RasterImage * riIn,int ignoredInt)202 int bmVerticalFlip(	RasterImage *			riOut,
203 			const RasterImage *		riIn,
204 			int				ignoredInt )
205     {
206     int				rval= 0;
207     const BitmapDescription *	bdIn= &(riIn->riDescription);
208 
209     unsigned int		row;
210 
211     RasterImage			ri;
212 
213     bmInitRasterImage( &ri );
214 
215     if  ( bmCopyDescription( &(ri.riDescription), bdIn ) )
216 	{ LDEB(1); rval= -1; goto ready;	}
217 
218     ri.riBytes= (unsigned char *)malloc( ri.riDescription.bdBufferLength );
219     if  ( ! ri.riBytes )
220 	{ LLDEB(ri.riDescription.bdBufferLength,ri.riBytes); rval= -1; goto ready; }
221 
222     for ( row= 0; row < bdIn->bdPixelsHigh; row++ )
223 	{
224 	const unsigned char *	from;
225 	unsigned char *		to;
226 
227 	from= riIn->riBytes+ row* bdIn->bdBytesPerRow;
228 	to= ri.riBytes+ ( bdIn->bdPixelsHigh- row -1 )* bdIn->bdBytesPerRow;
229 
230 	memcpy( to, from, bdIn->bdBytesPerRow );
231 	}
232 
233     /* steal */
234     *riOut= ri; bmInitRasterImage( &ri );
235 
236   ready:
237 
238     bmCleanRasterImage( &ri );
239 
240     return rval;
241     }
242 
243 /************************************************************************/
244 /*									*/
245 /*  Mirror bitmap images: Rotate 180 degrees.				*/
246 /*									*/
247 /************************************************************************/
248 
bmRotate180(RasterImage * riOut,const RasterImage * riIn,int ignoredInt)249 int bmRotate180(	RasterImage *			riOut,
250 			const RasterImage *		riIn,
251 			int				ignoredInt )
252     {
253     int				rval= 0;
254     const BitmapDescription *	bdIn= &(riIn->riDescription);
255 
256     unsigned int		row;
257     int				pixelsPerByte= 8/ bdIn->bdBitsPerPixel;
258     void			(*flip)( unsigned char *,
259 					const unsigned char *, int, int );
260 
261     RasterImage			ri;
262 
263     bmInitRasterImage( &ri );
264 
265     if  ( bmCopyDescription( &(ri.riDescription), bdIn ) )
266 	{ LDEB(1); rval= -1; goto ready;	}
267 
268     ri.riBytes= (unsigned char *)malloc( ri.riDescription.bdBufferLength );
269     if  ( ! ri.riBytes )
270 	{ LLDEB(ri.riDescription.bdBufferLength,ri.riBytes); rval= -1; goto ready; }
271 
272     switch( bdIn->bdBitsPerPixel )
273 	{
274 	case  1:
275 	    flip= bmFlipBits;	bmFlip1Init( bdIn->bdPixelsWide ); break;
276 	case  2:
277 	    flip= bmFlipBits;	bmFlip2Init( bdIn->bdPixelsWide ); break;
278 	case  4:
279 	    flip= bmFlipBits;	bmFlip4Init( bdIn->bdPixelsWide ); break;
280 	case  8:
281 	    flip= bmFlip8Bits;	break;
282 	case 24:
283 	    flip= bmFlip24Bits;	break;
284 	default:
285 	    LDEB(bdIn->bdBitsPerPixel); rval= -1; goto ready;
286 	}
287 
288     for ( row= 0; row < bdIn->bdPixelsHigh; row++ )
289 	{
290 	const unsigned char *	from;
291 	unsigned char *		to;
292 
293 	from= riIn->riBytes+ row* bdIn->bdBytesPerRow;
294 	to= ri.riBytes+ ( bdIn->bdPixelsHigh- row -1 )* bdIn->bdBytesPerRow;
295 
296 	(*flip)( to, from, bdIn->bdPixelsWide, pixelsPerByte );
297 	}
298 
299     /* steal */
300     *riOut= ri; bmInitRasterImage( &ri );
301 
302   ready:
303 
304     bmCleanRasterImage( &ri );
305 
306     return rval;
307     }
308 
309 /************************************************************************/
310 /*									*/
311 /*  Mirror bitmap images: Flip over vertical axis.			*/
312 /*									*/
313 /************************************************************************/
314 
bmHorizontalFlip(RasterImage * riOut,const RasterImage * riIn,int ignoredInt)315 int bmHorizontalFlip(	RasterImage *			riOut,
316 			const RasterImage *		riIn,
317 			int				ignoredInt )
318     {
319     int				rval= 0;
320     const BitmapDescription *	bdIn= &(riIn->riDescription);
321 
322     unsigned int		row;
323     int				pixelsPerByte= 8/ bdIn->bdBitsPerPixel;
324     void			(*flip)( unsigned char *,
325 					const unsigned char *, int, int );
326 
327     RasterImage			ri;
328 
329     bmInitRasterImage( &ri );
330 
331     if  ( bmCopyDescription( &(ri.riDescription), bdIn ) )
332 	{ LDEB(1); rval= -1; goto ready;	}
333 
334     ri.riBytes= (unsigned char *)malloc( ri.riDescription.bdBufferLength );
335     if  ( ! ri.riBytes )
336 	{ LLDEB(ri.riDescription.bdBufferLength,ri.riBytes); rval= -1; goto ready; }
337 
338     switch( bdIn->bdBitsPerPixel )
339 	{
340 	case  1:
341 	    flip= bmFlipBits;	bmFlip1Init( bdIn->bdPixelsWide ); break;
342 	case  2:
343 	    flip= bmFlipBits;	bmFlip2Init( bdIn->bdPixelsWide ); break;
344 	case  4:
345 	    flip= bmFlipBits;	bmFlip4Init( bdIn->bdPixelsWide ); break;
346 	case  8:
347 	    flip= bmFlip8Bits;	break;
348 	case 24:
349 	    flip= bmFlip24Bits;	break;
350 	default:
351 	    LDEB(bdIn->bdBitsPerPixel); rval= -1; goto ready;
352 	}
353 
354     for ( row= 0; row < bdIn->bdPixelsHigh; row++ )
355 	{
356 	const unsigned char *	from;
357 	unsigned char *		to;
358 
359 	from= riIn->riBytes+ row* bdIn->bdBytesPerRow;
360 	to= ri.riBytes+ row* bdIn->bdBytesPerRow;
361 
362 	(*flip)( to, from, bdIn->bdPixelsWide, pixelsPerByte );
363 	}
364 
365     /* steal */
366     *riOut= ri; bmInitRasterImage( &ri );
367 
368   ready:
369 
370     bmCleanRasterImage( &ri );
371 
372     return rval;
373     }
374 
375 /************************************************************************/
376 /*									*/
377 /*  Rotate a bitmap by 0,90,180,270 degrees.				*/
378 /*									*/
379 /************************************************************************/
380 
bmRotate90(RasterImage * riOut,const RasterImage * riIn,int angle)381 int bmRotate90(		RasterImage *			riOut,
382 			const RasterImage *		riIn,
383 			int				angle )
384     {
385     int				rval= 0;
386     const BitmapDescription *	bdIn= &(riIn->riDescription);
387 
388     const unsigned char *	from;
389     unsigned char *		to;
390     unsigned int		row, col;
391 
392     int				s;
393     int				shift;
394     unsigned char		m= 0;
395     unsigned char		mr;
396     int				step;
397 
398     RasterImage			ri;
399 
400     bmInitRasterImage( &ri );
401 
402     switch( angle )
403 	{
404 	case 0:
405 	    if  ( bmCopyRasterImage( riOut, riIn ) )
406 		{ LDEB(1); rval= -1; goto ready;	}
407 	    goto ready;
408 
409 	case 180:
410 	    if  ( bmRotate180( riOut, riIn, angle ) )
411 		{ LDEB(180); rval= -1; goto ready;	}
412 	    goto ready;
413 
414 	case 270:
415 	case 90:
416 	    break;
417 
418 	default:
419 	    LDEB(angle); rval= -1; goto ready;
420 	}
421 
422 
423     if  ( bmCopyDescription( &(ri.riDescription), bdIn ) )
424 	{ LDEB(1); rval= -1; goto ready;	}
425 
426     ri.riDescription.bdPixelsWide= bdIn->bdPixelsHigh;
427     ri.riDescription.bdPixelsHigh= bdIn->bdPixelsWide;
428 
429     if  ( bmCalculateSizes( &(ri.riDescription) ) )
430 	{ LDEB(1); rval= -1; goto ready;	}
431 
432     if  ( bmAllocateBuffer( &ri ) )
433 	{ LLDEB(ri.riDescription.bdBufferLength,ri.riBytes); rval= -1; goto ready; }
434 
435     switch( bdIn->bdBitsPerPixel )
436 	{
437 	case  4:
438 	    m |= 0x30;
439 	    /*FALLTHROUGH*/
440 	case  2:
441 	    m |= 0x40;
442 	    /*FALLTHROUGH*/
443 	case  1:
444 	    m |= 0x80;
445 
446 	    memset( ri.riBytes, 0, ri.riDescription.bdBufferLength );
447 	    step= 8/ bdIn->bdBitsPerPixel;
448 
449 	    if  ( angle == 90 )
450 		{
451 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
452 		    {
453 		    int		toRow= ri.riDescription.bdPixelsHigh- row- 1;
454 
455 		    mr= m >> bdIn->bdBitsPerPixel* ( row % step );
456 
457 		    for ( s= 0; s < row % step; s++ )
458 			{
459 			to= ri.riBytes+ toRow* ri.riDescription.bdBytesPerRow;
460 			from= riIn->riBytes+ row/step+ s* bdIn->bdBytesPerRow;
461 
462 			shift= row % step- s;
463 			shift *= bdIn->bdBitsPerPixel;
464 
465 			for ( col= s; col < ri.riDescription.bdPixelsWide; col += step )
466 			    {
467 			    *(to++) |= ( *from & mr ) << shift;
468 			    from += step* bdIn->bdBytesPerRow;
469 			    }
470 			}
471 
472 		    for ( s= row % step; s < step; s++ )
473 			{
474 			to= ri.riBytes+ toRow* ri.riDescription.bdBytesPerRow;
475 			from= riIn->riBytes+ row/step+ s* bdIn->bdBytesPerRow;
476 
477 			shift= s- row % step;
478 			shift *= bdIn->bdBitsPerPixel;
479 
480 			for ( col= s; col < ri.riDescription.bdPixelsWide; col += step )
481 			    {
482 			    *(to++) |= ( *from & mr ) >> shift;
483 			    from += step* bdIn->bdBytesPerRow;
484 			    }
485 			}
486 		    }
487 		}
488 	    else{
489 		/*270*/
490 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
491 		    {
492 		    mr= m >> bdIn->bdBitsPerPixel* ( row % step );
493 
494 		    for ( s= 0; s < row % step; s++ )
495 			{
496 			int r= bdIn->bdPixelsHigh- 1;
497 
498 			to= ri.riBytes+ row* ri.riDescription.bdBytesPerRow;
499 			from= riIn->riBytes+ ( bdIn->bdPixelsHigh- 1 )*
500 							bdIn->bdBytesPerRow;
501 			from -= s* bdIn->bdBytesPerRow;
502 			r -= s;
503 			from += row/ step;
504 
505 			shift= row % step- s;
506 			shift *= bdIn->bdBitsPerPixel;
507 
508 			for ( col= 0; col < ri.riDescription.bdPixelsWide; col += step )
509 			    {
510 			    if  ( r < 0 )
511 				{ break;	}
512 
513 			    *(to++) |= ( *from & mr ) << shift;
514 			    from -= step* bdIn->bdBytesPerRow;
515 			    r -= step;
516 			    }
517 			}
518 
519 		    for ( s= row % step; s < step; s++ )
520 			{
521 			int r= bdIn->bdPixelsHigh- 1;
522 
523 			to= ri.riBytes+ row* ri.riDescription.bdBytesPerRow;
524 			from= riIn->riBytes+ ( bdIn->bdPixelsHigh- 1 )*
525 							bdIn->bdBytesPerRow;
526 			from -= s* bdIn->bdBytesPerRow;
527 			r -= s;
528 			from += row/ step;
529 
530 			shift= s- row % step;
531 			shift *= bdIn->bdBitsPerPixel;
532 
533 			for ( col= 0; col < ri.riDescription.bdPixelsWide; col += step )
534 			    {
535 			    if  ( r < 0 )
536 				{ break;	}
537 
538 			    *(to++) |= ( *from & mr ) >> shift;
539 			    from -= step* bdIn->bdBytesPerRow;
540 			    r -= step;
541 			    }
542 			}
543 		    }
544 		}
545 
546 	    break;
547 	case  8:
548 	    if  ( angle == 90 )
549 		{
550 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
551 		    {
552 		    from= riIn->riBytes+ row;
553 		    to= ri.riBytes+ ( ri.riDescription.bdPixelsHigh- row- 1 )* ri.riDescription.bdBytesPerRow;
554 
555 		    for ( col= 0; col < ri.riDescription.bdPixelsWide; col++ )
556 			{ *(to++)= *from; from += bdIn->bdBytesPerRow; }
557 		    }
558 		}
559 	    else{
560 		/*270*/
561 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
562 		    {
563 		    from= riIn->riBytes+ row;
564 		    to= ri.riBytes+ ( row+ 1 )* ri.riDescription.bdBytesPerRow- 1;
565 
566 		    for ( col= 0; col < ri.riDescription.bdPixelsWide; col++ )
567 			{ *(to--)= *from; from += bdIn->bdBytesPerRow; }
568 		    }
569 		}
570 	    break;
571 
572 	case 24:
573 	    if  ( angle == 90 )
574 		{
575 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
576 		    {
577 		    from= riIn->riBytes+ 3* row;
578 		    to= ri.riBytes+ ( ri.riDescription.bdPixelsHigh- row- 1 )* ri.riDescription.bdBytesPerRow;
579 
580 		    for ( col= 0; col < ri.riDescription.bdPixelsWide; col++ )
581 			{
582 			*(to++)= from[0]; *(to++)= from[1]; *(to++)= from[2];
583 			from += bdIn->bdBytesPerRow;
584 			}
585 		    }
586 		}
587 	    else{
588 		for ( row= 0; row < ri.riDescription.bdPixelsHigh; row++ )
589 		    {
590 		    from= riIn->riBytes+ 3* row;
591 		    to= ri.riBytes+ ( row+ 1 )* ri.riDescription.bdBytesPerRow- 3;
592 
593 		    for ( col= 0; col < ri.riDescription.bdPixelsWide; col++ )
594 			{
595 			to[0]= from[0]; to[1]= from[1]; to[2]= from[2];
596 			to -= 3; from += bdIn->bdBytesPerRow;
597 			}
598 		    }
599 		}
600 	    break;
601 	default:
602 	    LDEB(bdIn->bdBitsPerPixel); rval= -1; goto ready;
603 	}
604 
605     /* steal */
606     *riOut= ri; bmInitRasterImage( &ri );
607 
608   ready:
609 
610     bmCleanRasterImage( &ri );
611 
612     return rval;
613     }
614 
615 /************************************************************************/
616 /*									*/
617 /*  Shear operations.							*/
618 /*									*/
619 /************************************************************************/
620 
621 typedef void (*ShearRow)(	unsigned char *			rowBufOut,
622 				const unsigned char *		rowBufIn,
623 				const BitmapDescription *	bdIn,
624 				const BitmapDescription *	bdOut,
625 				int				colShift,
626 				int				fl );
627 
628 typedef void (*ShearCol)(	unsigned char *			imgBufOut,
629 				const unsigned char *		imgBufIn,
630 				const BitmapDescription *	bdIn,
631 				const BitmapDescription *	bdOut,
632 				int				col,
633 				int				rowShift,
634 				int				fl );
635 
bmShearRow8Bit(unsigned char * rowBufOut,const unsigned char * rowBufIn,const BitmapDescription * bdIn,const BitmapDescription * bdOut,int colShift,int fl)636 static void bmShearRow8Bit(	unsigned char *			rowBufOut,
637 				const unsigned char *		rowBufIn,
638 				const BitmapDescription *	bdIn,
639 				const BitmapDescription *	bdOut,
640 				int				colShift,
641 				int				fl )
642     {
643     int		fr= 255- fl;
644     int		spp= bdIn->bdSamplesPerPixel;
645     int		i;
646 
647     int		colIn0;
648     int		colIn1;
649     int		colIn;
650 
651     int		prev[5];
652 
653     /*  1  */
654     colIn0= 0;
655     colIn1= bdIn->bdPixelsWide- 1;
656 
657     if  ( colShift < 0 )
658 	{ colIn0= -colShift; }
659 
660     if  ( colIn1+ colShift >= bdOut->bdPixelsWide )
661 	{ colIn1= bdOut->bdPixelsWide- colShift- 1; }
662 
663     rowBufOut += spp* colShift;
664 
665     for ( i= 0; i < spp; i++ )
666 	{ prev[i]= rowBufIn[i]; }
667 
668     for ( colIn= colIn0; colIn <= colIn1; colIn++ )
669 	{
670 	const unsigned char *	f= rowBufIn;
671 	unsigned char *		t= rowBufOut;
672 
673 	for ( i= 0; i < spp; i++ )
674 	    {
675 	    t[0]= ( ( fl* prev[i] )+ ( fr* f[0] ) )/ 255;
676 	    prev[i]= f[0];
677 
678 	    f++; t++;
679 	    }
680 
681 	rowBufOut += spp; rowBufIn += spp;
682 	}
683 
684     return;
685     }
686 
687 /************************************************************************/
688 /*									*/
689 /*  Shear one column in a one byte per sample image.			*/
690 /*									*/
691 /*  1)  For all rows of the input image.				*/
692 /*									*/
693 /************************************************************************/
694 
bmShearCol8Bit(unsigned char * imgBufOut,const unsigned char * imgBufIn,const BitmapDescription * bdIn,const BitmapDescription * bdOut,int col,int rowShift,int fl)695 static void bmShearCol8Bit(	unsigned char *			imgBufOut,
696 				const unsigned char *		imgBufIn,
697 				const BitmapDescription *	bdIn,
698 				const BitmapDescription *	bdOut,
699 				int				col,
700 				int				rowShift,
701 				int				fl )
702     {
703     int				fr= 255- fl;
704     int				spp= bdIn->bdSamplesPerPixel;
705     int				i;
706 
707     int				rowIn0;
708     int				rowIn1;
709     int				rowIn;
710     int				rowTo0;
711     int				prev[5];
712 
713     const unsigned char *	from;
714     unsigned char *		to;
715 
716     for ( i= 0; i < spp; i++ )
717 	{ prev[i]= 0; }
718 
719     /*  1  */
720     rowIn0= 0;
721     rowIn1= bdIn->bdPixelsHigh- 1;
722 
723     if  ( rowShift < 0 )
724 	{ rowIn0= -rowShift; }
725     rowTo0= rowIn0+ rowShift;
726 
727     if  ( rowIn1+ rowShift >= bdOut->bdPixelsHigh )
728 	{ rowIn1= bdOut->bdPixelsHigh- rowShift- 1; }
729 
730     from= imgBufIn+ rowIn0* bdIn->bdBytesPerRow+ spp* col;
731     to= imgBufOut+ rowTo0* bdOut->bdBytesPerRow+ spp* col;
732 
733     /*  1  */
734     for ( rowIn= rowIn0; rowIn <= rowIn1; rowIn++ )
735 	{
736 	const unsigned char *	f= from;
737 	unsigned char *		t= to;
738 
739 	for ( i= 0; i < spp; i++ )
740 	    {
741 	    t[0]= ( ( fl* prev[i] )+ ( fr* f[0] ) )/ 255;
742 	    prev[i]= f[0];
743 
744 	    f++; t++;
745 	    }
746 
747 	from += bdIn->bdBytesPerRow;
748 	to += bdOut->bdBytesPerRow;
749 	}
750 
751     return;
752     }
753 
bmShearRows(unsigned char * bufOut,const BitmapDescription * bdOut,int shear,const DocumentRectangle * drOut,const RasterImage * riIn,ShearRow shearRow)754 static int bmShearRows(		unsigned char *			bufOut,
755 				const BitmapDescription *	bdOut,
756 				int				shear,
757 				const DocumentRectangle *	drOut,
758 				const RasterImage *		riIn,
759 				ShearRow			shearRow )
760     {
761     const BitmapDescription *	bdIn= &(riIn->riDescription);
762     int				row;
763 
764     int				fl;
765     int				colShift;
766 
767     if  ( bdOut->bdPixelsHigh != bdIn->bdPixelsHigh )
768 	{ LLDEB(bdOut->bdPixelsHigh,bdIn->bdPixelsHigh); return -1; }
769 
770     for ( row= 0; row < bdIn->bdPixelsHigh; row++ )
771 	{
772 	unsigned char *		rowBufOut;
773 	const unsigned char *	rowBufIn;
774 
775 	rowBufOut= bufOut+ row* bdOut->bdBytesPerRow;
776 	rowBufIn= riIn->riBytes+ row* bdIn->bdBytesPerRow;
777 
778 	fl= ( 255* shear* row )/ (int)bdIn->bdPixelsHigh;
779 	colShift= ( shear* row )/ (int)bdIn->bdPixelsHigh;
780 
781 	if  ( fl >= 0 )
782 	    { fl -= 255* colShift;		}
783 	else{ fl -= 255* colShift; fl += 255;	}
784 
785 	colShift -= drOut->drX0;
786 
787 	(*shearRow)( rowBufOut, rowBufIn, bdIn, bdOut, colShift, fl );
788 	}
789 
790     return 0;
791     }
792 
bmShearCols(unsigned char * bufOut,const BitmapDescription * bdOut,int shear,const DocumentRectangle * drOut,const RasterImage * riIn,ShearCol shearCol)793 static int bmShearCols(		unsigned char *			bufOut,
794 				const BitmapDescription *	bdOut,
795 				int				shear,
796 				const DocumentRectangle *	drOut,
797 				const RasterImage *		riIn,
798 				ShearCol			shearCol )
799     {
800     const BitmapDescription *	bdIn= &(riIn->riDescription);
801     int				col;
802 
803     if  ( bdOut->bdPixelsWide != bdIn->bdPixelsWide )
804 	{ LLDEB(bdOut->bdPixelsWide,bdIn->bdPixelsWide); return -1; }
805 
806     for ( col= 0; col < bdIn->bdPixelsWide; col++ )
807 	{
808 	int			fl;
809 	int			rowShift;
810 
811 	fl= ( 255* shear* col )/ (int)bdIn->bdPixelsWide;
812 	rowShift= ( shear* col )/ (int)bdIn->bdPixelsWide;
813 
814 	if  ( fl >= 0 )
815 	    { fl -= 255* rowShift;		}
816 	else{ fl -= 255* rowShift; fl += 255;	}
817 
818 	rowShift -= drOut->drY0;
819 
820 	(*shearCol)( bufOut, riIn->riBytes, bdIn, bdOut, col, rowShift, fl );
821 	}
822 
823     return 0;
824     }
825 
826 /************************************************************************/
827 /*									*/
828 /*  Apply an affine transform to the rectangle from the original image.	*/
829 /*									*/
830 /*  The routine used to determine the smallest rectangle that encloses	*/
831 /*  the result of an intermediate result in the rotation of an image.	*/
832 /*									*/
833 /************************************************************************/
834 
bmTransformRectangle(BitmapDescription * bd,Point2DI to[4],DocumentRectangle * drTo,const AffineTransform2D * at,const Point2DI from[4],const DocumentRectangle * drFrom)835 static void bmTransformRectangle(
836 				BitmapDescription *		bd,
837 				Point2DI			to[4],
838 				DocumentRectangle *		drTo,
839 				const AffineTransform2D *	at,
840 				const Point2DI			from[4],
841 				const DocumentRectangle *	drFrom )
842     {
843     int		i;
844 
845     for ( i= 0; i < 4; i++ )
846 	{
847 	to[i].x= AT2_X( from[i].x- drFrom->drX0,
848 					    from[i].y- drFrom->drY0, at );
849 	to[i].y= AT2_Y( from[i].x- drFrom->drX0,
850 					    from[i].y- drFrom->drY0, at );
851 	}
852 
853     drTo->drX0= drTo->drX1= to[0].x;
854     drTo->drY0= drTo->drY1= to[0].y;
855 
856     for ( i= 1; i < 4; i++ )
857 	{
858 	if  ( drTo->drX0 > to[i].x )
859 	    { drTo->drX0=  to[i].x;	}
860 	if  ( drTo->drY0 > to[i].y )
861 	    { drTo->drY0=  to[i].y;	}
862 
863 	if  ( drTo->drX1 < to[i].x )
864 	    { drTo->drX1=  to[i].x;	}
865 	if  ( drTo->drY1 < to[i].y )
866 	    { drTo->drY1=  to[i].y;	}
867 	}
868 
869     bd->bdPixelsWide= drTo->drX1- drTo->drX0+ 1;
870     bd->bdPixelsHigh= drTo->drY1- drTo->drY0+ 1;
871 
872     bmCalculateSizes( bd );
873 
874     return;
875     }
876 
877 /************************************************************************/
878 /*									*/
879 /*  Rotate a pixmap image over an arbitrary angle.			*/
880 /*									*/
881 /*  Use the algorithm outlined in:					*/
882 /*  PAETH, Alan: "A Fast Algorithm for General Raster Rotation" pp 179-	*/
883 /*  195 in: GLASSNER, Andrew S: "Graphics Gems", Academic Press,	*/
884 /*  Boston, 1990.							*/
885 /*									*/
886 /*  The two main advantages of the algorithm are fast and easy anti-	*/
887 /*  aliassing and the simple continuous loops that prevent holes in the	*/
888 /*  rendering.								*/
889 /*									*/
890 /*  Counterclockwise rotation of (x,y) onto (x',y') by an angle theta	*/
891 /*  is a multiplication of the vector my the matrix:			*/
892 /*	[  cos(theta) -sin(theta) ]					*/
893 /*	[  sin(theta)  cos(theta) ]					*/
894 /*  The matrix is orhogonal: the inverse is the transpose:		*/
895 /*	[  cos(theta)  sin(theta) ]					*/
896 /*	[ -sin(theta)  cos(theta) ]					*/
897 /*  It can be written as the product of three shears:			*/
898 /*	[ 1 a ] [ 1 0 ] [ 1 c ]   [ cos(theta) -sin(theta) ]		*/
899 /*	[ 0 1 ] [ b 1 ] [ 0 1 ] = [ sin(theta)  cos(theta) ]		*/
900 /*  Where:								*/
901 /*      a= -tan( theta/ 2 ).						*/
902 /*      b= sin( theta ).						*/
903 /*      c= -tan( theta/ 2 ).						*/
904 /*									*/
905 /*  1)  Find a theta <= 45 degrees.					*/
906 /*  2)  Initial X Shear.						*/
907 /*  3)  Subsequent Y Shear.						*/
908 /*  4)  Final X Shear.							*/
909 /*									*/
910 /************************************************************************/
911 
bmRotate(RasterImage * riOut,const RasterImage * riIn,double theta)912 int bmRotate(	RasterImage *			riOut,
913 		const RasterImage *		riIn,
914 		double				theta )
915     {
916     const BitmapDescription *	bdIn= &(riIn->riDescription);
917     int				rval= 0;
918 
919     int				rot90;
920 
921     double			a;
922     double			b;
923     double			c;
924 
925     AffineTransform2D		C;
926     AffineTransform2D		B;
927     AffineTransform2D		A;
928 
929     Point2DI			rectIn[4];
930     Point2DI			rectC[4];
931     Point2DI			rectB[4];
932     Point2DI			rectA[4];
933 
934     DocumentRectangle		drIn;
935     DocumentRectangle		drC;
936     DocumentRectangle		drB;
937     DocumentRectangle		drA;
938 
939     int				shearC;
940     int				shearB;
941     int				shearA;
942 
943     RasterImage			riC;
944     RasterImage			riB;
945     RasterImage			riA;
946 
947     ShearRow			shearRow= (ShearRow)0;
948     ShearCol			shearCol= (ShearCol)0;
949 
950     bmInitRasterImage( &riC );
951     bmInitRasterImage( &riB );
952     bmInitRasterImage( &riA );
953 
954     geoIdentityAffineTransform2D( &C );
955     geoIdentityAffineTransform2D( &B );
956     geoIdentityAffineTransform2D( &A );
957 
958     switch( bdIn->bdColorEncoding )
959 	{
960 	case BMcoBLACKWHITE:
961 	case BMcoWHITEBLACK:
962 	    switch( bdIn->bdBitsPerPixel )
963 		{
964 		case 8:
965 		    shearRow= bmShearRow8Bit;
966 		    shearCol= bmShearCol8Bit;
967 		    break;
968 
969 		default:
970 		    LLDEB(bdIn->bdColorEncoding,bdIn->bdBitsPerPixel);
971 		    rval= -1; goto ready;
972 		}
973 	    break;
974 
975 	case BMcoRGB:
976 	    switch( bdIn->bdBitsPerSample )
977 		{
978 		case 8:
979 		    shearRow= bmShearRow8Bit;
980 		    shearCol= bmShearCol8Bit;
981 		    break;
982 
983 		default:
984 		    LLDEB(bdIn->bdColorEncoding,bdIn->bdBitsPerPixel);
985 		    rval= -1; goto ready;
986 		}
987 	    break;
988 
989 	case BMcoRGB8PALETTE:
990 	    LDEB(bdIn->bdColorEncoding);
991 	    rval= -1; goto ready;
992 	    break;
993 
994 	default:
995 	    LDEB(bdIn->bdColorEncoding);
996 	    rval= -1; goto ready;
997 	}
998 
999     /*********/
1000     /*  0 1  */
1001     /*  3 2  */
1002     /*********/
1003     drIn.drX0= 0; drIn.drX1= bdIn->bdPixelsWide- 1;
1004     drIn.drY0= 0; drIn.drY1= bdIn->bdPixelsHigh- 1;
1005 
1006     rectIn[0].x= 0;		rectIn[0].y= 0;
1007     rectIn[1].x= drIn.drX1;	rectIn[1].y= 0;
1008     rectIn[2].x= drIn.drX1;	rectIn[2].y= drIn.drY1;
1009     rectIn[3].x= 0;		rectIn[3].y= drIn.drY1;
1010 
1011     /*  1  */
1012     while( theta < -M_PI/4 )
1013 	{ theta += 2* M_PI;	}
1014     for ( rot90= 0; theta > M_PI/4; rot90++ )
1015 	{ theta -= M_PI/2;	}
1016     rot90= rot90 % 4;
1017 
1018     c= -tan( theta/ 2.0 );
1019     b= sin( theta );
1020     a= -tan( theta/ 2.0 );
1021 
1022     C.at2Ayx= c;
1023     B.at2Axy= b;
1024     A.at2Ayx= a;
1025 
1026     /*  2  */
1027     if  ( bmCopyDescription( &(riC.riDescription), bdIn ) )
1028 	{ LDEB(1); rval= -1; goto ready;	}
1029 
1030     bmTransformRectangle( &(riC.riDescription), rectC, &drC, &C,
1031 							rectIn, &drIn );
1032 
1033     shearC= c* bdIn->bdPixelsHigh;
1034 
1035     riC.riBytes= (unsigned char *)malloc( riC.riDescription.bdBufferLength );
1036     if  ( ! riC.riBytes )
1037 	{ LLDEB(riC.riDescription.bdBufferLength,riC.riBytes); rval= -1; goto ready;	}
1038     memset( riC.riBytes, 0, riC.riDescription.bdBufferLength );
1039 
1040     if  ( bmShearRows( riC.riBytes, &(riC.riDescription), shearC, &drC, riIn, shearRow ) )
1041 	{ LDEB(1); rval= -1; goto ready; }
1042 
1043 #   define	RET_C	0
1044 #   if		RET_C
1045     bmCopyDescription( bdOut, &bdC );
1046     *pBufOut= bufC;
1047     bufC= (unsigned char *)0;
1048     goto ready;
1049 #   endif
1050 #   define	NO_C	0
1051 #   if		NO_C
1052     bmCopyDescription(&bdC,bdIn);
1053     memcpy( bufC, bufIn, bdIn->bdBufferLength );
1054 #   endif
1055 
1056     /*  3  */
1057     if  ( bmCopyDescription( &(riB.riDescription), &(riC.riDescription) ) )
1058 	{ LDEB(1); rval= -1; goto ready;	}
1059     bmTransformRectangle( &(riB.riDescription), rectB, &drB, &B, rectC, &drC );
1060 
1061     shearB= b* riC.riDescription.bdPixelsWide;
1062 
1063     riB.riBytes= (unsigned char *)malloc( riB.riDescription.bdBufferLength );
1064     if  ( ! riB.riBytes )
1065 	{ LLDEB(riB.riDescription.bdBufferLength,riB.riBytes); rval= -1; goto ready;	}
1066     memset( riB.riBytes, 0, riB.riDescription.bdBufferLength );
1067 
1068     if  ( bmShearCols( riB.riBytes, &(riB.riDescription), shearB, &drB,
1069 							    &riC, shearCol ) )
1070 	{ LDEB(1); rval= -1; goto ready; }
1071 
1072 #   define	RET_B	0
1073 #   if		RET_B
1074     bmCopyDescription( bdOut, &bdB );
1075     *pBufOut= bufB;
1076     bufB= (unsigned char *)0;
1077     goto ready;
1078 #   endif
1079 #   define	NO_B	0
1080 #   if		NO_B
1081     bmCopyDescription(&bdB,&bdC);
1082     memcpy( bufB, bufC, bdC.bdBufferLength );
1083 #   endif
1084 
1085     /*  4  */
1086     if  ( bmCopyDescription( &(riA.riDescription), &(riB.riDescription) ) )
1087 	{ LDEB(1); rval= -1; goto ready;	}
1088     bmTransformRectangle( &(riA.riDescription), rectA, &drA, &A, rectB, &drB );
1089 
1090     shearA= a* riB.riDescription.bdPixelsHigh;
1091 
1092     riA.riBytes= (unsigned char *)malloc( riA.riDescription.bdBufferLength );
1093     if  ( ! riA.riBytes )
1094 	{ LLDEB(riA.riDescription.bdBufferLength,riA.riBytes); rval= -1; goto ready;	}
1095     memset( riA.riBytes, 0, riA.riDescription.bdBufferLength );
1096 
1097     if  ( bmShearRows( riA.riBytes, &(riA.riDescription), shearA, &drA, &riB, shearRow ) )
1098 	{ LDEB(1); rval= -1; goto ready; }
1099 
1100     if  ( rot90 != 0 )
1101 	{
1102 	if  ( bmRotate90( riOut, &riA, 90* rot90 ) )
1103 	    { LDEB(rot90); rval= -1; goto ready; }
1104 	}
1105     else{
1106 	/*  steal */
1107 	*riOut= riA; bmInitRasterImage( &riA );
1108 	}
1109 
1110   ready:
1111 
1112     bmCleanRasterImage( &riC );
1113     bmCleanRasterImage( &riB );
1114     bmCleanRasterImage( &riA );
1115 
1116     return rval;
1117     }
1118