]> Creatis software - clitk.git/blob - utilities/CxImage/ximatran.cpp
9f136a05d69ff48d8fc91237e5258727863e9309
[clitk.git] / utilities / CxImage / ximatran.cpp
1 // xImaTran.cpp : Transformation functions\r
2 /* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
3  * CxImage version 6.0.0 02/Feb/2008\r
4  */\r
5 \r
6 #include "ximage.h"\r
7 #include "ximath.h"\r
8 \r
9 #if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
10 ////////////////////////////////////////////////////////////////////////////////\r
11 bool CxImage::GrayScale()\r
12 {\r
13         if (!pDib) return false;\r
14         if (head.biBitCount<=8){\r
15                 RGBQUAD* ppal=GetPalette();\r
16                 int gray;\r
17                 //converts the colors to gray, use the blue channel only\r
18                 for(DWORD i=0;i<head.biClrUsed;i++){\r
19                         gray=(int)RGB2GRAY(ppal[i].rgbRed,ppal[i].rgbGreen,ppal[i].rgbBlue);\r
20                         ppal[i].rgbBlue = (BYTE)gray;\r
21                 }\r
22                 // preserve transparency\r
23                 if (info.nBkgndIndex >= 0) info.nBkgndIndex = ppal[info.nBkgndIndex].rgbBlue;\r
24                 //create a "real" 8 bit gray scale image\r
25                 if (head.biBitCount==8){\r
26                         BYTE *img=info.pImage;\r
27                         for(DWORD i=0;i<head.biSizeImage;i++) img[i]=ppal[img[i]].rgbBlue;\r
28                         SetGrayPalette();\r
29                 }\r
30                 //transform to 8 bit gray scale\r
31                 if (head.biBitCount==4 || head.biBitCount==1){\r
32                         CxImage ima;\r
33                         ima.CopyInfo(*this);\r
34                         if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false;\r
35                         ima.SetGrayPalette();\r
36 #if CXIMAGE_SUPPORT_SELECTION\r
37                         ima.SelectionCopy(*this);\r
38 #endif //CXIMAGE_SUPPORT_SELECTION\r
39 #if CXIMAGE_SUPPORT_ALPHA\r
40                         ima.AlphaCopy(*this);\r
41 #endif //CXIMAGE_SUPPORT_ALPHA\r
42                         for (long y=0;y<head.biHeight;y++){\r
43                                 BYTE *iDst = ima.GetBits(y);\r
44                                 BYTE *iSrc = GetBits(y);\r
45                                 for (long x=0;x<head.biWidth; x++){\r
46                                         //iDst[x]=ppal[BlindGetPixelIndex(x,y)].rgbBlue;\r
47                                         if (head.biBitCount==4){\r
48                                                 BYTE pos = (BYTE)(4*(1-x%2));\r
49                                                 iDst[x]= ppal[(BYTE)((iSrc[x >> 1]&((BYTE)0x0F<<pos)) >> pos)].rgbBlue;\r
50                                         } else {\r
51                                                 BYTE pos = (BYTE)(7-x%8);\r
52                                                 iDst[x]= ppal[(BYTE)((iSrc[x >> 3]&((BYTE)0x01<<pos)) >> pos)].rgbBlue;\r
53                                         }\r
54                                 }\r
55                         }\r
56                         Transfer(ima);\r
57                 }\r
58         } else { //from RGB to 8 bit gray scale\r
59                 BYTE *iSrc=info.pImage;\r
60                 CxImage ima;\r
61                 ima.CopyInfo(*this);\r
62                 if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false;\r
63                 ima.SetGrayPalette();\r
64 #if CXIMAGE_SUPPORT_SELECTION\r
65                 ima.SelectionCopy(*this);\r
66 #endif //CXIMAGE_SUPPORT_SELECTION\r
67 #if CXIMAGE_SUPPORT_ALPHA\r
68                 ima.AlphaCopy(*this);\r
69 #endif //CXIMAGE_SUPPORT_ALPHA\r
70                 BYTE *img=ima.GetBits();\r
71                 long l8=ima.GetEffWidth();\r
72                 long l=head.biWidth * 3;\r
73                 for(long y=0; y < head.biHeight; y++) {\r
74                         for(long x=0,x8=0; x < l; x+=3,x8++) {\r
75                                 img[x8+y*l8]=(BYTE)RGB2GRAY(*(iSrc+x+2),*(iSrc+x+1),*(iSrc+x+0));\r
76                         }\r
77                         iSrc+=info.dwEffWidth;\r
78                 }\r
79                 Transfer(ima);\r
80         }\r
81         return true;\r
82 }\r
83 ////////////////////////////////////////////////////////////////////////////////\r
84 /**\r
85  * \sa Mirror\r
86  * \author [qhbo]\r
87  */\r
88 bool CxImage::Flip(bool bFlipSelection, bool bFlipAlpha)\r
89 {\r
90         if (!pDib) return false;\r
91 \r
92         BYTE *buff = (BYTE*)malloc(info.dwEffWidth);\r
93         if (!buff) return false;\r
94 \r
95         BYTE *iSrc,*iDst;\r
96         iSrc = GetBits(head.biHeight-1);\r
97         iDst = GetBits(0);\r
98         for (long i=0; i<(head.biHeight/2); ++i)\r
99         {\r
100                 memcpy(buff, iSrc, info.dwEffWidth);\r
101                 memcpy(iSrc, iDst, info.dwEffWidth);\r
102                 memcpy(iDst, buff, info.dwEffWidth);\r
103                 iSrc-=info.dwEffWidth;\r
104                 iDst+=info.dwEffWidth;\r
105         }\r
106 \r
107         free(buff);\r
108 \r
109         if (bFlipSelection){\r
110 #if CXIMAGE_SUPPORT_SELECTION\r
111                 SelectionFlip();\r
112 #endif //CXIMAGE_SUPPORT_SELECTION\r
113         }\r
114 \r
115         if (bFlipAlpha){\r
116 #if CXIMAGE_SUPPORT_ALPHA\r
117                 AlphaFlip();\r
118 #endif //CXIMAGE_SUPPORT_ALPHA\r
119         }\r
120 \r
121         return true;\r
122 }\r
123 ////////////////////////////////////////////////////////////////////////////////\r
124 /**\r
125  * \sa Flip\r
126  */\r
127 bool CxImage::Mirror(bool bMirrorSelection, bool bMirrorAlpha)\r
128 {\r
129         if (!pDib) return false;\r
130 \r
131         CxImage* imatmp = new CxImage(*this,false,true,true);\r
132         if (!imatmp) return false;\r
133         if (!imatmp->IsValid()){\r
134                 delete imatmp;\r
135                 return false;\r
136         }\r
137 \r
138         BYTE *iSrc,*iDst;\r
139         long wdt=(head.biWidth-1) * (head.biBitCount==24 ? 3:1);\r
140         iSrc=info.pImage + wdt;\r
141         iDst=imatmp->info.pImage;\r
142         long x,y;\r
143         switch (head.biBitCount){\r
144         case 24:\r
145                 for(y=0; y < head.biHeight; y++){\r
146                         for(x=0; x <= wdt; x+=3){\r
147                                 *(iDst+x)=*(iSrc-x);\r
148                                 *(iDst+x+1)=*(iSrc-x+1);\r
149                                 *(iDst+x+2)=*(iSrc-x+2);\r
150                         }\r
151                         iSrc+=info.dwEffWidth;\r
152                         iDst+=info.dwEffWidth;\r
153                 }\r
154                 break;\r
155         case 8:\r
156                 for(y=0; y < head.biHeight; y++){\r
157                         for(x=0; x <= wdt; x++)\r
158                                 *(iDst+x)=*(iSrc-x);\r
159                         iSrc+=info.dwEffWidth;\r
160                         iDst+=info.dwEffWidth;\r
161                 }\r
162                 break;\r
163         default:\r
164                 for(y=0; y < head.biHeight; y++){\r
165                         for(x=0; x <= wdt; x++)\r
166                                 imatmp->SetPixelIndex(x,y,GetPixelIndex(wdt-x,y));\r
167                 }\r
168         }\r
169 \r
170         if (bMirrorSelection){\r
171 #if CXIMAGE_SUPPORT_SELECTION\r
172                 imatmp->SelectionMirror();\r
173 #endif //CXIMAGE_SUPPORT_SELECTION\r
174         }\r
175 \r
176         if (bMirrorAlpha){\r
177 #if CXIMAGE_SUPPORT_ALPHA\r
178                 imatmp->AlphaMirror();\r
179 #endif //CXIMAGE_SUPPORT_ALPHA\r
180         }\r
181 \r
182         Transfer(*imatmp);\r
183         delete imatmp;\r
184         return true;\r
185 }\r
186 \r
187 ////////////////////////////////////////////////////////////////////////////////\r
188 #define RBLOCK 64\r
189 \r
190 ////////////////////////////////////////////////////////////////////////////////\r
191 bool CxImage::RotateLeft(CxImage* iDst)\r
192 {\r
193         if (!pDib) return false;\r
194 \r
195         long newWidth = GetHeight();\r
196         long newHeight = GetWidth();\r
197 \r
198         CxImage imgDest;\r
199         imgDest.CopyInfo(*this);\r
200         imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
201         imgDest.SetPalette(GetPalette());\r
202 \r
203 #if CXIMAGE_SUPPORT_ALPHA\r
204         if (AlphaIsValid()) imgDest.AlphaCreate();\r
205 #endif\r
206 \r
207 #if CXIMAGE_SUPPORT_SELECTION\r
208         if (SelectionIsValid()) imgDest.SelectionCreate();\r
209 #endif\r
210 \r
211         long x,x2,y,dlineup;\r
212         \r
213         // Speedy rotate for BW images <Robert Abram>\r
214         if (head.biBitCount == 1) {\r
215         \r
216                 BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp;\r
217                 ldiv_t div_r;\r
218 \r
219                 BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits();\r
220                 dbitsmax = bdest + imgDest.head.biSizeImage - 1;\r
221                 dlineup = 8 * imgDest.info.dwEffWidth - imgDest.head.biWidth;\r
222 \r
223                 imgDest.Clear(0);\r
224                 for (y = 0; y < head.biHeight; y++) {\r
225                         // Figure out the Column we are going to be copying to\r
226                         div_r = ldiv(y + dlineup, (long)8);\r
227                         // set bit pos of src column byte                               \r
228                         bitpos = (BYTE)(1 << div_r.rem);\r
229                         srcdisp = bsrc + y * info.dwEffWidth;\r
230                         for (x = 0; x < (long)info.dwEffWidth; x++) {\r
231                                 // Get Source Bits\r
232                                 sbits = srcdisp + x;\r
233                                 // Get destination column\r
234                                 nrow = bdest + (x * 8) * imgDest.info.dwEffWidth + imgDest.info.dwEffWidth - 1 - div_r.quot;\r
235                                 for (long z = 0; z < 8; z++) {\r
236                                    // Get Destination Byte\r
237                                         dbits = nrow + z * imgDest.info.dwEffWidth;\r
238                                         if ((dbits < bdest) || (dbits > dbitsmax)) break;\r
239                                         if (*sbits & (128 >> z)) *dbits |= bitpos;\r
240                                 }\r
241                         }\r
242                 }//for y\r
243 \r
244 #if CXIMAGE_SUPPORT_ALPHA\r
245                 if (AlphaIsValid()) {\r
246                         for (x = 0; x < newWidth; x++){\r
247                                 x2=newWidth-x-1;\r
248                                 for (y = 0; y < newHeight; y++){\r
249                                         imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2));\r
250                                 }//for y\r
251                         }//for x\r
252                 }\r
253 #endif //CXIMAGE_SUPPORT_ALPHA\r
254 \r
255 #if CXIMAGE_SUPPORT_SELECTION\r
256                 if (SelectionIsValid()) {\r
257                         imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top;\r
258                         imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom;\r
259                         imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left;\r
260                         imgDest.info.rSelectionBox.top = info.rSelectionBox.right;\r
261                         for (x = 0; x < newWidth; x++){\r
262                                 x2=newWidth-x-1;\r
263                                 for (y = 0; y < newHeight; y++){\r
264                                         imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2));\r
265                                 }//for y\r
266                         }//for x\r
267                 }\r
268 #endif //CXIMAGE_SUPPORT_SELECTION\r
269 \r
270         } else {\r
271         //anything other than BW:\r
272         //bd, 10. 2004: This optimized version of rotation rotates image by smaller blocks. It is quite\r
273         //a bit faster than obvious algorithm, because it produces much less CPU cache misses.\r
274         //This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current\r
275         //CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase\r
276         //speed somehow, but once you drop out of CPU's cache, things will slow down drastically.\r
277         //For older CPUs with less cache, lower value would yield better results.\r
278                 \r
279                 BYTE *srcPtr, *dstPtr;                        //source and destionation for 24-bit version\r
280                 int xs, ys;                                   //x-segment and y-segment\r
281                 for (xs = 0; xs < newWidth; xs+=RBLOCK) {       //for all image blocks of RBLOCK*RBLOCK pixels\r
282                         for (ys = 0; ys < newHeight; ys+=RBLOCK) {\r
283                                 if (head.biBitCount==24) {\r
284                                         //RGB24 optimized pixel access:\r
285                                         for (x = xs; x < min(newWidth, xs+RBLOCK); x++){    //do rotation\r
286                                                 info.nProgress = (long)(100*x/newWidth);\r
287                                                 x2=newWidth-x-1;\r
288                                                 dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(x,ys);\r
289                                                 srcPtr = (BYTE*) BlindGetPixelPointer(ys, x2);\r
290                                                 for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
291                                                         //imgDest.SetPixelColor(x, y, GetPixelColor(y, x2));\r
292                                                         *(dstPtr) = *(srcPtr);\r
293                                                         *(dstPtr+1) = *(srcPtr+1);\r
294                                                         *(dstPtr+2) = *(srcPtr+2);\r
295                                                         srcPtr += 3;\r
296                                                         dstPtr += imgDest.info.dwEffWidth;\r
297                                                 }//for y\r
298                                         }//for x\r
299                                 } else {\r
300                                         //anything else than 24bpp (and 1bpp): palette\r
301                                         for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
302                                                 info.nProgress = (long)(100*x/newWidth); //<Anatoly Ivasyuk>\r
303                                                 x2=newWidth-x-1;\r
304                                                 for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
305                                                         imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y, x2));\r
306                                                 }//for y\r
307                                         }//for x\r
308                                 }//if (version selection)\r
309 #if CXIMAGE_SUPPORT_ALPHA\r
310                                 if (AlphaIsValid()) {\r
311                                         for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
312                                                 x2=newWidth-x-1;\r
313                                                 for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
314                                                         imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2));\r
315                                                 }//for y\r
316                                         }//for x\r
317                                 }//if (alpha channel)\r
318 #endif //CXIMAGE_SUPPORT_ALPHA\r
319 \r
320 #if CXIMAGE_SUPPORT_SELECTION\r
321                                 if (SelectionIsValid()) {\r
322                                         imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top;\r
323                                         imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom;\r
324                                         imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left;\r
325                                         imgDest.info.rSelectionBox.top = info.rSelectionBox.right;\r
326                                         for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
327                                                 x2=newWidth-x-1;\r
328                                                 for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
329                                                         imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2));\r
330                                                 }//for y\r
331                                         }//for x\r
332                                 }//if (selection)\r
333 #endif //CXIMAGE_SUPPORT_SELECTION\r
334                         }//for ys\r
335                 }//for xs\r
336         }//if\r
337 \r
338         //select the destination\r
339         if (iDst) iDst->Transfer(imgDest);\r
340         else Transfer(imgDest);\r
341         return true;\r
342 }\r
343 \r
344 ////////////////////////////////////////////////////////////////////////////////\r
345 bool CxImage::RotateRight(CxImage* iDst)\r
346 {\r
347         if (!pDib) return false;\r
348 \r
349         long newWidth = GetHeight();\r
350         long newHeight = GetWidth();\r
351 \r
352         CxImage imgDest;\r
353         imgDest.CopyInfo(*this);\r
354         imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
355         imgDest.SetPalette(GetPalette());\r
356 \r
357 #if CXIMAGE_SUPPORT_ALPHA\r
358         if (AlphaIsValid()) imgDest.AlphaCreate();\r
359 #endif\r
360 \r
361 #if CXIMAGE_SUPPORT_SELECTION\r
362         if (SelectionIsValid()) imgDest.SelectionCreate();\r
363 #endif\r
364 \r
365         long x,y,y2;\r
366         // Speedy rotate for BW images <Robert Abram>\r
367         if (head.biBitCount == 1) {\r
368         \r
369                 BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp;\r
370                 ldiv_t div_r;\r
371 \r
372                 BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits();\r
373                 dbitsmax = bdest + imgDest.head.biSizeImage - 1;\r
374 \r
375                 imgDest.Clear(0);\r
376                 for (y = 0; y < head.biHeight; y++) {\r
377                         // Figure out the Column we are going to be copying to\r
378                         div_r = ldiv(y, (long)8);\r
379                         // set bit pos of src column byte                               \r
380                         bitpos = (BYTE)(128 >> div_r.rem);\r
381                         srcdisp = bsrc + y * info.dwEffWidth;\r
382                         for (x = 0; x < (long)info.dwEffWidth; x++) {\r
383                                 // Get Source Bits\r
384                                 sbits = srcdisp + x;\r
385                                 // Get destination column\r
386                                 nrow = bdest + (imgDest.head.biHeight-1-(x*8)) * imgDest.info.dwEffWidth + div_r.quot;\r
387                                 for (long z = 0; z < 8; z++) {\r
388                                    // Get Destination Byte\r
389                                         dbits = nrow - z * imgDest.info.dwEffWidth;\r
390                                         if ((dbits < bdest) || (dbits > dbitsmax)) break;\r
391                                         if (*sbits & (128 >> z)) *dbits |= bitpos;\r
392                                 }\r
393                         }\r
394                 }\r
395 \r
396 #if CXIMAGE_SUPPORT_ALPHA\r
397                 if (AlphaIsValid()){\r
398                         for (y = 0; y < newHeight; y++){\r
399                                 y2=newHeight-y-1;\r
400                                 for (x = 0; x < newWidth; x++){\r
401                                         imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x));\r
402                                 }\r
403                         }\r
404                 }\r
405 #endif //CXIMAGE_SUPPORT_ALPHA\r
406 \r
407 #if CXIMAGE_SUPPORT_SELECTION\r
408                 if (SelectionIsValid()){\r
409                         imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom;\r
410                         imgDest.info.rSelectionBox.right = info.rSelectionBox.top;\r
411                         imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right;\r
412                         imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left;\r
413                         for (y = 0; y < newHeight; y++){\r
414                                 y2=newHeight-y-1;\r
415                                 for (x = 0; x < newWidth; x++){\r
416                                         imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));\r
417                                 }\r
418                         }\r
419                 }\r
420 #endif //CXIMAGE_SUPPORT_SELECTION\r
421 \r
422         } else {\r
423                 //anything else but BW\r
424                 BYTE *srcPtr, *dstPtr;                        //source and destionation for 24-bit version\r
425                 int xs, ys;                                   //x-segment and y-segment\r
426                 for (xs = 0; xs < newWidth; xs+=RBLOCK) {\r
427                         for (ys = 0; ys < newHeight; ys+=RBLOCK) {\r
428                                 if (head.biBitCount==24) {\r
429                                         //RGB24 optimized pixel access:\r
430                                         for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
431                                                 info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>\r
432                                                 y2=newHeight-y-1;\r
433                                                 dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(xs,y);\r
434                                                 srcPtr = (BYTE*) BlindGetPixelPointer(y2, xs);\r
435                                                 for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
436                                                         //imgDest.SetPixelColor(x, y, GetPixelColor(y2, x));\r
437                                                         *(dstPtr) = *(srcPtr);\r
438                                                         *(dstPtr+1) = *(srcPtr+1);\r
439                                                         *(dstPtr+2) = *(srcPtr+2);\r
440                                                         dstPtr += 3;\r
441                                                         srcPtr += info.dwEffWidth;\r
442                                                 }//for x\r
443                                         }//for y\r
444                                 } else {\r
445                                         //anything else than BW & RGB24: palette\r
446                                         for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
447                                                 info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>\r
448                                                 y2=newHeight-y-1;\r
449                                                 for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
450                                                         imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y2, x));\r
451                                                 }//for x\r
452                                         }//for y\r
453                                 }//if\r
454 #if CXIMAGE_SUPPORT_ALPHA\r
455                                 if (AlphaIsValid()){\r
456                                         for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
457                                                 y2=newHeight-y-1;\r
458                                                 for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
459                                                         imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x));\r
460                                                 }//for x\r
461                                         }//for y\r
462                                 }//if (has alpha)\r
463 #endif //CXIMAGE_SUPPORT_ALPHA\r
464 \r
465 #if CXIMAGE_SUPPORT_SELECTION\r
466                                 if (SelectionIsValid()){\r
467                                         imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom;\r
468                                         imgDest.info.rSelectionBox.right = info.rSelectionBox.top;\r
469                                         imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right;\r
470                                         imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left;\r
471                                         for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
472                                                 y2=newHeight-y-1;\r
473                                                 for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
474                                                         imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));\r
475                                                 }//for x\r
476                                         }//for y\r
477                                 }//if (has alpha)\r
478 #endif //CXIMAGE_SUPPORT_SELECTION\r
479                         }//for ys\r
480                 }//for xs\r
481         }//if\r
482 \r
483         //select the destination\r
484         if (iDst) iDst->Transfer(imgDest);\r
485         else Transfer(imgDest);\r
486         return true;\r
487 }\r
488 \r
489 ////////////////////////////////////////////////////////////////////////////////\r
490 bool CxImage::Negative()\r
491 {\r
492         if (!pDib) return false;\r
493 \r
494         if (head.biBitCount<=8){\r
495                 if (IsGrayScale()){ //GRAYSCALE, selection\r
496                         if (pSelection){\r
497                                 for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){\r
498                                         for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){\r
499 #if CXIMAGE_SUPPORT_SELECTION\r
500                                                 if (BlindSelectionIsInside(x,y))\r
501 #endif //CXIMAGE_SUPPORT_SELECTION\r
502                                                 {\r
503                                                         BlindSetPixelIndex(x,y,(BYTE)(255-BlindGetPixelIndex(x,y)));\r
504                                                 }\r
505                                         }\r
506                                 }\r
507                         } else {\r
508                                 BYTE *iSrc=info.pImage;\r
509                                 for(unsigned long i=0; i < head.biSizeImage; i++){\r
510                                         *iSrc=(BYTE)~(*(iSrc));\r
511                                         iSrc++;\r
512                                 }\r
513                         }\r
514                 } else { //PALETTE, full image\r
515                         RGBQUAD* ppal=GetPalette();\r
516                         for(DWORD i=0;i<head.biClrUsed;i++){\r
517                                 ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue);\r
518                                 ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen);\r
519                                 ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed);\r
520                         }\r
521                 }\r
522         } else {\r
523                 if (pSelection==NULL){ //RGB, full image\r
524                         BYTE *iSrc=info.pImage;\r
525                         for(unsigned long i=0; i < head.biSizeImage; i++){\r
526                                 *iSrc=(BYTE)~(*(iSrc));\r
527                                 iSrc++;\r
528                         }\r
529                 } else { // RGB with selection\r
530                         RGBQUAD color;\r
531                         for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){\r
532                                 for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){\r
533 #if CXIMAGE_SUPPORT_SELECTION\r
534                                         if (BlindSelectionIsInside(x,y))\r
535 #endif //CXIMAGE_SUPPORT_SELECTION\r
536                                         {\r
537                                                 color = BlindGetPixelColor(x,y);\r
538                                                 color.rgbRed = (BYTE)(255-color.rgbRed);\r
539                                                 color.rgbGreen = (BYTE)(255-color.rgbGreen);\r
540                                                 color.rgbBlue = (BYTE)(255-color.rgbBlue);\r
541                                                 BlindSetPixelColor(x,y,color);\r
542                                         }\r
543                                 }\r
544                         }\r
545                 }\r
546                 //<DP> invert transparent color too\r
547                 info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue);\r
548                 info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen);\r
549                 info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed);\r
550         }\r
551         return true;\r
552 }\r
553 \r
554 ////////////////////////////////////////////////////////////////////////////////\r
555 #endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
556 ////////////////////////////////////////////////////////////////////////////////\r
557 #if CXIMAGE_SUPPORT_TRANSFORMATION\r
558 ////////////////////////////////////////////////////////////////////////////////\r
559 \r
560 ////////////////////////////////////////////////////////////////////////////////\r
561 bool CxImage::Rotate(float angle, CxImage* iDst)\r
562 {\r
563         if (!pDib) return false;\r
564 \r
565         //  Copyright (c) 1996-1998 Ulrich von Zadow\r
566 \r
567         // Negative the angle, because the y-axis is negative.\r
568         double ang = -angle*acos((float)0)/90;\r
569         int newWidth, newHeight;\r
570         int nWidth = GetWidth();\r
571         int nHeight= GetHeight();\r
572         double cos_angle = cos(ang);\r
573         double sin_angle = sin(ang);\r
574 \r
575         // Calculate the size of the new bitmap\r
576         POINT p1={0,0};\r
577         POINT p2={nWidth,0};\r
578         POINT p3={0,nHeight};\r
579         POINT p4={nWidth,nHeight};\r
580         CxPoint2 newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom;\r
581 \r
582         newP1.x = (float)p1.x;\r
583         newP1.y = (float)p1.y;\r
584         newP2.x = (float)(p2.x*cos_angle - p2.y*sin_angle);\r
585         newP2.y = (float)(p2.x*sin_angle + p2.y*cos_angle);\r
586         newP3.x = (float)(p3.x*cos_angle - p3.y*sin_angle);\r
587         newP3.y = (float)(p3.x*sin_angle + p3.y*cos_angle);\r
588         newP4.x = (float)(p4.x*cos_angle - p4.y*sin_angle);\r
589         newP4.y = (float)(p4.x*sin_angle + p4.y*cos_angle);\r
590 \r
591         leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x));\r
592         leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y));\r
593         rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x));\r
594         rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y));\r
595         leftBottom.x = leftTop.x;\r
596         leftBottom.y = rightBottom.y;\r
597         rightTop.x = rightBottom.x;\r
598         rightTop.y = leftTop.y;\r
599 \r
600         newWidth = (int) floor(0.5f + rightTop.x - leftTop.x);\r
601         newHeight= (int) floor(0.5f + leftBottom.y - leftTop.y);\r
602         CxImage imgDest;\r
603         imgDest.CopyInfo(*this);\r
604         imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
605         imgDest.SetPalette(GetPalette());\r
606 \r
607 #if CXIMAGE_SUPPORT_ALPHA\r
608         if(AlphaIsValid())      //MTA: Fix for rotation problem when the image has an alpha channel\r
609         {\r
610                 imgDest.AlphaCreate();\r
611                 imgDest.AlphaClear();\r
612         }\r
613 #endif //CXIMAGE_SUPPORT_ALPHA\r
614 \r
615         int x,y,newX,newY,oldX,oldY;\r
616 \r
617         if (head.biClrUsed==0){ //RGB\r
618                 for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){\r
619                         info.nProgress = (long)(100*newY/newHeight);\r
620                         if (info.nEscape) break;\r
621                         for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){\r
622                                 oldX = (long)(x*cos_angle + y*sin_angle + 0.5);\r
623                                 oldY = (long)(y*cos_angle - x*sin_angle + 0.5);\r
624                                 imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY));\r
625 #if CXIMAGE_SUPPORT_ALPHA\r
626                                 imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY));                                //MTA: copy the alpha value\r
627 #endif //CXIMAGE_SUPPORT_ALPHA\r
628                         }\r
629                 }\r
630         } else { //PALETTE\r
631                 for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){\r
632                         info.nProgress = (long)(100*newY/newHeight);\r
633                         if (info.nEscape) break;\r
634                         for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){\r
635                                 oldX = (long)(x*cos_angle + y*sin_angle + 0.5);\r
636                                 oldY = (long)(y*cos_angle - x*sin_angle + 0.5);\r
637                                 imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY));\r
638 #if CXIMAGE_SUPPORT_ALPHA\r
639                                 imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY));                                //MTA: copy the alpha value\r
640 #endif //CXIMAGE_SUPPORT_ALPHA\r
641                         }\r
642                 }\r
643         }\r
644         //select the destination\r
645         if (iDst) iDst->Transfer(imgDest);\r
646         else Transfer(imgDest);\r
647 \r
648         return true;\r
649 }\r
650 ////////////////////////////////////////////////////////////////////////////////\r
651 /**\r
652  * Rotates image around it's center.\r
653  * Method can use interpolation with paletted images, but does not change pallete, so results vary.\r
654  * (If you have only four colours in a palette, there's not much room for interpolation.)\r
655  * \r
656  * \param  angle - angle in degrees (positive values rotate clockwise)\r
657  * \param  *iDst - destination image (if null, this image is changed)\r
658  * \param  inMethod - interpolation method used\r
659  *              (IM_NEAREST_NEIGHBOUR produces aliasing (fast), IM_BILINEAR softens picture a bit (slower)\r
660  *               IM_SHARPBICUBIC is slower and produces some halos...)\r
661  * \param  ofMethod - overflow method (how to choose colour of pixels that have no source)\r
662  * \param  replColor - replacement colour to use (OM_COLOR, OM_BACKGROUND with no background colour...)\r
663  * \param  optimizeRightAngles - call faster methods for 90, 180, and 270 degree rotations. Faster methods\r
664  *                         are called for angles, where error (in location of corner pixels) is less\r
665  *                         than 0.25 pixels.\r
666  * \param  bKeepOriginalSize - rotates the image without resizing.\r
667  *\r
668  * \author ***bd*** 2.2004\r
669  */\r
670 bool CxImage::Rotate2(float angle, \r
671                        CxImage *iDst, \r
672                        InterpolationMethod inMethod, \r
673                        OverflowMethod ofMethod, \r
674                        RGBQUAD *replColor,\r
675                        bool const optimizeRightAngles,\r
676                                            bool const bKeepOriginalSize)\r
677 {\r
678         if (!pDib) return false;                                        //no dib no go\r
679         \r
680         double ang = -angle*acos(0.0f)/90.0f;           //convert angle to radians and invert (positive angle performs clockwise rotation)\r
681         float cos_angle = (float) cos(ang);                     //these two are needed later (to rotate)\r
682         float sin_angle = (float) sin(ang);\r
683         \r
684         //Calculate the size of the new bitmap (rotate corners of image)\r
685         CxPoint2 p[4];                                                          //original corners of the image\r
686         p[0]=CxPoint2(-0.5f,-0.5f);\r
687         p[1]=CxPoint2(GetWidth()-0.5f,-0.5f);\r
688         p[2]=CxPoint2(-0.5f,GetHeight()-0.5f);\r
689         p[3]=CxPoint2(GetWidth()-0.5f,GetHeight()-0.5f);\r
690         CxPoint2 newp[4];                                                               //rotated positions of corners\r
691         //(rotate corners)\r
692         if (bKeepOriginalSize){\r
693                 for (int i=0; i<4; i++) {\r
694                         newp[i].x = p[i].x;\r
695                         newp[i].y = p[i].y;\r
696                 }//for\r
697         } else {\r
698                 for (int i=0; i<4; i++) {\r
699                         newp[i].x = (p[i].x*cos_angle - p[i].y*sin_angle);\r
700                         newp[i].y = (p[i].x*sin_angle + p[i].y*cos_angle);\r
701                 }//for i\r
702                 \r
703                 if (optimizeRightAngles) { \r
704                         //For rotations of 90, -90 or 180 or 0 degrees, call faster routines\r
705                         if (newp[3].Distance(CxPoint2(GetHeight()-0.5f, 0.5f-GetWidth())) < 0.25) \r
706                                 //rotation right for circa 90 degrees (diagonal pixels less than 0.25 pixel away from 90 degree rotation destination)\r
707                                 return RotateRight(iDst);\r
708                         if (newp[3].Distance(CxPoint2(0.5f-GetHeight(), -0.5f+GetWidth())) < 0.25) \r
709                                 //rotation left for ~90 degrees\r
710                                 return RotateLeft(iDst);\r
711                         if (newp[3].Distance(CxPoint2(0.5f-GetWidth(), 0.5f-GetHeight())) < 0.25) \r
712                                 //rotation left for ~180 degrees\r
713                                 return Rotate180(iDst);\r
714                         if (newp[3].Distance(p[3]) < 0.25) {\r
715                                 //rotation not significant\r
716                                 if (iDst) iDst->Copy(*this);            //copy image to iDst, if required\r
717                                 return true;                                            //and we're done\r
718                         }//if\r
719                 }//if\r
720         }//if\r
721 \r
722         //(read new dimensions from location of corners)\r
723         float minx = (float) min(min(newp[0].x,newp[1].x),min(newp[2].x,newp[3].x));\r
724         float miny = (float) min(min(newp[0].y,newp[1].y),min(newp[2].y,newp[3].y));\r
725         float maxx = (float) max(max(newp[0].x,newp[1].x),max(newp[2].x,newp[3].x));\r
726         float maxy = (float) max(max(newp[0].y,newp[1].y),max(newp[2].y,newp[3].y));\r
727         int newWidth = (int) floor(maxx-minx+0.5f);\r
728         int newHeight= (int) floor(maxy-miny+0.5f);\r
729         float ssx=((maxx+minx)- ((float) newWidth-1))/2.0f;   //start for x\r
730         float ssy=((maxy+miny)- ((float) newHeight-1))/2.0f;  //start for y\r
731 \r
732         float newxcenteroffset = 0.5f * newWidth;\r
733         float newycenteroffset = 0.5f * newHeight;\r
734         if (bKeepOriginalSize){\r
735                 ssx -= 0.5f * GetWidth();\r
736                 ssy -= 0.5f * GetHeight();\r
737         }\r
738 \r
739         //create destination image\r
740         CxImage imgDest;\r
741         imgDest.CopyInfo(*this);\r
742         imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
743         imgDest.SetPalette(GetPalette());\r
744 #if CXIMAGE_SUPPORT_ALPHA\r
745         if(AlphaIsValid()) imgDest.AlphaCreate(); //MTA: Fix for rotation problem when the image has an alpha channel\r
746 #endif //CXIMAGE_SUPPORT_ALPHA\r
747         \r
748         RGBQUAD rgb;                    //pixel colour\r
749         RGBQUAD rc;\r
750         if (replColor!=0) \r
751                 rc=*replColor; \r
752         else {\r
753                 rc.rgbRed=255; rc.rgbGreen=255; rc.rgbBlue=255; rc.rgbReserved=0;\r
754         }//if\r
755         float x,y;              //destination location (float, with proper offset)\r
756         float origx, origy;     //origin location\r
757         int destx, desty;       //destination location\r
758         \r
759         y=ssy;                  //initialize y\r
760         if (!IsIndexed()){ //RGB24\r
761                 //optimized RGB24 implementation (direct write to destination):\r
762                 BYTE *pxptr;\r
763 #if CXIMAGE_SUPPORT_ALPHA\r
764                 BYTE *pxptra=0;\r
765 #endif //CXIMAGE_SUPPORT_ALPHA\r
766                 for (desty=0; desty<newHeight; desty++) {\r
767                         info.nProgress = (long)(100*desty/newHeight);\r
768                         if (info.nEscape) break;\r
769                         //initialize x\r
770                         x=ssx;\r
771                         //calculate pointer to first byte in row\r
772                         pxptr=(BYTE *)imgDest.BlindGetPixelPointer(0, desty);\r
773 #if CXIMAGE_SUPPORT_ALPHA\r
774                         //calculate pointer to first byte in row\r
775                         if (AlphaIsValid()) pxptra=imgDest.AlphaGetPointer(0, desty);\r
776 #endif //CXIMAGE_SUPPORT_ALPHA\r
777                         for (destx=0; destx<newWidth; destx++) {\r
778                                 //get source pixel coordinate for current destination point\r
779                                 //origx = (cos_angle*(x-head.biWidth/2)+sin_angle*(y-head.biHeight/2))+newWidth/2;\r
780                                 //origy = (cos_angle*(y-head.biHeight/2)-sin_angle*(x-head.biWidth/2))+newHeight/2;\r
781                                 origx = cos_angle*x+sin_angle*y;\r
782                                 origy = cos_angle*y-sin_angle*x;\r
783                                 if (bKeepOriginalSize){\r
784                                         origx += newxcenteroffset;\r
785                                         origy += newycenteroffset;\r
786                                 }\r
787                                 rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc);   //get interpolated colour value\r
788                                 //copy alpha and colour value to destination\r
789 #if CXIMAGE_SUPPORT_ALPHA\r
790                                 if (pxptra) *pxptra++ = rgb.rgbReserved;\r
791 #endif //CXIMAGE_SUPPORT_ALPHA\r
792                                 *pxptr++ = rgb.rgbBlue;\r
793                                 *pxptr++ = rgb.rgbGreen;\r
794                                 *pxptr++ = rgb.rgbRed;\r
795                                 x++;\r
796                         }//for destx\r
797                         y++;\r
798                 }//for desty\r
799         } else { \r
800                 //non-optimized implementation for paletted images\r
801                 for (desty=0; desty<newHeight; desty++) {\r
802                         info.nProgress = (long)(100*desty/newHeight);\r
803                         if (info.nEscape) break;\r
804                         x=ssx;\r
805                         for (destx=0; destx<newWidth; destx++) {\r
806                                 //get source pixel coordinate for current destination point\r
807                                 origx=(cos_angle*x+sin_angle*y);\r
808                                 origy=(cos_angle*y-sin_angle*x);\r
809                                 if (bKeepOriginalSize){\r
810                                         origx += newxcenteroffset;\r
811                                         origy += newycenteroffset;\r
812                                 }\r
813                                 rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc);\r
814                                 //***!*** SetPixelColor is slow for palleted images\r
815 #if CXIMAGE_SUPPORT_ALPHA\r
816                                 if (AlphaIsValid()) \r
817                                         imgDest.SetPixelColor(destx,desty,rgb,true);\r
818                                 else \r
819 #endif //CXIMAGE_SUPPORT_ALPHA     \r
820                                         imgDest.SetPixelColor(destx,desty,rgb,false);\r
821                                 x++;\r
822                         }//for destx\r
823                         y++;\r
824                 }//for desty\r
825         }\r
826         //select the destination\r
827         \r
828         if (iDst) iDst->Transfer(imgDest);\r
829         else Transfer(imgDest);\r
830         \r
831         return true;\r
832 }\r
833 ////////////////////////////////////////////////////////////////////////////////\r
834 bool CxImage::Rotate180(CxImage* iDst)\r
835 {\r
836         if (!pDib) return false;\r
837 \r
838         long wid = GetWidth();\r
839         long ht = GetHeight();\r
840 \r
841         CxImage imgDest;\r
842         imgDest.CopyInfo(*this);\r
843         imgDest.Create(wid,ht,GetBpp(),GetType());\r
844         imgDest.SetPalette(GetPalette());\r
845 \r
846 #if CXIMAGE_SUPPORT_ALPHA\r
847         if (AlphaIsValid())     imgDest.AlphaCreate();\r
848 #endif //CXIMAGE_SUPPORT_ALPHA\r
849 \r
850         long x,y,y2;\r
851         for (y = 0; y < ht; y++){\r
852                 info.nProgress = (long)(100*y/ht); //<Anatoly Ivasyuk>\r
853                 y2=ht-y-1;\r
854                 for (x = 0; x < wid; x++){\r
855                         if(head.biClrUsed==0)//RGB\r
856                                 imgDest.SetPixelColor(wid-x-1, y2, BlindGetPixelColor(x, y));\r
857                         else  //PALETTE\r
858                                 imgDest.SetPixelIndex(wid-x-1, y2, BlindGetPixelIndex(x, y));\r
859 \r
860 #if CXIMAGE_SUPPORT_ALPHA\r
861                         if (AlphaIsValid())     imgDest.AlphaSet(wid-x-1, y2,BlindAlphaGet(x, y));\r
862 #endif //CXIMAGE_SUPPORT_ALPHA\r
863 \r
864                 }\r
865         }\r
866 \r
867         //select the destination\r
868         if (iDst) iDst->Transfer(imgDest);\r
869         else Transfer(imgDest);\r
870         return true;\r
871 }\r
872 \r
873 ////////////////////////////////////////////////////////////////////////////////\r
874 /**\r
875  * Resizes the image. mode can be 0 for slow (bilinear) method ,\r
876  * 1 for fast (nearest pixel) method, or 2 for accurate (bicubic spline interpolation) method.\r
877  * The function is faster with 24 and 1 bpp images, slow for 4 bpp images and slowest for 8 bpp images.\r
878  */\r
879 bool CxImage::Resample(long newx, long newy, int mode, CxImage* iDst)\r
880 {\r
881         if (newx==0 || newy==0) return false;\r
882 \r
883         if (head.biWidth==newx && head.biHeight==newy){\r
884                 if (iDst) iDst->Copy(*this);\r
885                 return true;\r
886         }\r
887 \r
888         float xScale, yScale, fX, fY;\r
889         xScale = (float)head.biWidth  / (float)newx;\r
890         yScale = (float)head.biHeight / (float)newy;\r
891 \r
892         CxImage newImage;\r
893         newImage.CopyInfo(*this);\r
894         newImage.Create(newx,newy,head.biBitCount,GetType());\r
895         newImage.SetPalette(GetPalette());\r
896         if (!newImage.IsValid()){\r
897                 strcpy(info.szLastError,newImage.GetLastError());\r
898                 return false;\r
899         }\r
900 \r
901         switch (mode) {\r
902         case 1: // nearest pixel\r
903         { \r
904                 for(long y=0; y<newy; y++){\r
905                         info.nProgress = (long)(100*y/newy);\r
906                         if (info.nEscape) break;\r
907                         fY = y * yScale;\r
908                         for(long x=0; x<newx; x++){\r
909                                 fX = x * xScale;\r
910                                 newImage.SetPixelColor(x,y,GetPixelColor((long)fX,(long)fY));\r
911                         }\r
912                 }\r
913                 break;\r
914         }\r
915         case 2: // bicubic interpolation by Blake L. Carlson <blake-carlson(at)uiowa(dot)edu\r
916         {\r
917                 float f_x, f_y, a, b, rr, gg, bb, r1, r2;\r
918                 int   i_x, i_y, xx, yy;\r
919                 RGBQUAD rgb;\r
920                 BYTE* iDst;\r
921                 for(long y=0; y<newy; y++){\r
922                         info.nProgress = (long)(100*y/newy);\r
923                         if (info.nEscape) break;\r
924                         f_y = (float) y * yScale - 0.5f;\r
925                         i_y = (int) floor(f_y);\r
926                         a   = f_y - (float)floor(f_y);\r
927                         for(long x=0; x<newx; x++){\r
928                                 f_x = (float) x * xScale - 0.5f;\r
929                                 i_x = (int) floor(f_x);\r
930                                 b   = f_x - (float)floor(f_x);\r
931 \r
932                                 rr = gg = bb = 0.0f;\r
933                                 for(int m=-1; m<3; m++) {\r
934                                         r1 = KernelBSpline((float) m - a);\r
935                                         yy = i_y+m;\r
936                                         if (yy<0) yy=0;\r
937                                         if (yy>=head.biHeight) yy = head.biHeight-1;\r
938                                         for(int n=-1; n<3; n++) {\r
939                                                 r2 = r1 * KernelBSpline(b - (float)n);\r
940                                                 xx = i_x+n;\r
941                                                 if (xx<0) xx=0;\r
942                                                 if (xx>=head.biWidth) xx=head.biWidth-1;\r
943 \r
944                                                 if (head.biClrUsed){\r
945                                                         rgb = GetPixelColor(xx,yy);\r
946                                                 } else {\r
947                                                         iDst  = info.pImage + yy*info.dwEffWidth + xx*3;\r
948                                                         rgb.rgbBlue = *iDst++;\r
949                                                         rgb.rgbGreen= *iDst++;\r
950                                                         rgb.rgbRed  = *iDst;\r
951                                                 }\r
952 \r
953                                                 rr += rgb.rgbRed * r2;\r
954                                                 gg += rgb.rgbGreen * r2;\r
955                                                 bb += rgb.rgbBlue * r2;\r
956                                         }\r
957                                 }\r
958 \r
959                                 if (head.biClrUsed)\r
960                                         newImage.SetPixelColor(x,y,RGB(rr,gg,bb));\r
961                                 else {\r
962                                         iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3;\r
963                                         *iDst++ = (BYTE)bb;\r
964                                         *iDst++ = (BYTE)gg;\r
965                                         *iDst   = (BYTE)rr;\r
966                                 }\r
967 \r
968                         }\r
969                 }\r
970                 break;\r
971         }\r
972         default: // bilinear interpolation\r
973                 if (!(head.biWidth>newx && head.biHeight>newy && head.biBitCount==24)) {\r
974                         // (c) 1999 Steve McMahon (steve@dogma.demon.co.uk)\r
975                         long ifX, ifY, ifX1, ifY1, xmax, ymax;\r
976                         float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy;\r
977                         BYTE r,g,b;\r
978                         RGBQUAD rgb1, rgb2, rgb3, rgb4;\r
979                         xmax = head.biWidth-1;\r
980                         ymax = head.biHeight-1;\r
981                         for(long y=0; y<newy; y++){\r
982                                 info.nProgress = (long)(100*y/newy);\r
983                                 if (info.nEscape) break;\r
984                                 fY = y * yScale;\r
985                                 ifY = (int)fY;\r
986                                 ifY1 = min(ymax, ifY+1);\r
987                                 dy = fY - ifY;\r
988                                 for(long x=0; x<newx; x++){\r
989                                         fX = x * xScale;\r
990                                         ifX = (int)fX;\r
991                                         ifX1 = min(xmax, ifX+1);\r
992                                         dx = fX - ifX;\r
993                                         // Interpolate using the four nearest pixels in the source\r
994                                         if (head.biClrUsed){\r
995                                                 rgb1=GetPaletteColor(GetPixelIndex(ifX,ifY));\r
996                                                 rgb2=GetPaletteColor(GetPixelIndex(ifX1,ifY));\r
997                                                 rgb3=GetPaletteColor(GetPixelIndex(ifX,ifY1));\r
998                                                 rgb4=GetPaletteColor(GetPixelIndex(ifX1,ifY1));\r
999                                         }\r
1000                                         else {\r
1001                                                 BYTE* iDst;\r
1002                                                 iDst = info.pImage + ifY*info.dwEffWidth + ifX*3;\r
1003                                                 rgb1.rgbBlue = *iDst++; rgb1.rgbGreen= *iDst++; rgb1.rgbRed =*iDst;\r
1004                                                 iDst = info.pImage + ifY*info.dwEffWidth + ifX1*3;\r
1005                                                 rgb2.rgbBlue = *iDst++; rgb2.rgbGreen= *iDst++; rgb2.rgbRed =*iDst;\r
1006                                                 iDst = info.pImage + ifY1*info.dwEffWidth + ifX*3;\r
1007                                                 rgb3.rgbBlue = *iDst++; rgb3.rgbGreen= *iDst++; rgb3.rgbRed =*iDst;\r
1008                                                 iDst = info.pImage + ifY1*info.dwEffWidth + ifX1*3;\r
1009                                                 rgb4.rgbBlue = *iDst++; rgb4.rgbGreen= *iDst++; rgb4.rgbRed =*iDst;\r
1010                                         }\r
1011                                         // Interplate in x direction:\r
1012                                         ir1 = rgb1.rgbRed   + (rgb3.rgbRed   - rgb1.rgbRed)   * dy;\r
1013                                         ig1 = rgb1.rgbGreen + (rgb3.rgbGreen - rgb1.rgbGreen) * dy;\r
1014                                         ib1 = rgb1.rgbBlue  + (rgb3.rgbBlue  - rgb1.rgbBlue)  * dy;\r
1015                                         ir2 = rgb2.rgbRed   + (rgb4.rgbRed   - rgb2.rgbRed)   * dy;\r
1016                                         ig2 = rgb2.rgbGreen + (rgb4.rgbGreen - rgb2.rgbGreen) * dy;\r
1017                                         ib2 = rgb2.rgbBlue  + (rgb4.rgbBlue  - rgb2.rgbBlue)  * dy;\r
1018                                         // Interpolate in y:\r
1019                                         r = (BYTE)(ir1 + (ir2-ir1) * dx);\r
1020                                         g = (BYTE)(ig1 + (ig2-ig1) * dx);\r
1021                                         b = (BYTE)(ib1 + (ib2-ib1) * dx);\r
1022                                         // Set output\r
1023                                         newImage.SetPixelColor(x,y,RGB(r,g,b));\r
1024                                 }\r
1025                         } \r
1026                 } else {\r
1027                         //high resolution shrink, thanks to Henrik Stellmann <henrik.stellmann@volleynet.de>\r
1028                         const long ACCURACY = 1000;\r
1029                         long i,j; // index for faValue\r
1030                         long x,y; // coordinates in  source image\r
1031                         BYTE* pSource;\r
1032                         BYTE* pDest = newImage.info.pImage;\r
1033                         long* naAccu  = new long[3 * newx + 3];\r
1034                         long* naCarry = new long[3 * newx + 3];\r
1035                         long* naTemp;\r
1036                         long  nWeightX,nWeightY;\r
1037                         float fEndX;\r
1038                         long nScale = (long)(ACCURACY * xScale * yScale);\r
1039 \r
1040                         memset(naAccu,  0, sizeof(long) * 3 * newx);\r
1041                         memset(naCarry, 0, sizeof(long) * 3 * newx);\r
1042 \r
1043                         int u, v = 0; // coordinates in dest image\r
1044                         float fEndY = yScale - 1.0f;\r
1045                         for (y = 0; y < head.biHeight; y++){\r
1046                                 info.nProgress = (long)(100*y/head.biHeight); //<Anatoly Ivasyuk>\r
1047                                 if (info.nEscape) break;\r
1048                                 pSource = info.pImage + y * info.dwEffWidth;\r
1049                                 u = i = 0;\r
1050                                 fEndX = xScale - 1.0f;\r
1051                                 if ((float)y < fEndY) {       // complete source row goes into dest row\r
1052                                         for (x = 0; x < head.biWidth; x++){\r
1053                                                 if ((float)x < fEndX){       // complete source pixel goes into dest pixel\r
1054                                                         for (j = 0; j < 3; j++) naAccu[i + j] += (*pSource++) * ACCURACY;\r
1055                                                 } else {       // source pixel is splitted for 2 dest pixels\r
1056                                                         nWeightX = (long)(((float)x - fEndX) * ACCURACY);\r
1057                                                         for (j = 0; j < 3; j++){\r
1058                                                                 naAccu[i] += (ACCURACY - nWeightX) * (*pSource);\r
1059                                                                 naAccu[3 + i++] += nWeightX * (*pSource++);\r
1060                                                         }\r
1061                                                         fEndX += xScale;\r
1062                                                         u++;\r
1063                                                 }\r
1064                                         }\r
1065                                 } else {       // source row is splitted for 2 dest rows       \r
1066                                         nWeightY = (long)(((float)y - fEndY) * ACCURACY);\r
1067                                         for (x = 0; x < head.biWidth; x++){\r
1068                                                 if ((float)x < fEndX){       // complete source pixel goes into 2 pixel\r
1069                                                         for (j = 0; j < 3; j++){\r
1070                                                                 naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource));\r
1071                                                                 naCarry[i + j] += nWeightY * (*pSource++);\r
1072                                                         }\r
1073                                                 } else {       // source pixel is splitted for 4 dest pixels\r
1074                                                         nWeightX = (int)(((float)x - fEndX) * ACCURACY);\r
1075                                                         for (j = 0; j < 3; j++) {\r
1076                                                                 naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY;\r
1077                                                                 *pDest++ = (BYTE)(naAccu[i] / nScale);\r
1078                                                                 naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY;\r
1079                                                                 naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY;\r
1080                                                                 naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY;\r
1081                                                                 i++;\r
1082                                                                 pSource++;\r
1083                                                         }\r
1084                                                         fEndX += xScale;\r
1085                                                         u++;\r
1086                                                 }\r
1087                                         }\r
1088                                         if (u < newx){ // possibly not completed due to rounding errors\r
1089                                                 for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale);\r
1090                                         }\r
1091                                         naTemp = naCarry;\r
1092                                         naCarry = naAccu;\r
1093                                         naAccu = naTemp;\r
1094                                         memset(naCarry, 0, sizeof(int) * 3);    // need only to set first pixel zero\r
1095                                         pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth);\r
1096                                         fEndY += yScale;\r
1097                                 }\r
1098                         }\r
1099                         if (v < newy){  // possibly not completed due to rounding errors\r
1100                                 for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale);\r
1101                         }\r
1102                         delete [] naAccu;\r
1103                         delete [] naCarry;\r
1104                 }\r
1105         }\r
1106 \r
1107 #if CXIMAGE_SUPPORT_ALPHA\r
1108         if (AlphaIsValid()){\r
1109                 newImage.AlphaCreate();\r
1110                 for(long y=0; y<newy; y++){\r
1111                         fY = y * yScale;\r
1112                         for(long x=0; x<newx; x++){\r
1113                                 fX = x * xScale;\r
1114                                 newImage.AlphaSet(x,y,AlphaGet((long)fX,(long)fY));\r
1115                         }\r
1116                 }\r
1117         }\r
1118 #endif //CXIMAGE_SUPPORT_ALPHA\r
1119 \r
1120         //select the destination\r
1121         if (iDst) iDst->Transfer(newImage);\r
1122         else Transfer(newImage);\r
1123 \r
1124         return true;\r
1125 }\r
1126 ////////////////////////////////////////////////////////////////////////////////\r
1127 /**\r
1128  * New simpler resample. Adds new interpolation methods and simplifies code (using GetPixelColorInterpolated\r
1129  * and GetAreaColorInterpolated). It also (unlike old method) interpolates alpha layer. \r
1130  *\r
1131  * \param  newx, newy - size of resampled image\r
1132  * \param  inMethod - interpolation method to use (see comments at GetPixelColorInterpolated)\r
1133  *              If image size is being reduced, averaging is used instead (or simultaneously with) inMethod.\r
1134  * \param  ofMethod - what to replace outside pixels by (only significant for bordering pixels of enlarged image)\r
1135  * \param  iDst - pointer to destination CxImage or NULL.\r
1136  * \param  disableAveraging - force no averaging when shrinking images (Produces aliasing.\r
1137  *                      You probably just want to leave this off...)\r
1138  *\r
1139  * \author ***bd*** 2.2004\r
1140  */\r
1141 bool CxImage::Resample2(\r
1142   long newx, long newy, \r
1143   InterpolationMethod const inMethod, \r
1144   OverflowMethod const ofMethod, \r
1145   CxImage* const iDst,\r
1146   bool const disableAveraging)\r
1147 {\r
1148         if (newx<=0 || newy<=0 || !pDib) return false;\r
1149         \r
1150         if (head.biWidth==newx && head.biHeight==newy) {\r
1151                 //image already correct size (just copy and return)\r
1152                 if (iDst) iDst->Copy(*this);\r
1153                 return true;\r
1154         }//if\r
1155         \r
1156         //calculate scale of new image (less than 1 for enlarge)\r
1157         float xScale, yScale;\r
1158         xScale = (float)head.biWidth  / (float)newx;    \r
1159         yScale = (float)head.biHeight / (float)newy;\r
1160         \r
1161         //create temporary destination image\r
1162         CxImage newImage;\r
1163         newImage.CopyInfo(*this);\r
1164         newImage.Create(newx,newy,head.biBitCount,GetType());\r
1165         newImage.SetPalette(GetPalette());\r
1166         if (!newImage.IsValid()){\r
1167                 strcpy(info.szLastError,newImage.GetLastError());\r
1168                 return false;\r
1169         }\r
1170         \r
1171         //and alpha channel if required\r
1172 #if CXIMAGE_SUPPORT_ALPHA\r
1173         if (AlphaIsValid()) newImage.AlphaCreate();\r
1174         BYTE *pxptra = 0;       // destination alpha data\r
1175 #endif\r
1176         \r
1177         float sX, sY;         //source location\r
1178         long dX,dY;           //destination pixel (int value)\r
1179         if ((xScale<=1 && yScale<=1) || disableAveraging) {\r
1180                 //image is being enlarged (or interpolation on demand)\r
1181                 if (!IsIndexed()) {\r
1182                         //RGB24 image (optimized version with direct writes)\r
1183                         RGBQUAD q;              //pixel colour\r
1184                         BYTE *pxptr;            //pointer to destination pixel\r
1185                         for(dY=0; dY<newy; dY++){\r
1186                                 info.nProgress = (long)(100*dY/newy);\r
1187                                 if (info.nEscape) break;\r
1188                                 sY = (dY + 0.5f) * yScale - 0.5f;\r
1189                                 pxptr=(BYTE*)(newImage.BlindGetPixelPointer(0,dY));\r
1190 #if CXIMAGE_SUPPORT_ALPHA\r
1191                                 pxptra=newImage.AlphaGetPointer(0,dY);\r
1192 #endif\r
1193                                 for(dX=0; dX<newx; dX++){\r
1194                                         sX = (dX + 0.5f) * xScale - 0.5f;\r
1195                                         q=GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0);\r
1196                                         *pxptr++=q.rgbBlue;\r
1197                                         *pxptr++=q.rgbGreen;\r
1198                                         *pxptr++=q.rgbRed;\r
1199 #if CXIMAGE_SUPPORT_ALPHA\r
1200                                         if (pxptra) *pxptra++=q.rgbReserved;\r
1201 #endif\r
1202                                 }//for dX\r
1203                         }//for dY\r
1204                 } else {\r
1205                         //enlarge paletted image. Slower method.\r
1206                         for(dY=0; dY<newy; dY++){\r
1207                                 info.nProgress = (long)(100*dY/newy);\r
1208                                 if (info.nEscape) break;\r
1209                                 sY = (dY + 0.5f) * yScale - 0.5f;\r
1210                                 for(dX=0; dX<newx; dX++){\r
1211                                         sX = (dX + 0.5f) * xScale - 0.5f;\r
1212                                         newImage.SetPixelColor(dX,dY,GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0),true);\r
1213                                 }//for x\r
1214                         }//for y\r
1215                 }//if\r
1216         } else {\r
1217                 //image size is being reduced (averaging enabled)\r
1218                 for(dY=0; dY<newy; dY++){\r
1219                         info.nProgress = (long)(100*dY/newy); if (info.nEscape) break;\r
1220                         sY = (dY+0.5f) * yScale - 0.5f;\r
1221                         for(dX=0; dX<newx; dX++){\r
1222                                 sX = (dX+0.5f) * xScale - 0.5f;\r
1223                                 newImage.SetPixelColor(dX,dY,GetAreaColorInterpolated(sX, sY, xScale, yScale, inMethod, ofMethod,0),true);\r
1224                         }//for x\r
1225                 }//for y\r
1226         }//if\r
1227 \r
1228 #if CXIMAGE_SUPPORT_ALPHA\r
1229         if (AlphaIsValid() && pxptra == 0){\r
1230                 for(long y=0; y<newy; y++){\r
1231                         dY = (long)(y * yScale);\r
1232                         for(long x=0; x<newx; x++){\r
1233                                 dX = (long)(x * xScale);\r
1234                                 newImage.AlphaSet(x,y,AlphaGet(dX,dY));\r
1235                         }\r
1236                 }\r
1237         }\r
1238 #endif //CXIMAGE_SUPPORT_ALPHA\r
1239 \r
1240         //copy new image to the destination\r
1241         if (iDst) \r
1242                 iDst->Transfer(newImage);\r
1243         else \r
1244                 Transfer(newImage);\r
1245         return true;\r
1246 }\r
1247 ////////////////////////////////////////////////////////////////////////////////\r
1248 /**\r
1249  * Reduces the number of bits per pixel to nbit (1, 4 or 8).\r
1250  * ppal points to a valid palette for the final image; if not supplied the function will use a standard palette.\r
1251  * ppal is not necessary for reduction to 1 bpp.\r
1252  */\r
1253 bool CxImage::DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal, DWORD clrimportant)\r
1254 {\r
1255         if (!pDib) return false;\r
1256         if (head.biBitCount <  nbit){\r
1257                 strcpy(info.szLastError,"DecreaseBpp: target BPP greater than source BPP");\r
1258                 return false;\r
1259         }\r
1260         if (head.biBitCount == nbit){\r
1261                 if (clrimportant==0) return true;\r
1262                 if (head.biClrImportant && (head.biClrImportant<clrimportant)) return true;\r
1263         }\r
1264 \r
1265         long er,eg,eb;\r
1266         RGBQUAD c,ce;\r
1267 \r
1268         CxImage tmp;\r
1269         tmp.CopyInfo(*this);\r
1270         tmp.Create(head.biWidth,head.biHeight,(WORD)nbit,info.dwType);\r
1271         if (clrimportant) tmp.SetClrImportant(clrimportant);\r
1272         if (!tmp.IsValid()){\r
1273                 strcpy(info.szLastError,tmp.GetLastError());\r
1274                 return false;\r
1275         }\r
1276 \r
1277 #if CXIMAGE_SUPPORT_SELECTION\r
1278         tmp.SelectionCopy(*this);\r
1279 #endif //CXIMAGE_SUPPORT_SELECTION\r
1280 \r
1281 #if CXIMAGE_SUPPORT_ALPHA\r
1282         tmp.AlphaCopy(*this);\r
1283 #endif //CXIMAGE_SUPPORT_ALPHA\r
1284 \r
1285         if (ppal) {\r
1286                 if (clrimportant) {\r
1287                         tmp.SetPalette(ppal,clrimportant);\r
1288                 } else {\r
1289                         tmp.SetPalette(ppal,1<<tmp.head.biBitCount);\r
1290                 }\r
1291         } else {\r
1292                 tmp.SetStdPalette();\r
1293         }\r
1294 \r
1295         for (long y=0;y<head.biHeight;y++){\r
1296                 if (info.nEscape) break;\r
1297                 info.nProgress = (long)(100*y/head.biHeight);\r
1298                 for (long x=0;x<head.biWidth;x++){\r
1299                         if (!errordiffusion){\r
1300                                 tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y));\r
1301                         } else {\r
1302                                 c = BlindGetPixelColor(x,y);\r
1303                                 tmp.BlindSetPixelColor(x,y,c);\r
1304 \r
1305                                 ce = tmp.BlindGetPixelColor(x,y);\r
1306                                 er=(long)c.rgbRed - (long)ce.rgbRed;\r
1307                                 eg=(long)c.rgbGreen - (long)ce.rgbGreen;\r
1308                                 eb=(long)c.rgbBlue - (long)ce.rgbBlue;\r
1309 \r
1310                                 c = GetPixelColor(x+1,y);\r
1311                                 c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er*7)/16)));\r
1312                                 c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg*7)/16)));\r
1313                                 c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb*7)/16)));\r
1314                                 SetPixelColor(x+1,y,c);\r
1315                                 int coeff=1;\r
1316                                 for(int i=-1; i<2; i++){\r
1317                                         switch(i){\r
1318                                         case -1:\r
1319                                                 coeff=2; break;\r
1320                                         case 0:\r
1321                                                 coeff=4; break;\r
1322                                         case 1:\r
1323                                                 coeff=1; break;\r
1324                                         }\r
1325                                         c = GetPixelColor(x+i,y+1);\r
1326                                         c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er * coeff)/16)));\r
1327                                         c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg * coeff)/16)));\r
1328                                         c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb * coeff)/16)));\r
1329                                         SetPixelColor(x+i,y+1,c);\r
1330                                 }\r
1331                         }\r
1332                 }\r
1333         }\r
1334 \r
1335         Transfer(tmp);\r
1336         return true;\r
1337 }\r
1338 ////////////////////////////////////////////////////////////////////////////////\r
1339 /**\r
1340  * Increases the number of bits per pixel of the image.\r
1341  * \param nbit: 4, 8, 24\r
1342  */\r
1343 bool CxImage::IncreaseBpp(DWORD nbit)\r
1344 {\r
1345         if (!pDib) return false;\r
1346         switch (nbit){\r
1347         case 4:\r
1348                 {\r
1349                         if (head.biBitCount==4) return true;\r
1350                         if (head.biBitCount>4) return false;\r
1351 \r
1352                         CxImage tmp;\r
1353                         tmp.CopyInfo(*this);\r
1354                         tmp.Create(head.biWidth,head.biHeight,4,info.dwType);\r
1355                         tmp.SetPalette(GetPalette(),GetNumColors());\r
1356                         if (!tmp.IsValid()){\r
1357                                 strcpy(info.szLastError,tmp.GetLastError());\r
1358                                 return false;\r
1359                         }\r
1360 \r
1361 \r
1362 #if CXIMAGE_SUPPORT_SELECTION\r
1363                         tmp.SelectionCopy(*this);\r
1364 #endif //CXIMAGE_SUPPORT_SELECTION\r
1365 \r
1366 #if CXIMAGE_SUPPORT_ALPHA\r
1367                         tmp.AlphaCopy(*this);\r
1368 #endif //CXIMAGE_SUPPORT_ALPHA\r
1369 \r
1370                         for (long y=0;y<head.biHeight;y++){\r
1371                                 if (info.nEscape) break;\r
1372                                 for (long x=0;x<head.biWidth;x++){\r
1373                                         tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));\r
1374                                 }\r
1375                         }\r
1376                         Transfer(tmp);\r
1377                         return true;\r
1378                 }\r
1379         case 8:\r
1380                 {\r
1381                         if (head.biBitCount==8) return true;\r
1382                         if (head.biBitCount>8) return false;\r
1383 \r
1384                         CxImage tmp;\r
1385                         tmp.CopyInfo(*this);\r
1386                         tmp.Create(head.biWidth,head.biHeight,8,info.dwType);\r
1387                         tmp.SetPalette(GetPalette(),GetNumColors());\r
1388                         if (!tmp.IsValid()){\r
1389                                 strcpy(info.szLastError,tmp.GetLastError());\r
1390                                 return false;\r
1391                         }\r
1392 \r
1393 #if CXIMAGE_SUPPORT_SELECTION\r
1394                         tmp.SelectionCopy(*this);\r
1395 #endif //CXIMAGE_SUPPORT_SELECTION\r
1396 \r
1397 #if CXIMAGE_SUPPORT_ALPHA\r
1398                         tmp.AlphaCopy(*this);\r
1399 #endif //CXIMAGE_SUPPORT_ALPHA\r
1400 \r
1401                         for (long y=0;y<head.biHeight;y++){\r
1402                                 if (info.nEscape) break;\r
1403                                 for (long x=0;x<head.biWidth;x++){\r
1404                                         tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));\r
1405                                 }\r
1406                         }\r
1407                         Transfer(tmp);\r
1408                         return true;\r
1409                 }\r
1410         case 24:\r
1411                 {\r
1412                         if (head.biBitCount==24) return true;\r
1413                         if (head.biBitCount>24) return false;\r
1414 \r
1415                         CxImage tmp;\r
1416                         tmp.CopyInfo(*this);\r
1417                         tmp.Create(head.biWidth,head.biHeight,24,info.dwType);\r
1418                         if (!tmp.IsValid()){\r
1419                                 strcpy(info.szLastError,tmp.GetLastError());\r
1420                                 return false;\r
1421                         }\r
1422 \r
1423                         if (info.nBkgndIndex>=0) //translate transparency\r
1424                                 tmp.info.nBkgndColor=GetPaletteColor((BYTE)info.nBkgndIndex);\r
1425 \r
1426 #if CXIMAGE_SUPPORT_SELECTION\r
1427                         tmp.SelectionCopy(*this);\r
1428 #endif //CXIMAGE_SUPPORT_SELECTION\r
1429 \r
1430 #if CXIMAGE_SUPPORT_ALPHA\r
1431                         tmp.AlphaCopy(*this);\r
1432                         if (AlphaPaletteIsValid() && !AlphaIsValid()) tmp.AlphaCreate();\r
1433 #endif //CXIMAGE_SUPPORT_ALPHA\r
1434 \r
1435                         for (long y=0;y<head.biHeight;y++){\r
1436                                 if (info.nEscape) break;\r
1437                                 for (long x=0;x<head.biWidth;x++){\r
1438                                         tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y),true);\r
1439                                 }\r
1440                         }\r
1441                         Transfer(tmp);\r
1442                         return true;\r
1443                 }\r
1444         }\r
1445         return false;\r
1446 }\r
1447 ////////////////////////////////////////////////////////////////////////////////\r
1448 /**\r
1449  * Converts the image to B&W using the desired method :\r
1450  * - 0 = Floyd-Steinberg\r
1451  * - 1 = Ordered-Dithering (4x4) \r
1452  * - 2 = Burkes\r
1453  * - 3 = Stucki\r
1454  * - 4 = Jarvis-Judice-Ninke\r
1455  * - 5 = Sierra\r
1456  * - 6 = Stevenson-Arce\r
1457  * - 7 = Bayer (4x4 ordered dithering) \r
1458  */\r
1459 bool CxImage::Dither(long method)\r
1460 {\r
1461         if (!pDib) return false;\r
1462         if (head.biBitCount == 1) return true;\r
1463         \r
1464         GrayScale();\r
1465 \r
1466         CxImage tmp;\r
1467         tmp.CopyInfo(*this);\r
1468         tmp.Create(head.biWidth, head.biHeight, 1, info.dwType);\r
1469         if (!tmp.IsValid()){\r
1470                 strcpy(info.szLastError,tmp.GetLastError());\r
1471                 return false;\r
1472         }\r
1473 \r
1474 #if CXIMAGE_SUPPORT_SELECTION\r
1475         tmp.SelectionCopy(*this);\r
1476 #endif //CXIMAGE_SUPPORT_SELECTION\r
1477 \r
1478 #if CXIMAGE_SUPPORT_ALPHA\r
1479         tmp.AlphaCopy(*this);\r
1480 #endif //CXIMAGE_SUPPORT_ALPHA\r
1481 \r
1482         switch (method){\r
1483         case 1:\r
1484         {\r
1485                 // Multi-Level Ordered-Dithering by Kenny Hoff (Oct. 12, 1995)\r
1486                 #define dth_NumRows 4\r
1487                 #define dth_NumCols 4\r
1488                 #define dth_NumIntensityLevels 2\r
1489                 #define dth_NumRowsLessOne (dth_NumRows-1)\r
1490                 #define dth_NumColsLessOne (dth_NumCols-1)\r
1491                 #define dth_RowsXCols (dth_NumRows*dth_NumCols)\r
1492                 #define dth_MaxIntensityVal 255\r
1493                 #define dth_MaxDitherIntensityVal (dth_NumRows*dth_NumCols*(dth_NumIntensityLevels-1))\r
1494 \r
1495                 int DitherMatrix[dth_NumRows][dth_NumCols] = {{0,8,2,10}, {12,4,14,6}, {3,11,1,9}, {15,7,13,5} };\r
1496                 \r
1497                 unsigned char Intensity[dth_NumIntensityLevels] = { 0,1 };                       // 2 LEVELS B/W\r
1498                 //unsigned char Intensity[NumIntensityLevels] = { 0,255 };                       // 2 LEVELS\r
1499                 //unsigned char Intensity[NumIntensityLevels] = { 0,127,255 };                   // 3 LEVELS\r
1500                 //unsigned char Intensity[NumIntensityLevels] = { 0,85,170,255 };                // 4 LEVELS\r
1501                 //unsigned char Intensity[NumIntensityLevels] = { 0,63,127,191,255 };            // 5 LEVELS\r
1502                 //unsigned char Intensity[NumIntensityLevels] = { 0,51,102,153,204,255 };        // 6 LEVELS\r
1503                 //unsigned char Intensity[NumIntensityLevels] = { 0,42,85,127,170,213,255 };     // 7 LEVELS\r
1504                 //unsigned char Intensity[NumIntensityLevels] = { 0,36,73,109,145,182,219,255 }; // 8 LEVELS\r
1505                 int DitherIntensity, DitherMatrixIntensity, Offset, DeviceIntensity;\r
1506                 unsigned char DitherValue;\r
1507   \r
1508                 for (long y=0;y<head.biHeight;y++){\r
1509                         info.nProgress = (long)(100*y/head.biHeight);\r
1510                         if (info.nEscape) break;\r
1511                         for (long x=0;x<head.biWidth;x++){\r
1512 \r
1513                                 DeviceIntensity = BlindGetPixelIndex(x,y);\r
1514                                 DitherIntensity = DeviceIntensity*dth_MaxDitherIntensityVal/dth_MaxIntensityVal;\r
1515                                 DitherMatrixIntensity = DitherIntensity % dth_RowsXCols;\r
1516                                 Offset = DitherIntensity / dth_RowsXCols;\r
1517                                 if (DitherMatrix[y&dth_NumRowsLessOne][x&dth_NumColsLessOne] < DitherMatrixIntensity)\r
1518                                         DitherValue = Intensity[1+Offset];\r
1519                                 else\r
1520                                         DitherValue = Intensity[0+Offset];\r
1521 \r
1522                                 tmp.BlindSetPixelIndex(x,y,DitherValue);\r
1523                         }\r
1524                 }\r
1525                 break;\r
1526         }\r
1527         case 2:\r
1528         {\r
1529                 //Burkes error diffusion (Thanks to Franco Gerevini)\r
1530                 int TotalCoeffSum = 32;\r
1531                 long error, nlevel, coeff=1;\r
1532                 BYTE level;\r
1533 \r
1534                 for (long y = 0; y < head.biHeight; y++) {\r
1535                         info.nProgress = (long)(100 * y / head.biHeight);\r
1536                         if (info.nEscape) \r
1537                                 break;\r
1538                         for (long x = 0; x < head.biWidth; x++) {\r
1539                                 level = BlindGetPixelIndex(x, y);\r
1540                                 if (level > 128) {\r
1541                                         tmp.SetPixelIndex(x, y, 1);\r
1542                                         error = level - 255;\r
1543                                 } else {\r
1544                                         tmp.SetPixelIndex(x, y, 0);\r
1545                                         error = level;\r
1546                                 }\r
1547 \r
1548                                 nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;\r
1549                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1550                                 SetPixelIndex(x + 1, y, level);\r
1551                                 nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;\r
1552                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1553                                 SetPixelIndex(x + 2, y, level);\r
1554                                 int i;\r
1555                                 for (i = -2; i < 3; i++) {\r
1556                                         switch (i) {\r
1557                                         case -2:\r
1558                                                 coeff = 2;\r
1559                                                 break;\r
1560                                         case -1:\r
1561                                                 coeff = 4;\r
1562                                                 break;\r
1563                                         case 0:\r
1564                                                 coeff = 8; \r
1565                                                 break;\r
1566                                         case 1:\r
1567                                                 coeff = 4; \r
1568                                                 break;\r
1569                                         case 2:\r
1570                                                 coeff = 2; \r
1571                                                 break;\r
1572                                         }\r
1573                                         nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
1574                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1575                                         SetPixelIndex(x + i, y + 1, level);\r
1576                                 }\r
1577                         }\r
1578                 }\r
1579                 break;\r
1580         }\r
1581         case 3:\r
1582         {\r
1583                 //Stucki error diffusion (Thanks to Franco Gerevini)\r
1584                 int TotalCoeffSum = 42;\r
1585                 long error, nlevel, coeff=1;\r
1586                 BYTE level;\r
1587 \r
1588                 for (long y = 0; y < head.biHeight; y++) {\r
1589                         info.nProgress = (long)(100 * y / head.biHeight);\r
1590                         if (info.nEscape) \r
1591                                 break;\r
1592                         for (long x = 0; x < head.biWidth; x++) {\r
1593                                 level = BlindGetPixelIndex(x, y);\r
1594                                 if (level > 128) {\r
1595                                         tmp.SetPixelIndex(x, y, 1);\r
1596                                         error = level - 255;\r
1597                                 } else {\r
1598                                         tmp.SetPixelIndex(x, y, 0);\r
1599                                         error = level;\r
1600                                 }\r
1601 \r
1602                                 nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;\r
1603                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1604                                 SetPixelIndex(x + 1, y, level);\r
1605                                 nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;\r
1606                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1607                                 SetPixelIndex(x + 2, y, level);\r
1608                                 int i;\r
1609                                 for (i = -2; i < 3; i++) {\r
1610                                         switch (i) {\r
1611                                         case -2:\r
1612                                                 coeff = 2;\r
1613                                                 break;\r
1614                                         case -1:\r
1615                                                 coeff = 4;\r
1616                                                 break;\r
1617                                         case 0:\r
1618                                                 coeff = 8; \r
1619                                                 break;\r
1620                                         case 1:\r
1621                                                 coeff = 4; \r
1622                                                 break;\r
1623                                         case 2:\r
1624                                                 coeff = 2; \r
1625                                                 break;\r
1626                                         }\r
1627                                         nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
1628                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1629                                         SetPixelIndex(x + i, y + 1, level);\r
1630                                 }\r
1631                                 for (i = -2; i < 3; i++) {\r
1632                                         switch (i) {\r
1633                                         case -2:\r
1634                                                 coeff = 1;\r
1635                                                 break;\r
1636                                         case -1:\r
1637                                                 coeff = 2;\r
1638                                                 break;\r
1639                                         case 0:\r
1640                                                 coeff = 4; \r
1641                                                 break;\r
1642                                         case 1:\r
1643                                                 coeff = 2; \r
1644                                                 break;\r
1645                                         case 2:\r
1646                                                 coeff = 1; \r
1647                                                 break;\r
1648                                         }\r
1649                                         nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
1650                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1651                                         SetPixelIndex(x + i, y + 2, level);\r
1652                                 }\r
1653                         }\r
1654                 }\r
1655                 break;\r
1656         }\r
1657         case 4:\r
1658         {\r
1659                 //Jarvis, Judice and Ninke error diffusion (Thanks to Franco Gerevini)\r
1660                 int TotalCoeffSum = 48;\r
1661                 long error, nlevel, coeff=1;\r
1662                 BYTE level;\r
1663 \r
1664                 for (long y = 0; y < head.biHeight; y++) {\r
1665                         info.nProgress = (long)(100 * y / head.biHeight);\r
1666                         if (info.nEscape) \r
1667                                 break;\r
1668                         for (long x = 0; x < head.biWidth; x++) {\r
1669                                 level = BlindGetPixelIndex(x, y);\r
1670                                 if (level > 128) {\r
1671                                         tmp.SetPixelIndex(x, y, 1);\r
1672                                         error = level - 255;\r
1673                                 } else {\r
1674                                         tmp.SetPixelIndex(x, y, 0);\r
1675                                         error = level;\r
1676                                 }\r
1677 \r
1678                                 nlevel = GetPixelIndex(x + 1, y) + (error * 7) / TotalCoeffSum;\r
1679                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1680                                 SetPixelIndex(x + 1, y, level);\r
1681                                 nlevel = GetPixelIndex(x + 2, y) + (error * 5) / TotalCoeffSum;\r
1682                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1683                                 SetPixelIndex(x + 2, y, level);\r
1684                                 int i;\r
1685                                 for (i = -2; i < 3; i++) {\r
1686                                         switch (i) {\r
1687                                         case -2:\r
1688                                                 coeff = 3;\r
1689                                                 break;\r
1690                                         case -1:\r
1691                                                 coeff = 5;\r
1692                                                 break;\r
1693                                         case 0:\r
1694                                                 coeff = 7; \r
1695                                                 break;\r
1696                                         case 1:\r
1697                                                 coeff = 5; \r
1698                                                 break;\r
1699                                         case 2:\r
1700                                                 coeff = 3; \r
1701                                                 break;\r
1702                                         }\r
1703                                         nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
1704                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1705                                         SetPixelIndex(x + i, y + 1, level);\r
1706                                 }\r
1707                                 for (i = -2; i < 3; i++) {\r
1708                                         switch (i) {\r
1709                                         case -2:\r
1710                                                 coeff = 1;\r
1711                                                 break;\r
1712                                         case -1:\r
1713                                                 coeff = 3;\r
1714                                                 break;\r
1715                                         case 0:\r
1716                                                 coeff = 5; \r
1717                                                 break;\r
1718                                         case 1:\r
1719                                                 coeff = 3; \r
1720                                                 break;\r
1721                                         case 2:\r
1722                                                 coeff = 1; \r
1723                                                 break;\r
1724                                         }\r
1725                                         nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
1726                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1727                                         SetPixelIndex(x + i, y + 2, level);\r
1728                                 }\r
1729                         }\r
1730                 }\r
1731                 break;\r
1732         }\r
1733         case 5:\r
1734         {\r
1735                 //Sierra error diffusion (Thanks to Franco Gerevini)\r
1736                 int TotalCoeffSum = 32;\r
1737                 long error, nlevel, coeff=1;\r
1738                 BYTE level;\r
1739 \r
1740                 for (long y = 0; y < head.biHeight; y++) {\r
1741                         info.nProgress = (long)(100 * y / head.biHeight);\r
1742                         if (info.nEscape) \r
1743                                 break;\r
1744                         for (long x = 0; x < head.biWidth; x++) {\r
1745                                 level = BlindGetPixelIndex(x, y);\r
1746                                 if (level > 128) {\r
1747                                         tmp.SetPixelIndex(x, y, 1);\r
1748                                         error = level - 255;\r
1749                                 } else {\r
1750                                         tmp.SetPixelIndex(x, y, 0);\r
1751                                         error = level;\r
1752                                 }\r
1753 \r
1754                                 nlevel = GetPixelIndex(x + 1, y) + (error * 5) / TotalCoeffSum;\r
1755                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1756                                 SetPixelIndex(x + 1, y, level);\r
1757                                 nlevel = GetPixelIndex(x + 2, y) + (error * 3) / TotalCoeffSum;\r
1758                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1759                                 SetPixelIndex(x + 2, y, level);\r
1760                                 int i;\r
1761                                 for (i = -2; i < 3; i++) {\r
1762                                         switch (i) {\r
1763                                         case -2:\r
1764                                                 coeff = 2;\r
1765                                                 break;\r
1766                                         case -1:\r
1767                                                 coeff = 4;\r
1768                                                 break;\r
1769                                         case 0:\r
1770                                                 coeff = 5; \r
1771                                                 break;\r
1772                                         case 1:\r
1773                                                 coeff = 4; \r
1774                                                 break;\r
1775                                         case 2:\r
1776                                                 coeff = 2; \r
1777                                                 break;\r
1778                                         }\r
1779                                         nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
1780                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1781                                         SetPixelIndex(x + i, y + 1, level);\r
1782                                 }\r
1783                                 for (i = -1; i < 2; i++) {\r
1784                                         switch (i) {\r
1785                                         case -1:\r
1786                                                 coeff = 2;\r
1787                                                 break;\r
1788                                         case 0:\r
1789                                                 coeff = 3; \r
1790                                                 break;\r
1791                                         case 1:\r
1792                                                 coeff = 2; \r
1793                                                 break;\r
1794                                         }\r
1795                                         nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
1796                                         level = (BYTE)min(255, max(0, (int)nlevel));\r
1797                                         SetPixelIndex(x + i, y + 2, level);\r
1798                                 }\r
1799                         }\r
1800                 }\r
1801                 break;\r
1802         }\r
1803         case 6:\r
1804         {\r
1805                 //Stevenson and Arce error diffusion (Thanks to Franco Gerevini)\r
1806                 int TotalCoeffSum = 200;\r
1807                 long error, nlevel;\r
1808                 BYTE level;\r
1809 \r
1810                 for (long y = 0; y < head.biHeight; y++) {\r
1811                         info.nProgress = (long)(100 * y / head.biHeight);\r
1812                         if (info.nEscape) \r
1813                                 break;\r
1814                         for (long x = 0; x < head.biWidth; x++) {\r
1815                                 level = BlindGetPixelIndex(x, y);\r
1816                                 if (level > 128) {\r
1817                                         tmp.SetPixelIndex(x, y, 1);\r
1818                                         error = level - 255;\r
1819                                 } else {\r
1820                                         tmp.SetPixelIndex(x, y, 0);\r
1821                                         error = level;\r
1822                                 }\r
1823 \r
1824                                 int tmp_index_x = x + 2;\r
1825                                 int tmp_index_y = y;\r
1826                                 int tmp_coeff = 32;\r
1827                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1828                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1829                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1830 \r
1831                                 tmp_index_x = x - 3;\r
1832                                 tmp_index_y = y + 1;\r
1833                                 tmp_coeff = 12;\r
1834                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1835                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1836                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1837 \r
1838                                 tmp_index_x = x - 1;\r
1839                                 tmp_coeff = 26;\r
1840                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1841                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1842                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1843 \r
1844                                 tmp_index_x = x + 1;\r
1845                                 tmp_coeff = 30;\r
1846                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1847                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1848                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1849 \r
1850                                 tmp_index_x = x + 3;\r
1851                                 tmp_coeff = 16;\r
1852                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1853                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1854                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1855 \r
1856                                 tmp_index_x = x - 2;\r
1857                                 tmp_index_y = y + 2;\r
1858                                 tmp_coeff = 12;\r
1859                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1860                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1861                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1862 \r
1863                                 tmp_index_x = x;\r
1864                                 tmp_coeff = 26;\r
1865                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1866                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1867                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1868 \r
1869                                 tmp_index_x = x + 2;\r
1870                                 tmp_coeff = 12;\r
1871                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1872                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1873                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1874 \r
1875                                 tmp_index_x = x - 3;\r
1876                                 tmp_index_y = y + 3;\r
1877                                 tmp_coeff = 5;\r
1878                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1879                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1880                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1881 \r
1882                                 tmp_index_x = x - 1;\r
1883                                 tmp_coeff = 12;\r
1884                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1885                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1886                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1887 \r
1888                                 tmp_index_x = x + 1;\r
1889                                 tmp_coeff = 12;\r
1890                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1891                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1892                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1893 \r
1894                                 tmp_index_x = x + 3;\r
1895                                 tmp_coeff = 5;\r
1896                                 nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
1897                                 level = (BYTE)min(255, max(0, (int)nlevel));\r
1898                                 SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
1899                         }\r
1900                 }\r
1901                 break;\r
1902         }\r
1903         case 7:\r
1904         {\r
1905                 // Bayer ordered dither\r
1906                 int order = 4;\r
1907                 //create Bayer matrix\r
1908                 if (order>4) order = 4;\r
1909                 int size = (1 << (2*order));\r
1910                 BYTE* Bmatrix = (BYTE*) malloc(size * sizeof(BYTE));\r
1911                 for(int i = 0; i < size; i++) {\r
1912                         int n = order;\r
1913                         int x = i / n;\r
1914                         int y = i % n;\r
1915                         int dither = 0;\r
1916                         while (n-- > 0){\r
1917                                 dither = (((dither<<1)|((x&1) ^ (y&1)))<<1) | (y&1);\r
1918                                 x >>= 1;\r
1919                                 y >>= 1;\r
1920                         }\r
1921                         Bmatrix[i] = (BYTE)(dither);\r
1922                 }\r
1923 \r
1924                 int scale = max(0,(8-2*order));\r
1925                 int level;\r
1926                 for (long y=0;y<head.biHeight;y++){\r
1927                         info.nProgress = (long)(100*y/head.biHeight);\r
1928                         if (info.nEscape) break;\r
1929                         for (long x=0;x<head.biWidth;x++){\r
1930                                 level = BlindGetPixelIndex(x,y) >> scale;\r
1931                                 if(level > Bmatrix[ (x % order) + order * (y % order) ]){\r
1932                                         tmp.SetPixelIndex(x,y,1);\r
1933                                 } else {\r
1934                                         tmp.SetPixelIndex(x,y,0);\r
1935                                 }\r
1936                         }\r
1937                 }\r
1938 \r
1939                 free(Bmatrix);\r
1940 \r
1941                 break;\r
1942         }\r
1943         default:\r
1944         {\r
1945                 // Floyd-Steinberg error diffusion (Thanks to Steve McMahon)\r
1946                 long error,nlevel,coeff=1;\r
1947                 BYTE level;\r
1948 \r
1949                 for (long y=0;y<head.biHeight;y++){\r
1950                         info.nProgress = (long)(100*y/head.biHeight);\r
1951                         if (info.nEscape) break;\r
1952                         for (long x=0;x<head.biWidth;x++){\r
1953 \r
1954                                 level = BlindGetPixelIndex(x,y);\r
1955                                 if (level > 128){\r
1956                                         tmp.SetPixelIndex(x,y,1);\r
1957                                         error = level-255;\r
1958                                 } else {\r
1959                                         tmp.SetPixelIndex(x,y,0);\r
1960                                         error = level;\r
1961                                 }\r
1962 \r
1963                                 nlevel = GetPixelIndex(x+1,y) + (error * 7)/16;\r
1964                                 level = (BYTE)min(255,max(0,(int)nlevel));\r
1965                                 SetPixelIndex(x+1,y,level);\r
1966                                 for(int i=-1; i<2; i++){\r
1967                                         switch(i){\r
1968                                         case -1:\r
1969                                                 coeff=3; break;\r
1970                                         case 0:\r
1971                                                 coeff=5; break;\r
1972                                         case 1:\r
1973                                                 coeff=1; break;\r
1974                                         }\r
1975                                         nlevel = GetPixelIndex(x+i,y+1) + (error * coeff)/16;\r
1976                                         level = (BYTE)min(255,max(0,(int)nlevel));\r
1977                                         SetPixelIndex(x+i,y+1,level);\r
1978                                 }\r
1979                         }\r
1980                 }\r
1981         }\r
1982         }\r
1983 \r
1984         tmp.SetPaletteColor(0,0,0,0);\r
1985         tmp.SetPaletteColor(1,255,255,255);\r
1986         Transfer(tmp);\r
1987 \r
1988         return true;\r
1989 }\r
1990 ////////////////////////////////////////////////////////////////////////////////\r
1991 /**\r
1992  *      CropRotatedRectangle\r
1993  * \param topx,topy : topmost and leftmost point of the rectangle \r
1994           (topmost, and if there are 2 topmost points, the left one)\r
1995  * \param  width     : size of the right hand side of rect, from (topx,topy) roundwalking clockwise\r
1996  * \param  height    : size of the left hand side of rect, from (topx,topy) roundwalking clockwise\r
1997  * \param  angle     : angle of the right hand side of rect, from (topx,topy)\r
1998  * \param  iDst      : pointer to destination image (if 0, this image is modified)\r
1999  * \author  [VATI]\r
2000  */\r
2001 bool CxImage::CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst)\r
2002 {\r
2003         if (!pDib) return false;\r
2004 \r
2005         \r
2006         long startx,starty,endx,endy;\r
2007         double cos_angle = cos(angle/*/57.295779513082320877*/);\r
2008     double sin_angle = sin(angle/*/57.295779513082320877*/);\r
2009 \r
2010         // if there is nothing special, call the original Crop():\r
2011         if ( fabs(angle)<0.0002 )\r
2012                 return Crop( topx, topy, topx+width, topy+height, iDst);\r
2013 \r
2014         startx = min(topx, topx - (long)(sin_angle*(double)height));\r
2015         endx   = topx + (long)(cos_angle*(double)width);\r
2016         endy   = topy + (long)(cos_angle*(double)height + sin_angle*(double)width);\r
2017         // check: corners of the rectangle must be inside\r
2018         if ( IsInside( startx, topy )==false ||\r
2019                  IsInside( endx, endy ) == false )\r
2020                  return false;\r
2021 \r
2022         // first crop to bounding rectangle\r
2023         CxImage tmp(*this, true, false, true);\r
2024         // tmp.Copy(*this, true, false, true);\r
2025         if (!tmp.IsValid()){\r
2026                 strcpy(info.szLastError,tmp.GetLastError());\r
2027                 return false;\r
2028         }\r
2029     if (!tmp.Crop( startx, topy, endx, endy)){\r
2030                 strcpy(info.szLastError,tmp.GetLastError());\r
2031                 return false;\r
2032         }\r
2033         \r
2034         // the midpoint of the image now became the same as the midpoint of the rectangle\r
2035         // rotate new image with minus angle amount\r
2036     if ( false == tmp.Rotate( (float)(-angle*57.295779513082320877) ) ) // Rotate expects angle in degrees\r
2037                 return false;\r
2038 \r
2039         // crop rotated image to the original selection rectangle\r
2040     endx   = (tmp.head.biWidth+width)/2;\r
2041         startx = (tmp.head.biWidth-width)/2;\r
2042         starty = (tmp.head.biHeight+height)/2;\r
2043     endy   = (tmp.head.biHeight-height)/2;\r
2044     if ( false == tmp.Crop( startx, starty, endx, endy ) )\r
2045                 return false;\r
2046 \r
2047         if (iDst) iDst->Transfer(tmp);\r
2048         else Transfer(tmp);\r
2049 \r
2050         return true;\r
2051 }\r
2052 ////////////////////////////////////////////////////////////////////////////////\r
2053 bool CxImage::Crop(const RECT& rect, CxImage* iDst)\r
2054 {\r
2055         return Crop(rect.left, rect.top, rect.right, rect.bottom, iDst);\r
2056 }\r
2057 ////////////////////////////////////////////////////////////////////////////////\r
2058 bool CxImage::Crop(long left, long top, long right, long bottom, CxImage* iDst)\r
2059 {\r
2060         if (!pDib) return false;\r
2061 \r
2062         long startx = max(0L,min(left,head.biWidth));\r
2063         long endx = max(0L,min(right,head.biWidth));\r
2064         long starty = head.biHeight - max(0L,min(top,head.biHeight));\r
2065         long endy = head.biHeight - max(0L,min(bottom,head.biHeight));\r
2066 \r
2067         if (startx==endx || starty==endy) return false;\r
2068 \r
2069         if (startx>endx) {long tmp=startx; startx=endx; endx=tmp;}\r
2070         if (starty>endy) {long tmp=starty; starty=endy; endy=tmp;}\r
2071 \r
2072         CxImage tmp(endx-startx,endy-starty,head.biBitCount,info.dwType);\r
2073         if (!tmp.IsValid()){\r
2074                 strcpy(info.szLastError,tmp.GetLastError());\r
2075                 return false;\r
2076         }\r
2077 \r
2078         tmp.SetPalette(GetPalette(),head.biClrUsed);\r
2079         tmp.info.nBkgndIndex = info.nBkgndIndex;\r
2080         tmp.info.nBkgndColor = info.nBkgndColor;\r
2081 \r
2082         switch (head.biBitCount) {\r
2083         case 1:\r
2084         case 4:\r
2085         {\r
2086                 for(long y=starty, yd=0; y<endy; y++, yd++){\r
2087                         info.nProgress = (long)(100*(y-starty)/(endy-starty)); //<Anatoly Ivasyuk>\r
2088                         for(long x=startx, xd=0; x<endx; x++, xd++){\r
2089                                 tmp.SetPixelIndex(xd,yd,GetPixelIndex(x,y));\r
2090                         }\r
2091                 }\r
2092                 break;\r
2093         }\r
2094         case 8:\r
2095         case 24:\r
2096         {\r
2097                 int linelen = tmp.head.biWidth * tmp.head.biBitCount >> 3;\r
2098                 BYTE* pDest = tmp.info.pImage;\r
2099                 BYTE* pSrc = info.pImage + starty * info.dwEffWidth + (startx*head.biBitCount >> 3);\r
2100                 for(long y=starty; y<endy; y++){\r
2101                         info.nProgress = (long)(100*(y-starty)/(endy-starty)); //<Anatoly Ivasyuk>\r
2102                         memcpy(pDest,pSrc,linelen);\r
2103                         pDest+=tmp.info.dwEffWidth;\r
2104                         pSrc+=info.dwEffWidth;\r
2105                 }\r
2106     }\r
2107         }\r
2108 \r
2109 #if CXIMAGE_SUPPORT_ALPHA\r
2110         if (AlphaIsValid()){ //<oboolo>\r
2111                 tmp.AlphaCreate();\r
2112                 if (!tmp.AlphaIsValid()) return false;\r
2113                 BYTE* pDest = tmp.pAlpha;\r
2114                 BYTE* pSrc = pAlpha + startx + starty*head.biWidth;\r
2115                 for (long y=starty; y<endy; y++){\r
2116                         memcpy(pDest,pSrc,endx-startx);\r
2117                         pDest+=tmp.head.biWidth;\r
2118                         pSrc+=head.biWidth;\r
2119                 }\r
2120         }\r
2121 #endif //CXIMAGE_SUPPORT_ALPHA\r
2122 \r
2123         //select the destination\r
2124         if (iDst) iDst->Transfer(tmp);\r
2125         else Transfer(tmp);\r
2126 \r
2127         return true;\r
2128 }\r
2129 ////////////////////////////////////////////////////////////////////////////////\r
2130 /**\r
2131  * \param xgain, ygain : can be from 0 to 1.\r
2132  * \param xpivot, ypivot : is the center of the transformation.\r
2133  * \param bEnableInterpolation : if true, enables bilinear interpolation.\r
2134  * \return true if everything is ok \r
2135  */\r
2136 bool CxImage::Skew(float xgain, float ygain, long xpivot, long ypivot, bool bEnableInterpolation)\r
2137 {\r
2138         if (!pDib) return false;\r
2139         float nx,ny;\r
2140 \r
2141         CxImage tmp(*this);\r
2142         if (!tmp.IsValid()){\r
2143                 strcpy(info.szLastError,tmp.GetLastError());\r
2144                 return false;\r
2145         }\r
2146 \r
2147         long xmin,xmax,ymin,ymax;\r
2148         if (pSelection){\r
2149                 xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
2150                 ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
2151         } else {\r
2152                 xmin = ymin = 0;\r
2153                 xmax = head.biWidth; ymax=head.biHeight;\r
2154         }\r
2155         for(long y=ymin; y<ymax; y++){\r
2156                 info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
2157                 if (info.nEscape) break;\r
2158                 for(long x=xmin; x<xmax; x++){\r
2159 #if CXIMAGE_SUPPORT_SELECTION\r
2160                         if (BlindSelectionIsInside(x,y))\r
2161 #endif //CXIMAGE_SUPPORT_SELECTION\r
2162                         {\r
2163                                 nx = x + (xgain*(y - ypivot));\r
2164                                 ny = y + (ygain*(x - xpivot));\r
2165 #if CXIMAGE_SUPPORT_INTERPOLATION\r
2166                                 if (bEnableInterpolation){\r
2167                                         tmp.SetPixelColor(x,y,GetPixelColorInterpolated(nx, ny, CxImage::IM_BILINEAR, CxImage::OM_BACKGROUND),true);\r
2168                                 } else\r
2169 #endif //CXIMAGE_SUPPORT_INTERPOLATION\r
2170                                 {\r
2171                                         if (head.biClrUsed==0){\r
2172                                                 tmp.SetPixelColor(x,y,GetPixelColor((long)nx,(long)ny));\r
2173                                         } else {\r
2174                                                 tmp.SetPixelIndex(x,y,GetPixelIndex((long)nx,(long)ny));\r
2175                                         }\r
2176 #if CXIMAGE_SUPPORT_ALPHA\r
2177                                         tmp.AlphaSet(x,y,AlphaGet((long)nx,(long)ny));\r
2178 #endif //CXIMAGE_SUPPORT_ALPHA\r
2179                                 }\r
2180                         }\r
2181                 }\r
2182         }\r
2183         Transfer(tmp);\r
2184         return true;\r
2185 }\r
2186 ////////////////////////////////////////////////////////////////////////////////\r
2187 /**\r
2188  * Expands the borders.\r
2189  * \param left, top, right, bottom = additional dimensions, should be greater than 0.\r
2190  * \param canvascolor = border color. canvascolor.rgbReserved will set the alpha channel (if any) in the border.\r
2191  * \param iDst = pointer to destination image (if it's 0, this image is modified)\r
2192  * \return true if everything is ok \r
2193  * \author [Colin Urquhart]; changes [DP]\r
2194  */\r
2195 bool CxImage::Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage* iDst)\r
2196 {\r
2197     if (!pDib) return false;\r
2198 \r
2199     if ((left < 0) || (right < 0) || (bottom < 0) || (top < 0)) return false;\r
2200 \r
2201     long newWidth = head.biWidth + left + right;\r
2202     long newHeight = head.biHeight + top + bottom;\r
2203 \r
2204     right = left + head.biWidth - 1;\r
2205     top = bottom + head.biHeight - 1;\r
2206     \r
2207     CxImage tmp;\r
2208         tmp.CopyInfo(*this);\r
2209         if (!tmp.Create(newWidth, newHeight, head.biBitCount, info.dwType)){\r
2210                 strcpy(info.szLastError,tmp.GetLastError());\r
2211                 return false;\r
2212         }\r
2213 \r
2214     tmp.SetPalette(GetPalette(),head.biClrUsed);\r
2215 \r
2216     switch (head.biBitCount) {\r
2217     case 1:\r
2218     case 4:\r
2219                 {\r
2220                         BYTE pixel = tmp.GetNearestIndex(canvascolor);\r
2221                         for(long y=0; y < newHeight; y++){\r
2222                                 info.nProgress = (long)(100*y/newHeight);\r
2223                                 for(long x=0; x < newWidth; x++){\r
2224                                         if ((y < bottom) || (y > top) || (x < left) || (x > right)) {\r
2225                                                 tmp.SetPixelIndex(x,y, pixel);\r
2226                                         } else {\r
2227                                                 tmp.SetPixelIndex(x,y,GetPixelIndex(x-left,y-bottom));\r
2228                                         }\r
2229                                 }\r
2230                         }\r
2231                         break;\r
2232                 }\r
2233     case 8:\r
2234     case 24:\r
2235                 {\r
2236                         if (head.biBitCount == 8) {\r
2237                                 BYTE pixel = tmp.GetNearestIndex( canvascolor);\r
2238                                 memset(tmp.info.pImage, pixel,  + (tmp.info.dwEffWidth * newHeight));\r
2239                         } else {\r
2240                                 for (long y = 0; y < newHeight; ++y) {\r
2241                                         BYTE *pDest = tmp.info.pImage + (y * tmp.info.dwEffWidth);\r
2242                                         for (long x = 0; x < newWidth; ++x) {\r
2243                                                 *pDest++ = canvascolor.rgbBlue;\r
2244                                                 *pDest++ = canvascolor.rgbGreen;\r
2245                                                 *pDest++ = canvascolor.rgbRed;\r
2246                                         }\r
2247                                 }\r
2248                         }\r
2249 \r
2250                         BYTE* pDest = tmp.info.pImage + (tmp.info.dwEffWidth * bottom) + (left*(head.biBitCount >> 3));\r
2251                         BYTE* pSrc = info.pImage;\r
2252                         for(long y=bottom; y <= top; y++){\r
2253                                 info.nProgress = (long)(100*y/(1 + top - bottom));\r
2254                                 memcpy(pDest,pSrc,(head.biBitCount >> 3) * (right - left + 1));\r
2255                                 pDest+=tmp.info.dwEffWidth;\r
2256                                 pSrc+=info.dwEffWidth;\r
2257                         }\r
2258                 }\r
2259     }\r
2260 \r
2261 #if CXIMAGE_SUPPORT_SELECTION\r
2262         if (SelectionIsValid()){\r
2263                 if (!tmp.SelectionCreate())\r
2264                         return false;\r
2265                 BYTE* pSrc = SelectionGetPointer();\r
2266                 BYTE* pDst = tmp.SelectionGetPointer(left,bottom);\r
2267                 for(long y=bottom; y <= top; y++){\r
2268                         memcpy(pDst,pSrc, (right - left + 1));\r
2269                         pSrc+=head.biWidth;\r
2270                         pDst+=tmp.head.biWidth;\r
2271                 }\r
2272                 tmp.info.rSelectionBox.left = info.rSelectionBox.left + left;\r
2273                 tmp.info.rSelectionBox.right = info.rSelectionBox.right + left;\r
2274                 tmp.info.rSelectionBox.top = info.rSelectionBox.top + bottom;\r
2275                 tmp.info.rSelectionBox.bottom = info.rSelectionBox.bottom + bottom;\r
2276         }\r
2277 #endif //CXIMAGE_SUPPORT_SELECTION\r
2278 \r
2279 #if CXIMAGE_SUPPORT_ALPHA\r
2280         if (AlphaIsValid()){\r
2281                 if (!tmp.AlphaCreate())\r
2282                         return false;\r
2283                 tmp.AlphaSet(canvascolor.rgbReserved);\r
2284                 BYTE* pSrc = AlphaGetPointer();\r
2285                 BYTE* pDst = tmp.AlphaGetPointer(left,bottom);\r
2286                 for(long y=bottom; y <= top; y++){\r
2287                         memcpy(pDst,pSrc, (right - left + 1));\r
2288                         pSrc+=head.biWidth;\r
2289                         pDst+=tmp.head.biWidth;\r
2290                 }\r
2291         }\r
2292 #endif //CXIMAGE_SUPPORT_ALPHA\r
2293 \r
2294     //select the destination\r
2295         if (iDst) iDst->Transfer(tmp);\r
2296     else Transfer(tmp);\r
2297 \r
2298     return true;\r
2299 }\r
2300 ////////////////////////////////////////////////////////////////////////////////\r
2301 bool CxImage::Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst)\r
2302 {\r
2303         //thanks to <Colin Urquhart>\r
2304 \r
2305     if (!pDib) return false;\r
2306 \r
2307     if ((newx < head.biWidth) || (newy < head.biHeight)) return false;\r
2308 \r
2309     int nAddLeft = (newx - head.biWidth) / 2;\r
2310     int nAddTop = (newy - head.biHeight) / 2;\r
2311 \r
2312     return Expand(nAddLeft, nAddTop, newx - (head.biWidth + nAddLeft), newy - (head.biHeight + nAddTop), canvascolor, iDst);\r
2313 }\r
2314 ////////////////////////////////////////////////////////////////////////////////\r
2315 /**\r
2316  * Resamples the image with the correct aspect ratio, and fills the borders.\r
2317  * \param newx, newy = thumbnail size.\r
2318  * \param canvascolor = border color.\r
2319  * \param iDst = pointer to destination image (if it's 0, this image is modified).\r
2320  * \return true if everything is ok.\r
2321  * \author [Colin Urquhart]\r
2322  */\r
2323 bool CxImage::Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst)\r
2324 {\r
2325     if (!pDib) return false;\r
2326 \r
2327     if ((newx <= 0) || (newy <= 0)) return false;\r
2328 \r
2329     CxImage tmp(*this);\r
2330         if (!tmp.IsValid()){\r
2331                 strcpy(info.szLastError,tmp.GetLastError());\r
2332                 return false;\r
2333         }\r
2334 \r
2335     // determine whether we need to shrink the image\r
2336     if ((head.biWidth > newx) || (head.biHeight > newy)) {\r
2337         float fScale;\r
2338         float fAspect = (float) newx / (float) newy;\r
2339         if (fAspect * head.biHeight > head.biWidth) {\r
2340             fScale = (float) newy / head.biHeight;\r
2341         } else {\r
2342             fScale = (float) newx / head.biWidth;\r
2343         }\r
2344         tmp.Resample((long) (fScale * head.biWidth), (long) (fScale * head.biHeight), 0);\r
2345     }\r
2346 \r
2347     // expand the frame\r
2348     tmp.Expand(newx, newy, canvascolor, iDst);\r
2349 \r
2350     //select the destination\r
2351     if (iDst) iDst->Transfer(tmp);\r
2352     else Transfer(tmp);\r
2353     return true;\r
2354 }\r
2355 ////////////////////////////////////////////////////////////////////////////////\r
2356 /**\r
2357  * Perform circle_based transformations.\r
2358  * \param type - for different transformations\r
2359  * - 0 for normal (proturberant) FishEye\r
2360  * - 1 for reverse (concave) FishEye\r
2361  * - 2 for Swirle \r
2362  * - 3 for Cilinder mirror\r
2363  * - 4 for bathroom\r
2364  *\r
2365  * \param rmax - effect radius. If 0, the whole image is processed\r
2366  * \param Koeff - only for swirle\r
2367  * \author Arkadiy Olovyannikov ark(at)msun(dot)ru\r
2368  */\r
2369 bool CxImage::CircleTransform(int type,long rmax,float Koeff)\r
2370 {\r
2371         if (!pDib) return false;\r
2372 \r
2373         long nx,ny;\r
2374         double angle,radius,rnew;\r
2375 \r
2376         CxImage tmp(*this);\r
2377         if (!tmp.IsValid()){\r
2378                 strcpy(info.szLastError,tmp.GetLastError());\r
2379                 return false;\r
2380         }\r
2381 \r
2382         long xmin,xmax,ymin,ymax,xmid,ymid;\r
2383         if (pSelection){\r
2384                 xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
2385                 ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
2386         } else {\r
2387                 xmin = ymin = 0;\r
2388                 xmax = head.biWidth; ymax=head.biHeight;\r
2389         }\r
2390         \r
2391         xmid = (long) (tmp.GetWidth()/2);\r
2392         ymid = (long) (tmp.GetHeight()/2);\r
2393 \r
2394         if (!rmax) rmax=(long)sqrt((float)((xmid-xmin)*(xmid-xmin)+(ymid-ymin)*(ymid-ymin)));\r
2395         if (Koeff==0.0f) Koeff=1.0f;\r
2396 \r
2397         for(long y=ymin; y<ymax; y++){\r
2398                 info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
2399                 if (info.nEscape) break;\r
2400                 for(long x=xmin; x<xmax; x++){\r
2401 #if CXIMAGE_SUPPORT_SELECTION\r
2402                         if (BlindSelectionIsInside(x,y))\r
2403 #endif //CXIMAGE_SUPPORT_SELECTION\r
2404                         {\r
2405                                 nx=xmid-x;\r
2406                                 ny=ymid-y;\r
2407                                 radius=sqrt((float)(nx*nx+ny*ny));\r
2408                                 if (radius<rmax) {\r
2409                                         angle=atan2((double)ny,(double)nx);\r
2410                                         if (type==0)      rnew=radius*radius/rmax;\r
2411                                         else if (type==1) rnew=sqrt(radius*rmax);\r
2412                                         else if (type==2) {rnew=radius;angle += radius / Koeff;}\r
2413                                         else rnew = 1; // potentially uninitialized\r
2414                                         if (type<3){\r
2415                                                 nx = xmid + (long)(rnew * cos(angle));\r
2416                                                 ny = ymid - (long)(rnew * sin(angle));\r
2417                                         }\r
2418                                         else if (type==3){\r
2419                                                 nx = (long)fabs((angle*xmax/6.2831852));\r
2420                                                 ny = (long)fabs((radius*ymax/rmax));\r
2421                                         }\r
2422                                         else {\r
2423                                                 nx=x+(x%32)-16;\r
2424                                                 ny=y;\r
2425                                         }\r
2426 //                                      nx=max(xmin,min(nx,xmax));\r
2427 //                                      ny=max(ymin,min(ny,ymax));\r
2428                                 }\r
2429                                 else { nx=-1;ny=-1;}\r
2430                                 if (head.biClrUsed==0){\r
2431                                         tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));\r
2432                                 } else {\r
2433                                         tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));\r
2434                                 }\r
2435 #if CXIMAGE_SUPPORT_ALPHA\r
2436                                 tmp.AlphaSet(x,y,AlphaGet(nx,ny));\r
2437 #endif //CXIMAGE_SUPPORT_ALPHA\r
2438                         }\r
2439                 }\r
2440         }\r
2441         Transfer(tmp);\r
2442         return true;\r
2443 }\r
2444 ////////////////////////////////////////////////////////////////////////////////\r
2445 /**\r
2446  * Faster way to almost properly shrink image. Algorithm produces results comparable with "high resoultion shrink"\r
2447  * when resulting image is much smaller (that would be 3 times or more) than original. When\r
2448  * resulting image is only slightly smaller, results are closer to nearest pixel.\r
2449  * This algorithm works by averaging, but it does not calculate fractions of pixels. It adds whole\r
2450  * source pixels to the best destionation. It is not geometrically "correct".\r
2451  * It's main advantage over "high" resulution shrink is speed, so it's useful, when speed is most\r
2452  * important (preview thumbnails, "map" view, ...).\r
2453  * Method is optimized for RGB24 images.\r
2454  * \r
2455  * \param  newx, newy - size of destination image (must be smaller than original!)\r
2456  * \param  iDst - pointer to destination image (if it's 0, this image is modified)\r
2457  * \param  bChangeBpp - flag points to change result image bpp (if it's true, this result image bpp = 24 (useful for B/W image thumbnails))\r
2458  *\r
2459  * \return true if everything is ok\r
2460  * \author [bd], 9.2004; changes [Artiom Mirolubov], 1.2005\r
2461  */\r
2462 bool CxImage::QIShrink(long newx, long newy, CxImage* const iDst, bool bChangeBpp)\r
2463 {\r
2464         if (!pDib) return false;\r
2465         \r
2466         if (newx>head.biWidth || newy>head.biHeight) { \r
2467                 //let me repeat... this method can't enlarge image\r
2468                 strcpy(info.szLastError,"QIShrink can't enlarge image");\r
2469                 return false;\r
2470         }\r
2471 \r
2472         if (newx==head.biWidth && newy==head.biHeight) {\r
2473                 //image already correct size (just copy and return)\r
2474                 if (iDst) iDst->Copy(*this);\r
2475                 return true;\r
2476         }//if\r
2477         \r
2478         //create temporary destination image\r
2479         CxImage newImage;\r
2480         newImage.CopyInfo(*this);\r
2481         newImage.Create(newx,newy,(bChangeBpp)?24:head.biBitCount,GetType());\r
2482         newImage.SetPalette(GetPalette());\r
2483         if (!newImage.IsValid()){\r
2484                 strcpy(info.szLastError,newImage.GetLastError());\r
2485                 return false;\r
2486         }\r
2487 \r
2488         //and alpha channel if required\r
2489 #if CXIMAGE_SUPPORT_ALPHA\r
2490         if (AlphaIsValid()) newImage.AlphaCreate();\r
2491 #endif\r
2492 \r
2493     const int oldx = head.biWidth;\r
2494     const int oldy = head.biHeight;\r
2495 \r
2496     int accuCellSize = 4;\r
2497 #if CXIMAGE_SUPPORT_ALPHA\r
2498         BYTE *alphaPtr;\r
2499         if (AlphaIsValid()) accuCellSize=5;\r
2500 #endif\r
2501 \r
2502     unsigned int *accu = new unsigned int[newx*accuCellSize];      //array for suming pixels... one pixel for every destination column\r
2503     unsigned int *accuPtr;                              //pointer for walking through accu\r
2504     //each cell consists of blue, red, green component and count of pixels summed in this cell\r
2505     memset(accu, 0, newx * accuCellSize * sizeof(unsigned int));  //clear accu\r
2506 \r
2507     if (!IsIndexed()) {\r
2508                 //RGB24 version with pointers\r
2509                 BYTE *destPtr, *srcPtr, *destPtrS, *srcPtrS;        //destination and source pixel, and beginnings of current row\r
2510                 srcPtrS=(BYTE*)BlindGetPixelPointer(0,0);\r
2511                 destPtrS=(BYTE*)newImage.BlindGetPixelPointer(0,0);\r
2512                 int ex=0, ey=0;                                               //ex and ey replace division... \r
2513                 int dy=0;\r
2514                 //(we just add pixels, until by adding newx or newy we get a number greater than old size... then\r
2515                 // it's time to move to next pixel)\r
2516         \r
2517                 for(int y=0; y<oldy; y++){                                    //for all source rows\r
2518                         info.nProgress = (long)(100*y/oldy); if (info.nEscape) break;\r
2519                         ey += newy;                                                   \r
2520                         ex = 0;                                                       //restart with ex = 0\r
2521                         accuPtr=accu;                                                 //restart from beginning of accu\r
2522                         srcPtr=srcPtrS;                                               //and from new source line\r
2523 #if CXIMAGE_SUPPORT_ALPHA\r
2524                         alphaPtr = AlphaGetPointer(0, y);\r
2525 #endif\r
2526 \r
2527                         for(int x=0; x<oldx; x++){                                    //for all source columns\r
2528                                 ex += newx;\r
2529                                 *accuPtr     += *(srcPtr++);                                  //add current pixel to current accu slot\r
2530                                 *(accuPtr+1) += *(srcPtr++);\r
2531                                 *(accuPtr+2) += *(srcPtr++);\r
2532                                 (*(accuPtr+3)) ++;\r
2533 #if CXIMAGE_SUPPORT_ALPHA\r
2534                                 if (alphaPtr) *(accuPtr+4) += *(alphaPtr++);\r
2535 #endif\r
2536                                 if (ex>oldx) {                                                //when we reach oldx, it's time to move to new slot\r
2537                                         accuPtr += accuCellSize;\r
2538                                         ex -= oldx;                                                   //(substract oldx from ex and resume from there on)\r
2539                                 }//if (ex overflow)\r
2540                         }//for x\r
2541 \r
2542                         if (ey>=oldy) {                                                 //now when this happens\r
2543                                 ey -= oldy;                                                     //it's time to move to new destination row\r
2544                                 destPtr = destPtrS;                                             //reset pointers to proper initial values\r
2545                                 accuPtr = accu;\r
2546 #if CXIMAGE_SUPPORT_ALPHA\r
2547                                 alphaPtr = newImage.AlphaGetPointer(0, dy++);\r
2548 #endif\r
2549                                 for (int k=0; k<newx; k++) {                                    //copy accu to destination row (divided by number of pixels in each slot)\r
2550                                         *(destPtr++) = (BYTE)(*(accuPtr) / *(accuPtr+3));\r
2551                                         *(destPtr++) = (BYTE)(*(accuPtr+1) / *(accuPtr+3));\r
2552                                         *(destPtr++) = (BYTE)(*(accuPtr+2) / *(accuPtr+3));\r
2553 #if CXIMAGE_SUPPORT_ALPHA\r
2554                                         if (alphaPtr) *(alphaPtr++) = (BYTE)(*(accuPtr+4) / *(accuPtr+3));\r
2555 #endif\r
2556                                         accuPtr += accuCellSize;\r
2557                                 }//for k\r
2558                                 memset(accu, 0, newx * accuCellSize * sizeof(unsigned int));                   //clear accu\r
2559                                 destPtrS += newImage.info.dwEffWidth;\r
2560                         }//if (ey overflow)\r
2561 \r
2562                         srcPtrS += info.dwEffWidth;                                     //next round we start from new source row\r
2563                 }//for y\r
2564     } else {\r
2565                 //standard version with GetPixelColor...\r
2566                 int ex=0, ey=0;                                               //ex and ey replace division... \r
2567                 int dy=0;\r
2568                 //(we just add pixels, until by adding newx or newy we get a number greater than old size... then\r
2569                 // it's time to move to next pixel)\r
2570                 RGBQUAD rgb;\r
2571         \r
2572                 for(int y=0; y<oldy; y++){                                    //for all source rows\r
2573                         info.nProgress = (long)(100*y/oldy); if (info.nEscape) break;\r
2574                         ey += newy;                                                   \r
2575                         ex = 0;                                                       //restart with ex = 0\r
2576                         accuPtr=accu;                                                 //restart from beginning of accu\r
2577                         for(int x=0; x<oldx; x++){                                    //for all source columns\r
2578                                 ex += newx;\r
2579                                 rgb = GetPixelColor(x, y, true);\r
2580                                 *accuPtr     += rgb.rgbBlue;                                  //add current pixel to current accu slot\r
2581                                 *(accuPtr+1) += rgb.rgbRed;\r
2582                                 *(accuPtr+2) += rgb.rgbGreen;\r
2583                                 (*(accuPtr+3)) ++;\r
2584 #if CXIMAGE_SUPPORT_ALPHA\r
2585                                 if (pAlpha) *(accuPtr+4) += rgb.rgbReserved;\r
2586 #endif\r
2587                                 if (ex>oldx) {                                                //when we reach oldx, it's time to move to new slot\r
2588                                         accuPtr += accuCellSize;\r
2589                                         ex -= oldx;                                                   //(substract oldx from ex and resume from there on)\r
2590                                 }//if (ex overflow)\r
2591                         }//for x\r
2592 \r
2593                         if (ey>=oldy) {                                                 //now when this happens\r
2594                                 ey -= oldy;                                                     //it's time to move to new destination row\r
2595                                 accuPtr = accu;\r
2596                                 for (int dx=0; dx<newx; dx++) {                                 //copy accu to destination row (divided by number of pixels in each slot)\r
2597                                         rgb.rgbBlue = (BYTE)(*(accuPtr) / *(accuPtr+3));\r
2598                                         rgb.rgbRed  = (BYTE)(*(accuPtr+1) / *(accuPtr+3));\r
2599                                         rgb.rgbGreen= (BYTE)(*(accuPtr+2) / *(accuPtr+3));\r
2600 #if CXIMAGE_SUPPORT_ALPHA\r
2601                                         if (pAlpha) rgb.rgbReserved = (BYTE)(*(accuPtr+4) / *(accuPtr+3));\r
2602 #endif\r
2603                                         newImage.SetPixelColor(dx, dy, rgb, pAlpha!=0);\r
2604                                         accuPtr += accuCellSize;\r
2605                                 }//for dx\r
2606                                 memset(accu, 0, newx * accuCellSize * sizeof(unsigned int));                   //clear accu\r
2607                                 dy++;\r
2608                         }//if (ey overflow)\r
2609                 }//for y\r
2610     }//if\r
2611 \r
2612     delete [] accu;                                                 //delete helper array\r
2613         \r
2614         //copy new image to the destination\r
2615         if (iDst) \r
2616                 iDst->Transfer(newImage);\r
2617         else \r
2618                 Transfer(newImage);\r
2619     return true;\r
2620 \r
2621 }\r
2622 \r
2623 ////////////////////////////////////////////////////////////////////////////////\r
2624 #endif //CXIMAGE_SUPPORT_TRANSFORMATION\r