listboxcontent: add support for pixmaps in list
[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 int loadPNG(ePtr<gPixmap> &result, const char *filename)
7 {
8         __u8 header[8];
9         FILE *fp=fopen(filename, "rb");
10         
11         if (!fp)
12         {
13 //              eDebug("couldn't open %s", filename );
14                 return 0;
15         }
16         if (!fread(header, 8, 1, fp))
17         {
18                 eDebug("couldn't read");
19                 fclose(fp);
20                 return 0;
21         }
22         if (png_sig_cmp(header, 0, 8))
23         {
24                 fclose(fp);
25                 return 0;
26         }
27         png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
28         if (!png_ptr)
29         {
30                 eDebug("no pngptr");
31                 fclose(fp);
32                 return 0;
33         }
34         png_infop info_ptr=png_create_info_struct(png_ptr);
35         if (!info_ptr)
36         {
37                 eDebug("no info ptr");
38                 png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
39                 fclose(fp);
40                 return 0;
41         }
42         png_infop end_info = png_create_info_struct(png_ptr);
43         if (!end_info)
44         {
45                 eDebug("no end");
46                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
47                 fclose(fp);
48                 return 0;
49          }
50         if (setjmp(png_ptr->jmpbuf))
51         {
52                 eDebug("das war wohl nix");
53                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
54                 fclose(fp);
55                 result = 0;
56                 return 0;
57         }
58         png_init_io(png_ptr, fp);
59         png_set_sig_bytes(png_ptr, 8);
60         png_set_invert_alpha(png_ptr);
61         png_read_info(png_ptr, info_ptr);
62         
63         png_uint_32 width, height;
64         int bit_depth;
65         int color_type;
66         
67         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
68         
69         eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type);
70         
71         if (color_type != 6)
72         {
73                 result=new gPixmap(eSize(width, height), bit_depth);
74                 eDebug("gPixmap at %p", (gPixmap*)result);
75                 gSurface *surface = result->surface;
76         
77                 png_bytep *rowptr=new png_bytep[height];
78         
79                 for (unsigned int i=0; i<height; i++)
80                         rowptr[i]=((png_byte*)(surface->data))+i*surface->stride;
81                 png_read_rows(png_ptr, rowptr, 0, height);
82         
83                 delete [] rowptr;
84         
85                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
86                 {
87                         png_color *palette;
88                         int num_palette;
89                         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
90                         if (num_palette)
91                                 surface->clut.data=new gRGB[num_palette];
92                         else
93                                 surface->clut.data=0;
94                         surface->clut.colors=num_palette;
95                         
96                         for (int i=0; i<num_palette; i++)
97                         {
98                                 surface->clut.data[i].a=0;
99                                 surface->clut.data[i].r=palette[i].red;
100                                 surface->clut.data[i].g=palette[i].green;
101                                 surface->clut.data[i].b=palette[i].blue;
102                         }
103                         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
104                         {
105                                 png_byte *trans;
106                                 png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0);
107                                 for (int i=0; i<num_palette; i++)
108                                         surface->clut.data[i].a=255-trans[i];
109                         }
110                 } else
111                 {
112                         surface->clut.data=0;
113                         surface->clut.colors=0;
114                 }
115                 surface->clut.start=0;
116                 png_read_end(png_ptr, end_info);
117         } else
118                 result=0;
119
120         png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
121         fclose(fp);
122         return 0;
123 }
124
125 int savePNG(const char *filename, gPixmap *pixmap)
126 {
127         FILE *fp=fopen(filename, "wb");
128         if (!fp)
129                 return -1;
130         
131         gSurface *surface = pixmap->surface;
132         if (!surface)
133                 return -2;
134         
135         png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
136         if (!png_ptr)
137         {
138                 eDebug("write png, couldnt allocate write struct");
139                 fclose(fp);
140                 unlink(filename);
141                 return -2;
142         }
143         png_infop info_ptr=png_create_info_struct(png_ptr);
144         if (!info_ptr)
145         {
146                 eDebug("info");
147                 png_destroy_write_struct(&png_ptr, 0);
148                 fclose(fp);
149                 unlink(filename);
150                 return -3;
151         }
152         if (setjmp(png_ptr->jmpbuf))
153         {
154                 eDebug("error :/");
155                 png_destroy_write_struct(&png_ptr, &info_ptr);
156                 fclose(fp);
157                 unlink(filename);
158                 return -4;
159         }
160         png_init_io(png_ptr, fp);
161         png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
162         png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
163
164         png_set_IHDR(png_ptr, info_ptr, surface->x, surface->y, surface->bpp, 
165                 surface->clut.data ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY, 
166                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
167         if (surface->clut.data)
168         {
169                 png_color palette[surface->clut.colors];
170                 png_byte trans[surface->clut.colors];
171                 for (int i=0; i<surface->clut.colors; ++i)
172                 {
173                         palette[i].red=surface->clut.data[i].r;
174                         palette[i].green=surface->clut.data[i].g;
175                         palette[i].blue=surface->clut.data[i].b;
176                         trans[i]=255-surface->clut.data[i].a;
177                 }
178                 png_set_PLTE(png_ptr, info_ptr, palette, surface->clut.colors);
179                 png_set_tRNS(png_ptr, info_ptr, trans, surface->clut.colors, 0);
180         }
181         png_write_info(png_ptr, info_ptr);
182         png_set_packing(png_ptr);
183         png_byte *row_pointers[surface->y];
184         for (int i=0; i<surface->y; ++i)
185                 row_pointers[i]=((png_byte*)surface->data)+i*surface->stride;
186         png_write_image(png_ptr, row_pointers);
187         png_write_end(png_ptr, info_ptr);
188         png_destroy_write_struct(&png_ptr, &info_ptr);
189         fclose(fp);
190         eDebug("wrote png ! fine !");
191         return 0;
192 }