Merge branch 'bug_487_service_selection_event_text_color'
[enigma2.git] / lib / gdi / epng.cpp
1 #include <png.h>
2 #include <stdio.h>
3 #include <lib/gdi/epng.h>
4 #include <unistd.h>
5
6 extern "C" {
7 #include <jpeglib.h>
8 }
9
10 int loadPNG(ePtr<gPixmap> &result, const char *filename)
11 {
12         __u8 header[8];
13         FILE *fp=fopen(filename, "rb");
14         
15         if (!fp)
16         {
17 //              eDebug("couldn't open %s", filename );
18                 return 0;
19         }
20         if (!fread(header, 8, 1, fp))
21         {
22                 eDebug("couldn't read");
23                 fclose(fp);
24                 return 0;
25         }
26         if (png_sig_cmp(header, 0, 8))
27         {
28                 fclose(fp);
29                 return 0;
30         }
31         png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
32         if (!png_ptr)
33         {
34                 eDebug("no pngptr");
35                 fclose(fp);
36                 return 0;
37         }
38         png_infop info_ptr=png_create_info_struct(png_ptr);
39         if (!info_ptr)
40         {
41                 eDebug("no info ptr");
42                 png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
43                 fclose(fp);
44                 return 0;
45         }
46         png_infop end_info = png_create_info_struct(png_ptr);
47         if (!end_info)
48         {
49                 eDebug("no end");
50                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
51                 fclose(fp);
52                 return 0;
53          }
54         if (setjmp(png_ptr->jmpbuf))
55         {
56                 eDebug("das war wohl nix");
57                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
58                 fclose(fp);
59                 result = 0;
60                 return 0;
61         }
62         png_init_io(png_ptr, fp);
63         png_set_sig_bytes(png_ptr, 8);
64         png_set_invert_alpha(png_ptr);
65         png_read_info(png_ptr, info_ptr);
66         
67         png_uint_32 width, height;
68         int bit_depth;
69         int color_type;
70         
71         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
72         
73         if (color_type == PNG_COLOR_TYPE_GRAY || color_type & PNG_COLOR_MASK_PALETTE)
74         {
75                 result=new gPixmap(eSize(width, height), bit_depth);
76                 gSurface *surface = result->surface;
77         
78                 png_bytep *rowptr=new png_bytep[height];
79         
80                 for (unsigned int i=0; i<height; i++)
81                         rowptr[i]=((png_byte*)(surface->data))+i*surface->stride;
82                 png_read_rows(png_ptr, rowptr, 0, height);
83         
84                 delete [] rowptr;
85         
86                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
87                 {
88                         png_color *palette;
89                         int num_palette;
90                         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
91                         if (num_palette)
92                                 surface->clut.data=new gRGB[num_palette];
93                         else
94                                 surface->clut.data=0;
95                         surface->clut.colors=num_palette;
96                         
97                         for (int i=0; i<num_palette; i++)
98                         {
99                                 surface->clut.data[i].a=0;
100                                 surface->clut.data[i].r=palette[i].red;
101                                 surface->clut.data[i].g=palette[i].green;
102                                 surface->clut.data[i].b=palette[i].blue;
103                         }
104                         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
105                         {
106                                 png_byte *trans;
107                                 png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0);
108                                 for (int i=0; i<num_palette; i++)
109                                         surface->clut.data[i].a=255-trans[i];
110                         }
111                 } else
112                 {
113                         surface->clut.data=0;
114                         surface->clut.colors=0;
115                 }
116                 surface->clut.start=0;
117                 png_read_end(png_ptr, end_info);
118         } else {
119                 result=0;
120                 eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type);
121         }
122
123         png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
124         fclose(fp);
125         return 0;
126 }
127
128 struct my_error_mgr {
129         struct jpeg_error_mgr pub;
130         jmp_buf setjmp_buffer;
131 };
132
133 typedef struct my_error_mgr * my_error_ptr;
134
135 static void
136 my_error_exit (j_common_ptr cinfo)
137 {
138         my_error_ptr myerr = (my_error_ptr) cinfo->err;
139         (*cinfo->err->output_message) (cinfo);
140         longjmp(myerr->setjmp_buffer, 1);
141 }
142
143 int loadJPG(ePtr<gPixmap> &result, const char *filename, ePtr<gPixmap> alpha)
144 {
145         struct jpeg_decompress_struct cinfo;
146         struct my_error_mgr jerr;
147         FILE *infile;
148         JSAMPARRAY buffer;
149         int row_stride;
150         infile = fopen(filename, "rb");
151         result = 0;
152
153         if (alpha)
154         {
155                 if (alpha->surface->bpp != 8)
156                 {
157                         eWarning("alpha channel for jpg must be 8bit");
158                         alpha = 0;
159                 }
160         }
161
162         if (!infile)
163                 return -1;
164         cinfo.err = jpeg_std_error(&jerr.pub);
165         jerr.pub.error_exit = my_error_exit;
166         if (setjmp(jerr.setjmp_buffer)) {
167                 result = 0;
168                 jpeg_destroy_decompress(&cinfo);
169                 fclose(infile);
170                 return -1;
171         }
172         jpeg_create_decompress(&cinfo);
173         jpeg_stdio_src(&cinfo, infile);
174         (void) jpeg_read_header(&cinfo, TRUE);
175         cinfo.out_color_space = JCS_RGB;
176         cinfo.scale_denom = 1;
177
178         (void) jpeg_start_decompress(&cinfo);
179
180         int grayscale = cinfo.output_components == 1;
181
182         if (alpha)
183         {
184                 if (((int)cinfo.output_width != alpha->surface->x) || ((int)cinfo.output_height != alpha->surface->y))
185                 {
186                         eWarning("alpha channel size (%dx%d) must match jpeg size (%dx%d)", alpha->surface->x, alpha->surface->y, cinfo.output_width, cinfo.output_height);
187                         alpha = 0;
188                 }
189                 if (grayscale)
190                 {
191                         eWarning("we don't support grayscale + alpha at the moment");
192                         alpha = 0;
193                 }
194         }
195
196         result = new gPixmap(eSize(cinfo.output_width, cinfo.output_height), grayscale ? 8 : 32);
197
198         row_stride = cinfo.output_width * cinfo.output_components;
199         buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
200         while (cinfo.output_scanline < cinfo.output_height) {
201                 int y = cinfo.output_scanline;
202                 (void) jpeg_read_scanlines(&cinfo, buffer, 1);
203                 unsigned char *dst = ((unsigned char*)result->surface->data) + result->surface->stride * y;
204                 unsigned char *src = (unsigned char*)buffer[0];
205                 unsigned char *palpha = alpha ? ((unsigned char*)alpha->surface->data + alpha->surface->stride * y) : 0;
206                 if (grayscale)
207                         memcpy(dst, src, cinfo.output_width);
208                 else
209                 {
210                         int x;
211                         for (x = 0; x < (int)cinfo.output_width; ++x)
212                         {
213                                 *dst++ = src[2];
214                                 *dst++ = src[1];
215                                 *dst++ = src[0];
216                                 src += 3;
217                                 if (palpha)
218                                         *dst++ = *palpha++;
219                                 else 
220                                         *dst++ = 0xFF;
221                         }
222                 }
223         }
224         (void) jpeg_finish_decompress(&cinfo);
225         jpeg_destroy_decompress(&cinfo);
226         fclose(infile);
227         return 0;
228 }
229
230 int savePNG(const char *filename, gPixmap *pixmap)
231 {
232
233         eDebug("\33[33m %s \33[0m",filename);
234         FILE *fp=fopen(filename, "wb");
235         if (!fp)
236                 return -1;
237         
238         gSurface *surface = pixmap->surface;
239         if (!surface)
240                 return -2;
241         
242         png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
243         if (!png_ptr)
244         {
245                 eDebug("write png, couldnt allocate write struct");
246                 fclose(fp);
247                 unlink(filename);
248                 return -2;
249         }
250         png_infop info_ptr=png_create_info_struct(png_ptr);
251         if (!info_ptr)
252         {
253                 eDebug("info");
254                 png_destroy_write_struct(&png_ptr, 0);
255                 fclose(fp);
256                 unlink(filename);
257                 return -3;
258         }
259
260         png_set_IHDR(png_ptr, info_ptr, surface->x, surface->y, surface->bpp/surface->bypp, 
261                 PNG_COLOR_TYPE_RGB_ALPHA, 
262                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
263
264         if (setjmp(png_ptr->jmpbuf))
265         {
266                 eDebug("error :/");
267                 png_destroy_write_struct(&png_ptr, &info_ptr);
268                 fclose(fp);
269                 unlink(filename);
270                 return -4;
271         }
272         png_init_io(png_ptr, fp);
273         png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
274         png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
275
276         png_write_info(png_ptr, info_ptr);
277         png_set_packing(png_ptr);
278
279         png_byte *row_pointer;
280         png_byte *cr = new png_byte[surface->y * surface->stride];
281         if (cr == NULL)
282         {
283                 printf("Error: malloc\n");
284                 return -5;
285         }
286         for (int i=0; i<surface->y; ++i)
287         {
288                 row_pointer=((png_byte*)surface->data)+i*surface->stride;
289                 if (surface->bypp == 4)
290                 {
291                         memcpy(cr, row_pointer, surface->stride);
292                         for (int j=0; j<surface->stride; j+=4)
293                         {
294                                 unsigned char tmp = cr[j];
295                                 cr[j] = cr[j+2];
296                                 cr[j+2]= tmp;
297                         }
298                         png_write_row(png_ptr, cr);
299                 }
300                 else
301                         png_write_row(png_ptr, row_pointer);
302         }
303         delete [] cr;
304
305         png_write_end(png_ptr, info_ptr);
306         png_destroy_write_struct(&png_ptr, &info_ptr);
307         fclose(fp);
308         eDebug("wrote png ! fine !");
309         return 0;
310 }