]> Creatis software - clitk.git/blob - utilities/CxImage/ximalpha.cpp
Debug RTStruct conversion with empty struc
[clitk.git] / utilities / CxImage / ximalpha.cpp
1 // xImalpha.cpp : Alpha channel 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 #if CXIMAGE_SUPPORT_ALPHA
9
10 ////////////////////////////////////////////////////////////////////////////////
11 /**
12  * \sa AlphaSetMax
13  */
14 BYTE CxImage::AlphaGetMax() const
15 {
16         return info.nAlphaMax;
17 }
18 ////////////////////////////////////////////////////////////////////////////////
19 /**
20  * Sets global Alpha (opacity) value applied to the whole image,
21  * valid only for painting functions.
22  * \param nAlphaMax: can be from 0 to 255
23  */
24 void CxImage::AlphaSetMax(BYTE nAlphaMax)
25 {
26         info.nAlphaMax=nAlphaMax;
27 }
28 ////////////////////////////////////////////////////////////////////////////////
29 /**
30  * Checks if the image has a valid alpha channel.
31  */
32 bool CxImage::AlphaIsValid()
33 {
34         return pAlpha!=0;
35 }
36 ////////////////////////////////////////////////////////////////////////////////
37 /**
38  * Enables the alpha palette, so the Draw() function changes its behavior.
39  */
40 void CxImage::AlphaPaletteEnable(bool enable)
41 {
42         info.bAlphaPaletteEnabled=enable;
43 }
44 ////////////////////////////////////////////////////////////////////////////////
45 /**
46  * True if the alpha palette is enabled for painting.
47  */
48 bool CxImage::AlphaPaletteIsEnabled()
49 {
50         return info.bAlphaPaletteEnabled;
51 }
52 ////////////////////////////////////////////////////////////////////////////////
53 /**
54  * Sets the alpha channel to full transparent. AlphaSet(0) has the same effect
55  */
56 void CxImage::AlphaClear()
57 {
58         if (pAlpha)     memset(pAlpha,0,head.biWidth * head.biHeight);
59 }
60 ////////////////////////////////////////////////////////////////////////////////
61 /**
62  * Sets the alpha level for the whole image.
63  * \param level : from 0 (transparent) to 255 (opaque)
64  */
65 void CxImage::AlphaSet(BYTE level)
66 {
67         if (pAlpha)     memset(pAlpha,level,head.biWidth * head.biHeight);
68 }
69 ////////////////////////////////////////////////////////////////////////////////
70 /**
71  * Allocates an empty (opaque) alpha channel.
72  */
73 bool CxImage::AlphaCreate()
74 {
75         if (pAlpha==NULL) {
76                 pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);
77                 if (pAlpha) memset(pAlpha,255,head.biWidth * head.biHeight);
78         }
79         return (pAlpha!=0);
80 }
81 ////////////////////////////////////////////////////////////////////////////////
82 void CxImage::AlphaDelete()
83 {
84         if (pAlpha) { free(pAlpha); pAlpha=0; }
85 }
86 ////////////////////////////////////////////////////////////////////////////////
87 void CxImage::AlphaInvert()
88 {
89         if (pAlpha) {
90                 BYTE *iSrc=pAlpha;
91                 long n=head.biHeight*head.biWidth;
92                 for(long i=0; i < n; i++){
93                         *iSrc=(BYTE)~(*(iSrc));
94                         iSrc++;
95                 }
96         }
97 }
98 ////////////////////////////////////////////////////////////////////////////////
99 /**
100  * Imports an existing alpa channel from another image with the same width and height.
101  */
102 bool CxImage::AlphaCopy(CxImage &from)
103 {
104         if (from.pAlpha == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;
105         if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);
106         if (pAlpha==NULL) return false;
107         memcpy(pAlpha,from.pAlpha,head.biWidth * head.biHeight);
108         info.nAlphaMax=from.info.nAlphaMax;
109         return true;
110 }
111 ////////////////////////////////////////////////////////////////////////////////
112 /**
113  * Creates the alpha channel from a gray scale image.
114  */
115 bool CxImage::AlphaSet(CxImage &from)
116 {
117         if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;
118         if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);
119         BYTE* src = from.info.pImage;
120         BYTE* dst = pAlpha;
121         if (src==NULL || dst==NULL) return false;
122         for (long y=0; y<head.biHeight; y++){
123                 memcpy(dst,src,head.biWidth);
124                 dst += head.biWidth;
125                 src += from.info.dwEffWidth;
126         }
127         return true;
128 }
129 ////////////////////////////////////////////////////////////////////////////////
130 /**
131  * Sets the alpha level for a single pixel 
132  */
133 void CxImage::AlphaSet(const long x,const long y,const BYTE level)
134 {
135         if (pAlpha && IsInside(x,y)) pAlpha[x+y*head.biWidth]=level;
136 }
137 ////////////////////////////////////////////////////////////////////////////////
138 /**
139  * Gets the alpha level for a single pixel 
140  */
141 BYTE CxImage::AlphaGet(const long x,const long y)
142 {
143         if (pAlpha && IsInside(x,y)) return pAlpha[x+y*head.biWidth];
144         return 0;
145 }
146 ////////////////////////////////////////////////////////////////////////////////
147 /**
148  * Returns pointer to alpha data for pixel (x,y).
149  *
150  * \author ***bd*** 2.2004
151  */
152 BYTE* CxImage::AlphaGetPointer(const long x,const long y)
153 {
154         if (pAlpha && IsInside(x,y)) return pAlpha+x+y*head.biWidth;
155         return 0;
156 }
157 ////////////////////////////////////////////////////////////////////////////////
158 /**
159  * Get alpha value without boundscheck (a bit faster). Pixel must be inside the image.
160  *
161  * \author ***bd*** 2.2004
162  */
163 BYTE CxImage::BlindAlphaGet(const long x,const long y)
164 {
165 #ifdef _DEBUG
166         if (!IsInside(x,y) || (pAlpha==0))
167   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
168                 throw 0;
169   #else
170                 return 0;
171   #endif
172 #endif
173         return pAlpha[x+y*head.biWidth];
174 }
175 ////////////////////////////////////////////////////////////////////////////////
176 /**
177  * Resets the alpha palette 
178  */
179 void CxImage::AlphaPaletteClear()
180 {
181         RGBQUAD c;
182         for(WORD ip=0; ip<head.biClrUsed;ip++){
183                 c=GetPaletteColor((BYTE)ip);
184                 c.rgbReserved=0;
185                 SetPaletteColor((BYTE)ip,c);
186         }
187 }
188 ////////////////////////////////////////////////////////////////////////////////
189 /**
190  * Checks if the image has a valid alpha palette. 
191  */
192 bool CxImage::AlphaPaletteIsValid()
193 {
194         RGBQUAD c;
195         for(WORD ip=0; ip<head.biClrUsed;ip++){
196                 c=GetPaletteColor((BYTE)ip);
197                 if (c.rgbReserved != 0) return true;
198         }
199         return false;
200 }
201 ////////////////////////////////////////////////////////////////////////////////
202 /**
203  * Blends the alpha channel and the alpha palette with the pixels. The result is a 24 bit image.
204  * The background color can be selected using SetTransColor().
205  */
206 void CxImage::AlphaStrip()
207 {
208         bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
209         bool bAlphaIsValid = AlphaIsValid();
210         if (!(bAlphaIsValid || bAlphaPaletteIsValid)) return;
211         RGBQUAD c;
212         long a, a1;
213         if (head.biBitCount==24){
214                 for(long y=0; y<head.biHeight; y++){
215                         for(long x=0; x<head.biWidth; x++){
216                                 c = BlindGetPixelColor(x,y);
217                                 if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;
218                                 a1 = 256-a;
219                                 c.rgbBlue = (BYTE)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);
220                                 c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);
221                                 c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);
222                                 BlindSetPixelColor(x,y,c);
223                         }
224                 }
225                 AlphaDelete();
226         } else {
227                 CxImage tmp(head.biWidth,head.biHeight,24);
228                 if (!tmp.IsValid()){
229                         strcpy(info.szLastError,tmp.GetLastError());
230                         return;
231                 }
232
233                 for(long y=0; y<head.biHeight; y++){
234                         for(long x=0; x<head.biWidth; x++){
235                                 c = BlindGetPixelColor(x,y);
236                                 if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;
237                                 if (bAlphaPaletteIsValid) a=(c.rgbReserved*a)/255;
238                                 a1 = 256-a;
239                                 c.rgbBlue = (BYTE)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);
240                                 c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);
241                                 c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);
242                                 tmp.BlindSetPixelColor(x,y,c);
243                         }
244                 }
245                 Transfer(tmp);
246         }
247         return;
248 }
249 ////////////////////////////////////////////////////////////////////////////////
250 bool CxImage::AlphaFlip()
251 {
252         if (!pAlpha) return false;
253
254         BYTE *buff = (BYTE*)malloc(head.biWidth);
255         if (!buff) return false;
256
257         BYTE *iSrc,*iDst;
258         iSrc = pAlpha + (head.biHeight-1)*head.biWidth;
259         iDst = pAlpha;
260         for (long i=0; i<(head.biHeight/2); ++i)
261         {
262                 memcpy(buff, iSrc, head.biWidth);
263                 memcpy(iSrc, iDst, head.biWidth);
264                 memcpy(iDst, buff, head.biWidth);
265                 iSrc-=head.biWidth;
266                 iDst+=head.biWidth;
267         }
268
269         free(buff);
270
271         return true;
272 }
273 ////////////////////////////////////////////////////////////////////////////////
274 bool CxImage::AlphaMirror()
275 {
276         if (!pAlpha) return false;
277         BYTE* pAlpha2 = (BYTE*)malloc(head.biWidth * head.biHeight);
278         if (!pAlpha2) return false;
279         BYTE *iSrc,*iDst;
280         long wdt=head.biWidth-1;
281         iSrc=pAlpha + wdt;
282         iDst=pAlpha2;
283         for(long y=0; y < head.biHeight; y++){
284                 for(long x=0; x <= wdt; x++)
285                         *(iDst+x)=*(iSrc-x);
286                 iSrc+=head.biWidth;
287                 iDst+=head.biWidth;
288         }
289         free(pAlpha);
290         pAlpha=pAlpha2;
291         return true;
292 }
293 ////////////////////////////////////////////////////////////////////////////////
294 /**
295  * Exports the alpha channel in a 8bpp grayscale image. 
296  */
297 bool CxImage::AlphaSplit(CxImage *dest)
298 {
299         if (!pAlpha || !dest) return false;
300
301         CxImage tmp(head.biWidth,head.biHeight,8);
302         if (!tmp.IsValid()){
303                 strcpy(info.szLastError,tmp.GetLastError());
304                 return false;
305         }
306
307         for(long y=0; y<head.biHeight; y++){
308                 for(long x=0; x<head.biWidth; x++){
309                         tmp.BlindSetPixelIndex(x,y,pAlpha[x+y*head.biWidth]);
310                 }
311         }
312
313         tmp.SetGrayPalette();
314         dest->Transfer(tmp);
315
316         return true;
317 }
318 ////////////////////////////////////////////////////////////////////////////////
319 /**
320  * Exports the alpha palette channel in a 8bpp grayscale image. 
321  */
322 bool CxImage::AlphaPaletteSplit(CxImage *dest)
323 {
324         if (!AlphaPaletteIsValid() || !dest) return false;
325
326         CxImage tmp(head.biWidth,head.biHeight,8);
327         if (!tmp.IsValid()){
328                 strcpy(info.szLastError,tmp.GetLastError());
329                 return false;
330         }
331
332         for(long y=0; y<head.biHeight; y++){
333                 for(long x=0; x<head.biWidth; x++){
334                         tmp.BlindSetPixelIndex(x,y,BlindGetPixelColor(x,y).rgbReserved);
335                 }
336         }
337
338         tmp.SetGrayPalette();
339         dest->Transfer(tmp);
340
341         return true;
342 }
343 ////////////////////////////////////////////////////////////////////////////////
344 /**
345  * Merge in the alpha layer the transparent color mask
346  * (previously set with SetTransColor or SetTransIndex) 
347  */
348 bool CxImage::AlphaFromTransparency()
349 {
350         if (!IsValid() || !IsTransparent())
351                 return false;
352
353         AlphaCreate();
354
355         for(long y=0; y<head.biHeight; y++){
356                 for(long x=0; x<head.biWidth; x++){
357                         if (IsTransparent(x,y)){
358                                 AlphaSet(x,y,0);
359                         }
360                 }
361         }
362         return true;
363 }
364 ////////////////////////////////////////////////////////////////////////////////
365 #endif //CXIMAGE_SUPPORT_ALPHA