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