]> Creatis software - clitk.git/blob - utilities/CxImage/ximapal.cpp
f7de9eb73768c654eb50a3bc58f3caad01ede1b5
[clitk.git] / utilities / CxImage / ximapal.cpp
1 // xImaPal.cpp : Palette and Pixel 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 \r
8 ////////////////////////////////////////////////////////////////////////////////\r
9 /**\r
10  * returns the palette dimension in byte\r
11  */\r
12 DWORD CxImage::GetPaletteSize()\r
13 {\r
14         return (head.biClrUsed * sizeof(RGBQUAD));\r
15 }\r
16 ////////////////////////////////////////////////////////////////////////////////\r
17 void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha)\r
18 {\r
19         if ((pDib)&&(head.biClrUsed)){\r
20                 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
21                 if (idx<head.biClrUsed){\r
22                         long ldx=idx*sizeof(RGBQUAD);\r
23                         iDst[ldx++] = (BYTE) b;\r
24                         iDst[ldx++] = (BYTE) g;\r
25                         iDst[ldx++] = (BYTE) r;\r
26                         iDst[ldx] = (BYTE) alpha;\r
27                         info.last_c_isvalid = false;\r
28                 }\r
29         }\r
30 }\r
31 ////////////////////////////////////////////////////////////////////////////////\r
32 void CxImage::SetPaletteColor(BYTE idx, RGBQUAD c)\r
33 {\r
34         if ((pDib)&&(head.biClrUsed)){\r
35                 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
36                 if (idx<head.biClrUsed){\r
37                         long ldx=idx*sizeof(RGBQUAD);\r
38                         iDst[ldx++] = (BYTE) c.rgbBlue;\r
39                         iDst[ldx++] = (BYTE) c.rgbGreen;\r
40                         iDst[ldx++] = (BYTE) c.rgbRed;\r
41                         iDst[ldx] = (BYTE) c.rgbReserved;\r
42                         info.last_c_isvalid = false;\r
43                 }\r
44         }\r
45 }\r
46 ////////////////////////////////////////////////////////////////////////////////\r
47 void CxImage::SetPaletteColor(BYTE idx, COLORREF cr)\r
48 {\r
49         if ((pDib)&&(head.biClrUsed)){\r
50                 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
51                 if (idx<head.biClrUsed){\r
52                         long ldx=idx*sizeof(RGBQUAD);\r
53                         iDst[ldx++] = (BYTE) GetBValue(cr);\r
54                         iDst[ldx++] = (BYTE) GetGValue(cr);\r
55                         iDst[ldx++] = (BYTE) GetRValue(cr);\r
56                         iDst[ldx] = (BYTE) 0;\r
57                         info.last_c_isvalid = false;\r
58                 }\r
59         }\r
60 }\r
61 ////////////////////////////////////////////////////////////////////////////////\r
62 /**\r
63  * returns the pointer to the first palette index\r
64  */\r
65 RGBQUAD* CxImage::GetPalette() const\r
66 {\r
67         if ((pDib)&&(head.biClrUsed))\r
68                 return (RGBQUAD*)((BYTE*)pDib + sizeof(BITMAPINFOHEADER));\r
69         return NULL;\r
70 }\r
71 ////////////////////////////////////////////////////////////////////////////////\r
72 /**\r
73  * Returns the color of the specified index.\r
74  */\r
75 RGBQUAD CxImage::GetPaletteColor(BYTE idx)\r
76 {\r
77         RGBQUAD rgb = {0,0,0,0};\r
78         if ((pDib)&&(head.biClrUsed)){\r
79                 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
80                 if (idx<head.biClrUsed){\r
81                         long ldx=idx*sizeof(RGBQUAD);\r
82                         rgb.rgbBlue = iDst[ldx++];\r
83                         rgb.rgbGreen=iDst[ldx++];\r
84                         rgb.rgbRed =iDst[ldx++];\r
85                         rgb.rgbReserved = iDst[ldx];\r
86                 }\r
87         }\r
88         return rgb;\r
89 }\r
90 ////////////////////////////////////////////////////////////////////////////////\r
91 /**\r
92  * Returns the palette index of the specified pixel.\r
93  */\r
94 BYTE CxImage::GetPixelIndex(long x,long y)\r
95 {\r
96         if ((pDib==NULL)||(head.biClrUsed==0)) return 0;\r
97 \r
98         if ((x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) {\r
99                 if (info.nBkgndIndex >= 0)      return (BYTE)info.nBkgndIndex;\r
100                 else return *info.pImage;\r
101         }\r
102         if (head.biBitCount==8){\r
103                 return info.pImage[y*info.dwEffWidth + x];\r
104         } else {\r
105                 BYTE pos;\r
106                 BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];\r
107                 if (head.biBitCount==4){\r
108                         pos = (BYTE)(4*(1-x%2));\r
109                         iDst &= (0x0F<<pos);\r
110                         return (BYTE)(iDst >> pos);\r
111                 } else if (head.biBitCount==1){\r
112                         pos = (BYTE)(7-x%8);\r
113                         iDst &= (0x01<<pos);\r
114                         return (BYTE)(iDst >> pos);\r
115                 }\r
116         }\r
117         return 0;\r
118 }\r
119 ////////////////////////////////////////////////////////////////////////////////\r
120 BYTE CxImage::BlindGetPixelIndex(const long x,const long y)\r
121 {\r
122 #ifdef _DEBUG\r
123         if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y))\r
124   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
125                 throw 0;\r
126   #else\r
127                 return 0;\r
128   #endif\r
129 #endif\r
130 \r
131         if (head.biBitCount==8){\r
132                 return info.pImage[y*info.dwEffWidth + x];\r
133         } else {\r
134                 BYTE pos;\r
135                 BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];\r
136                 if (head.biBitCount==4){\r
137                         pos = (BYTE)(4*(1-x%2));\r
138                         iDst &= (0x0F<<pos);\r
139                         return (BYTE)(iDst >> pos);\r
140                 } else if (head.biBitCount==1){\r
141                         pos = (BYTE)(7-x%8);\r
142                         iDst &= (0x01<<pos);\r
143                         return (BYTE)(iDst >> pos);\r
144                 }\r
145         }\r
146         return 0;\r
147 }\r
148 ////////////////////////////////////////////////////////////////////////////////\r
149 RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha)\r
150 {\r
151 //      RGBQUAD rgb={0,0,0,0};\r
152         RGBQUAD rgb=info.nBkgndColor; //<mpwolski>\r
153         if ((pDib==NULL)||(x<0)||(y<0)||\r
154                 (x>=head.biWidth)||(y>=head.biHeight)){\r
155                 if (info.nBkgndIndex >= 0){\r
156                         if (head.biBitCount<24) return GetPaletteColor((BYTE)info.nBkgndIndex);\r
157                         else return info.nBkgndColor;\r
158                 } else if (pDib) return GetPixelColor(0,0);\r
159                 return rgb;\r
160         }\r
161 \r
162         if (head.biClrUsed){\r
163                 rgb = GetPaletteColor(BlindGetPixelIndex(x,y));\r
164         } else {\r
165                 BYTE* iDst  = info.pImage + y*info.dwEffWidth + x*3;\r
166                 rgb.rgbBlue = *iDst++;\r
167                 rgb.rgbGreen= *iDst++;\r
168                 rgb.rgbRed  = *iDst;\r
169         }\r
170 #if CXIMAGE_SUPPORT_ALPHA\r
171         if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);\r
172 #else\r
173         rgb.rgbReserved = 0;\r
174 #endif //CXIMAGE_SUPPORT_ALPHA\r
175         return rgb;\r
176 }\r
177 ////////////////////////////////////////////////////////////////////////////////\r
178 /**\r
179  * This is (a bit) faster version of GetPixelColor. \r
180  * It tests bounds only in debug mode (_DEBUG defined).\r
181  * \r
182  * It is an error to request out-of-borders pixel with this method. \r
183  * In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode. \r
184  * \author ***bd*** 2.2004\r
185  */\r
186 RGBQUAD CxImage::BlindGetPixelColor(const long x,const long y, bool bGetAlpha)\r
187 {\r
188   RGBQUAD rgb;\r
189 #ifdef _DEBUG\r
190         if ((pDib==NULL) || !IsInside(x,y))\r
191   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
192                 throw 0;\r
193   #else\r
194                 {rgb.rgbReserved = 0; return rgb;}\r
195   #endif\r
196 #endif\r
197 \r
198         if (head.biClrUsed){\r
199                 rgb = GetPaletteColor(BlindGetPixelIndex(x,y));\r
200         } else {\r
201                 BYTE* iDst  = info.pImage + y*info.dwEffWidth + x*3;\r
202                 rgb.rgbBlue = *iDst++;\r
203                 rgb.rgbGreen= *iDst++;\r
204                 rgb.rgbRed  = *iDst;\r
205                 rgb.rgbReserved = 0; //needed for images without alpha layer\r
206         }\r
207 #if CXIMAGE_SUPPORT_ALPHA\r
208         if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);\r
209 #else\r
210         rgb.rgbReserved = 0;\r
211 #endif //CXIMAGE_SUPPORT_ALPHA\r
212         return rgb;\r
213 }\r
214 ////////////////////////////////////////////////////////////////////////////////\r
215 BYTE CxImage::GetPixelGray(long x, long y)\r
216 {\r
217         RGBQUAD color = GetPixelColor(x,y);\r
218         return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);\r
219 }\r
220 ////////////////////////////////////////////////////////////////////////////////\r
221 void CxImage::BlindSetPixelIndex(long x,long y,BYTE i)\r
222 {\r
223 #ifdef _DEBUG\r
224         if ((pDib==NULL)||(head.biClrUsed==0)||\r
225                 (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight))\r
226   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
227                 throw 0;\r
228   #else\r
229                 return;\r
230   #endif\r
231 #endif\r
232 \r
233         if (head.biBitCount==8){\r
234                 info.pImage[y*info.dwEffWidth + x]=i;\r
235                 return;\r
236         } else {\r
237                 BYTE pos;\r
238                 BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);\r
239                 if (head.biBitCount==4){\r
240                         pos = (BYTE)(4*(1-x%2));\r
241                         *iDst &= ~(0x0F<<pos);\r
242                         *iDst |= ((i & 0x0F)<<pos);\r
243                         return;\r
244                 } else if (head.biBitCount==1){\r
245                         pos = (BYTE)(7-x%8);\r
246                         *iDst &= ~(0x01<<pos);\r
247                         *iDst |= ((i & 0x01)<<pos);\r
248                         return;\r
249                 }\r
250         }\r
251 }\r
252 ////////////////////////////////////////////////////////////////////////////////\r
253 void CxImage::SetPixelIndex(long x,long y,BYTE i)\r
254 {\r
255         if ((pDib==NULL)||(head.biClrUsed==0)||\r
256                 (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) return ;\r
257 \r
258         if (head.biBitCount==8){\r
259                 info.pImage[y*info.dwEffWidth + x]=i;\r
260                 return;\r
261         } else {\r
262                 BYTE pos;\r
263                 BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);\r
264                 if (head.biBitCount==4){\r
265                         pos = (BYTE)(4*(1-x%2));\r
266                         *iDst &= ~(0x0F<<pos);\r
267                         *iDst |= ((i & 0x0F)<<pos);\r
268                         return;\r
269                 } else if (head.biBitCount==1){\r
270                         pos = (BYTE)(7-x%8);\r
271                         *iDst &= ~(0x01<<pos);\r
272                         *iDst |= ((i & 0x01)<<pos);\r
273                         return;\r
274                 }\r
275         }\r
276 }\r
277 ////////////////////////////////////////////////////////////////////////////////\r
278 void CxImage::SetPixelColor(long x,long y,COLORREF cr)\r
279 {\r
280         SetPixelColor(x,y,RGBtoRGBQUAD(cr));\r
281 }\r
282 ////////////////////////////////////////////////////////////////////////////////\r
283 void CxImage::BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)\r
284 {\r
285 #ifdef _DEBUG\r
286         if ((pDib==NULL)||(x<0)||(y<0)||\r
287                 (x>=head.biWidth)||(y>=head.biHeight))\r
288   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
289                 throw 0;\r
290   #else\r
291                 return;\r
292   #endif\r
293 #endif\r
294         if (head.biClrUsed)\r
295                 BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
296         else {\r
297                 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
298                 *iDst++ = c.rgbBlue;\r
299                 *iDst++ = c.rgbGreen;\r
300                 *iDst   = c.rgbRed;\r
301         }\r
302 #if CXIMAGE_SUPPORT_ALPHA\r
303         if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
304 #endif //CXIMAGE_SUPPORT_ALPHA\r
305 }\r
306 ////////////////////////////////////////////////////////////////////////////////\r
307 void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)\r
308 {\r
309         if ((pDib==NULL)||(x<0)||(y<0)||\r
310                 (x>=head.biWidth)||(y>=head.biHeight)) return;\r
311         if (head.biClrUsed)\r
312                 BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
313         else {\r
314                 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
315                 *iDst++ = c.rgbBlue;\r
316                 *iDst++ = c.rgbGreen;\r
317                 *iDst   = c.rgbRed;\r
318         }\r
319 #if CXIMAGE_SUPPORT_ALPHA\r
320         if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
321 #endif //CXIMAGE_SUPPORT_ALPHA\r
322 }\r
323 ////////////////////////////////////////////////////////////////////////////////\r
324 /**\r
325  * Blends the current pixel color with a new color.\r
326  * \param x,y = pixel\r
327  * \param c = new color\r
328  * \param blend = can be from 0 (no effect) to 1 (full effect).\r
329  * \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved\r
330  */\r
331 void CxImage::BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha)\r
332 {\r
333         if ((pDib==NULL)||(x<0)||(y<0)||\r
334                 (x>=head.biWidth)||(y>=head.biHeight)) return;\r
335 \r
336         int a0 = (int)(256*blend);\r
337         int a1 = 256 - a0;\r
338 \r
339         RGBQUAD c0 = BlindGetPixelColor(x,y);\r
340         c.rgbRed  = (BYTE)((c.rgbRed * a0 + c0.rgbRed * a1)>>8);\r
341         c.rgbBlue  = (BYTE)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8);\r
342         c.rgbGreen  = (BYTE)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8);\r
343 \r
344         if (head.biClrUsed)\r
345                 BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
346         else {\r
347                 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
348                 *iDst++ = c.rgbBlue;\r
349                 *iDst++ = c.rgbGreen;\r
350                 *iDst   = c.rgbRed;\r
351 #if CXIMAGE_SUPPORT_ALPHA\r
352                 if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
353 #endif //CXIMAGE_SUPPORT_ALPHA\r
354         }\r
355 }\r
356 ////////////////////////////////////////////////////////////////////////////////\r
357 /**\r
358  * Returns the best palette index that matches a specified color.\r
359  */\r
360 BYTE CxImage::GetNearestIndex(RGBQUAD c)\r
361 {\r
362         if ((pDib==NULL)||(head.biClrUsed==0)) return 0;\r
363 \r
364         // <RJ> check matching with the previous result\r
365         if (info.last_c_isvalid && (*(long*)&info.last_c == *(long*)&c)) return info.last_c_index;\r
366         info.last_c = c;\r
367         info.last_c_isvalid = true;\r
368 \r
369         BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
370         long distance=200000;\r
371         int i,j = 0;\r
372         long k,l;\r
373         int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant);\r
374         for(i=0,l=0;i<m;i++,l+=sizeof(RGBQUAD)){\r
375                 k = (iDst[l]-c.rgbBlue)*(iDst[l]-c.rgbBlue)+\r
376                         (iDst[l+1]-c.rgbGreen)*(iDst[l+1]-c.rgbGreen)+\r
377                         (iDst[l+2]-c.rgbRed)*(iDst[l+2]-c.rgbRed);\r
378 //              k = abs(iDst[l]-c.rgbBlue)+abs(iDst[l+1]-c.rgbGreen)+abs(iDst[l+2]-c.rgbRed);\r
379                 if (k==0){\r
380                         j=i;\r
381                         break;\r
382                 }\r
383                 if (k<distance){\r
384                         distance=k;\r
385                         j=i;\r
386                 }\r
387         }\r
388         info.last_c_index = (BYTE)j;\r
389         return (BYTE)j;\r
390 }\r
391 ////////////////////////////////////////////////////////////////////////////////\r
392 /**\r
393  * swaps the blue and red components (for RGB images)\r
394  * \param buffer : pointer to the pixels\r
395  * \param length : number of bytes to swap. lenght may not exceed the scan line.\r
396  */\r
397 void CxImage::RGBtoBGR(BYTE *buffer, int length)\r
398 {\r
399         if (buffer && (head.biClrUsed==0)){\r
400                 BYTE temp;\r
401                 length = min(length,(int)info.dwEffWidth);\r
402                 length = min(length,(int)(3*head.biWidth));\r
403                 for (int i=0;i<length;i+=3){\r
404                         temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp;\r
405                 }\r
406         }\r
407 }\r
408 ////////////////////////////////////////////////////////////////////////////////\r
409 RGBQUAD CxImage::RGBtoRGBQUAD(COLORREF cr)\r
410 {\r
411         RGBQUAD c;\r
412         c.rgbRed = GetRValue(cr);       /* get R, G, and B out of DWORD */\r
413         c.rgbGreen = GetGValue(cr);\r
414         c.rgbBlue = GetBValue(cr);\r
415         c.rgbReserved=0;\r
416         return c;\r
417 }\r
418 ////////////////////////////////////////////////////////////////////////////////\r
419 COLORREF CxImage::RGBQUADtoRGB (RGBQUAD c)\r
420 {\r
421         return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue);\r
422 }\r
423 ////////////////////////////////////////////////////////////////////////////////\r
424 /**\r
425  * Returns the color of the specified index.\r
426  * \param i = palette index\r
427  * \param r, g, b = output color channels\r
428  */\r
429 bool CxImage::GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b)\r
430 {\r
431         RGBQUAD* ppal=GetPalette();\r
432         if (ppal) {\r
433                 *r = ppal[i].rgbRed;\r
434                 *g = ppal[i].rgbGreen;\r
435                 *b = ppal[i].rgbBlue; \r
436                 return true;\r
437         }\r
438         return false;\r
439 }\r
440 ////////////////////////////////////////////////////////////////////////////////\r
441 void CxImage::SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b)\r
442 {\r
443         if ((!r)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
444         if (!g) g = r;\r
445         if (!b) b = g;\r
446         RGBQUAD* ppal=GetPalette();\r
447         DWORD m=min(n,head.biClrUsed);\r
448         for (DWORD i=0; i<m;i++){\r
449                 ppal[i].rgbRed=r[i];\r
450                 ppal[i].rgbGreen=g[i];\r
451                 ppal[i].rgbBlue=b[i];\r
452         }\r
453         info.last_c_isvalid = false;\r
454 }\r
455 ////////////////////////////////////////////////////////////////////////////////\r
456 void CxImage::SetPalette(rgb_color *rgb,DWORD nColors)\r
457 {\r
458         if ((!rgb)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
459         RGBQUAD* ppal=GetPalette();\r
460         DWORD m=min(nColors,head.biClrUsed);\r
461         for (DWORD i=0; i<m;i++){\r
462                 ppal[i].rgbRed=rgb[i].r;\r
463                 ppal[i].rgbGreen=rgb[i].g;\r
464                 ppal[i].rgbBlue=rgb[i].b;\r
465         }\r
466         info.last_c_isvalid = false;\r
467 }\r
468 ////////////////////////////////////////////////////////////////////////////////\r
469 void CxImage::SetPalette(RGBQUAD* pPal,DWORD nColors)\r
470 {\r
471         if ((pPal==NULL)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
472         memcpy(GetPalette(),pPal,min(GetPaletteSize(),nColors*sizeof(RGBQUAD)));\r
473         info.last_c_isvalid = false;\r
474 }\r
475 ////////////////////////////////////////////////////////////////////////////////\r
476 /**\r
477  * Sets (or replaces) the palette to gray scale palette.\r
478  * The function doesn't change the pixels; for standard\r
479  * gray scale conversion use GrayScale().\r
480  */\r
481 void CxImage::SetGrayPalette()\r
482 {\r
483         if ((pDib==NULL)||(head.biClrUsed==0)) return;\r
484         RGBQUAD* pal=GetPalette();\r
485         for (DWORD ni=0;ni<head.biClrUsed;ni++)\r
486                 pal[ni].rgbBlue=pal[ni].rgbGreen = pal[ni].rgbRed = (BYTE)(ni*(255/(head.biClrUsed-1)));\r
487 }\r
488 ////////////////////////////////////////////////////////////////////////////////\r
489 /**\r
490  * Colorize the palette.\r
491  * \sa Colorize\r
492  */\r
493 void CxImage::BlendPalette(COLORREF cr,long perc)\r
494 {\r
495         if ((pDib==NULL)||(head.biClrUsed==0)) return;\r
496         BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
497         DWORD i,r,g,b;\r
498         RGBQUAD* pPal=(RGBQUAD*)iDst;\r
499         r = GetRValue(cr);\r
500         g = GetGValue(cr);\r
501         b = GetBValue(cr);\r
502         if (perc>100) perc=100;\r
503         for(i=0;i<head.biClrUsed;i++){\r
504                 pPal[i].rgbBlue=(BYTE)((pPal[i].rgbBlue*(100-perc)+b*perc)/100);\r
505                 pPal[i].rgbGreen =(BYTE)((pPal[i].rgbGreen*(100-perc)+g*perc)/100);\r
506                 pPal[i].rgbRed =(BYTE)((pPal[i].rgbRed*(100-perc)+r*perc)/100);\r
507         }\r
508 }\r
509 ////////////////////////////////////////////////////////////////////////////////\r
510 /**\r
511  * Returns true if the image has 256 colors and a linear grey scale palette.\r
512  */\r
513 bool CxImage::IsGrayScale()\r
514 {\r
515         RGBQUAD* ppal=GetPalette();\r
516         if(!(pDib && ppal && head.biClrUsed)) return false;\r
517         for(DWORD i=0;i<head.biClrUsed;i++){\r
518                 if (ppal[i].rgbBlue!=i || ppal[i].rgbGreen!=i || ppal[i].rgbRed!=i) return false;\r
519         }\r
520         return true;\r
521 }\r
522 ////////////////////////////////////////////////////////////////////////////////\r
523 /**\r
524  * swap two indexes in the image and their colors in the palette\r
525  */\r
526 void CxImage::SwapIndex(BYTE idx1, BYTE idx2)\r
527 {\r
528         RGBQUAD* ppal=GetPalette();\r
529         if(!(pDib && ppal)) return;\r
530         //swap the colors\r
531         RGBQUAD tempRGB=GetPaletteColor(idx1);\r
532         SetPaletteColor(idx1,GetPaletteColor(idx2));\r
533         SetPaletteColor(idx2,tempRGB);\r
534         //swap the pixels\r
535         BYTE idx;\r
536         for(long y=0; y < head.biHeight; y++){\r
537                 for(long x=0; x < head.biWidth; x++){\r
538                         idx=BlindGetPixelIndex(x,y);\r
539                         if (idx==idx1) BlindSetPixelIndex(x,y,idx2);\r
540                         if (idx==idx2) BlindSetPixelIndex(x,y,idx1);\r
541                 }\r
542         }\r
543 }\r
544 ////////////////////////////////////////////////////////////////////////////////\r
545 /**\r
546  * swap Red and Blue colors\r
547  */\r
548 void CxImage::SwapRGB2BGR()\r
549 {\r
550         if (!pDib) return;\r
551 \r
552         if (head.biClrUsed){\r
553                 RGBQUAD* ppal=GetPalette();\r
554                 BYTE b;\r
555                 if(!ppal) return;\r
556                 for(WORD a=0;a<head.biClrUsed;a++){\r
557                         b=ppal[a].rgbBlue; ppal[a].rgbBlue=ppal[a].rgbRed; ppal[a].rgbRed=b;\r
558                 }\r
559         } else {\r
560                 for(long y=0;y<head.biHeight;y++){\r
561                         RGBtoBGR(GetBits(y),3*head.biWidth);\r
562                 }\r
563         }\r
564 }\r
565 ////////////////////////////////////////////////////////////////////////////////\r
566 bool CxImage::IsTransparent(long x, long y)\r
567 {\r
568         if (!pDib) return false;\r
569 \r
570         if (info.nBkgndIndex>=0){\r
571                 if (head.biClrUsed){\r
572                         if (GetPixelIndex(x,y) == info.nBkgndIndex) return true;\r
573                 } else {\r
574                         RGBQUAD ct = info.nBkgndColor;\r
575                         RGBQUAD c = GetPixelColor(x,y,false);\r
576                         if (*(long*)&c==*(long*)&ct) return true;\r
577                 }\r
578         }\r
579 \r
580 #if CXIMAGE_SUPPORT_ALPHA\r
581         if (pAlpha) return AlphaGet(x,y)==0;\r
582 #endif\r
583 \r
584         return false;\r
585 }\r
586 ////////////////////////////////////////////////////////////////////////////////\r
587 bool CxImage::GetTransparentMask(CxImage* iDst)\r
588 {\r
589         if (!pDib) return false;\r
590 \r
591         CxImage tmp;\r
592         tmp.Create(head.biWidth, head.biHeight, 1, GetType());\r
593         tmp.SetStdPalette();\r
594         tmp.Clear(0);\r
595 \r
596         for(long y=0; y<head.biHeight; y++){\r
597                 for(long x=0; x<head.biWidth; x++){\r
598                         if (IsTransparent(x,y)){\r
599                                 tmp.BlindSetPixelIndex(x,y,1);\r
600                         }\r
601                 }\r
602         }\r
603 \r
604         if (iDst) iDst->Transfer(tmp);\r
605         else Transfer(tmp);\r
606 \r
607         return true;\r
608 }\r
609 ////////////////////////////////////////////////////////////////////////////////\r
610 /**\r
611  * Checks if image has the same palette, if any.\r
612  * \param img = image to compare.\r
613  * \param bCheckAlpha = check also the rgbReserved field.\r
614  */\r
615 bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha)\r
616 {\r
617         if (head.biClrUsed != img.head.biClrUsed)\r
618                 return false;\r
619         if (head.biClrUsed == 0)\r
620                 return false;\r
621 \r
622         RGBQUAD c1,c2;\r
623         for (DWORD n=0; n<head.biClrUsed; n++){\r
624                 c1 = GetPaletteColor((BYTE)n);\r
625                 c2 = img.GetPaletteColor((BYTE)n);\r
626                 if (c1.rgbRed != c2.rgbRed) return false;\r
627                 if (c1.rgbBlue != c2.rgbBlue) return false;\r
628                 if (c1.rgbGreen != c2.rgbGreen) return false;\r
629                 if (bCheckAlpha && (c1.rgbReserved != c2.rgbReserved)) return false;\r
630         }\r
631         return true;\r
632 }\r
633 ////////////////////////////////////////////////////////////////////////////////\r
634 /**\r
635  * \sa SetClrImportant\r
636  */\r
637 DWORD CxImage::GetClrImportant() const\r
638 {\r
639         return head.biClrImportant;\r
640 }\r
641 ////////////////////////////////////////////////////////////////////////////////\r
642 /**\r
643  * sets the maximum number of colors that some functions like\r
644  * DecreaseBpp() or GetNearestIndex() will use on indexed images\r
645  * \param ncolors should be less than 2^bpp,\r
646  * or 0 if all the colors are important.\r
647  */\r
648 void CxImage::SetClrImportant(DWORD ncolors)\r
649 {\r
650         if (ncolors==0 || ncolors>256) {\r
651                 head.biClrImportant = 0;\r
652                 return;\r
653         }\r
654 \r
655         switch(head.biBitCount){\r
656         case 1:\r
657                 head.biClrImportant = min(ncolors,2);\r
658                 break;\r
659         case 4:\r
660                 head.biClrImportant = min(ncolors,16);\r
661                 break;\r
662         case 8:\r
663                 head.biClrImportant = ncolors;\r
664                 break;\r
665         }\r
666         return;\r
667 }\r
668 ////////////////////////////////////////////////////////////////////////////////\r
669 /**\r
670  * Returns pointer to pixel. Currently implemented only for truecolor images.\r
671  *  \r
672  * \param  x,y - coordinates\r
673  *\r
674  * \return pointer to first byte of pixel data\r
675  *\r
676  * \author ***bd*** 2.2004\r
677  */\r
678 void* CxImage::BlindGetPixelPointer(const long x, const long y)\r
679 {\r
680 #ifdef _DEBUG\r
681         if ((pDib==NULL) || !IsInside(x,y))\r
682   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
683                 throw 0;\r
684   #else\r
685                 return 0;\r
686   #endif\r
687 #endif\r
688   if (!IsIndexed())\r
689     return info.pImage + y*info.dwEffWidth + x*3;\r
690   else\r
691     return 0;\r
692 }\r
693 ////////////////////////////////////////////////////////////////////////////////\r
694 void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr)\r
695 {\r
696         DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr));\r
697 }\r
698 ////////////////////////////////////////////////////////////////////////////////\r
699 void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha)\r
700 {\r
701         if (!pDib) return;\r
702         //////////////////////////////////////////////////////\r
703         // Draws a line using the Bresenham line algorithm\r
704         // Thanks to Jordan DeLozier <JDL>\r
705         //////////////////////////////////////////////////////\r
706         int x1 = StartX;\r
707         int y1 = StartY;\r
708         int x = x1;                       // Start x off at the first pixel\r
709         int y = y1;                       // Start y off at the first pixel\r
710         int x2 = EndX;\r
711         int y2 = EndY;\r
712 \r
713         int xinc1,xinc2,yinc1,yinc2;      // Increasing values\r
714         int den, num, numadd,numpixels;   \r
715         int deltax = abs(x2 - x1);        // The difference between the x's\r
716         int deltay = abs(y2 - y1);        // The difference between the y's\r
717 \r
718         // Get Increasing Values\r
719         if (x2 >= x1) {                // The x-values are increasing\r
720                 xinc1 = 1;\r
721                 xinc2 = 1;\r
722         } else {                         // The x-values are decreasing\r
723                 xinc1 = -1;\r
724                 xinc2 = -1;\r
725         }\r
726 \r
727         if (y2 >= y1) {                // The y-values are increasing\r
728                 yinc1 = 1;\r
729                 yinc2 = 1;\r
730         } else {                         // The y-values are decreasing\r
731                 yinc1 = -1;\r
732                 yinc2 = -1;\r
733         }\r
734 \r
735         // Actually draw the line\r
736         if (deltax >= deltay)         // There is at least one x-value for every y-value\r
737         {\r
738                 xinc1 = 0;                  // Don't change the x when numerator >= denominator\r
739                 yinc2 = 0;                  // Don't change the y for every iteration\r
740                 den = deltax;\r
741                 num = deltax / 2;\r
742                 numadd = deltay;\r
743                 numpixels = deltax;         // There are more x-values than y-values\r
744         }\r
745         else                          // There is at least one y-value for every x-value\r
746         {\r
747                 xinc2 = 0;                  // Don't change the x for every iteration\r
748                 yinc1 = 0;                  // Don't change the y when numerator >= denominator\r
749                 den = deltay;\r
750                 num = deltay / 2;\r
751                 numadd = deltax;\r
752                 numpixels = deltay;         // There are more y-values than x-values\r
753         }\r
754         \r
755         for (int curpixel = 0; curpixel <= numpixels; curpixel++)\r
756         {\r
757                 // Draw the current pixel\r
758                 SetPixelColor(x,y,color,bSetAlpha);\r
759                 \r
760                 num += numadd;              // Increase the numerator by the top of the fraction\r
761                 if (num >= den)             // Check if numerator >= denominator\r
762                 {\r
763                         num -= den;               // Calculate the new numerator value\r
764                         x += xinc1;               // Change the x as appropriate\r
765                         y += yinc1;               // Change the y as appropriate\r
766                 }\r
767                 x += xinc2;                 // Change the x as appropriate\r
768                 y += yinc2;                 // Change the y as appropriate\r
769         }\r
770 }\r
771 ////////////////////////////////////////////////////////////////////////////////\r
772 /**\r
773  * Sets a palette with standard colors for 1, 4 and 8 bpp images.\r
774  */\r
775 void CxImage::SetStdPalette()\r
776 {\r
777         if (!pDib) return;\r
778         switch (head.biBitCount){\r
779         case 8:\r
780                 {\r
781                         const BYTE pal256[1024] = {0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0,\r
782                         192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0,\r
783                         72,184,255,0,37,170,255,0,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,\r
784                         50,80,0,212,227,255,0,177,199,255,0,142,171,255,0,107,143,255,0,72,115,255,0,37,87,255,0,0,\r
785                         85,255,0,0,73,220,0,0,61,185,0,0,49,150,0,0,37,115,0,0,25,80,0,212,212,255,0,177,177,255,0,\r
786                         142,142,255,0,107,107,255,0,72,72,255,0,37,37,255,0,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,\r
787                         0,0,115,0,0,0,80,0,227,212,255,0,199,177,255,0,171,142,255,0,143,107,255,0,115,72,255,0,\r
788                         87,37,255,0,85,0,255,0,73,0,220,0,61,0,185,0,49,0,150,0,37,0,115,0,25,0,80,0,240,212,255,0,\r
789                         226,177,255,0,212,142,255,0,198,107,255,0,184,72,255,0,170,37,255,0,170,0,255,0,146,0,220,0,\r
790                         122,0,185,0,98,0,150,0,74,0,115,0,50,0,80,0,255,212,255,0,255,177,255,0,255,142,255,0,255,107,255,0,\r
791                         255,72,255,0,255,37,255,0,254,0,254,0,220,0,220,0,185,0,185,0,150,0,150,0,115,0,115,0,80,0,80,0,\r
792                         255,212,240,0,255,177,226,0,255,142,212,0,255,107,198,0,255,72,184,0,255,37,170,0,255,0,170,0,\r
793                         220,0,146,0,185,0,122,0,150,0,98,0,115,0,74,0,80,0,50,0,255,212,227,0,255,177,199,0,255,142,171,0,\r
794                         255,107,143,0,255,72,115,0,255,37,87,0,255,0,85,0,220,0,73,0,185,0,61,0,150,0,49,0,115,0,37,0,\r
795                         80,0,25,0,255,212,212,0,255,177,177,0,255,142,142,0,255,107,107,0,255,72,72,0,255,37,37,0,254,0,\r
796                         0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,0,255,227,212,0,255,199,177,0,255,171,142,0,\r
797                         255,143,107,0,255,115,72,0,255,87,37,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,115,37,0,\r
798                         0,80,25,0,0,255,240,212,0,255,226,177,0,255,212,142,0,255,198,107,0,255,184,72,0,255,170,37,0,\r
799                         255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,0,255,255,212,0,255,255,177,0,\r
800                         255,255,142,0,255,255,107,0,255,255,72,0,255,255,37,0,254,254,0,0,220,220,0,0,185,185,0,0,150,150,0,\r
801                         0,115,115,0,0,80,80,0,0,240,255,212,0,226,255,177,0,212,255,142,0,198,255,107,0,184,255,72,0,\r
802                         170,255,37,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,50,80,0,0,227,255,212,0,\r
803                         199,255,177,0,171,255,142,0,143,255,107,0,115,255,72,0,87,255,37,0,85,255,0,0,73,220,0,0,61,185,0,\r
804                         0,49,150,0,0,37,115,0,0,25,80,0,0,212,255,212,0,177,255,177,0,142,255,142,0,107,255,107,0,72,255,72,0,\r
805                         37,255,37,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,212,255,227,0,177,255,199,0,\r
806                         142,255,171,0,107,255,143,0,72,255,115,0,37,255,87,0,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,\r
807                         115,37,0,0,80,25,0,212,255,240,0,177,255,226,0,142,255,212,0,107,255,198,0,72,255,184,0,37,255,170,0,\r
808                         0,255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,212,255,255,0,177,255,255,0,\r
809                         142,255,255,0,107,255,255,0,72,255,255,0,37,255,255,0,0,254,254,0,0,220,220,0,0,185,185,0,0,\r
810                         150,150,0,0,115,115,0,0,80,80,0,242,242,242,0,230,230,230,0,218,218,218,0,206,206,206,0,194,194,194,0,\r
811                         182,182,182,0,170,170,170,0,158,158,158,0,146,146,146,0,134,134,134,0,122,122,122,0,110,110,110,0,\r
812                         98,98,98,0,86,86,86,0,74,74,74,0,62,62,62,0,50,50,50,0,38,38,38,0,26,26,26,0,14,14,14,0,240,251,255,0,\r
813                         164,160,160,0,128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0};\r
814                         memcpy(GetPalette(),pal256,1024);\r
815                         break;\r
816                 }\r
817         case 4:\r
818                 {\r
819                         const BYTE pal16[64]={0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0,\r
820                                                                 128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0};\r
821                         memcpy(GetPalette(),pal16,64);\r
822                         break;\r
823                 }\r
824         case 1:\r
825                 {\r
826                         const BYTE pal2[8]={0,0,0,0,255,255,255,0};\r
827                         memcpy(GetPalette(),pal2,8);\r
828                         break;\r
829                 }\r
830         }\r
831         info.last_c_isvalid = false;\r
832         return;\r
833 }\r
834 ////////////////////////////////////////////////////////////////////////////////\r