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