Fix for UBSan build
[platform/upstream/doxygen.git] / src / image.cpp
1 /******************************************************************************
2  *
3  * $Id: image.cpp,v 1.14 2001/03/19 19:27:40 root Exp $
4  *
5  *
6  * Copyright (C) 1997-2012 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby 
10  * granted. No representations are made about the suitability of this software 
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18
19 #include "qtbc.h"
20 #include "image.h"
21 #include <qfile.h>
22 #include <math.h>
23 #include "lodepng.h"
24 #include "config.h"
25
26 typedef unsigned char  Byte;
27
28 /** Helper struct representing a RGBA color */
29 struct Color
30 {
31   Byte red;
32   Byte green;
33   Byte blue;
34   Byte alpha;
35 };
36
37 const int charSetWidth=80;
38 const int charHeight=12;
39 const int numChars=96;
40
41 unsigned short charPos[numChars]    = 
42   {   
43       0,  5,  8, 13, 20, 27, 38, 47, 
44      50, 54, 58, 65, 72, 76, 83, 87, 
45      91, 98,105,112,119,126,133,140,
46     147,154,161,164,167,174,181,188,
47     195,207,216,224,233,242,250,258,
48     267,276,279,286,294,301,312,321,
49     331,339,349,357,365,372,380,389,
50     400,409,418,427,430,434,437,443,
51     450,453,460,467,474,481,488,492,
52     499,506,509,512,518,521,530,537,
53     544,551,557,562,568,571,578,585,
54     594,600,607,613,617,620,624,631
55   };
56
57 unsigned char charWidth[numChars] = 
58   {
59      5, 3, 5, 7, 7,11, 9, 3,
60      4, 4, 7, 7, 4, 7, 4, 4,
61
62      7, 7, 7, 7, 7, 7, 7, 7,
63      7, 7, 3, 3, 7, 7, 7, 7,
64     12, 9, 8, 9, 9, 8, 8, 9,
65      9, 3, 7, 8, 7,11, 9,10,
66      8,10, 8, 8, 7, 8, 9,11,
67      9, 9, 9, 3, 4, 3, 6, 7,
68      3, 7, 7, 7, 7, 7, 4, 7,
69      7, 3, 3, 6, 3, 9, 7, 7,
70      7, 6, 5, 6, 3, 7, 7, 9,
71      6, 7, 6, 4, 3, 4, 7, 5   
72   };
73
74 unsigned char fontRaw[charSetWidth*charHeight] = {
75   0x02, 0x50, 0x01, 0x06, 0x20, 0x60, 0xc6, 0x04, 0x00, 0x00, 0x00, 0x27,
76   0x04, 0x1c, 0x38, 0x11, 0xf1, 0xc7, 0xc7, 0x0e, 0x00, 0x00, 0x00, 0x03,
77   0x81, 0xf0, 0x10, 0x7c, 0x1e, 0x3e, 0x1f, 0x9f, 0x87, 0x88, 0x24, 0x09,
78   0x09, 0x02, 0x02, 0x41, 0x0f, 0x0f, 0x83, 0xc3, 0xe1, 0xe7, 0xf4, 0x24,
79   0x12, 0x22, 0x41, 0x20, 0x9f, 0xce, 0x30, 0x00, 0x10, 0x04, 0x00, 0x01,
80   0x00, 0x30, 0x08, 0x12, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
81   0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x02, 0x51, 0x43, 0x89,
82   0x40, 0x90, 0x49, 0x15, 0x00, 0x00, 0x00, 0x28, 0x9c, 0x22, 0x44, 0x31,
83   0x02, 0x20, 0x48, 0x91, 0x00, 0x00, 0x00, 0x04, 0x46, 0x08, 0x28, 0x42,
84   0x21, 0x21, 0x10, 0x10, 0x08, 0x48, 0x24, 0x09, 0x11, 0x03, 0x06, 0x61,
85   0x10, 0x88, 0x44, 0x22, 0x12, 0x10, 0x84, 0x24, 0x12, 0x22, 0x22, 0x20,
86   0x80, 0x4a, 0x11, 0x00, 0x20, 0x04, 0x00, 0x01, 0x00, 0x40, 0x08, 0x00,
87   0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
88   0x02, 0x22, 0x00, 0x00, 0x02, 0x51, 0x45, 0x49, 0x40, 0x90, 0x89, 0x0a,
89   0x00, 0x00, 0x00, 0x48, 0x84, 0x02, 0x04, 0x51, 0x02, 0x00, 0x88, 0x91,
90   0x00, 0x00, 0x00, 0x04, 0x44, 0xd4, 0x28, 0x42, 0x40, 0x20, 0x90, 0x10,
91   0x10, 0x08, 0x24, 0x09, 0x21, 0x03, 0x06, 0x51, 0x20, 0x48, 0x48, 0x12,
92   0x12, 0x00, 0x84, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00, 0x89, 0x12, 0x80,
93   0x31, 0xc5, 0x87, 0x0d, 0x1c, 0xe3, 0x4b, 0x12, 0x49, 0x29, 0x16, 0x1c,
94   0x58, 0x69, 0x4c, 0xe8, 0x91, 0x44, 0x61, 0x44, 0xf2, 0x22, 0x00, 0x00,
95   0x02, 0x07, 0xe5, 0x06, 0x80, 0x60, 0x10, 0x95, 0x08, 0x00, 0x00, 0x48,
96   0x84, 0x04, 0x18, 0x51, 0xe2, 0xc0, 0x87, 0x11, 0x24, 0x18, 0x03, 0x00,
97   0x89, 0x24, 0x44, 0x42, 0x40, 0x20, 0x90, 0x10, 0x10, 0x08, 0x24, 0x09,
98   0x41, 0x02, 0x8a, 0x51, 0x20, 0x48, 0x48, 0x12, 0x11, 0x80, 0x84, 0x22,
99   0x21, 0x24, 0x14, 0x11, 0x01, 0x09, 0x14, 0x40, 0x02, 0x26, 0x48, 0x93,
100   0x22, 0x44, 0xcc, 0x92, 0x51, 0x36, 0x99, 0x22, 0x64, 0x99, 0x92, 0x48,
101   0x91, 0x44, 0x52, 0x44, 0x12, 0x22, 0x00, 0x00, 0x02, 0x01, 0x43, 0x80,
102   0x80, 0xa0, 0x10, 0x84, 0x08, 0x00, 0x00, 0x88, 0x84, 0x08, 0x04, 0x90,
103   0x13, 0x21, 0x08, 0x8f, 0x00, 0x61, 0xf0, 0xc0, 0x8a, 0x24, 0x44, 0x7c,
104   0x40, 0x20, 0x9f, 0x9f, 0x11, 0xcf, 0xe4, 0x09, 0xc1, 0x02, 0x8a, 0x49,
105   0x20, 0x4f, 0x88, 0x13, 0xe0, 0x60, 0x84, 0x22, 0x21, 0x54, 0x08, 0x0a,
106   0x02, 0x08, 0x90, 0x00, 0x00, 0x24, 0x48, 0x11, 0x22, 0x44, 0x48, 0x92,
107   0x61, 0x24, 0x91, 0x22, 0x44, 0x89, 0x10, 0x48, 0x91, 0x24, 0x8c, 0x44,
108   0x22, 0x22, 0x64, 0x00, 0x02, 0x07, 0xe1, 0x41, 0x31, 0x14, 0x10, 0x80,
109   0x3e, 0x07, 0xc0, 0x88, 0x84, 0x10, 0x05, 0x10, 0x12, 0x21, 0x08, 0x81,
110   0x01, 0x80, 0x00, 0x31, 0x0a, 0x24, 0x7c, 0x42, 0x40, 0x20, 0x90, 0x10,
111   0x10, 0x48, 0x24, 0x09, 0x21, 0x02, 0x52, 0x45, 0x20, 0x48, 0x08, 0x92,
112   0x20, 0x10, 0x84, 0x21, 0x41, 0x54, 0x14, 0x04, 0x04, 0x08, 0x90, 0x00,
113   0x01, 0xe4, 0x48, 0x11, 0x3e, 0x44, 0x48, 0x92, 0x61, 0x24, 0x91, 0x22,
114   0x44, 0x89, 0x0c, 0x48, 0x8a, 0x24, 0x8c, 0x48, 0x44, 0x21, 0x98, 0x00,
115   0x02, 0x02, 0x85, 0x41, 0x49, 0x08, 0x10, 0x80, 0x08, 0x00, 0x00, 0x88,
116   0x84, 0x20, 0x45, 0xf9, 0x12, 0x21, 0x08, 0x81, 0x00, 0x61, 0xf0, 0xc1,
117   0x0a, 0x68, 0x82, 0x42, 0x40, 0x20, 0x90, 0x10, 0x10, 0x48, 0x24, 0x89,
118   0x11, 0x02, 0x52, 0x45, 0x20, 0x48, 0x08, 0x52, 0x12, 0x10, 0x84, 0x21,
119   0x40, 0x88, 0x22, 0x04, 0x08, 0x08, 0x90, 0x00, 0x02, 0x24, 0x48, 0x11,
120   0x20, 0x44, 0x48, 0x92, 0x51, 0x24, 0x91, 0x22, 0x44, 0x89, 0x02, 0x48,
121   0x8a, 0x2a, 0x92, 0x28, 0x42, 0x22, 0x00, 0x00, 0x00, 0x02, 0x85, 0x41,
122   0x49, 0x18, 0x10, 0x80, 0x08, 0x00, 0x01, 0x08, 0x84, 0x20, 0x44, 0x11,
123   0x12, 0x22, 0x08, 0x91, 0x00, 0x18, 0x03, 0x00, 0x09, 0xb0, 0x82, 0x42,
124   0x21, 0x21, 0x10, 0x10, 0x08, 0xc8, 0x24, 0x89, 0x09, 0x02, 0x22, 0x43,
125   0x10, 0x88, 0x04, 0x22, 0x12, 0x10, 0x84, 0x20, 0x80, 0x88, 0x22, 0x04,
126   0x10, 0x08, 0x50, 0x00, 0x02, 0x26, 0x48, 0x93, 0x22, 0x44, 0xc8, 0x92,
127   0x49, 0x24, 0x91, 0x22, 0x64, 0x99, 0x12, 0x49, 0x84, 0x11, 0x21, 0x28,
128   0x82, 0x22, 0x00, 0x00, 0x02, 0x02, 0x83, 0x82, 0x30, 0xe4, 0x10, 0x80,
129   0x00, 0x20, 0x05, 0x07, 0x04, 0x3e, 0x38, 0x10, 0xe1, 0xc2, 0x07, 0x0e,
130   0x24, 0x00, 0x00, 0x01, 0x04, 0x00, 0x82, 0x7c, 0x1e, 0x3e, 0x1f, 0x90,
131   0x07, 0x48, 0x24, 0x71, 0x05, 0xf2, 0x22, 0x41, 0x0f, 0x08, 0x03, 0xd2,
132   0x11, 0xe0, 0x83, 0xc0, 0x80, 0x88, 0x41, 0x04, 0x1f, 0xc8, 0x50, 0x00,
133   0x01, 0xd5, 0x87, 0x0d, 0x1c, 0x43, 0x48, 0x92, 0x45, 0x24, 0x91, 0x1c,
134   0x58, 0x69, 0x0c, 0x66, 0x84, 0x11, 0x21, 0x10, 0xf2, 0x22, 0x00, 0x00,
135   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x20, 0x00, 0x00,
136   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
137   0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139   0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
140   0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00,
141   0x00, 0x00, 0x00, 0x10, 0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142   0x00, 0x00, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143   0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146   0x00, 0x08, 0x10, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x02,
147   0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
148   0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
149   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00,
153   0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00,
154   0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xac, 0x00, 0x00
155 };
156
157 static Color palette[] =
158 {
159   { 0xff, 0xff, 0xff, 0x00 },
160   { 0x00, 0x00, 0x00, 0xff },
161   { 0xff, 0xff, 0xc0, 0xff },
162   { 0x9f, 0x9f, 0x60, 0xff },
163   { 0x90, 0x00, 0x00, 0xff },
164   { 0x00, 0x90, 0x00, 0xff },
165   { 0x00, 0x00, 0x90, 0xff },
166   { 0xc0, 0xc0, 0xc0, 0xff }
167 };
168
169 // for alpha we use x^(1/1.3)
170 static Color palette2[] =
171 {
172   { 0x00, 0x00, 0x00, 0x00 },
173   { 0x00, 0x00, 0x00, 0x2e },
174   { 0x00, 0x00, 0x00, 0x48 },
175   { 0x00, 0x00, 0x00, 0x5d },
176   { 0x00, 0x00, 0x00, 0x6f },
177   { 0x00, 0x00, 0x00, 0x80 },
178   { 0x00, 0x00, 0x00, 0x8f },
179   { 0x00, 0x00, 0x00, 0x9e },
180   { 0x00, 0x00, 0x00, 0xac },
181   { 0x00, 0x00, 0x00, 0xb9 },
182   { 0x00, 0x00, 0x00, 0xc5 },
183   { 0x00, 0x00, 0x00, 0xd2 },
184   { 0x00, 0x00, 0x00, 0xdd },
185   { 0x00, 0x00, 0x00, 0xe9 },
186   { 0x00, 0x00, 0x00, 0xf4 },
187   { 0x00, 0x00, 0x00, 0xff }
188 };
189
190 static Color palette3[] =
191 {
192   { 0xff, 0xff, 0xff, 0xff },
193   { 0xe0, 0xe0, 0xe0, 0xff },
194   { 0xd0, 0xd0, 0xd0, 0xff },
195   { 0xc0, 0xc0, 0xc0, 0xff },
196   { 0xb0, 0xb0, 0xb0, 0xff },
197   { 0xa0, 0xa0, 0xa0, 0xff },
198   { 0x90, 0x90, 0x90, 0xff },
199   { 0x80, 0x80, 0x80, 0xff },
200   { 0x70, 0x70, 0x70, 0xff },
201   { 0x60, 0x60, 0x60, 0xff },
202   { 0x50, 0x50, 0x50, 0xff },
203   { 0x40, 0x40, 0x40, 0xff },
204   { 0x30, 0x30, 0x30, 0xff },
205   { 0x20, 0x20, 0x20, 0xff },
206   { 0x10, 0x10, 0x10, 0xff },
207   { 0x00, 0x00, 0x00, 0xff }
208 };
209
210
211 Image::Image(int w,int h)
212 {
213   static int hue   = Config_getInt("HTML_COLORSTYLE_HUE");
214   static int sat   = Config_getInt("HTML_COLORSTYLE_SAT");
215   static int gamma = Config_getInt("HTML_COLORSTYLE_GAMMA");
216
217   double red1,green1,blue1;
218   double red2,green2,blue2;
219
220   ColoredImage::hsl2rgb(hue/360.0,                  // hue
221                         sat/255.0,                  // saturation
222                         pow(235/255.0,gamma/100.0), // luma (gamma corrected)
223                         &red1,&green1,&blue1
224                        );
225
226   ColoredImage::hsl2rgb(hue/360.0,                  // hue
227                         sat/255.0,                  // saturation
228                         pow(138/255.0,gamma/100.0), // luma (gamma corrected)
229                         &red2,&green2,&blue2
230                        );
231
232   palette[2].red   = (int)(red1   * 255.0);
233   palette[2].green = (int)(green1 * 255.0);
234   palette[2].blue  = (int)(blue1  * 255.0);
235
236   palette[3].red   = (int)(red2   * 255.0);
237   palette[3].green = (int)(green2 * 255.0);
238   palette[3].blue  = (int)(blue2  * 255.0);
239
240   data = new uchar[w*h];
241   memset(data,0,w*h);
242   width = w;
243   height = h;
244 }
245
246 Image::~Image()
247 {
248   delete[] data;
249 }
250
251 void Image::setPixel(int x,int y,uchar val)
252 {
253   if (x>=0 && x<width && y>=0 && y<height)
254     data[y*width+x] = val;
255 }
256
257 uchar Image::getPixel(int x,int y) const
258 {
259   if (x>=0 && x<width && y>=0 && y<height)
260     return data[y*width+x];
261   else
262     return 0;
263 }
264
265 void Image::writeChar(int x,int y,char c,uchar fg) 
266 {
267   if (c>=' ')
268   {
269     int xf,yf,ci=c-' ';
270     int rowOffset=0;
271     int cw = charWidth[ci];
272     int cp = charPos[ci];
273     for (yf=0;yf<charHeight;yf++)
274     {
275       unsigned short bitPattern=0;
276       int bitsLeft=cw;
277       int byteOffset = rowOffset+(cp>>3);
278       int bitOffset  = cp&7;
279       // get the bit pattern for row yf of the character from the font data
280       while (bitsLeft>0)
281       {
282         int bits=8-bitOffset;
283         if (bits>bitsLeft) bits=bitsLeft; 
284         bitPattern<<=bits; 
285         bitPattern|=((fontRaw[byteOffset]<<bitOffset)&0xff)>>(8-bits);
286         bitsLeft-=bits;
287         bitOffset=0;
288         byteOffset++;
289       }
290       int mask=1<<(cw-1);
291       // draw character row yf
292       for (xf=0;xf<cw;xf++)
293       {
294         setPixel(x+xf,y+yf,(bitPattern&mask) ? fg : getPixel(x+xf,y+yf));
295         mask>>=1;
296       }
297       rowOffset+=charSetWidth;
298     }
299   } 
300 }
301
302 void Image::writeString(int x,int y,const char *s,uchar fg) 
303 {
304   if (s)
305   {
306     char c;
307     while ((c=*s++))
308     {
309       writeChar(x,y,c,fg);
310       x+=charWidth[c-' '];
311     }
312   }
313 }
314
315 uint Image::stringLength(const char *s) 
316 {
317   int w=0;
318   if (s)
319   {
320     char c;
321     while ((c=*s++)) w+=charWidth[c-' '];
322   }
323   return w;
324 }
325
326 void Image::drawHorzLine(int y,int xs,int xe,uchar colIndex,uint mask)
327 {
328   int x,i=0,j=0;
329   for (x=xs;x<=xe;x++,j++) 
330   {
331     if (j&1) i++;
332     if (mask&(1<<(i&0x1f))) setPixel(x,y,colIndex);
333   }
334
335
336 void Image::drawHorzArrow(int y,int xs,int xe,uchar colIndex,uint mask)
337 {
338   drawHorzLine(y,xs,xe,colIndex,mask);
339   int i;
340   for (i=0;i<6;i++)
341   {
342     int h=i>>1;
343     drawVertLine(xe-i,y-h,y+h,colIndex,0xffffffff);
344   }
345
346
347 void Image::drawVertLine(int x,int ys,int ye,uchar colIndex,uint mask)
348 {
349   int y,i=0;
350   for (y=ys;y<=ye;y++,i++) 
351   {
352     if (mask&(1<<(i&0x1f))) setPixel(x,y,colIndex);
353   }
354 }
355
356 void Image::drawVertArrow(int x,int ys,int ye,uchar colIndex,uint mask)
357 {
358   drawVertLine(x,ys,ye,colIndex,mask);
359   int i;
360   for (i=0;i<6;i++)
361   {
362     int h=i>>1;
363     drawHorzLine(ys+i,x-h,x+h,colIndex,0xffffffff);
364   }
365 }
366
367 void Image::drawRect(int x,int y,int w,int h,uchar colIndex,uint mask)
368 {
369   drawHorzLine(y,x,x+w-1,colIndex,mask);
370   drawHorzLine(y+h-1,x,x+w-1,colIndex,mask);
371   drawVertLine(x,y,y+h-1,colIndex,mask);
372   drawVertLine(x+w-1,y,y+h-1,colIndex,mask);
373 }
374
375 void Image::fillRect(int x,int y,int lwidth,int lheight,uchar colIndex,uint mask)
376 {
377   int xp,yp,xi,yi;
378   for (yp=y,yi=0;yp<y+lheight;yp++,yi++)
379     for (xp=x,xi=0;xp<x+lwidth;xp++,xi++)
380       if (mask&(1<<((xi+yi)&0x1f))) 
381         setPixel(xp,yp,colIndex);
382 }
383
384 bool Image::save(const char *fileName,int mode)
385 {
386 #if 0
387   GifEncoder gifenc(data,
388                     mode==0 ? palette : palette2,
389                     width,height,
390                     mode==0 ? 3 : 4,
391                     0);
392   QFile file(fileName);
393   if (file.open(IO_WriteOnly))
394   {
395     gifenc.writeGIF(file);
396     return TRUE;
397   }
398   else
399   {
400     return FALSE;
401   }
402 #endif
403   static bool useTransparency = Config_getBool("FORMULA_TRANSPARENT");
404   uchar* buffer;
405   size_t bufferSize;
406   LodePNG_Encoder encoder;
407   LodePNG_Encoder_init(&encoder);
408   int numCols = mode==0 ? 8 : 16;
409   Color *pPal = mode==0         ? palette  : 
410                 useTransparency ? palette2 : 
411                                   palette3 ;
412   int i;
413   for (i=0;i<numCols;i++,pPal++)
414   {
415     LodePNG_InfoColor_addPalette(&encoder.infoPng.color,
416                                  pPal->red,pPal->green,pPal->blue,pPal->alpha);
417   }
418   encoder.infoPng.color.colorType = 3; 
419   encoder.infoRaw.color.colorType = 3;
420   LodePNG_encode(&encoder, &buffer, &bufferSize, data, width, height);
421   LodePNG_saveFile(buffer, bufferSize, fileName);
422   free(buffer);
423   LodePNG_Encoder_cleanup(&encoder);
424   return TRUE;
425 }
426
427 //----------------------------------------------------------------
428
429 void ColoredImage::hsl2rgb(double h,double s,double l,
430                          double *pRed,double *pGreen,double *pBlue)
431 {
432   double v;
433   double r,g,b;
434
435   r = l;   // default to gray
436   g = l;
437   b = l;
438   v = (l <= 0.5) ? (l * (1.0 + s)) : (l + s - l * s);
439   if (v > 0)
440   {
441     double m;
442     double sv;
443     int sextant;
444     double fract, vsf, mid1, mid2;
445
446     m       = l + l - v;
447     sv      = (v - m ) / v;
448     h      *= 6.0;
449     sextant = (int)h;
450     fract   = h - sextant;
451     vsf     = v * sv * fract;
452     mid1    = m + vsf;
453     mid2    = v - vsf;
454     switch (sextant)
455     {
456       case 0:
457         r = v;
458         g = mid1;
459         b = m;
460         break;
461       case 1:
462         r = mid2;
463         g = v;
464         b = m;
465         break;
466       case 2:
467         r = m;
468         g = v;
469         b = mid1;
470         break;
471       case 3:
472         r = m;
473         g = mid2;
474         b = v;
475         break;
476       case 4:
477         r = mid1;
478         g = m;
479         b = v;
480         break;
481       case 5:
482         r = v;
483         g = m;
484         b = mid2;
485         break;
486     }
487   }
488   *pRed   = r;
489   *pGreen = g;
490   *pBlue  = b;
491 }
492
493 ColoredImage::ColoredImage(int width,int height,
494            const uchar *greyLevels,const uchar *alphaLevels,
495            int saturation,int hue,int gamma)
496 {
497   m_hasAlpha = alphaLevels!=0;
498   m_width    = width;
499   m_height   = height;
500   m_data     = (uchar*)malloc(width*height*4);
501   int i;
502   for (i=0;i<width*height;i++)
503   {
504     uchar r,g,b,a;
505     double red,green,blue;
506     hsl2rgb(hue/360.0,                            // hue
507             saturation/255.0,                     // saturation
508             pow(greyLevels[i]/255.0,gamma/100.0), // luma (gamma corrected)
509             &red,&green,&blue);
510     r = (int)(red  *255.0);
511     g = (int)(green*255.0);
512     b = (int)(blue *255.0);
513     a = alphaLevels ? alphaLevels[i] : 255;
514     m_data[i*4+0]=r;
515     m_data[i*4+1]=g;
516     m_data[i*4+2]=b;
517     m_data[i*4+3]=a;
518   }
519 }
520
521 ColoredImage::~ColoredImage()
522 {
523   free(m_data);
524 }
525
526 bool ColoredImage::save(const char *fileName)
527 {
528   uchar *buffer;
529   size_t bufferSize;
530   LodePNG_Encoder encoder;
531   LodePNG_Encoder_init(&encoder);
532   encoder.infoPng.color.colorType = m_hasAlpha ? 6 : 2; // 2=RGB 24 bit, 6=RGBA 32 bit
533   encoder.infoRaw.color.colorType = 6; // 6=RGBA 32 bit
534   LodePNG_encode(&encoder, &buffer, &bufferSize, m_data, m_width, m_height);
535   LodePNG_saveFile(buffer, bufferSize, fileName);
536   LodePNG_Encoder_cleanup(&encoder);
537   free(buffer);
538   return TRUE;
539 }
540
541