1 /* === S Y N F I G ========================================================= */
2 /*! \file
3 ** \brief PixelFormat and conversions
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2012-2013 Carlos López
11 ** Copyright (c) 2015 Diego Barrios Romero
12 **
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
17 **
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
22 ** \endlegal
23 */
24 /* ========================================================================= */
25
26 #ifndef __SYNFIG_COLOR_PIXELFORMAT_H
27 #define __SYNFIG_COLOR_PIXELFORMAT_H
28
29 #include <synfig/color/color.h>
30
31 namespace synfig {
32
33
34 enum PixelFormat
35 {
36 /* Bit Descriptions (ON/OFF)
37 ** ----+-------------
38 ** 0 Color Channels (Gray/RGB)
39 ** 1 Alpha Channel (WITH/WITHOUT)
40 ** 2 ZDepth (WITH/WITHOUT)
41 ** 3 Endian (BGR/RGB)
42 ** 4 Alpha Location (Start/End)
43 ** 5 ZDepth Location (Start/End)
44 ** 6 Alpha/ZDepth Arrangement (ZA,AZ)
45 ** 7 Alpha Range (Inverted,Normal)
46 ** 8 Z Range (Inverted,Normal)
47 */
48 PF_RGB = 0,
49 PF_GRAY = (1<<0), //!< If set, use one grayscale channel. If clear, use three channels for RGB
50 PF_A = (1<<1), //!< If set, include alpha channel
51 PF_Z = (1<<2), //!< If set, include ZDepth channel
52 PF_BGR = (1<<3), //!< If set, reverse the order of the RGB channels
53 PF_A_START = (1<<4), //!< If set, alpha channel is before the color data. If clear, it is after.
54 PF_Z_START = (1<<5), //!< If set, ZDepth channel is before the color data. If clear, it is after.
55 PF_ZA = (1<<6), //!< If set, the ZDepth channel will be in front of the alpha channel. If clear, they are reversed.
56 PF_A_INV = (1<<7), //!< If set, the alpha channel is stored as 1.0-a
57 PF_Z_INV = (1<<8), //!< If set, the ZDepth channel is stored as 1.0-z
58 PF_RAW_COLOR = (1<<9)+(1<<1) //!< If set, the data represents a raw Color data structure, and all other bits are ignored.
59 };
60
61 inline PixelFormat operator|(PixelFormat lhs, PixelFormat rhs)
62 { return static_cast<PixelFormat>((int)lhs|(int)rhs); }
63
64 inline PixelFormat operator&(PixelFormat lhs, PixelFormat rhs)
65 { return static_cast<PixelFormat>((int)lhs&(int)rhs); }
66 #define FLAGS(x,y) (((x)&(y))==(y))
67
68 //! Returns the number of channels that the given PixelFormat calls for
channels(const PixelFormat x)69 inline int channels(const PixelFormat x)
70 {
71 int chan = 0;
72 if(FLAGS(x, PF_GRAY))
73 {
74 ++chan;
75 }
76 else
77 {
78 chan += 3;
79 }
80
81 if(FLAGS(x, PF_A))
82 {
83 ++chan;
84 }
85 if(FLAGS(x, PF_Z))
86 {
87 ++chan;
88 }
89 if(FLAGS(x, PF_RAW_COLOR))
90 {
91 chan = sizeof(Color);
92 }
93
94 return chan;
95 }
96
Color2PixelFormat(const Color & color,const PixelFormat & pf,unsigned char * out,const Gamma & gamma)97 inline unsigned char * Color2PixelFormat(const Color &color, const PixelFormat &pf,
98 unsigned char *out, const Gamma &gamma)
99 {
100 if(FLAGS(pf, PF_RAW_COLOR))
101 {
102 Color *outcol = reinterpret_cast<Color *>(out);
103 *outcol = color;
104 out += sizeof(color);
105 return out;
106 }
107
108 int alpha = 0;
109 if (FLAGS(pf, PF_A_INV))
110 {
111 alpha = (-(float)color.get_a()+1) * 255;
112 }
113 else
114 {
115 alpha = (float)color.get_a() * 255;
116 }
117
118 if(alpha < 0)
119 {
120 alpha=0;
121 }
122 if(alpha > 255)
123 {
124 alpha=255;
125 }
126
127 if(FLAGS(pf, PF_ZA|PF_A_START|PF_Z_START))
128 {
129 if(FLAGS(pf, PF_Z_START))
130 {
131 out++;
132 }
133 if(FLAGS(pf, PF_A_START))
134 {
135 *out++ = static_cast<unsigned char>(alpha);
136 }
137 }
138 else
139 {
140 if(FLAGS(pf, PF_A_START))
141 {
142 *out++ = static_cast<unsigned char>(alpha);
143 }
144 if(FLAGS(pf, PF_Z_START))
145 {
146 out++;
147 }
148 }
149
150 if(FLAGS(pf,PF_GRAY))
151 {
152 *out++ = static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_y()));
153 }
154 else
155 {
156 if(FLAGS(pf,PF_BGR))
157 {
158 *out++ = static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_b()));
159 *out++ = static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
160 *out++ = static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_r()));
161 }
162 else
163 {
164 *out++ = static_cast<unsigned char>(gamma.r_F32_to_U8(color.get_r()));
165 *out++ = static_cast<unsigned char>(gamma.g_F32_to_U8(color.get_g()));
166 *out++ = static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_b()));
167 }
168 }
169
170 if(FLAGS(pf, PF_ZA))
171 {
172 if(!FLAGS(pf, PF_Z_START) && FLAGS(pf, PF_Z))
173 {
174 out++;
175 }
176 if(!FLAGS(pf, PF_A_START) && FLAGS(pf, PF_A))
177 {
178 *out++ = static_cast<unsigned char>(alpha);
179 }
180 }
181 else
182 {
183 if(!FLAGS(pf, PF_Z_START) && FLAGS(pf, PF_Z))
184 {
185 out++;
186 }
187 if(!FLAGS(pf, PF_A_START) && FLAGS(pf, PF_A))
188 {
189 *out++ = static_cast<unsigned char>(alpha);
190 }
191 }
192
193 return out;
194 }
195
convert_color_format(unsigned char * dest,const Color * src,int w,PixelFormat pf,const Gamma & gamma)196 inline void convert_color_format(unsigned char *dest, const Color *src,
197 int w, PixelFormat pf,const Gamma &gamma)
198 {
199 assert(w >= 0);
200 while(w--)
201 {
202 dest = Color2PixelFormat((*(src++)).clamped(),
203 pf, dest, gamma);
204 }
205 }
206
PixelFormat2Color(Color & color,const PixelFormat & pf,const unsigned char * out)207 inline const unsigned char * PixelFormat2Color(Color &color,
208 const PixelFormat &pf,
209 const unsigned char *out)
210 {
211 if(FLAGS(pf, PF_ZA|PF_A_START|PF_Z_START))
212 {
213 if(FLAGS(pf, PF_Z_START))
214 {
215 out++;
216 }
217 if(FLAGS(pf,PF_A_START))
218 {
219 color.set_a((float)*out++ / 255);
220 }
221 }
222 else
223 {
224 if(FLAGS(pf, PF_A_START))
225 {
226 color.set_a((float)*out++ / 255);
227 }
228 if(FLAGS(pf, PF_Z_START))
229 {
230 out++;
231 }
232 }
233
234 if(FLAGS(pf, PF_GRAY))
235 {
236 color.set_yuv((float)*out++ / 255, 0, 0);
237 }
238 else
239 {
240 if(FLAGS(pf, PF_BGR))
241 {
242 color.set_b((float)*out++ / 255);
243 color.set_g((float)*out++ / 255);
244 color.set_r((float)*out++ / 255);
245 }
246 else
247 {
248 color.set_r((float)*out++ / 255);
249 color.set_g((float)*out++ / 255);
250 color.set_b((float)*out++ / 255);
251 }
252 }
253
254 if(FLAGS(pf, PF_ZA))
255 {
256 if(!FLAGS(pf, PF_Z_START) && FLAGS(pf, PF_Z))
257 {
258 out++;
259 }
260 if(!FLAGS(pf, PF_A_START) && FLAGS(pf, PF_A))
261 {
262 color.set_a((float)*out++ / 255);
263 }
264 }
265 else
266 {
267 if(!FLAGS(pf, PF_A_START) && FLAGS(pf, PF_A))
268 {
269 color.set_a((float)*out++ / 255);
270 }
271 if(!FLAGS(pf, PF_Z_START) && FLAGS(pf, PF_Z))
272 {
273 out++;
274 }
275 }
276
277 return out;
278 }
279
280 } // synfig namespace
281
282 #endif // __SYNFIG_COLOR_PIXELFORMAT_H
283
284