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
|
---|