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