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