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