1 #include "config.h"
2 #include <png.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <setjmp.h>
6 #include "types.h"
7 #include "png.h"
8
9 #ifdef PNG_DEBUG
10 #define debug_printf(...) fprintf (stderr, __VA_ARGS__)
11 #else
12 #define debug_printf(format,args...) ((void)0)
13 #endif
14
15 struct png_virt_io
16 {
17 uint8_t *src;
18 uint_fast32_t len;
19 uint_fast32_t pos;
20 };
21
png_read_ocp(png_structp png_ptr,png_bytep data,png_size_t length)22 static void png_read_ocp(png_structp png_ptr, png_bytep data, png_size_t length)
23 {
24 struct png_virt_io *io = png_get_io_ptr (png_ptr);
25
26 if ((io->pos + length) > io->len)
27 {
28 debug_printf("[CPIFACE/PNG] png_read_ocp(): ran out of data - EOF\n");
29 longjmp( png_jmpbuf( png_ptr), 1);
30 }
31 memcpy (data, io->src + io->pos, length);
32 io->pos += length;
33 }
34
try_open_png(uint16_t * width,uint16_t * height,uint8_t ** data_bgra,uint8_t * src,uint_fast32_t srclen)35 int try_open_png (uint16_t *width, uint16_t *height, uint8_t **data_bgra, uint8_t *src, uint_fast32_t srclen)
36 {
37 png_structp png_ptr = 0;
38 png_infop info_ptr = 0;
39 png_infop end_info = 0;
40 struct png_virt_io io = {src, srclen, 0};
41 png_bytep *row_pointers = 0;
42
43 *data_bgra = 0;
44 *width = *height = 0;
45
46 if (srclen < 8)
47 {
48 debug_printf("[CPIFACE/PNG] try_open_png(): srclen < 8, unable to check header\n");
49 return -1;
50 }
51 if (png_sig_cmp(src, 0, 8))
52 {
53 debug_printf("[CPIFACE/PNG] try_open_png(): header is not a valid PNG file\n");
54 return -1;
55 }
56
57 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
58 NULL /*(png_voidp)user_error_ptr*/,
59 NULL /*user_error_fn*/,
60 NULL /*user_warning_fn*/);
61 if (!png_ptr)
62 {
63 debug_printf("[CPIFACE/PNG] png_create_read_struct() failed\n");
64 return -1;
65 }
66
67 info_ptr = png_create_info_struct (png_ptr);
68 if (!info_ptr)
69 {
70 debug_printf ("[CPIFACE/PNG] png_create_info_struct() failed #1\n");
71 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
72 return -1;
73 }
74
75 end_info = png_create_info_struct( png_ptr);
76 if (!end_info)
77 {
78 debug_printf ("[CPIFACE/PNG] png_create_info_struct() failed #2\n");
79 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
80 return -1;
81 }
82
83 if (setjmp (png_jmpbuf( png_ptr)))
84 {
85 debug_printf ("[CPIFACE/PNG] loading PNG, fatal error\n");
86 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
87 free (row_pointers);
88 free (*data_bgra); *data_bgra = 0;
89 *width = *height = 0;
90 return -1;
91 }
92
93 png_set_read_fn (png_ptr, &io, png_read_ocp);
94
95 png_set_user_limits (png_ptr, 1920, 1080);
96
97 #if 1
98 png_read_info (png_ptr, info_ptr);
99
100 {
101 png_uint_32 w, h;
102 int bit_depth, color_type, interlace_type, compression_type, filter_method;
103 int i;
104 int number_of_passes = 1;
105
106 png_get_IHDR(png_ptr, info_ptr, &w, &h,
107 &bit_depth, &color_type, &interlace_type,
108 &compression_type, &filter_method);
109
110 debug_printf ("[CPIFACE/PNG] png_get_IHDR: width=%"PRIu32" height=%"PRIu32" bit_depth=%d color_type=0x%x, interlace_type=0x%x, compression_type=0x%x filter_method=0x%x\n", w, h, bit_depth, color_type, interlace_type, compression_type, filter_method);
111
112 switch (color_type)
113 {
114 case PNG_COLOR_TYPE_GRAY:
115 /* (bit depths 1, 2, 4, 8, 16) */
116 if (bit_depth == 16)
117 {
118 png_set_strip_16 (png_ptr);
119 } else if (bit_depth < 8)
120 {
121 png_set_packing (png_ptr);
122 }
123 png_set_expand (png_ptr);
124 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
125 break;
126 case PNG_COLOR_TYPE_GRAY_ALPHA:
127 /* (bit depths 8, 16) */
128 if (bit_depth == 16)
129 {
130 png_set_strip_16 (png_ptr);
131 }
132 png_set_expand (png_ptr);
133 break;
134 case PNG_COLOR_TYPE_PALETTE:
135 /* bit depths 1, 2, 4, 8) */
136 png_set_palette_to_rgb (png_ptr);
137 png_set_bgr (png_ptr);
138 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
139 break;
140 case PNG_COLOR_TYPE_RGB:
141 /* (bit_depths 8, 16) */
142 if (bit_depth == 16)
143 {
144 png_set_strip_16 (png_ptr);
145 }
146 png_set_bgr (png_ptr);
147 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
148 break;
149 case PNG_COLOR_TYPE_RGB_ALPHA:
150 /* (bit_depths 8, 16) */
151 png_set_bgr (png_ptr);
152 break;
153 default:
154 debug_printf ("[CPIFACE/PNG] unknown color_type\n");
155 longjmp( png_jmpbuf( png_ptr), 1);
156 }
157
158 if (interlace_type == PNG_INTERLACE_ADAM7)
159 {
160 number_of_passes = png_set_interlace_handling(png_ptr);
161 }
162
163 png_read_update_info(png_ptr, info_ptr);
164
165 *width = w;
166 *height = h;
167
168 *data_bgra = malloc (w * h * 4);
169
170 row_pointers = malloc (h * sizeof (row_pointers[0]));
171 for (i = 0; i < h; i++)
172 {
173 row_pointers[i] = *data_bgra + w * i * 4;
174 }
175 for (i=0; i < number_of_passes; i++)
176 {
177 png_read_image (png_ptr, row_pointers);
178 }
179 }
180
181 #else
182 png_read_png (png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_BGR | PNG_TRANSFORM_GRAY_TO_RGB, NULL)
183 #endif
184
185 png_read_end(png_ptr, end_info);
186
187 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
188
189 png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1);
190
191 free (row_pointers); row_pointers = 0;
192
193 return 0;
194 }
195