OSDN Git Service

delete png_set_gAMA
[swfed/swfed.git] / src / swf_png.c
1 /*
2   +----------------------------------------------------------------------+
3   | Author: yoya@awm.jp                                                  |
4   +----------------------------------------------------------------------+
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "swf_define.h"
10
11 #ifdef HAVE_PNG
12
13 #include <png.h>
14 #include "bitstream.h"
15 #include "swf_rgb.h"  // Lossless  format=3
16 #include "swf_rgba.h" // Lossless2 format=3
17 #include "swf_xrgb.h" // Lossless  format=5
18 #include "swf_argb.h" // Lossless2 format=5
19 #include "swf_png.h"
20
21 typedef struct my_png_buffer_ {
22     unsigned char *data;
23     unsigned long data_len;
24     unsigned long data_offset;
25 } my_png_buffer;
26
27 /*
28  * png read
29  */
30
31 static void
32 png_data_read_func(png_structp png_ptr, png_bytep buf, png_size_t size) {
33     my_png_buffer *png_buff = (my_png_buffer *)png_get_io_ptr(png_ptr);
34     if (png_buff->data_offset + size <= png_buff->data_len) {
35         memcpy(buf, png_buff->data + png_buff->data_offset, size);
36         png_buff->data_offset += size;
37     } else {
38         fprintf(stderr, "png_data_read_func: ! png_buff->data_offset(%lu) + size(%zd) <= png_buff->data_len(%lu)\n",
39                 png_buff->data_offset, size, png_buff->data_len);
40         png_error(png_ptr,"png_read_read_func failed");
41     }
42 }
43
44 static void png_data_read(png_structp png_ptr, my_png_buffer *png_buff) {
45     png_set_read_fn(png_ptr, (png_voidp) png_buff,
46                     (png_rw_ptr)png_data_read_func);
47 }
48
49 /*
50  * png write
51  */
52
53 void
54 png_data_write_func(png_structp png_ptr, png_bytep buf, png_size_t size) {
55     my_png_buffer *png_buff = (my_png_buffer *)png_get_io_ptr(png_ptr);
56     unsigned long new_data_len;
57     unsigned char *tmp;
58     if (png_buff->data_offset + size > png_buff->data_len) {
59         new_data_len = 2 * png_buff->data_len;
60         if (png_buff->data_offset + size > new_data_len) {
61             new_data_len = png_buff->data_offset + size;
62         }
63         tmp = realloc(png_buff->data, new_data_len);
64         if (tmp == NULL) {
65             fprintf(stderr, "png_data_write_func: can't realloc: new_data_len(%lu), data_len(%lu)\n",
66                     new_data_len, png_buff->data_len);
67             png_error(png_ptr,"png_data_write_func failed");
68         }
69         png_buff->data = tmp;
70         png_buff->data_len = new_data_len;
71     }
72     memcpy(png_buff->data + png_buff->data_offset, buf, size);
73     png_buff->data_offset += size;
74 }
75
76 void
77 png_data_write(png_structp png_ptr, my_png_buffer *png_buff) {
78     png_set_write_fn(png_ptr, (png_voidp) png_buff,
79                      (png_rw_ptr)png_data_write_func, NULL);
80 }
81
82 /*
83  *
84  */
85
86 void *
87 pngconv_png2lossless(unsigned char *png_data, unsigned long png_data_len,
88                      int *tag_no, int *format,
89                      unsigned short *width, unsigned short *height,
90                      void **colormap, int *colormap_count) {
91     volatile png_structp png_ptr = NULL;
92     volatile png_infop png_info_ptr = NULL;
93     my_png_buffer png_buff;
94     int is_png;
95     int bpp, color_type;
96     png_uint_32 png_width = 0, png_height = 0;
97     volatile png_bytepp png_image_data = NULL;
98     png_uint_32 x, y;
99     void *image_data = NULL;
100     png_color *palette = NULL;
101     int palette_num = 0;
102     png_bytep trans = NULL;
103     int num_trans = 0;
104     png_color_16p trans_values = NULL;
105
106     if (png_data == NULL) {
107         fprintf(stderr, "pngconv_png2lossless: png_data == NULL\n");
108         return NULL;
109     }
110     is_png = png_check_sig((png_bytep)png_data, 8);
111     if (! is_png) {
112         fprintf(stderr, "pngconv_png2lossless: is not PNG!\n");
113         return NULL;
114     }
115     png_ptr = png_create_read_struct
116         (PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
117     if (! png_ptr) {
118         fprintf(stderr, "pngconv_png2lossless: can't create read_struct\n");
119         return NULL;
120     }
121     if (setjmp(png_jmpbuf(png_ptr))) {
122         fprintf(stderr, "pngconv_png2lossless: libpng error jump occured\n");
123         png_destroy_read_struct((png_structpp) &png_ptr,
124                                 (png_infopp) &png_info_ptr, NULL);
125         if (png_image_data) {
126             for (y=0 ; y < png_height ; y++) {
127                 free(png_image_data[y]);
128             }
129             free(png_image_data);
130         }
131         return NULL;
132     }
133     png_info_ptr = png_create_info_struct(png_ptr);
134     if (! png_info_ptr) {
135         fprintf(stderr, "pngconv_png2lossless: can't create info_struct\n");
136         png_destroy_read_struct ((png_structpp)&png_ptr, NULL, NULL);
137         return NULL;
138     }
139     png_buff.data = png_data;
140     png_buff.data_len = png_data_len;
141     png_buff.data_offset = 0;
142
143     png_data_read(png_ptr, &png_buff);
144     png_read_info(png_ptr, png_info_ptr);
145     png_get_IHDR(png_ptr, png_info_ptr,
146                  &png_width, &png_height, &bpp, &color_type,
147                  NULL, NULL, NULL);
148     *width = (unsigned short) png_width;
149     *height = (unsigned short) png_height;
150     switch(color_type) {
151     case PNG_COLOR_TYPE_PALETTE:
152         *format = 3;
153         png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_num);
154         if (png_get_tRNS(png_ptr, png_info_ptr, &trans, &num_trans,
155                          &trans_values) && (num_trans > 0)) {
156             *tag_no = 36; // DefineBitsLossless2
157         } else {
158             *tag_no = 20; // DefineBitsLossless
159         }
160         break;
161     case PNG_COLOR_TYPE_RGB:
162         *format = 5;
163         *tag_no = 20; /* DefineBitsLossless */
164         break;
165     case PNG_COLOR_TYPE_RGB_ALPHA:
166         *format = 5;
167         *tag_no = 36; /* DefineBitsLossless2 */
168         if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS))
169             png_set_tRNS_to_alpha(png_ptr);
170         break;
171     default:
172         fprintf(stderr, "pngconv_png2lossless: color_type=%d not implemented yet.\n", color_type);
173         png_destroy_read_struct((png_structpp)&png_ptr,
174                                 (png_infopp)&png_info_ptr, NULL);
175         return NULL;
176     }
177     if (bpp > 8) {
178         fprintf(stderr, "pngconv_png2lossless: bpp=%d not implemented yet. accept only bpp <= 8\n", bpp);
179         png_destroy_read_struct((png_structpp)&png_ptr,
180                                 (png_infopp)&png_info_ptr, NULL);
181         return NULL;
182     }
183     
184     png_image_data = (png_bytepp) malloc(png_height * sizeof(png_bytep));
185     for (y=0 ; y < png_height ; y++) {
186         png_image_data[y] = (png_bytep) malloc(png_get_rowbytes(png_ptr, png_info_ptr));
187     }
188     png_read_image(png_ptr, png_image_data);
189     /*
190      * image copy
191      */
192     if (color_type == PNG_COLOR_TYPE_PALETTE) {
193         int i;
194         *colormap_count = palette_num;
195         if (num_trans == 0) {
196             swf_rgb_t *result_colormap = malloc(sizeof(swf_rgb_t) * palette_num);   // Lossless
197             for (i=0 ; i < palette_num ; i++) {
198                 result_colormap[i].red   = palette[i].red;
199                 result_colormap[i].green = palette[i].green;
200                 result_colormap[i].blue  = palette[i].blue;
201             }
202             *colormap = result_colormap;
203         } else {
204               swf_rgba_t *result_colormap = malloc(sizeof(swf_rgba_t) * palette_num);   // Lossless2
205             for (i=0 ; i < palette_num ; i++) {
206                 if (i < num_trans) {
207                     int alpha_value = trans[i];
208                     result_colormap[i].red   = palette[i].red   * alpha_value / 0xff;
209                     result_colormap[i].green = palette[i].green * alpha_value / 0xff;
210                     result_colormap[i].blue  = palette[i].blue  * alpha_value / 0xff;
211                     result_colormap[i].alpha = alpha_value;
212                 } else {
213                     result_colormap[i].red   = palette[i].red;
214                     result_colormap[i].green = palette[i].green;
215                     result_colormap[i].blue  = palette[i].blue;
216                     result_colormap[i].alpha = 0xff; // opaque
217                 }
218             }
219             *colormap = result_colormap;
220         }
221         unsigned char *indices_data = malloc(((png_width+ 3) & -4) * png_height);
222         i = 0;
223         for (y=0 ; y < png_height ; y++) {
224             bitstream_t *bs = bitstream_open();
225             if (bs == NULL) {
226               free(*colormap);
227               *colormap = NULL;
228               free(indices_data);
229               return NULL;
230             }
231             bitstream_input(bs, png_image_data[y], png_width);
232             for (x=0 ; x < png_width ; x++) {
233                 indices_data[i] = bitstream_getbits(bs, bpp);
234                 i++;
235             }
236             while (i % 4) { i++; } // 4byte alignment
237             bitstream_close(bs);
238         }
239         image_data = indices_data;
240     } else if (color_type == PNG_COLOR_TYPE_RGB) {
241         swf_xrgb_t *xrgb_list;
242         xrgb_list = malloc(sizeof(swf_xrgb_t) * png_width * png_height);
243         for (y=0 ; y < png_height ; y++) {
244             for (x=0 ; x < png_width ; x++) {
245                 xrgb_list[x+y*png_width].red   = png_image_data[y][3*x + 0];
246                 xrgb_list[x+y*png_width].green = png_image_data[y][3*x + 1];
247                 xrgb_list[x+y*png_width].blue  = png_image_data[y][3*x + 2];
248             }
249         }
250         image_data = xrgb_list;
251     } else { // PNG_COLOR_TYPE_RGB_ALPHA
252         swf_argb_t *argb_list;
253         argb_list = malloc(sizeof(swf_argb_t) * png_width * png_height);
254         for (y=0 ; y < png_height ; y++) {
255             for (x=0 ; x < png_width ; x++) {
256                 int alpha_value = png_image_data[y][4*x + 3];
257                 argb_list[x+y*png_width].red   = png_image_data[y][4*x + 0] * alpha_value / 0xff;
258                 argb_list[x+y*png_width].green = png_image_data[y][4*x + 1] * alpha_value / 0xff;
259                 argb_list[x+y*png_width].blue  = png_image_data[y][4*x + 2] * alpha_value / 0xff;
260                 argb_list[x+y*png_width].alpha = alpha_value;
261             }
262         }
263         image_data = argb_list;
264     }
265     for (y=0 ; y < png_height ; y++) {
266         free(png_image_data[y]);
267     }
268     free(png_image_data);
269     /*
270      * destruct
271      */
272     png_destroy_read_struct((png_structpp) &png_ptr,
273                             (png_infopp) &png_info_ptr, NULL);
274     return image_data;
275 }
276
277 unsigned char *
278 pngconv_lossless2png(void *image_data,
279                      unsigned short width, unsigned short height,
280                      void *index_data,
281                      unsigned short index_data_count,
282                      int tag_no, int format,
283                      unsigned long *length) {
284     volatile png_structp png_ptr = NULL;
285     volatile png_infop png_info_ptr = NULL;
286     volatile my_png_buffer png_buff;
287     png_uint_32 png_width = 0, png_height = 0;
288     int bpp, color_type;
289     volatile png_bytepp png_image_data = NULL;
290     png_uint_32 x, y;
291     volatile png_colorp png_palette = NULL;
292     if (image_data == NULL) {
293         fprintf(stderr, "pngconv_lossless2png: image_data == NULL\n");
294         return NULL;
295     }
296     if ((format != 3) && (format != 5)) {
297         fprintf(stderr, "jpegconv_lossless2png: format=%d not implemented yes.\n", format);
298         return NULL;
299     }
300     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
301     if (! png_ptr) {
302         fprintf(stderr, "jpegconv_lossless2png: can't create write_struct\n");
303         return NULL;
304     }
305     if (setjmp(png_jmpbuf(png_ptr))) {
306         fprintf(stderr, "pngconv_lossless2png: libpng error jump occured\n");
307         free(png_palette);
308         if (png_image_data) {
309             for (y=0 ; y < png_height ; y++) {
310                 free(png_image_data[y]);
311             }
312             free(png_image_data);
313         }
314         free(png_buff.data);
315         png_destroy_write_struct((png_structpp) &png_ptr,
316                                  (png_infopp) &png_info_ptr);
317         return NULL;
318     }
319     png_info_ptr = png_create_info_struct(png_ptr);
320     if (! png_info_ptr) {
321         fprintf(stderr, "jpegconv_lossless2png: can't create info_struct\n");
322         png_destroy_write_struct((png_structpp) &png_ptr, NULL);
323         return NULL;
324     }
325     //
326     png_width = width;
327     png_height = height;
328     bpp = 8;
329     if (format == 3) {
330         color_type =  PNG_COLOR_TYPE_PALETTE;
331     } else if (tag_no == 20) { /* DefineBitsLossless */
332         color_type = PNG_COLOR_TYPE_RGB;
333     } else if (tag_no == 36) { /* DefineBitsLossless2 */
334         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
335     } else {
336         fprintf(stderr, "jpegconv_lossless2png: format!=3 and tag_no=%d not implemented.\n",
337                 tag_no);
338         png_destroy_write_struct((png_structpp) &png_ptr,
339                                  (png_infopp) &png_info_ptr);
340         return NULL;
341     }
342     png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);
343     png_set_IHDR(png_ptr, png_info_ptr,
344                  png_width, png_height, bpp, color_type,
345                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
346                  PNG_FILTER_TYPE_DEFAULT);
347     if (format == 3) {
348         int i;
349         if (index_data_count == 0) {
350             fprintf(stderr, "jpegconv_lossless2png: index_data_count == 0 at line(%d)\n", __LINE__);
351             png_destroy_write_struct((png_structpp) &png_ptr,
352                                      (png_infopp) &png_info_ptr);
353             return NULL;
354         }
355         png_palette = (png_colorp) malloc(sizeof(png_color)*index_data_count);
356         png_set_packing(png_ptr);
357         if (tag_no == 20) {
358             swf_rgb_t *rgb_list  = index_data;
359             for (i=0 ; i < index_data_count ; i++) {
360                 png_palette[i].red   = rgb_list[i].red;
361                 png_palette[i].green = rgb_list[i].green;
362                 png_palette[i].blue  = rgb_list[i].blue;
363             }
364         } else {
365             swf_rgba_t *rgba_list  = index_data;
366             for (i=0 ; i < index_data_count ; i++) {
367                 png_palette[i].red   = rgba_list[i].red;
368                 png_palette[i].green = rgba_list[i].green;
369                 png_palette[i].blue  = rgba_list[i].blue;
370 //                png_palette[i].alpha = rgba_list[i].alpha;
371             }
372         }
373         png_set_PLTE( png_ptr, png_info_ptr, png_palette, index_data_count);
374         free(png_palette);
375     }
376     png_image_data = (png_bytepp) malloc(png_height * sizeof(png_bytep));
377     if (color_type == PNG_COLOR_TYPE_PALETTE) {
378         for (y=0 ; y < png_height ; y++) {
379             png_image_data[y] = (png_bytep) malloc(png_get_rowbytes(png_ptr, png_info_ptr));
380             for (x=0 ; x < png_width ; x++) {
381                 unsigned char *data = image_data;
382                 png_image_data[y][x] = data[x + y*((png_width +3) & -4)];
383             }
384         }
385         
386     } else if (color_type == PNG_COLOR_TYPE_RGB) {
387         swf_xrgb_t *xrgb_list = image_data;
388         for (y=0 ; y < png_height ; y++) {
389             png_image_data[y] = (png_bytep) malloc(png_get_rowbytes(png_ptr, png_info_ptr)) \
390                 ;
391             for (x=0 ; x < png_width ; x++) {
392                 png_image_data[y][3*x]   =  xrgb_list[x+y*png_width].red;
393                 png_image_data[y][3*x+1] =  xrgb_list[x+y*png_width].green;
394                 png_image_data[y][3*x+2] =  xrgb_list[x+y*png_width].blue;
395             }
396         }
397     } else {
398         swf_argb_t *argb_list = image_data;
399         for (y=0 ; y < png_height ; y++) {
400             png_image_data[y] = (png_bytep) malloc(png_get_rowbytes(png_ptr, png_info_ptr));
401             for (x=0 ; x < png_width ; x++) {
402                 png_image_data[y][4*x]   = argb_list[x+y*png_width].red;
403                 png_image_data[y][4*x+1] = argb_list[x+y*png_width].green;
404                 png_image_data[y][4*x+2] = argb_list[x+y*png_width].blue;
405                 png_image_data[y][4*x+3] = argb_list[x+y*png_width].alpha;
406             }
407         }
408         
409     }
410     png_buff.data = NULL;
411     png_buff.data_len = 0;
412     png_buff.data_offset = 0;
413     png_data_write((png_structp) png_ptr, (my_png_buffer*) &png_buff);
414
415     png_write_info(png_ptr, png_info_ptr);
416     png_write_image(png_ptr, png_image_data);
417     png_write_end(png_ptr, png_info_ptr);
418     //
419     for (y=0 ; y < png_height ; y++) {
420         free(png_image_data[y]);
421     }
422     free(png_image_data);
423     png_destroy_write_struct((png_structpp) &png_ptr,
424                              (png_infopp) &png_info_ptr);
425     *length = png_buff.data_offset;
426     return png_buff.data;
427 }
428
429 #endif /* HAVE_PNG */