trunk 20080912
[gitenigma.git] / lib / gdi / epng.cpp
blob82810a5821699d6748d461f3a9c7021faa38fa85
1 #include <png.h>
2 #include <stdio.h>
3 #include <lib/gdi/epng.h>
4 #include <unistd.h>
5 #include <errno.h>
7 gImage *loadPNG(const char *filename)
9 __u8 header[8];
10 FILE *fp;
11 gImage *res=0;
12 png_structp png_ptr = 0;
13 png_infop info_ptr = 0;
14 png_infop end_info = 0;
16 if (!(fp = fopen(filename, "rb")))
18 // eDebug("[ePNG] %s not found\n", filename);
19 return 0;
22 if (!fread(header, 8, 1, fp))
24 fclose(fp);
25 return 0;
28 if (png_sig_cmp(header, 0, 8))
29 goto pngerror;
31 if (!(png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
32 goto pngerror;
34 if (!(info_ptr=png_create_info_struct(png_ptr)))
35 goto pngerror;
37 if (!(end_info=png_create_info_struct(png_ptr)))
38 goto pngerror;
40 if (setjmp(png_ptr->jmpbuf))
41 goto pngerror;
43 png_init_io(png_ptr, fp);
44 png_set_sig_bytes(png_ptr, 8);
45 // png_set_invert_alpha(png_ptr); // has no effect on indexed images
46 png_read_info(png_ptr, info_ptr);
48 png_uint_32 width, height;
49 int bit_depth;
50 int color_type;
52 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
54 // convert 1,2 and 4 bpp to 8bpp images that enigma can blit
55 if (bit_depth < 8) {
56 png_set_packing(png_ptr);
57 bit_depth = 8;
60 if (bit_depth > 8)
61 goto pngerror;
63 // eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type);
65 switch (color_type)
67 case PNG_COLOR_TYPE_GRAY:
68 case PNG_COLOR_TYPE_PALETTE:
69 // case PNG_COLOR_TYPE_RGB: // in theory, gImage can handle RGB pics - but enigma can't blit them, so
70 // until this is fixed, imho we should reject RGB pictures right here
71 // because later on we get an fatal blitting error followed by an enigma shutdown
73 res=new gImage(eSize(width, height), bit_depth);
75 png_bytep *rowptr=new png_bytep[height];
76 for (unsigned int i=0; i<height; i++)
77 rowptr[i]=((png_byte*)(res->data))+i*res->stride;
78 png_read_rows(png_ptr, rowptr, 0, height);
80 delete [] rowptr;
82 if (color_type == PNG_COLOR_TYPE_PALETTE)
84 // indexed pictures without a palette make no sense
85 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
86 goto pngerror;
88 png_color *palette;
89 int num_palette;
90 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
91 if (num_palette)
93 res->clut.data=new gRGB[num_palette];
94 res->clut.colors=num_palette;
97 for (int i=0; i<num_palette; i++)
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;
104 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
106 png_byte *trans;
107 png_color_16 *transparent_color;
109 png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, &transparent_color);
110 if (transparent_color)
111 res->clut.data[transparent_color->index].a=255;
112 if (trans)
113 for (int i=0; i<num_palette; i++)
114 res->clut.data[i].a=255-trans[i];
117 break;
119 default:
120 eDebug("[ePNG] unsupported color_type in %s", filename);
121 goto pngerror2;
124 png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
125 fclose(fp);
126 return res;
128 pngerror:
129 eDebug("[ePNG] png structure failure in %s\n", filename);
130 pngerror2:
131 if (res)
132 delete res;
133 if (png_ptr)
134 png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)NULL, end_info ? &end_info : (png_infopp)NULL);
135 if (fp)
136 fclose(fp);
137 return 0;
140 int savePNG(const char *filename, gPixmap *pixmap)
142 FILE *fp=fopen(filename, "wb");
143 if (!fp)
144 return -1;
145 png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
146 if (!png_ptr)
148 eDebug("write png, couldnt allocate write struct");
149 fclose(fp);
150 unlink(filename);
151 return -2;
153 png_infop info_ptr=png_create_info_struct(png_ptr);
154 if (!info_ptr)
156 eDebug("info");
157 png_destroy_write_struct(&png_ptr, 0);
158 fclose(fp);
159 unlink(filename);
160 return -3;
162 if (setjmp(png_ptr->jmpbuf))
164 eDebug("error :/");
165 png_destroy_write_struct(&png_ptr, &info_ptr);
166 fclose(fp);
167 unlink(filename);
168 return -4;
170 png_init_io(png_ptr, fp);
171 png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
172 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
174 png_set_IHDR(png_ptr, info_ptr, pixmap->x, pixmap->y, pixmap->bpp,
175 pixmap->clut.data ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY,
176 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
177 if (pixmap->clut.data)
179 png_color palette[pixmap->clut.colors];
180 png_byte trans[pixmap->clut.colors];
181 for (int i=0; i<pixmap->clut.colors; ++i)
183 palette[i].red=pixmap->clut.data[i].r;
184 palette[i].green=pixmap->clut.data[i].g;
185 palette[i].blue=pixmap->clut.data[i].b;
186 trans[i]=255-pixmap->clut.data[i].a;
188 png_set_PLTE(png_ptr, info_ptr, palette, pixmap->clut.colors);
189 png_set_tRNS(png_ptr, info_ptr, trans, pixmap->clut.colors, 0);
191 png_write_info(png_ptr, info_ptr);
192 png_set_packing(png_ptr);
193 png_byte *row_pointers[pixmap->y];
194 for (int i=0; i<pixmap->y; ++i)
195 row_pointers[i]=((png_byte*)pixmap->data)+i*pixmap->stride;
196 png_write_image(png_ptr, row_pointers);
197 png_write_end(png_ptr, info_ptr);
198 png_destroy_write_struct(&png_ptr, &info_ptr);
199 fclose(fp);
200 eDebug("wrote png ! fine !");
201 return 0;