root/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImageToolkit/ClassicRotate.cpp @ 36

Revision 36, 29.8 KB (checked in by vsilva, 8 years ago)

FIX Xades encoding problems

Line 
1// ==========================================================
2// Bitmap rotation by means of 3 shears.
3//
4// Design and implementation by
5// - Hervé Drolon (drolon@infonie.fr)
6// - Thorsten Radde (support@IdealSoftware.com)
7//
8// This file is part of FreeImage 3
9//
10// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
11// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
12// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
13// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
14// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
15// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
16// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
17// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
18// THIS DISCLAIMER.
19//
20// Use at your own risk!
21// ==========================================================
22
23/*
24 ============================================================
25 References :
26 [1] Paeth A., A Fast Algorithm for General Raster Rotation.
27 Graphics Gems, p. 179, Andrew Glassner editor, Academic Press, 1990.
28 [2] Yariv E., High quality image rotation (rotate by shear).
29 [Online] http://www.codeproject.com/bitmap/rotatebyshear.asp
30 [3] Treskunov A., Fast and high quality true-color bitmap rotation function.
31 [Online] http://anton.treskunov.net/Software/doc/fast_and_high_quality_true_color_bitmap_rotation_function.html
32 ============================================================
33*/
34
35#include "FreeImagePTEiD.h"
36#include "Utilities.h"
37
38#define RBLOCK          64      // image blocks of RBLOCK*RBLOCK pixels
39
40/////////////////////////////////////////////////////////////////////////////////////////////////////////////
41// Prototypes definition
42
43static void HorizontalSkew(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double dWeight, const void *bkcolor);
44static void VerticalSkew(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double dWeight, const void *bkcolor);
45static FIBITMAP* Rotate90(FIBITMAP *src);
46static FIBITMAP* Rotate180(FIBITMAP *src);
47static FIBITMAP* Rotate270(FIBITMAP *src);
48static FIBITMAP* Rotate45(FIBITMAP *src, double dAngle, const void *bkcolor);
49static FIBITMAP* RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor);
50
51/////////////////////////////////////////////////////////////////////////////////////////////////////////////
52
53/**
54Skews a row horizontally (with filtered weights).
55Limited to 45 degree skewing only. Filters two adjacent pixels.
56Parameter T can be BYTE, WORD of float.
57@param src Pointer to source image to rotate
58@param dst Pointer to destination image
59@param row Row index
60@param iOffset Skew offset
61@param dWeight Relative weight of right pixel
62@param bkcolor Background color
63*/
64template <class T> void 
65HorizontalSkewT(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double weight, const void *bkcolor = NULL) {
66        unsigned i, j;
67        int iXPos;
68
69        unsigned src_width  = FreeImage_GetWidth(src);
70        unsigned dst_width  = FreeImage_GetWidth(dst);
71
72        T pxlSrc[4], pxlLeft[4], pxlOldLeft[4]; // 4 = 4*sizeof(T) max
73       
74        // background
75        const T pxlBlack[4] = {0, 0, 0, 0 };
76        const T *pxlBkg = static_cast<const T*>(bkcolor); // assume at least bytespp and 4*sizeof(T) max
77        if(!pxlBkg) {
78                // default background color is black
79                pxlBkg = pxlBlack;
80        }
81
82        // calculate the number of bytes per pixel
83        unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
84        // calculate the number of samples per pixel
85        unsigned samples = bytespp / sizeof(T);
86
87        BYTE *src_bits = FreeImage_GetScanLine(src, row);
88        BYTE *dst_bits = FreeImage_GetScanLine(dst, row);
89
90        // fill gap left of skew with background
91        if(bkcolor) {
92                for(int k = 0; k < iOffset; k++) {
93                        memcpy(&dst_bits[k * bytespp], bkcolor, bytespp);
94                }
95                memcpy(&pxlOldLeft[0], bkcolor, bytespp);
96        } else {
97                if(iOffset > 0) {
98                        memset(dst_bits, 0, iOffset * bytespp);
99                }               
100                memset(&pxlOldLeft[0], 0, bytespp);
101        }
102
103        for(i = 0; i < src_width; i++) {
104                // loop through row pixels
105                memcpy(&pxlSrc[0], src_bits, bytespp);
106                // calculate weights
107                for(j = 0; j < samples; j++) {
108                        pxlLeft[j] = static_cast<T>(pxlBkg[j] + (pxlSrc[j] - pxlBkg[j]) * weight + 0.5);
109                }
110                // check boundaries
111                iXPos = i + iOffset;
112                if((iXPos >= 0) && (iXPos < (int)dst_width)) {
113                        // update left over on source
114                        for(j = 0; j < samples; j++) {
115                                pxlSrc[j] = pxlSrc[j] - (pxlLeft[j] - pxlOldLeft[j]);
116                        }
117                        memcpy(&dst_bits[iXPos*bytespp], &pxlSrc[0], bytespp);
118                }
119                // save leftover for next pixel in scan
120                memcpy(&pxlOldLeft[0], &pxlLeft[0], bytespp);
121
122                // next pixel in scan
123                src_bits += bytespp;
124        }                       
125
126        // go to rightmost point of skew
127        iXPos = src_width + iOffset; 
128
129        if((iXPos >= 0) && (iXPos < (int)dst_width)) {
130                dst_bits = FreeImage_GetScanLine(dst, row) + iXPos * bytespp;
131
132                // If still in image bounds, put leftovers there
133                memcpy(dst_bits, &pxlOldLeft[0], bytespp);
134
135                // clear to the right of the skewed line with background
136                dst_bits += bytespp;
137                if(bkcolor) {
138                        for(i = 0; i < dst_width - iXPos - 1; i++) {
139                                memcpy(&dst_bits[i * bytespp], bkcolor, bytespp);
140                        }
141                } else {
142                        memset(dst_bits, 0, bytespp * (dst_width - iXPos - 1));
143                }
144
145        }
146}
147
148/**
149Skews a row horizontally (with filtered weights).
150Limited to 45 degree skewing only. Filters two adjacent pixels.
151@param src Pointer to source image to rotate
152@param dst Pointer to destination image
153@param row Row index
154@param iOffset Skew offset
155@param dWeight Relative weight of right pixel
156@param bkcolor Background color
157*/
158static void 
159HorizontalSkew(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double dWeight, const void *bkcolor) {
160        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
161
162        switch(image_type) {
163                case FIT_BITMAP:
164                        switch(FreeImage_GetBPP(src)) {
165                                case 8:
166                                case 24:
167                                case 32:
168                                        HorizontalSkewT<BYTE>(src, dst, row, iOffset, dWeight, bkcolor);
169                                break;
170                        }
171                        break;
172                case FIT_UINT16:
173                case FIT_RGB16:
174                case FIT_RGBA16:
175                        HorizontalSkewT<WORD>(src, dst, row, iOffset, dWeight, bkcolor);
176                        break;
177                case FIT_FLOAT:
178                case FIT_RGBF:
179                case FIT_RGBAF:
180                        HorizontalSkewT<float>(src, dst, row, iOffset, dWeight, bkcolor);
181                        break;
182        }
183}
184
185/**
186Skews a column vertically (with filtered weights).
187Limited to 45 degree skewing only. Filters two adjacent pixels.
188Parameter T can be BYTE, WORD of float.
189@param src Pointer to source image to rotate
190@param dst Pointer to destination image
191@param col Column index
192@param iOffset Skew offset
193@param dWeight Relative weight of upper pixel
194@param bkcolor Background color
195*/
196template <class T> void 
197VerticalSkewT(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double weight, const void *bkcolor = NULL) {
198        unsigned i, j;
199        int iYPos;
200
201        unsigned src_height = FreeImage_GetHeight(src);
202        unsigned dst_height = FreeImage_GetHeight(dst);
203
204        T pxlSrc[4], pxlLeft[4], pxlOldLeft[4]; // 4 = 4*sizeof(T) max
205
206        // background
207        const T pxlBlack[4] = {0, 0, 0, 0 };
208        const T *pxlBkg = static_cast<const T*>(bkcolor); // assume at least bytespp and 4*sizeof(T) max
209        if(!pxlBkg) {
210                // default background color is black
211                pxlBkg = pxlBlack;
212        }
213
214        // calculate the number of bytes per pixel
215        unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
216        // calculate the number of samples per pixel
217        unsigned samples = bytespp / sizeof(T);
218
219        unsigned src_pitch = FreeImage_GetPitch(src);
220        unsigned dst_pitch = FreeImage_GetPitch(dst);
221        unsigned index = col * bytespp;
222
223        BYTE *src_bits = FreeImage_GetBits(src) + index;
224        BYTE *dst_bits = FreeImage_GetBits(dst) + index;
225
226        // fill gap above skew with background
227        if(bkcolor) {
228                for(int k = 0; k < iOffset; k++) {
229                        memcpy(dst_bits, bkcolor, bytespp);
230                        dst_bits += dst_pitch;
231                }
232                memcpy(&pxlOldLeft[0], bkcolor, bytespp);
233        } else {
234                for(int k = 0; k < iOffset; k++) {
235                        memset(dst_bits, 0, bytespp);
236                        dst_bits += dst_pitch;
237                }
238                memset(&pxlOldLeft[0], 0, bytespp);
239        }
240
241        for(i = 0; i < src_height; i++) {
242                // loop through column pixels
243                memcpy(&pxlSrc[0], src_bits, bytespp);                         
244                // calculate weights
245                for(j = 0; j < samples; j++) {
246                        pxlLeft[j] = static_cast<T>(pxlBkg[j] + (pxlSrc[j] - pxlBkg[j]) * weight + 0.5);
247                }
248                // check boundaries
249                iYPos = i + iOffset;
250                if((iYPos >= 0) && (iYPos < (int)dst_height)) {
251                        // update left over on source
252                        for(j = 0; j < samples; j++) {
253                                pxlSrc[j] = pxlSrc[j] - (pxlLeft[j] - pxlOldLeft[j]);
254                        }
255                        dst_bits = FreeImage_GetScanLine(dst, iYPos) + index;
256                        memcpy(dst_bits, &pxlSrc[0], bytespp);
257                }
258                // save leftover for next pixel in scan
259                memcpy(&pxlOldLeft[0], &pxlLeft[0], bytespp);
260
261                // next pixel in scan
262                src_bits += src_pitch;
263        }
264        // go to bottom point of skew
265        iYPos = src_height + iOffset;
266
267        if((iYPos >= 0) && (iYPos < (int)dst_height)) {
268                dst_bits = FreeImage_GetScanLine(dst, iYPos) + index;
269
270                // if still in image bounds, put leftovers there                               
271                memcpy(dst_bits, &pxlOldLeft[0], bytespp);
272
273                // clear below skewed line with background
274                if(bkcolor) {
275                        while(++iYPos < (int)dst_height) {                                     
276                                dst_bits += dst_pitch;
277                                memcpy(dst_bits, bkcolor, bytespp);
278                        }
279                } else {
280                        while(++iYPos < (int)dst_height) {                                     
281                                dst_bits += dst_pitch;
282                                memset(dst_bits, 0, bytespp);
283                        }
284                }
285        }
286}
287
288/**
289Skews a column vertically (with filtered weights).
290Limited to 45 degree skewing only. Filters two adjacent pixels.
291@param src Pointer to source image to rotate
292@param dst Pointer to destination image
293@param col Column index
294@param iOffset Skew offset
295@param dWeight Relative weight of upper pixel
296@param bkcolor Background color
297*/
298static void 
299VerticalSkew(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double dWeight, const void *bkcolor) {
300        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
301
302        switch(image_type) {
303                case FIT_BITMAP:
304                        switch(FreeImage_GetBPP(src)) {
305                                case 8:
306                                case 24:
307                                case 32:
308                                        VerticalSkewT<BYTE>(src, dst, col, iOffset, dWeight, bkcolor);
309                                        break;
310                        }
311                        break;
312                        case FIT_UINT16:
313                        case FIT_RGB16:
314                        case FIT_RGBA16:
315                                VerticalSkewT<WORD>(src, dst, col, iOffset, dWeight, bkcolor);
316                                break;
317                        case FIT_FLOAT:
318                        case FIT_RGBF:
319                        case FIT_RGBAF:
320                                VerticalSkewT<float>(src, dst, col, iOffset, dWeight, bkcolor);
321                                break;
322        }
323} 
324
325/**
326Rotates an image by 90 degrees (counter clockwise).
327Precise rotation, no filters required.<br>
328Code adapted from CxImage (http://www.xdp.it/cximage.htm)
329@param src Pointer to source image to rotate
330@return Returns a pointer to a newly allocated rotated image if successful, returns NULL otherwise
331*/
332static FIBITMAP* 
333Rotate90(FIBITMAP *src) {
334        int x, y, y2;
335
336        int bpp = FreeImage_GetBPP(src);
337
338        int src_width  = FreeImage_GetWidth(src);
339        int src_height = FreeImage_GetHeight(src);     
340        int dst_width  = src_height;
341        int dst_height = src_width;
342
343        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
344
345        // allocate and clear dst image
346        FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp);
347        if(NULL == dst) return NULL;
348
349        // get src and dst scan width
350        int src_pitch  = FreeImage_GetPitch(src);
351        int dst_pitch  = FreeImage_GetPitch(dst);
352
353        switch(image_type) {
354                case FIT_BITMAP:
355                        if(bpp == 1) {
356                                // speedy rotate for BW images
357
358                                BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow, *srcdisp;
359                                div_t div_r;
360
361                                BYTE *bsrc  = FreeImage_GetBits(src); 
362                                BYTE *bdest = FreeImage_GetBits(dst);
363                                dbitsmax = bdest + dst_height * dst_pitch - 1;
364
365                                for(y = 0; y < src_height; y++) {
366                                        // figure out the column we are going to be copying to
367                                        div_r = div(y, 8);
368                                        // set bit pos of src column byte
369                                        bitpos = (BYTE)(128 >> div_r.rem);
370                                        srcdisp = bsrc + y * src_pitch;
371                                        for (x = 0; x < src_pitch; x++) {
372                                                // get source bits
373                                                sbits = srcdisp + x;
374                                                // get destination column
375                                                nrow = bdest + (dst_height - 1 - (x * 8)) * dst_pitch + div_r.quot;
376                                                for (int z = 0; z < 8; z++) {
377                                                   // get destination byte
378                                                        dbits = nrow - z * dst_pitch;
379                                                        if ((dbits < bdest) || (dbits > dbitsmax)) break;
380                                                        if (*sbits & (128 >> z)) *dbits |= bitpos;
381                                                }
382                                        }
383                                }
384                        }
385                        else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
386                                // anything other than BW :
387                                // This optimized version of rotation rotates image by smaller blocks. It is quite
388                                // a bit faster than obvious algorithm, because it produces much less CPU cache misses.
389                                // This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current
390                                // CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase
391                                // speed somehow, but once you drop out of CPU's cache, things will slow down drastically.
392                                // For older CPUs with less cache, lower value would yield better results.
393
394                                int xs, ys;                            // x-segment and y-segment
395                                BYTE *bsrc  = FreeImage_GetBits(src);  // source pixels
396                                BYTE *bdest = FreeImage_GetBits(dst);  // destination pixels
397
398                                // calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
399                                int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
400
401                                for(xs = 0; xs < dst_width; xs += RBLOCK) {    // for all image blocks of RBLOCK*RBLOCK pixels
402                                        for(ys = 0; ys < dst_height; ys += RBLOCK) {
403                                                for(y = ys; y < MIN(dst_height, ys + RBLOCK); y++) {    // do rotation
404                                                        y2 = dst_height - y - 1;
405                                                        // point to src pixel at (y2, xs)
406                                                        BYTE *src_bits = bsrc + (xs * src_pitch) + (y2 * bytespp);
407                                                        // point to dst pixel at (xs, y)
408                                                        BYTE *dst_bits = bdest + (y * dst_pitch) + (xs * bytespp);
409                                                        for (x = xs; x < MIN(dst_width, xs + RBLOCK); x++) {
410                                                                // dst.SetPixel(x, y, src.GetPixel(y2, x));
411                                                                for(int j = 0; j < bytespp; j++) {
412                                                                        dst_bits[j] = src_bits[j];
413                                                                }
414                                                                dst_bits += bytespp;
415                                                                src_bits += src_pitch;
416                                                        }
417                                                }
418                                        }
419                                }
420                        }
421                        break;
422                case FIT_UINT16:
423                case FIT_RGB16:
424                case FIT_RGBA16:
425                case FIT_FLOAT:
426                case FIT_RGBF:
427                case FIT_RGBAF:
428                {
429                        BYTE *bsrc  = FreeImage_GetBits(src);  // source pixels
430                        BYTE *bdest = FreeImage_GetBits(dst);  // destination pixels
431
432                        // calculate the number of bytes per pixel
433                        int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
434
435                        for(y = 0; y < dst_height; y++) {
436                                BYTE *src_bits = bsrc + (src_width - 1 - y) * bytespp;
437                                BYTE *dst_bits = bdest + (y * dst_pitch);
438                                for(x = 0; x < dst_width; x++) {
439                                        for(int j = 0; j < bytespp; j++) {
440                                                dst_bits[j] = src_bits[j];                                     
441                                        }
442                                        src_bits += src_pitch;
443                                        dst_bits += bytespp;
444                                }
445                        }
446                }
447                break;
448        }
449
450        return dst;
451}
452
453/**
454Rotates an image by 180 degrees (counter clockwise).
455Precise rotation, no filters required.
456@param src Pointer to source image to rotate
457@return Returns a pointer to a newly allocated rotated image if successful, returns NULL otherwise
458*/
459static FIBITMAP* 
460Rotate180(FIBITMAP *src) {
461        int x, y, k, pos;
462
463        int bpp = FreeImage_GetBPP(src);
464
465        int src_width  = FreeImage_GetWidth(src);
466        int src_height = FreeImage_GetHeight(src);
467        int dst_width  = src_width;
468        int dst_height = src_height;
469
470        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
471
472        FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp);
473        if(NULL == dst) return NULL;
474
475        switch(image_type) {
476                case FIT_BITMAP:
477                        if(bpp == 1) {
478                                for(int y = 0; y < src_height; y++) {
479                                        BYTE *src_bits = FreeImage_GetScanLine(src, y);
480                                        BYTE *dst_bits = FreeImage_GetScanLine(dst, dst_height - y - 1);
481                                        for(int x = 0; x < src_width; x++) {
482                                                // get bit at (x, y)
483                                                k = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
484                                                // set bit at (dst_width - x - 1, dst_height - y - 1)
485                                                pos = dst_width - x - 1;
486                                                k ? dst_bits[pos >> 3] |= (0x80 >> (pos & 0x7)) : dst_bits[pos >> 3] &= (0xFF7F >> (pos & 0x7));
487                                        }
488                                }
489                        }
490                        else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
491                                 // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
492                                int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
493
494                                for(y = 0; y < src_height; y++) {
495                                        BYTE *src_bits = FreeImage_GetScanLine(src, y);
496                                        BYTE *dst_bits = FreeImage_GetScanLine(dst, dst_height - y - 1) + (dst_width - 1) * bytespp;
497                                        for(x = 0; x < src_width; x++) {
498                                                // get pixel at (x, y)
499                                                // set pixel at (dst_width - x - 1, dst_height - y - 1)
500                                                for(k = 0; k < bytespp; k++) {
501                                                        dst_bits[k] = src_bits[k];
502                                                }                                       
503                                                src_bits += bytespp;
504                                                dst_bits -= bytespp;
505                                        }
506                                }
507                        }
508                        break;
509                case FIT_UINT16:
510                case FIT_RGB16:
511                case FIT_RGBA16:
512                case FIT_FLOAT:
513                case FIT_RGBF:
514                case FIT_RGBAF:
515                {
516                         // Calculate the number of bytes per pixel
517                        int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
518
519                        for(y = 0; y < src_height; y++) {
520                                BYTE *src_bits = FreeImage_GetScanLine(src, y);
521                                BYTE *dst_bits = FreeImage_GetScanLine(dst, dst_height - y - 1) + (dst_width - 1) * bytespp;
522                                for(x = 0; x < src_width; x++) {
523                                        // get pixel at (x, y)
524                                        // set pixel at (dst_width - x - 1, dst_height - y - 1)
525                                        for(k = 0; k < bytespp; k++) {
526                                                dst_bits[k] = src_bits[k];
527                                        }                                       
528                                        src_bits += bytespp;
529                                        dst_bits -= bytespp;
530                                }
531                        }
532                }
533                break;
534        }
535
536        return dst;
537}
538
539/**
540Rotates an image by 270 degrees (counter clockwise).
541Precise rotation, no filters required.<br>
542Code adapted from CxImage (http://www.xdp.it/cximage.htm)
543@param src Pointer to source image to rotate
544@return Returns a pointer to a newly allocated rotated image if successful, returns NULL otherwise
545*/
546static FIBITMAP* 
547Rotate270(FIBITMAP *src) {
548        int x, x2, y, dlineup;
549
550        int bpp = FreeImage_GetBPP(src);
551
552        int src_width  = FreeImage_GetWidth(src);
553        int src_height = FreeImage_GetHeight(src);     
554        int dst_width  = src_height;
555        int dst_height = src_width;
556
557        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
558
559        // allocate and clear dst image
560        FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp);
561        if(NULL == dst) return NULL;
562
563        // get src and dst scan width
564        int src_pitch  = FreeImage_GetPitch(src);
565        int dst_pitch  = FreeImage_GetPitch(dst);
566       
567        switch(image_type) {
568                case FIT_BITMAP:
569                        if(bpp == 1) {
570                                // speedy rotate for BW images
571                               
572                                BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow, *srcdisp;
573                                div_t div_r;
574
575                                BYTE *bsrc  = FreeImage_GetBits(src); 
576                                BYTE *bdest = FreeImage_GetBits(dst);
577                                dbitsmax = bdest + dst_height * dst_pitch - 1;
578                                dlineup = 8 * dst_pitch - dst_width;
579
580                                for(y = 0; y < src_height; y++) {
581                                        // figure out the column we are going to be copying to
582                                        div_r = div(y + dlineup, 8);
583                                        // set bit pos of src column byte
584                                        bitpos = (BYTE)(1 << div_r.rem);
585                                        srcdisp = bsrc + y * src_pitch;
586                                        for (x = 0; x < src_pitch; x++) {
587                                                // get source bits
588                                                sbits = srcdisp + x;
589                                                // get destination column
590                                                nrow = bdest + (x * 8) * dst_pitch + dst_pitch - 1 - div_r.quot;
591                                                for (int z = 0; z < 8; z++) {
592                                                   // get destination byte
593                                                        dbits = nrow + z * dst_pitch;
594                                                        if ((dbits < bdest) || (dbits > dbitsmax)) break;
595                                                        if (*sbits & (128 >> z)) *dbits |= bitpos;
596                                                }
597                                        }
598                                }
599                        } 
600                        else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
601                                // anything other than BW :
602                                // This optimized version of rotation rotates image by smaller blocks. It is quite
603                                // a bit faster than obvious algorithm, because it produces much less CPU cache misses.
604                                // This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current
605                                // CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase
606                                // speed somehow, but once you drop out of CPU's cache, things will slow down drastically.
607                                // For older CPUs with less cache, lower value would yield better results.
608
609                                int xs, ys;                            // x-segment and y-segment
610                                BYTE *bsrc  = FreeImage_GetBits(src);  // source pixels
611                                BYTE *bdest = FreeImage_GetBits(dst);  // destination pixels
612
613                                // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
614                                int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
615
616                                for(xs = 0; xs < dst_width; xs += RBLOCK) {    // for all image blocks of RBLOCK*RBLOCK pixels
617                                        for(ys = 0; ys < dst_height; ys += RBLOCK) {
618                                                for(x = xs; x < MIN(dst_width, xs + RBLOCK); x++) {    // do rotation
619                                                        x2 = dst_width - x - 1;
620                                                        // point to src pixel at (ys, x2)
621                                                        BYTE *src_bits = bsrc + (x2 * src_pitch) + (ys * bytespp);
622                                                        // point to dst pixel at (x, ys)
623                                                        BYTE *dst_bits = bdest + (ys * dst_pitch) + (x * bytespp);
624                                                        for (y = ys; y < MIN(dst_height, ys + RBLOCK); y++) {
625                                                                // dst.SetPixel(x, y, src.GetPixel(y, x2));
626                                                                for(int j = 0; j < bytespp; j++) {
627                                                                        dst_bits[j] = src_bits[j];
628                                                                }
629                                                                src_bits += bytespp;
630                                                                dst_bits += dst_pitch;
631                                                        }
632                                                }
633                                        }
634                                }
635                        }
636                        break;
637                case FIT_UINT16:
638                case FIT_RGB16:
639                case FIT_RGBA16:
640                case FIT_FLOAT:
641                case FIT_RGBF:
642                case FIT_RGBAF:
643                {
644                        BYTE *bsrc  = FreeImage_GetBits(src);  // source pixels
645                        BYTE *bdest = FreeImage_GetBits(dst);  // destination pixels
646
647                        // calculate the number of bytes per pixel
648                        int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
649
650                        for(y = 0; y < dst_height; y++) {
651                                BYTE *src_bits = bsrc + (src_height - 1) * src_pitch + y * bytespp;
652                                BYTE *dst_bits = bdest + (y * dst_pitch);
653                                for(x = 0; x < dst_width; x++) {
654                                        for(int j = 0; j < bytespp; j++) {
655                                                dst_bits[j] = src_bits[j];                                     
656                                        }
657                                        src_bits -= src_pitch;
658                                        dst_bits += bytespp;
659                                }
660                        }
661                }
662                break;
663        }
664
665        return dst;
666}
667
668/**
669Rotates an image by a given degree in range [-45 .. +45] (counter clockwise)
670using the 3-shear technique.
671@param src Pointer to source image to rotate
672@param dAngle Rotation angle
673@return Returns a pointer to a newly allocated rotated image if successful, returns NULL otherwise
674*/
675static FIBITMAP* 
676Rotate45(FIBITMAP *src, double dAngle, const void *bkcolor) {
677        const double ROTATE_PI = double(3.1415926535897932384626433832795);
678
679        unsigned u;
680
681        unsigned bpp = FreeImage_GetBPP(src);
682
683        double dRadAngle = dAngle * ROTATE_PI / double(180); // Angle in radians
684        double dSinE = sin(dRadAngle);
685        double dTan = tan(dRadAngle / 2);
686
687        unsigned src_width  = FreeImage_GetWidth(src);
688        unsigned src_height = FreeImage_GetHeight(src);
689
690        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
691
692        // Calc first shear (horizontal) destination image dimensions
693        unsigned width_1  = src_width + unsigned((double)src_height * fabs(dTan) + 0.5);
694        unsigned height_1 = src_height; 
695
696        // Perform 1st shear (horizontal)
697        // ----------------------------------------------------------------------
698
699        // Allocate image for 1st shear
700        FIBITMAP *dst1 = FreeImage_AllocateT(image_type, width_1, height_1, bpp);
701        if(NULL == dst1) {
702                return NULL;
703        }
704       
705        for(u = 0; u < height_1; u++) { 
706                double dShear;
707
708                if(dTan >= 0)   {
709                        // Positive angle
710                        dShear = (u + 0.5) * dTan;
711                }
712                else {
713                        // Negative angle
714                        dShear = (double(u) - height_1 + 0.5) * dTan;
715                }
716                int iShear = int(floor(dShear));
717                HorizontalSkew(src, dst1, u, iShear, dShear - double(iShear), bkcolor);
718        }
719
720        // Perform 2nd shear  (vertical)
721        // ----------------------------------------------------------------------
722
723        // Calc 2nd shear (vertical) destination image dimensions
724        unsigned width_2  = width_1;
725        unsigned height_2 = unsigned((double)src_width * fabs(dSinE) + (double)src_height * cos(dRadAngle) + 0.5) + 1;
726
727        // Allocate image for 2nd shear
728        FIBITMAP *dst2 = FreeImage_AllocateT(image_type, width_2, height_2, bpp);
729        if(NULL == dst2) {
730                FreeImage_Unload(dst1);
731                return NULL;
732        }
733
734        double dOffset;     // Variable skew offset
735        if(dSinE > 0)   {   
736                // Positive angle
737                dOffset = (src_width - 1.0) * dSinE;
738        }
739        else {
740                // Negative angle
741                dOffset = -dSinE * (double(src_width) - width_2);
742        }
743
744        for(u = 0; u < width_2; u++, dOffset -= dSinE) {
745                int iShear = int(floor(dOffset));
746                VerticalSkew(dst1, dst2, u, iShear, dOffset - double(iShear), bkcolor);
747        }
748
749        // Perform 3rd shear (horizontal)
750        // ----------------------------------------------------------------------
751
752        // Free result of 1st shear
753        FreeImage_Unload(dst1);
754
755        // Calc 3rd shear (horizontal) destination image dimensions
756        unsigned width_3  = unsigned(double(src_height) * fabs(dSinE) + double(src_width) * cos(dRadAngle) + 0.5) + 1;
757        unsigned height_3 = height_2;
758
759        // Allocate image for 3rd shear
760        FIBITMAP *dst3 = FreeImage_AllocateT(image_type, width_3, height_3, bpp);
761        if(NULL == dst3) {
762                FreeImage_Unload(dst2);
763                return NULL;
764        }
765
766        if(dSinE >= 0) {
767                // Positive angle
768                dOffset = (src_width - 1.0) * dSinE * -dTan;
769        }
770        else {
771                // Negative angle
772                dOffset = dTan * ( (src_width - 1.0) * -dSinE + (1.0 - height_3) );
773        }
774        for(u = 0; u < height_3; u++, dOffset += dTan) {
775                int iShear = int(floor(dOffset));
776                HorizontalSkew(dst2, dst3, u, iShear, dOffset - double(iShear), bkcolor);
777        }
778        // Free result of 2nd shear   
779        FreeImage_Unload(dst2);
780
781        // Return result of 3rd shear
782        return dst3;     
783}
784
785/**
786Rotates a 1-, 8-, 24- or 32-bit image by a given angle (given in degree).
787Angle is unlimited, except for 1-bit images (limited to integer multiples of 90 degree).
7883-shears technique is used.
789@param src Pointer to source image to rotate
790@param dAngle Rotation angle
791@return Returns a pointer to a newly allocated rotated image if successful, returns NULL otherwise
792*/
793static FIBITMAP* 
794RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor) {
795        if(NULL == src) {
796                return NULL;
797        }
798
799        FIBITMAP *image = src;
800
801        while(dAngle >= 360) {
802                // Bring angle to range of (-INF .. 360)
803                dAngle -= 360;
804        }
805        while(dAngle < 0) {
806                // Bring angle to range of [0 .. 360)
807                dAngle += 360;
808        }
809        if((dAngle > 45) && (dAngle <= 135)) {
810                // Angle in (45 .. 135]
811                // Rotate image by 90 degrees into temporary image,
812                // so it requires only an extra rotation angle
813                // of -45 .. +45 to complete rotation.
814                image = Rotate90(src);
815                dAngle -= 90;
816        }
817        else if((dAngle > 135) && (dAngle <= 225)) { 
818                // Angle in (135 .. 225]
819                // Rotate image by 180 degrees into temporary image,
820                // so it requires only an extra rotation angle
821                // of -45 .. +45 to complete rotation.
822                image = Rotate180(src);
823                dAngle -= 180;
824        }
825        else if((dAngle > 225) && (dAngle <= 315)) { 
826                // Angle in (225 .. 315]
827                // Rotate image by 270 degrees into temporary image,
828                // so it requires only an extra rotation angle
829                // of -45 .. +45 to complete rotation.
830                image = Rotate270(src);
831                dAngle -= 270;
832        }
833
834        // If we got here, angle is in (-45 .. +45]
835
836        if(NULL == image)       {
837                // Failed to allocate middle image
838                return NULL;
839        }
840
841        if(0 == dAngle) {
842                if(image == src) {
843                        // Nothing to do ...
844                        return FreeImage_Clone(src);
845                } else {
846                        // No more rotation needed
847                        return image;
848                }
849        }
850        else {
851                // Perform last rotation
852                FIBITMAP *dst = Rotate45(image, dAngle, bkcolor);
853
854                if(src != image) {
855                        // Middle image was required, free it now.
856                        FreeImage_Unload(image);
857                }
858
859                return dst;
860        }
861}
862
863// ==========================================================
864
865FIBITMAP *DLL_CALLCONV
866FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
867        if(!FreeImage_HasPixels(dib)) return NULL;
868
869        if(0 == angle) {
870                return FreeImage_Clone(dib);
871        }
872        // DIB are stored upside down ...
873        angle *= -1;
874
875        try {
876                unsigned bpp = FreeImage_GetBPP(dib);
877                FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
878               
879                switch(image_type) {
880                        case FIT_BITMAP:
881                                if(bpp == 1) {
882                                        // only rotate for integer multiples of 90 degree
883                                        if(fmod(angle, 90) != 0)
884                                                return NULL;
885
886                                        // perform the rotation
887                                        FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
888                                        if(!dst) throw(1);
889
890                                        // build a greyscale palette
891                                        RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
892                                        if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
893                                                dst_pal[0].rgbRed = dst_pal[0].rgbGreen = dst_pal[0].rgbBlue = 0;
894                                                dst_pal[1].rgbRed = dst_pal[1].rgbGreen = dst_pal[1].rgbBlue = 255;                     
895                                        } else {
896                                                dst_pal[0].rgbRed = dst_pal[0].rgbGreen = dst_pal[0].rgbBlue = 255;
897                                                dst_pal[1].rgbRed = dst_pal[1].rgbGreen = dst_pal[1].rgbBlue = 0;                       
898                                        }
899
900                                        // copy metadata from src to dst
901                                        FreeImage_CloneMetadata(dst, dib);
902
903                                        return dst;
904                                }
905                                else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
906                                        FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
907                                        if(!dst) throw(1);
908                                       
909                                        if(bpp == 8) {
910                                                // copy original palette to rotated bitmap
911                                                RGBQUAD *src_pal = FreeImage_GetPalette(dib);
912                                                RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
913                                                memcpy(&dst_pal[0], &src_pal[0], 256 * sizeof(RGBQUAD));
914
915                                                // copy transparency table
916                                                FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
917
918                                                // copy background color
919                                                RGBQUAD bkcolor; 
920                                                if( FreeImage_GetBackgroundColor(dib, &bkcolor) ) {
921                                                        FreeImage_SetBackgroundColor(dst, &bkcolor); 
922                                                }
923
924                                        }
925
926                                        // copy metadata from src to dst
927                                        FreeImage_CloneMetadata(dst, dib);
928
929                                        return dst;
930                                }
931                                break;
932                        case FIT_UINT16:
933                        case FIT_RGB16:
934                        case FIT_RGBA16:
935                        case FIT_FLOAT:
936                        case FIT_RGBF:
937                        case FIT_RGBAF:
938                        {
939                                FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
940                                if(!dst) throw(1);
941
942                                // copy metadata from src to dst
943                                FreeImage_CloneMetadata(dst, dib);
944
945                                return dst;
946                        }
947                        break;
948                }
949
950        } catch(int) {
951                return NULL;
952        }
953
954        return NULL;
955}
956
Note: See TracBrowser for help on using the browser.