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