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
8 #if CXIMAGE_SUPPORT_ALPHA
\r
10 ////////////////////////////////////////////////////////////////////////////////
\r
14 BYTE CxImage::AlphaGetMax() const
\r
16 return info.nAlphaMax;
\r
18 ////////////////////////////////////////////////////////////////////////////////
\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
24 void CxImage::AlphaSetMax(BYTE nAlphaMax)
\r
26 info.nAlphaMax=nAlphaMax;
\r
28 ////////////////////////////////////////////////////////////////////////////////
\r
30 * Checks if the image has a valid alpha channel.
\r
32 bool CxImage::AlphaIsValid()
\r
36 ////////////////////////////////////////////////////////////////////////////////
\r
38 * Enables the alpha palette, so the Draw() function changes its behavior.
\r
40 void CxImage::AlphaPaletteEnable(bool enable)
\r
42 info.bAlphaPaletteEnabled=enable;
\r
44 ////////////////////////////////////////////////////////////////////////////////
\r
46 * True if the alpha palette is enabled for painting.
\r
48 bool CxImage::AlphaPaletteIsEnabled()
\r
50 return info.bAlphaPaletteEnabled;
\r
52 ////////////////////////////////////////////////////////////////////////////////
\r
54 * Sets the alpha channel to full transparent. AlphaSet(0) has the same effect
\r
56 void CxImage::AlphaClear()
\r
58 if (pAlpha) memset(pAlpha,0,head.biWidth * head.biHeight);
\r
60 ////////////////////////////////////////////////////////////////////////////////
\r
62 * Sets the alpha level for the whole image.
\r
63 * \param level : from 0 (transparent) to 255 (opaque)
\r
65 void CxImage::AlphaSet(BYTE level)
\r
67 if (pAlpha) memset(pAlpha,level,head.biWidth * head.biHeight);
\r
69 ////////////////////////////////////////////////////////////////////////////////
\r
71 * Allocates an empty (opaque) alpha channel.
\r
73 bool CxImage::AlphaCreate()
\r
76 pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);
\r
77 if (pAlpha) memset(pAlpha,255,head.biWidth * head.biHeight);
\r
81 ////////////////////////////////////////////////////////////////////////////////
\r
82 void CxImage::AlphaDelete()
\r
84 if (pAlpha) { free(pAlpha); pAlpha=0; }
\r
86 ////////////////////////////////////////////////////////////////////////////////
\r
87 void CxImage::AlphaInvert()
\r
91 long n=head.biHeight*head.biWidth;
\r
92 for(long i=0; i < n; i++){
\r
93 *iSrc=(BYTE)~(*(iSrc));
\r
98 ////////////////////////////////////////////////////////////////////////////////
\r
100 * Imports an existing alpa channel from another image with the same width and height.
\r
102 bool CxImage::AlphaCopy(CxImage &from)
\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
111 ////////////////////////////////////////////////////////////////////////////////
\r
113 * Creates the alpha channel from a gray scale image.
\r
115 bool CxImage::AlphaSet(CxImage &from)
\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
129 ////////////////////////////////////////////////////////////////////////////////
\r
131 * Sets the alpha level for a single pixel
\r
133 void CxImage::AlphaSet(const long x,const long y,const BYTE level)
\r
135 if (pAlpha && IsInside(x,y)) pAlpha[x+y*head.biWidth]=level;
\r
137 ////////////////////////////////////////////////////////////////////////////////
\r
139 * Gets the alpha level for a single pixel
\r
141 BYTE CxImage::AlphaGet(const long x,const long y)
\r
143 if (pAlpha && IsInside(x,y)) return pAlpha[x+y*head.biWidth];
\r
146 ////////////////////////////////////////////////////////////////////////////////
\r
148 * Returns pointer to alpha data for pixel (x,y).
\r
150 * \author ***bd*** 2.2004
\r
152 BYTE* CxImage::AlphaGetPointer(const long x,const long y)
\r
154 if (pAlpha && IsInside(x,y)) return pAlpha+x+y*head.biWidth;
\r
157 ////////////////////////////////////////////////////////////////////////////////
\r
159 * Get alpha value without boundscheck (a bit faster). Pixel must be inside the image.
\r
161 * \author ***bd*** 2.2004
\r
163 BYTE CxImage::BlindAlphaGet(const long x,const long y)
\r
166 if (!IsInside(x,y) || (pAlpha==0))
\r
167 #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
\r
173 return pAlpha[x+y*head.biWidth];
\r
175 ////////////////////////////////////////////////////////////////////////////////
\r
177 * Resets the alpha palette
\r
179 void CxImage::AlphaPaletteClear()
\r
182 for(WORD ip=0; ip<head.biClrUsed;ip++){
\r
183 c=GetPaletteColor((BYTE)ip);
\r
185 SetPaletteColor((BYTE)ip,c);
\r
188 ////////////////////////////////////////////////////////////////////////////////
\r
190 * Checks if the image has a valid alpha palette.
\r
192 bool CxImage::AlphaPaletteIsValid()
\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
201 ////////////////////////////////////////////////////////////////////////////////
\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
206 void CxImage::AlphaStrip()
\r
208 bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
\r
209 bool bAlphaIsValid = AlphaIsValid();
\r
210 if (!(bAlphaIsValid || bAlphaPaletteIsValid)) return;
\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
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
227 CxImage tmp(head.biWidth,head.biHeight,24);
\r
228 if (!tmp.IsValid()){
\r
229 strcpy(info.szLastError,tmp.GetLastError());
\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
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
249 ////////////////////////////////////////////////////////////////////////////////
\r
250 bool CxImage::AlphaFlip()
\r
252 if (!pAlpha) return false;
\r
254 BYTE *buff = (BYTE*)malloc(head.biWidth);
\r
255 if (!buff) return false;
\r
258 iSrc = pAlpha + (head.biHeight-1)*head.biWidth;
\r
260 for (long i=0; i<(head.biHeight/2); ++i)
\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
273 ////////////////////////////////////////////////////////////////////////////////
\r
274 bool CxImage::AlphaMirror()
\r
276 if (!pAlpha) return false;
\r
277 BYTE* pAlpha2 = (BYTE*)malloc(head.biWidth * head.biHeight);
\r
278 if (!pAlpha2) return false;
\r
280 long wdt=head.biWidth-1;
\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
293 ////////////////////////////////////////////////////////////////////////////////
\r
295 * Exports the alpha channel in a 8bpp grayscale image.
\r
297 bool CxImage::AlphaSplit(CxImage *dest)
\r
299 if (!pAlpha || !dest) return false;
\r
301 CxImage tmp(head.biWidth,head.biHeight,8);
\r
302 if (!tmp.IsValid()){
\r
303 strcpy(info.szLastError,tmp.GetLastError());
\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
313 tmp.SetGrayPalette();
\r
314 dest->Transfer(tmp);
\r
318 ////////////////////////////////////////////////////////////////////////////////
\r
320 * Exports the alpha palette channel in a 8bpp grayscale image.
\r
322 bool CxImage::AlphaPaletteSplit(CxImage *dest)
\r
324 if (!AlphaPaletteIsValid() || !dest) return false;
\r
326 CxImage tmp(head.biWidth,head.biHeight,8);
\r
327 if (!tmp.IsValid()){
\r
328 strcpy(info.szLastError,tmp.GetLastError());
\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
338 tmp.SetGrayPalette();
\r
339 dest->Transfer(tmp);
\r
343 ////////////////////////////////////////////////////////////////////////////////
\r
345 * Merge in the alpha layer the transparent color mask
\r
346 * (previously set with SetTransColor or SetTransIndex)
\r
348 bool CxImage::AlphaFromTransparency()
\r
350 if (!IsValid() || !IsTransparent())
\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
364 ////////////////////////////////////////////////////////////////////////////////
\r
365 #endif //CXIMAGE_SUPPORT_ALPHA
\r