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