source: liacs/MIR2010/SourceCode/cximage/ximapal.cpp@ 177

Last change on this file since 177 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 26.6 KB
RevLine 
[95]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 */
12DWORD CxImage::GetPaletteSize()
13{
14 return (head.biClrUsed * sizeof(RGBQUAD));
15}
16////////////////////////////////////////////////////////////////////////////////
17void 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////////////////////////////////////////////////////////////////////////////////
32void 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////////////////////////////////////////////////////////////////////////////////
47void 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 */
65RGBQUAD* 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 */
75RGBQUAD 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 */
94BYTE 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////////////////////////////////////////////////////////////////////////////////
120BYTE 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////////////////////////////////////////////////////////////////////////////////
149RGBQUAD 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 */
186RGBQUAD 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////////////////////////////////////////////////////////////////////////////////
215BYTE 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////////////////////////////////////////////////////////////////////////////////
221void 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////////////////////////////////////////////////////////////////////////////////
253void 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////////////////////////////////////////////////////////////////////////////////
278void CxImage::SetPixelColor(long x,long y,COLORREF cr)
279{
280 SetPixelColor(x,y,RGBtoRGBQUAD(cr));
281}
282////////////////////////////////////////////////////////////////////////////////
283void 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////////////////////////////////////////////////////////////////////////////////
307void 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 */
331void 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 */
360BYTE 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 */
397void 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////////////////////////////////////////////////////////////////////////////////
409RGBQUAD 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////////////////////////////////////////////////////////////////////////////////
419COLORREF 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 */
429bool 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////////////////////////////////////////////////////////////////////////////////
441void 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////////////////////////////////////////////////////////////////////////////////
456void 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////////////////////////////////////////////////////////////////////////////////
469void 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 */
481void 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 */
493void 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 */
513bool 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 */
526void 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 */
548void 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////////////////////////////////////////////////////////////////////////////////
566bool 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////////////////////////////////////////////////////////////////////////////////
587bool 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 */
615bool 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 */
637DWORD 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 */
648void 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 */
678void* 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////////////////////////////////////////////////////////////////////////////////
694void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr)
695{
696 DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr));
697}
698////////////////////////////////////////////////////////////////////////////////
699void 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 */
775void 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////////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.