1 /* png.c
2  * PNG decoding
3  * (c) 2002 Karel 'Clock' Kulhavy
4  * This is a part of the Links program, released under GPL.
5  */
6 #include "cfg.h"
7 
8 #ifdef G
9 #include "links.h"
10 
11 #ifdef REPACK_16
12 #undef REPACK_16
13 #endif /* #ifdef REPACK_16 */
14 
15 #if SIZEOF_UNSIGNED_SHORT != 2
16 #define REPACK_16
17 #endif /* #if SIZEOF_UNSIGNED_SHORT != 2 */
18 
19 #ifndef REPACK_16
20 #ifndef C_LITTLE_ENDIAN
21 #ifndef C_BIG_ENDIAN
22 #define REPACK_16
23 #endif /* #ifndef C_BIG_ENDIAN */
24 #endif /* #ifndef C_LITTLE_ENDIAN */
25 #endif /* #ifndef REPACK_16 */
26 
27 /* Decoder structs */
28 
29 struct png_decoder{
30 	png_structp png_ptr;
31 	png_infop info_ptr;
32 };
33 
34 /* Warning for from-web PNG images */
img_my_png_warning(png_structp a,png_const_charp b)35 static void img_my_png_warning(png_structp a, png_const_charp b)
36 {
37 }
38 
39 /* Error for from-web PNG images. */
img_my_png_error(png_structp png_ptr,png_const_charp error_string)40 static void img_my_png_error(png_structp png_ptr, png_const_charp error_string)
41 {
42 #if (PNG_LIBPNG_VER < 10500)
43 	longjmp(png_ptr->jmpbuf,1);
44 #else
45 	png_longjmp(png_ptr,1);
46 #endif
47 }
48 
png_info_callback(png_structp png_ptr,png_infop info_ptr)49 static void png_info_callback(png_structp png_ptr, png_infop info_ptr)
50 {
51 	int bit_depth, color_type, intent;
52 	double gamma;
53 	unsigned char bytes_per_pixel=3;
54 	struct cached_image *cimg;
55 
56 	cimg=global_cimg;
57 
58 	bit_depth=png_get_bit_depth(png_ptr, info_ptr);
59 	color_type=png_get_color_type(png_ptr, info_ptr);
60 	if (color_type == PNG_COLOR_TYPE_PALETTE)
61 		png_set_expand(png_ptr);
62 	if (color_type == PNG_COLOR_TYPE_GRAY &&
63 		bit_depth < 8) png_set_expand(png_ptr);
64 	if (png_get_valid(png_ptr, info_ptr,
65 		PNG_INFO_tRNS)){
66 		png_set_expand(png_ptr); /* Legacy version of
67 		png_set_tRNS_to_alpha(png_ptr); */
68 		bytes_per_pixel++;
69 	}
70 	if (color_type == PNG_COLOR_TYPE_GRAY ||
71 		color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
72 		png_set_gray_to_rgb(png_ptr);
73 	if (bit_depth==16){
74 #ifndef REPACK_16
75 #ifdef C_LITTLE_ENDIAN
76 		/* We use native endianity only if unsigned short is 2-byte
77 		 * because otherwise we have to reassemble the buffer so we
78 		 * will leave in the libpng-native big endian.
79 		 */
80 		png_set_swap(png_ptr);
81 #endif /* #ifdef C_LITTLE_ENDIAN */
82 #endif /* #ifndef REPACK_16 */
83 		bytes_per_pixel*=(int)sizeof(unsigned short);
84 	}
85 	png_set_interlace_handling(png_ptr);
86 	if (color_type==PNG_COLOR_TYPE_RGB_ALPHA
87 		||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){
88 		if (bytes_per_pixel==3
89 			||bytes_per_pixel==3*sizeof(unsigned short))
90 			bytes_per_pixel=4*bytes_per_pixel/3;
91 	}
92 	cimg->width=(int)png_get_image_width(png_ptr,info_ptr);
93 	cimg->height=(int)png_get_image_height(png_ptr,info_ptr);
94 	cimg->buffer_bytes_per_pixel=bytes_per_pixel;
95 	if (png_get_sRGB(png_ptr, info_ptr, &intent)){
96 		gamma=sRGB_gamma;
97 	}
98 	else
99 	{
100 		if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){
101 			gamma=sRGB_gamma;
102 		}
103 	}
104 	if (gamma < 0.01 || gamma > 100)
105 		gamma = sRGB_gamma;
106 	cimg->red_gamma=(float)gamma;
107 	cimg->green_gamma=(float)gamma;
108 	cimg->blue_gamma=(float)gamma;
109 	png_read_update_info(png_ptr,info_ptr);
110 	cimg->strip_optimized=0;
111 	if (header_dimensions_known(cimg))
112 		img_my_png_error(png_ptr, "bad image size");
113 }
114 
115 #ifdef REPACK_16
116 /* Converts unsigned shorts to doublechars (in big endian) */
a2char_from_unsigned_short(unsigned char * chr,unsigned short * shrt,int len)117 static void a2char_from_unsigned_short(unsigned char *chr, unsigned short *shrt, int len)
118 {
119 	unsigned short s;
120 
121 	for (;len;len--,shrt++,chr+=2){
122 		s=*shrt;
123 		*chr=s>>8;
124 		chr[1]=s;
125 	}
126 }
127 
128 /* Converts doublechars (in big endian) to unsigned shorts */
unsigned_short_from_2char(unsigned short * shrt,unsigned char * chr,int len)129 static void unsigned_short_from_2char(unsigned short *shrt, unsigned char *chr, int len)
130 {
131 	unsigned short s;
132 
133 	for (;len;len--,shrt++,chr+=2){
134 		s=((*chr)<<8)|chr[1];
135 		*shrt=s;
136 	}
137 }
138 #endif
139 
png_row_callback(png_structp png_ptr,png_bytep new_row,png_uint_32 row_num,int pass)140 static void png_row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32
141 	row_num, int pass)
142 {
143 	struct cached_image *cimg;
144 #ifdef REPACK_16
145 	unsigned char *tmp;
146 	int channels;
147 #endif /* #ifdef REPACK_16 */
148 
149 	cimg=global_cimg;
150 #ifdef REPACK_16
151 	if (cimg->buffer_bytes_per_pixel>4)
152 	{
153 		channels=cimg->buffer_bytes_per_pixel/sizeof(unsigned
154 			short);
155 		if (PNG_INTERLACE_NONE==png_get_interlace_type(png_ptr,
156 			((struct png_decoder *)cimg->decoder)->info_ptr))
157 		{
158 			unsigned_short_from_2char((unsigned short *)(cimg->buffer+cimg
159 				->buffer_bytes_per_pixel *cimg->width
160 				*row_num), new_row, cimg->width
161 				*channels);
162 		}else{
163 			if ((unsigned)cimg->width > (unsigned)MAXINT / 2 / channels) overalloc();
164 			tmp=mem_alloc(cimg->width*2*channels);
165 			a2char_from_unsigned_short(tmp, (unsigned short *)(cimg->buffer
166 				+cimg->buffer_bytes_per_pixel
167 				*cimg->width*row_num), cimg->width*channels);
168 			png_progressive_combine_row(png_ptr, tmp, new_row);
169 			unsigned_short_from_2char((unsigned short *)(cimg->buffer
170 				+cimg->buffer_bytes_per_pixel
171 				*cimg->width*row_num), tmp, cimg->width*channels);
172 			mem_free(tmp);
173 		}
174 	}else
175 #endif /* #ifdef REPACK_16 */
176 	{
177 		png_progressive_combine_row(png_ptr,
178 			cimg->buffer+cimg->buffer_bytes_per_pixel
179 			*cimg->width*row_num, new_row);
180 	}
181 	cimg->rows_added=1;
182 }
183 
png_end_callback(png_structp png_ptr,png_infop info)184 static void png_end_callback(png_structp png_ptr, png_infop info)
185 {
186 	end_callback_hit=1;
187 }
188 
189 /* Decoder structs */
190 
png_start(struct cached_image * cimg)191 void png_start(struct cached_image *cimg)
192 {
193 	png_structp png_ptr;
194 	png_infop info_ptr;
195 	struct png_decoder *decoder;
196 
197 	retry1:
198 #ifdef PNG_USER_MEM_SUPPORTED
199 	png_ptr=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
200 			NULL, img_my_png_error, img_my_png_warning,
201 			NULL, my_png_alloc, my_png_free);
202 #else
203 	png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,
204 			NULL, img_my_png_error, img_my_png_warning);
205 #endif
206 	if (!png_ptr) {
207 		if (out_of_memory(0, NULL, 0)) goto retry1;
208 		fatal_exit("png_create_read_struct failed");
209 	}
210 	retry2:
211 	info_ptr=png_create_info_struct(png_ptr);
212 	if (!info_ptr) {
213 		if (out_of_memory(0, NULL, 0)) goto retry2;
214 		fatal_exit("png_create_info_struct failed");
215 	}
216 	if (setjmp(png_jmpbuf(png_ptr))){
217 error:
218 		png_destroy_read_struct(&png_ptr, &info_ptr,
219 			(png_infopp)NULL);
220 		img_end(cimg);
221 		return;
222 	}
223 	png_set_progressive_read_fn(png_ptr, NULL,
224 				    png_info_callback, &png_row_callback,
225 				    png_end_callback);
226 	if (setjmp(png_jmpbuf(png_ptr))) goto error;
227 	decoder=mem_alloc(sizeof(*decoder));
228 	decoder->png_ptr=png_ptr;
229 	decoder->info_ptr=info_ptr;
230 	cimg->decoder=decoder;
231 }
232 
png_restart(struct cached_image * cimg,unsigned char * data,int length)233 void png_restart(struct cached_image *cimg, unsigned char *data, int length)
234 {
235 	png_structp png_ptr;
236 	png_infop info_ptr;
237 	volatile int h;
238 
239 #ifdef DEBUG
240 	if (!cimg->decoder)
241 		internal_error("decoder NULL in png_restart\n");
242 
243 #endif /* #ifdef DEBUG */
244 	h = close_std_handle(2);
245 	png_ptr=((struct png_decoder *)(cimg->decoder))->png_ptr;
246 	info_ptr=((struct png_decoder *)(cimg->decoder))->info_ptr;
247 	end_callback_hit=0;
248 	if (setjmp(png_jmpbuf(png_ptr))) {
249 		restore_std_handle(2, h);
250 		img_end(cimg);
251 		return;
252 	}
253 	png_process_data(png_ptr, info_ptr, data, length);
254 	restore_std_handle(2, h);
255 	if (end_callback_hit) img_end(cimg);
256 }
257 
png_destroy_decoder(struct cached_image * cimg)258 void png_destroy_decoder(struct cached_image *cimg)
259 {
260 	struct png_decoder *decoder = (struct png_decoder *)cimg->decoder;
261 	png_destroy_read_struct(&decoder->png_ptr, &decoder->info_ptr, NULL);
262 }
263 
add_png_version(unsigned char ** s,int * l)264 void add_png_version(unsigned char **s, int *l)
265 {
266 	add_to_str(s, l, cast_uchar "PNG (");
267 #ifdef HAVE_PNG_GET_LIBPNG_VER
268 	add_to_str(s, l, cast_uchar png_get_libpng_ver(NULL));
269 #else
270 	add_to_str(s, l, cast_uchar PNG_LIBPNG_VER_STRING);
271 #endif
272 	add_chr_to_str(s, l, ')');
273 }
274 
275 #endif /* #ifdef G */
276