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
8 ////////////////////////////////////////////////////////////////////////////////
\r
10 * returns the palette dimension in byte
\r
12 DWORD CxImage::GetPaletteSize()
\r
14 return (head.biClrUsed * sizeof(RGBQUAD));
\r
16 ////////////////////////////////////////////////////////////////////////////////
\r
17 void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha)
\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
31 ////////////////////////////////////////////////////////////////////////////////
\r
32 void CxImage::SetPaletteColor(BYTE idx, RGBQUAD c)
\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
46 ////////////////////////////////////////////////////////////////////////////////
\r
47 void CxImage::SetPaletteColor(BYTE idx, COLORREF cr)
\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
61 ////////////////////////////////////////////////////////////////////////////////
\r
63 * returns the pointer to the first palette index
\r
65 RGBQUAD* CxImage::GetPalette() const
\r
67 if ((pDib)&&(head.biClrUsed))
\r
68 return (RGBQUAD*)((BYTE*)pDib + sizeof(BITMAPINFOHEADER));
\r
71 ////////////////////////////////////////////////////////////////////////////////
\r
73 * Returns the color of the specified index.
\r
75 RGBQUAD CxImage::GetPaletteColor(BYTE idx)
\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
90 ////////////////////////////////////////////////////////////////////////////////
\r
92 * Returns the palette index of the specified pixel.
\r
94 BYTE CxImage::GetPixelIndex(long x,long y)
\r
96 if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
\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
102 if (head.biBitCount==8){
\r
103 return info.pImage[y*info.dwEffWidth + x];
\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
119 ////////////////////////////////////////////////////////////////////////////////
\r
120 BYTE CxImage::BlindGetPixelIndex(const long x,const long y)
\r
123 if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y))
\r
124 #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
\r
131 if (head.biBitCount==8){
\r
132 return info.pImage[y*info.dwEffWidth + x];
\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
148 ////////////////////////////////////////////////////////////////////////////////
\r
149 RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha)
\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
162 if (head.biClrUsed){
\r
163 rgb = GetPaletteColor(BlindGetPixelIndex(x,y));
\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
170 #if CXIMAGE_SUPPORT_ALPHA
\r
171 if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);
\r
173 rgb.rgbReserved = 0;
\r
174 #endif //CXIMAGE_SUPPORT_ALPHA
\r
177 ////////////////////////////////////////////////////////////////////////////////
\r
179 * This is (a bit) faster version of GetPixelColor.
\r
180 * It tests bounds only in debug mode (_DEBUG defined).
\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
186 RGBQUAD CxImage::BlindGetPixelColor(const long x,const long y, bool bGetAlpha)
\r
190 if ((pDib==NULL) || !IsInside(x,y))
\r
191 #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
\r
194 {rgb.rgbReserved = 0; return rgb;}
\r
198 if (head.biClrUsed){
\r
199 rgb = GetPaletteColor(BlindGetPixelIndex(x,y));
\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
207 #if CXIMAGE_SUPPORT_ALPHA
\r
208 if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);
\r
210 rgb.rgbReserved = 0;
\r
211 #endif //CXIMAGE_SUPPORT_ALPHA
\r
214 ////////////////////////////////////////////////////////////////////////////////
\r
215 BYTE CxImage::GetPixelGray(long x, long y)
\r
217 RGBQUAD color = GetPixelColor(x,y);
\r
218 return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);
\r
220 ////////////////////////////////////////////////////////////////////////////////
\r
221 void CxImage::BlindSetPixelIndex(long x,long y,BYTE i)
\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
233 if (head.biBitCount==8){
\r
234 info.pImage[y*info.dwEffWidth + x]=i;
\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
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
252 ////////////////////////////////////////////////////////////////////////////////
\r
253 void CxImage::SetPixelIndex(long x,long y,BYTE i)
\r
255 if ((pDib==NULL)||(head.biClrUsed==0)||
\r
256 (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) return ;
\r
258 if (head.biBitCount==8){
\r
259 info.pImage[y*info.dwEffWidth + x]=i;
\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
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
277 ////////////////////////////////////////////////////////////////////////////////
\r
278 void CxImage::SetPixelColor(long x,long y,COLORREF cr)
\r
280 SetPixelColor(x,y,RGBtoRGBQUAD(cr));
\r
282 ////////////////////////////////////////////////////////////////////////////////
\r
283 void CxImage::BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)
\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
294 if (head.biClrUsed)
\r
295 BlindSetPixelIndex(x,y,GetNearestIndex(c));
\r
297 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;
\r
298 *iDst++ = c.rgbBlue;
\r
299 *iDst++ = c.rgbGreen;
\r
302 #if CXIMAGE_SUPPORT_ALPHA
\r
303 if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
\r
304 #endif //CXIMAGE_SUPPORT_ALPHA
\r
306 ////////////////////////////////////////////////////////////////////////////////
\r
307 void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)
\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
314 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;
\r
315 *iDst++ = c.rgbBlue;
\r
316 *iDst++ = c.rgbGreen;
\r
319 #if CXIMAGE_SUPPORT_ALPHA
\r
320 if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
\r
321 #endif //CXIMAGE_SUPPORT_ALPHA
\r
323 ////////////////////////////////////////////////////////////////////////////////
\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
331 void CxImage::BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha)
\r
333 if ((pDib==NULL)||(x<0)||(y<0)||
\r
334 (x>=head.biWidth)||(y>=head.biHeight)) return;
\r
336 int a0 = (int)(256*blend);
\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
344 if (head.biClrUsed)
\r
345 BlindSetPixelIndex(x,y,GetNearestIndex(c));
\r
347 BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;
\r
348 *iDst++ = c.rgbBlue;
\r
349 *iDst++ = c.rgbGreen;
\r
351 #if CXIMAGE_SUPPORT_ALPHA
\r
352 if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
\r
353 #endif //CXIMAGE_SUPPORT_ALPHA
\r
356 ////////////////////////////////////////////////////////////////////////////////
\r
358 * Returns the best palette index that matches a specified color.
\r
360 BYTE CxImage::GetNearestIndex(RGBQUAD c)
\r
362 if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
\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
367 info.last_c_isvalid = true;
\r
369 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
\r
370 long distance=200000;
\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
388 info.last_c_index = (BYTE)j;
\r
391 ////////////////////////////////////////////////////////////////////////////////
\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
397 void CxImage::RGBtoBGR(BYTE *buffer, int length)
\r
399 if (buffer && (head.biClrUsed==0)){
\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
408 ////////////////////////////////////////////////////////////////////////////////
\r
409 RGBQUAD CxImage::RGBtoRGBQUAD(COLORREF cr)
\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
418 ////////////////////////////////////////////////////////////////////////////////
\r
419 COLORREF CxImage::RGBQUADtoRGB (RGBQUAD c)
\r
421 return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue);
\r
423 ////////////////////////////////////////////////////////////////////////////////
\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
429 bool CxImage::GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b)
\r
431 RGBQUAD* ppal=GetPalette();
\r
433 *r = ppal[i].rgbRed;
\r
434 *g = ppal[i].rgbGreen;
\r
435 *b = ppal[i].rgbBlue;
\r
440 ////////////////////////////////////////////////////////////////////////////////
\r
441 void CxImage::SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b)
\r
443 if ((!r)||(pDib==NULL)||(head.biClrUsed==0)) return;
\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
453 info.last_c_isvalid = false;
\r
455 ////////////////////////////////////////////////////////////////////////////////
\r
456 void CxImage::SetPalette(rgb_color *rgb,DWORD nColors)
\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
466 info.last_c_isvalid = false;
\r
468 ////////////////////////////////////////////////////////////////////////////////
\r
469 void CxImage::SetPalette(RGBQUAD* pPal,DWORD nColors)
\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
475 ////////////////////////////////////////////////////////////////////////////////
\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
481 void CxImage::SetGrayPalette()
\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
488 ////////////////////////////////////////////////////////////////////////////////
\r
490 * Colorize the palette.
\r
493 void CxImage::BlendPalette(COLORREF cr,long perc)
\r
495 if ((pDib==NULL)||(head.biClrUsed==0)) return;
\r
496 BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
\r
498 RGBQUAD* pPal=(RGBQUAD*)iDst;
\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
509 ////////////////////////////////////////////////////////////////////////////////
\r
511 * Returns true if the image has 256 colors and a linear grey scale palette.
\r
513 bool CxImage::IsGrayScale()
\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
522 ////////////////////////////////////////////////////////////////////////////////
\r
524 * swap two indexes in the image and their colors in the palette
\r
526 void CxImage::SwapIndex(BYTE idx1, BYTE idx2)
\r
528 RGBQUAD* ppal=GetPalette();
\r
529 if(!(pDib && ppal)) return;
\r
531 RGBQUAD tempRGB=GetPaletteColor(idx1);
\r
532 SetPaletteColor(idx1,GetPaletteColor(idx2));
\r
533 SetPaletteColor(idx2,tempRGB);
\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
544 ////////////////////////////////////////////////////////////////////////////////
\r
546 * swap Red and Blue colors
\r
548 void CxImage::SwapRGB2BGR()
\r
552 if (head.biClrUsed){
\r
553 RGBQUAD* ppal=GetPalette();
\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
560 for(long y=0;y<head.biHeight;y++){
\r
561 RGBtoBGR(GetBits(y),3*head.biWidth);
\r
565 ////////////////////////////////////////////////////////////////////////////////
\r
566 bool CxImage::IsTransparent(long x, long y)
\r
568 if (!pDib) return false;
\r
570 if (info.nBkgndIndex>=0){
\r
571 if (head.biClrUsed){
\r
572 if (GetPixelIndex(x,y) == info.nBkgndIndex) return true;
\r
574 RGBQUAD ct = info.nBkgndColor;
\r
575 RGBQUAD c = GetPixelColor(x,y,false);
\r
576 if (*(long*)&c==*(long*)&ct) return true;
\r
580 #if CXIMAGE_SUPPORT_ALPHA
\r
581 if (pAlpha) return AlphaGet(x,y)==0;
\r
586 ////////////////////////////////////////////////////////////////////////////////
\r
587 bool CxImage::GetTransparentMask(CxImage* iDst)
\r
589 if (!pDib) return false;
\r
592 tmp.Create(head.biWidth, head.biHeight, 1, GetType());
\r
593 tmp.SetStdPalette();
\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
604 if (iDst) iDst->Transfer(tmp);
\r
605 else Transfer(tmp);
\r
609 ////////////////////////////////////////////////////////////////////////////////
\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
615 bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha)
\r
617 if (head.biClrUsed != img.head.biClrUsed)
\r
619 if (head.biClrUsed == 0)
\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
633 ////////////////////////////////////////////////////////////////////////////////
\r
635 * \sa SetClrImportant
\r
637 DWORD CxImage::GetClrImportant() const
\r
639 return head.biClrImportant;
\r
641 ////////////////////////////////////////////////////////////////////////////////
\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
648 void CxImage::SetClrImportant(DWORD ncolors)
\r
650 if (ncolors==0 || ncolors>256) {
\r
651 head.biClrImportant = 0;
\r
655 switch(head.biBitCount){
\r
657 head.biClrImportant = min(ncolors,2);
\r
660 head.biClrImportant = min(ncolors,16);
\r
663 head.biClrImportant = ncolors;
\r
668 ////////////////////////////////////////////////////////////////////////////////
\r
670 * Returns pointer to pixel. Currently implemented only for truecolor images.
\r
672 * \param x,y - coordinates
\r
674 * \return pointer to first byte of pixel data
\r
676 * \author ***bd*** 2.2004
\r
678 void* CxImage::BlindGetPixelPointer(const long x, const long y)
\r
681 if ((pDib==NULL) || !IsInside(x,y))
\r
682 #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
\r
689 return info.pImage + y*info.dwEffWidth + x*3;
\r
693 ////////////////////////////////////////////////////////////////////////////////
\r
694 void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr)
\r
696 DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr));
\r
698 ////////////////////////////////////////////////////////////////////////////////
\r
699 void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha)
\r
702 //////////////////////////////////////////////////////
\r
703 // Draws a line using the Bresenham line algorithm
\r
704 // Thanks to Jordan DeLozier <JDL>
\r
705 //////////////////////////////////////////////////////
\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
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
718 // Get Increasing Values
\r
719 if (x2 >= x1) { // The x-values are increasing
\r
722 } else { // The x-values are decreasing
\r
727 if (y2 >= y1) { // The y-values are increasing
\r
730 } else { // The y-values are decreasing
\r
735 // Actually draw the line
\r
736 if (deltax >= deltay) // There is at least one x-value for every y-value
\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
743 numpixels = deltax; // There are more x-values than y-values
\r
745 else // There is at least one y-value for every x-value
\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
752 numpixels = deltay; // There are more y-values than x-values
\r
755 for (int curpixel = 0; curpixel <= numpixels; curpixel++)
\r
757 // Draw the current pixel
\r
758 SetPixelColor(x,y,color,bSetAlpha);
\r
760 num += numadd; // Increase the numerator by the top of the fraction
\r
761 if (num >= den) // Check if numerator >= denominator
\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
767 x += xinc2; // Change the x as appropriate
\r
768 y += yinc2; // Change the y as appropriate
\r
771 ////////////////////////////////////////////////////////////////////////////////
\r
773 * Sets a palette with standard colors for 1, 4 and 8 bpp images.
\r
775 void CxImage::SetStdPalette()
\r
778 switch (head.biBitCount){
\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
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
826 const BYTE pal2[8]={0,0,0,0,255,255,255,0};
\r
827 memcpy(GetPalette(),pal2,8);
\r
831 info.last_c_isvalid = false;
\r
834 ////////////////////////////////////////////////////////////////////////////////
\r