]>
Commit | Line | Data |
---|---|---|
c801d85f KB |
1 | |
2 | /* pngread.c - read a PNG file | |
3 | * | |
4 | * libpng 1.0.1 | |
5 | * For conditions of distribution and use, see copyright notice in png.h | |
6 | * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. | |
7 | * Copyright (c) 1996, 1997 Andreas Dilger | |
8 | * Copyright (c) 1998, Glenn Randers-Pehrson | |
9 | * March 15, 1998 | |
10 | * | |
11 | * This file contains routines that an application calls directly to | |
12 | * read a PNG file or stream. | |
13 | */ | |
14 | ||
15 | #define PNG_INTERNAL | |
1f0299c1 | 16 | #include "../png/png.h" |
c801d85f KB |
17 | |
18 | /* Create a PNG structure for reading, and allocate any memory needed. */ | |
19 | png_structp | |
20 | png_create_read_struct(png_const_charp user_png_ver, voidp error_ptr, | |
21 | png_error_ptr error_fn, png_error_ptr warn_fn) | |
22 | { | |
23 | png_structp png_ptr; | |
24 | #ifdef USE_FAR_KEYWORD | |
25 | jmp_buf jmpbuf; | |
26 | #endif | |
27 | png_debug(1, "in png_create_read_struct\n"); | |
28 | if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL) | |
29 | { | |
30 | return (png_structp)NULL; | |
31 | } | |
32 | #ifdef USE_FAR_KEYWORD | |
33 | if (setjmp(jmpbuf)) | |
34 | #else | |
35 | if (setjmp(png_ptr->jmpbuf)) | |
36 | #endif | |
37 | { | |
38 | png_free(png_ptr, png_ptr->zbuf); | |
39 | png_destroy_struct(png_ptr); | |
40 | return (png_structp)NULL; | |
41 | } | |
42 | #ifdef USE_FAR_KEYWORD | |
43 | png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); | |
44 | #endif | |
45 | png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); | |
46 | ||
47 | /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so | |
48 | * we must recompile any applications that use any older library version. | |
49 | * For versions after libpng 1.0, we will be compatible, so we need | |
50 | * only check the first digit. | |
51 | */ | |
52 | if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || | |
53 | (user_png_ver[0] == '0' && user_png_ver[2] < '9')) | |
54 | { | |
55 | png_error(png_ptr, | |
56 | "Incompatible libpng version in application and library"); | |
57 | } | |
58 | ||
59 | /* initialize zbuf - compression buffer */ | |
60 | png_ptr->zbuf_size = PNG_ZBUF_SIZE; | |
61 | png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, | |
62 | (png_uint_32)png_ptr->zbuf_size); | |
63 | png_ptr->zstream.zalloc = png_zalloc; | |
64 | png_ptr->zstream.zfree = png_zfree; | |
65 | png_ptr->zstream.opaque = (voidpf)png_ptr; | |
66 | ||
67 | switch (inflateInit(&png_ptr->zstream)) | |
68 | { | |
69 | case Z_OK: /* Do nothing */ break; | |
70 | case Z_MEM_ERROR: | |
71 | case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; | |
72 | case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; | |
73 | default: png_error(png_ptr, "Unknown zlib error"); | |
74 | } | |
75 | ||
76 | png_ptr->zstream.next_out = png_ptr->zbuf; | |
77 | png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; | |
78 | ||
79 | png_set_read_fn(png_ptr, NULL, NULL); | |
80 | ||
81 | return (png_ptr); | |
82 | } | |
83 | ||
84 | /* Initialize PNG structure for reading, and allocate any memory needed. | |
85 | This interface is depreciated in favour of the png_create_read_struct(), | |
86 | and it will eventually disappear. */ | |
87 | void | |
88 | png_read_init(png_structp png_ptr) | |
89 | { | |
90 | jmp_buf tmp_jmp; /* to save current jump buffer */ | |
91 | ||
92 | png_debug(1, "in png_read_init\n"); | |
93 | /* save jump buffer and error functions */ | |
94 | png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); | |
95 | ||
96 | /* reset all variables to 0 */ | |
97 | png_memset(png_ptr, 0, sizeof (png_struct)); | |
98 | ||
99 | /* restore jump buffer */ | |
100 | png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); | |
101 | ||
102 | /* initialize zbuf - compression buffer */ | |
103 | png_ptr->zbuf_size = PNG_ZBUF_SIZE; | |
104 | png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, | |
105 | (png_uint_32)png_ptr->zbuf_size); | |
106 | png_ptr->zstream.zalloc = png_zalloc; | |
107 | png_ptr->zstream.zfree = png_zfree; | |
108 | png_ptr->zstream.opaque = (voidpf)png_ptr; | |
109 | ||
110 | switch (inflateInit(&png_ptr->zstream)) | |
111 | { | |
112 | case Z_OK: /* Do nothing */ break; | |
113 | case Z_MEM_ERROR: | |
114 | case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; | |
115 | case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; | |
116 | default: png_error(png_ptr, "Unknown zlib error"); | |
117 | } | |
118 | ||
119 | png_ptr->zstream.next_out = png_ptr->zbuf; | |
120 | png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; | |
121 | ||
122 | png_set_read_fn(png_ptr, NULL, NULL); | |
123 | } | |
124 | ||
125 | /* Read the information before the actual image data. This has been | |
126 | * changed in v0.90 to allow reading a file that already has the magic | |
127 | * bytes read from the stream. You can tell libpng how many bytes have | |
128 | * been read from the beginning of the stream (up to the maxumum of 8) | |
129 | * via png_set_sig_bytes(), and we will only check the remaining bytes | |
130 | * here. The application can then have access to the signature bytes we | |
131 | * read if it is determined that this isn't a valid PNG file. | |
132 | */ | |
133 | void | |
134 | png_read_info(png_structp png_ptr, png_infop info_ptr) | |
135 | { | |
136 | png_debug(1, "in png_read_info\n"); | |
137 | /* save jump buffer and error functions */ | |
138 | /* If we haven't checked all of the PNG signature bytes, do so now. */ | |
139 | if (png_ptr->sig_bytes < 8) | |
140 | { | |
141 | png_size_t num_checked = png_ptr->sig_bytes, | |
142 | num_to_check = 8 - num_checked; | |
143 | ||
144 | png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); | |
145 | png_ptr->sig_bytes = 8; | |
146 | ||
147 | if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) | |
148 | { | |
149 | if (num_checked < 4 && | |
150 | png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) | |
151 | png_error(png_ptr, "Not a PNG file"); | |
152 | else | |
153 | png_error(png_ptr, "PNG file corrupted by ASCII conversion"); | |
154 | } | |
155 | } | |
156 | ||
157 | for(;;) | |
158 | { | |
159 | png_byte chunk_length[4]; | |
160 | png_uint_32 length; | |
161 | ||
162 | png_read_data(png_ptr, chunk_length, 4); | |
163 | length = png_get_uint_32(chunk_length); | |
164 | ||
165 | png_reset_crc(png_ptr); | |
166 | png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |
167 | ||
168 | png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); | |
169 | ||
170 | /* This should be a binary subdivision search or a hash for | |
171 | * matching the chunk name rather than a linear search. | |
172 | */ | |
173 | if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) | |
174 | png_handle_IHDR(png_ptr, info_ptr, length); | |
175 | else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |
176 | png_handle_PLTE(png_ptr, info_ptr, length); | |
177 | else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |
178 | png_handle_IEND(png_ptr, info_ptr, length); | |
179 | else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
180 | { | |
181 | if (!(png_ptr->mode & PNG_HAVE_IHDR)) | |
182 | png_error(png_ptr, "Missing IHDR before IDAT"); | |
183 | else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && | |
184 | !(png_ptr->mode & PNG_HAVE_PLTE)) | |
185 | png_error(png_ptr, "Missing PLTE before IDAT"); | |
186 | ||
187 | png_ptr->idat_size = length; | |
188 | png_ptr->mode |= PNG_HAVE_IDAT; | |
189 | break; | |
190 | } | |
191 | #if defined(PNG_READ_bKGD_SUPPORTED) | |
192 | else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) | |
193 | png_handle_bKGD(png_ptr, info_ptr, length); | |
194 | #endif | |
195 | #if defined(PNG_READ_cHRM_SUPPORTED) | |
196 | else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) | |
197 | png_handle_cHRM(png_ptr, info_ptr, length); | |
198 | #endif | |
199 | #if defined(PNG_READ_gAMA_SUPPORTED) | |
200 | else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) | |
201 | png_handle_gAMA(png_ptr, info_ptr, length); | |
202 | #endif | |
203 | #if defined(PNG_READ_hIST_SUPPORTED) | |
204 | else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) | |
205 | png_handle_hIST(png_ptr, info_ptr, length); | |
206 | #endif | |
207 | #if defined(PNG_READ_oFFs_SUPPORTED) | |
208 | else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) | |
209 | png_handle_oFFs(png_ptr, info_ptr, length); | |
210 | #endif | |
211 | #if defined(PNG_READ_pCAL_SUPPORTED) | |
212 | else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) | |
213 | png_handle_pCAL(png_ptr, info_ptr, length); | |
214 | #endif | |
215 | #if defined(PNG_READ_pHYs_SUPPORTED) | |
216 | else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) | |
217 | png_handle_pHYs(png_ptr, info_ptr, length); | |
218 | #endif | |
219 | #if defined(PNG_READ_sBIT_SUPPORTED) | |
220 | else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) | |
221 | png_handle_sBIT(png_ptr, info_ptr, length); | |
222 | #endif | |
223 | #if defined(PNG_READ_sRGB_SUPPORTED) | |
224 | else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) | |
225 | png_handle_sRGB(png_ptr, info_ptr, length); | |
226 | #endif | |
227 | #if defined(PNG_READ_tEXt_SUPPORTED) | |
228 | else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) | |
229 | png_handle_tEXt(png_ptr, info_ptr, length); | |
230 | #endif | |
231 | #if defined(PNG_READ_tIME_SUPPORTED) | |
232 | else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) | |
233 | png_handle_tIME(png_ptr, info_ptr, length); | |
234 | #endif | |
235 | #if defined(PNG_READ_tRNS_SUPPORTED) | |
236 | else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) | |
237 | png_handle_tRNS(png_ptr, info_ptr, length); | |
238 | #endif | |
239 | #if defined(PNG_READ_zTXt_SUPPORTED) | |
240 | else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) | |
241 | png_handle_zTXt(png_ptr, info_ptr, length); | |
242 | #endif | |
243 | else | |
244 | png_handle_unknown(png_ptr, info_ptr, length); | |
245 | } | |
246 | } | |
247 | ||
248 | /* optional call to update the users info_ptr structure */ | |
249 | void | |
250 | png_read_update_info(png_structp png_ptr, png_infop info_ptr) | |
251 | { | |
252 | png_debug(1, "in png_read_update_info\n"); | |
253 | /* save jump buffer and error functions */ | |
254 | if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) | |
255 | png_read_start_row(png_ptr); | |
256 | png_read_transform_info(png_ptr, info_ptr); | |
257 | } | |
258 | ||
259 | /* Initialize palette, background, etc, after transformations | |
260 | * are set, but before any reading takes place. This allows | |
261 | * the user to obtail a gamma corrected palette, for example. | |
262 | * If the user doesn't call this, we will do it ourselves. | |
263 | */ | |
264 | void | |
265 | png_start_read_image(png_structp png_ptr) | |
266 | { | |
267 | png_debug(1, "in png_start_read_image\n"); | |
268 | /* save jump buffer and error functions */ | |
269 | if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) | |
270 | png_read_start_row(png_ptr); | |
271 | } | |
272 | ||
273 | void | |
274 | png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) | |
275 | { | |
276 | int ret; | |
277 | png_debug2(1, "in png_read_row (row %d, pass %d)\n", | |
278 | png_ptr->row_number, png_ptr->pass); | |
279 | /* save jump buffer and error functions */ | |
280 | if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) | |
281 | png_read_start_row(png_ptr); | |
282 | ||
283 | #if defined(PNG_READ_INTERLACING_SUPPORTED) | |
284 | /* if interlaced and we do not need a new row, combine row and return */ | |
285 | if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) | |
286 | { | |
287 | switch (png_ptr->pass) | |
288 | { | |
289 | case 0: | |
290 | if (png_ptr->row_number & 7) | |
291 | { | |
292 | if (dsp_row != NULL) | |
293 | png_combine_row(png_ptr, dsp_row, | |
294 | png_pass_dsp_mask[png_ptr->pass]); | |
295 | png_read_finish_row(png_ptr); | |
296 | return; | |
297 | } | |
298 | break; | |
299 | case 1: | |
300 | if ((png_ptr->row_number & 7) || png_ptr->width < 5) | |
301 | { | |
302 | if (dsp_row != NULL) | |
303 | png_combine_row(png_ptr, dsp_row, | |
304 | png_pass_dsp_mask[png_ptr->pass]); | |
305 | png_read_finish_row(png_ptr); | |
306 | return; | |
307 | } | |
308 | break; | |
309 | case 2: | |
310 | if ((png_ptr->row_number & 7) != 4) | |
311 | { | |
312 | if (dsp_row != NULL && (png_ptr->row_number & 4)) | |
313 | png_combine_row(png_ptr, dsp_row, | |
314 | png_pass_dsp_mask[png_ptr->pass]); | |
315 | png_read_finish_row(png_ptr); | |
316 | return; | |
317 | } | |
318 | break; | |
319 | case 3: | |
320 | if ((png_ptr->row_number & 3) || png_ptr->width < 3) | |
321 | { | |
322 | if (dsp_row != NULL) | |
323 | png_combine_row(png_ptr, dsp_row, | |
324 | png_pass_dsp_mask[png_ptr->pass]); | |
325 | png_read_finish_row(png_ptr); | |
326 | return; | |
327 | } | |
328 | break; | |
329 | case 4: | |
330 | if ((png_ptr->row_number & 3) != 2) | |
331 | { | |
332 | if (dsp_row != NULL && (png_ptr->row_number & 2)) | |
333 | png_combine_row(png_ptr, dsp_row, | |
334 | png_pass_dsp_mask[png_ptr->pass]); | |
335 | png_read_finish_row(png_ptr); | |
336 | return; | |
337 | } | |
338 | break; | |
339 | case 5: | |
340 | if ((png_ptr->row_number & 1) || png_ptr->width < 2) | |
341 | { | |
342 | if (dsp_row != NULL) | |
343 | png_combine_row(png_ptr, dsp_row, | |
344 | png_pass_dsp_mask[png_ptr->pass]); | |
345 | png_read_finish_row(png_ptr); | |
346 | return; | |
347 | } | |
348 | break; | |
349 | case 6: | |
350 | if (!(png_ptr->row_number & 1)) | |
351 | { | |
352 | png_read_finish_row(png_ptr); | |
353 | return; | |
354 | } | |
355 | break; | |
356 | } | |
357 | } | |
358 | #endif | |
359 | ||
360 | if (!(png_ptr->mode & PNG_HAVE_IDAT)) | |
361 | png_error(png_ptr, "Invalid attempt to read row data"); | |
362 | ||
363 | png_ptr->zstream.next_out = png_ptr->row_buf; | |
364 | png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; | |
365 | do | |
366 | { | |
367 | if (!(png_ptr->zstream.avail_in)) | |
368 | { | |
369 | while (!png_ptr->idat_size) | |
370 | { | |
371 | png_byte chunk_length[4]; | |
372 | ||
373 | png_crc_finish(png_ptr, 0); | |
374 | ||
375 | png_read_data(png_ptr, chunk_length, 4); | |
376 | png_ptr->idat_size = png_get_uint_32(chunk_length); | |
377 | ||
378 | png_reset_crc(png_ptr); | |
379 | png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |
380 | if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
381 | png_error(png_ptr, "Not enough image data"); | |
382 | } | |
383 | png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; | |
384 | png_ptr->zstream.next_in = png_ptr->zbuf; | |
385 | if (png_ptr->zbuf_size > png_ptr->idat_size) | |
386 | png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; | |
387 | png_crc_read(png_ptr, png_ptr->zbuf, | |
388 | (png_size_t)png_ptr->zstream.avail_in); | |
389 | png_ptr->idat_size -= png_ptr->zstream.avail_in; | |
390 | } | |
391 | ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); | |
392 | if (ret == Z_STREAM_END) | |
393 | { | |
394 | if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || | |
395 | png_ptr->idat_size) | |
396 | png_error(png_ptr, "Extra compressed data"); | |
397 | png_ptr->mode |= PNG_AFTER_IDAT; | |
398 | png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; | |
399 | break; | |
400 | } | |
401 | if (ret != Z_OK) | |
402 | png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : | |
403 | "Decompression error"); | |
404 | ||
405 | } while (png_ptr->zstream.avail_out); | |
406 | ||
407 | png_ptr->row_info.color_type = png_ptr->color_type; | |
408 | png_ptr->row_info.width = png_ptr->iwidth; | |
409 | png_ptr->row_info.channels = png_ptr->channels; | |
410 | png_ptr->row_info.bit_depth = png_ptr->bit_depth; | |
411 | png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; | |
412 | { | |
413 | png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * | |
414 | (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); | |
415 | } | |
416 | ||
417 | png_read_filter_row(png_ptr, &(png_ptr->row_info), | |
418 | png_ptr->row_buf + 1, png_ptr->prev_row + 1, | |
419 | (int)(png_ptr->row_buf[0])); | |
420 | ||
421 | png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, | |
422 | png_ptr->rowbytes + 1); | |
423 | ||
424 | if (png_ptr->transformations) | |
425 | png_do_read_transformations(png_ptr); | |
426 | ||
427 | #if defined(PNG_READ_INTERLACING_SUPPORTED) | |
428 | /* blow up interlaced rows to full size */ | |
429 | if (png_ptr->interlaced && | |
430 | (png_ptr->transformations & PNG_INTERLACE)) | |
431 | { | |
432 | if (png_ptr->pass < 6) | |
433 | png_do_read_interlace(&(png_ptr->row_info), | |
434 | png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); | |
435 | ||
436 | if (dsp_row != NULL) | |
437 | png_combine_row(png_ptr, dsp_row, | |
438 | png_pass_dsp_mask[png_ptr->pass]); | |
439 | if (row != NULL) | |
440 | png_combine_row(png_ptr, row, | |
441 | png_pass_mask[png_ptr->pass]); | |
442 | } | |
443 | else | |
444 | #endif | |
445 | { | |
446 | if (row != NULL) | |
447 | png_combine_row(png_ptr, row, 0xff); | |
448 | if (dsp_row != NULL) | |
449 | png_combine_row(png_ptr, dsp_row, 0xff); | |
450 | } | |
451 | png_read_finish_row(png_ptr); | |
452 | ||
453 | if (png_ptr->read_row_fn != NULL) | |
454 | (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); | |
455 | } | |
456 | ||
457 | /* Read one or more rows of image data. If the image is interlaced, | |
458 | * and png_set_interlace_handling() has been called, the rows need to | |
459 | * contain the contents of the rows from the previous pass. If the | |
460 | * image has alpha or transparency, and png_handle_alpha() has been | |
461 | * called, the rows contents must be initialized to the contents of the | |
462 | * screen. | |
463 | * | |
464 | * "row" holds the actual image, and pixels are placed in it | |
465 | * as they arrive. If the image is displayed after each pass, it will | |
466 | * appear to "sparkle" in. "display_row" can be used to display a | |
467 | * "chunky" progressive image, with finer detail added as it becomes | |
468 | * available. If you do not want this "chunky" display, you may pass | |
469 | * NULL for display_row. If you do not want the sparkle display, and | |
470 | * you have not called png_handle_alpha(), you may pass NULL for rows. | |
471 | * If you have called png_handle_alpha(), and the image has either an | |
472 | * alpha channel or a transparency chunk, you must provide a buffer for | |
473 | * rows. In this case, you do not have to provide a display_row buffer | |
474 | * also, but you may. If the image is not interlaced, or if you have | |
475 | * not called png_set_interlace_handling(), the display_row buffer will | |
476 | * be ignored, so pass NULL to it. | |
477 | */ | |
478 | ||
479 | void | |
480 | png_read_rows(png_structp png_ptr, png_bytepp row, | |
481 | png_bytepp display_row, png_uint_32 num_rows) | |
482 | { | |
483 | png_uint_32 i; | |
484 | png_bytepp rp; | |
485 | png_bytepp dp; | |
486 | ||
487 | png_debug(1, "in png_read_rows\n"); | |
488 | /* save jump buffer and error functions */ | |
489 | rp = row; | |
490 | dp = display_row; | |
491 | for (i = 0; i < num_rows; i++) | |
492 | { | |
493 | png_bytep rptr; | |
494 | png_bytep dptr; | |
495 | ||
496 | if (rp != NULL) | |
497 | rptr = *rp; | |
498 | else | |
499 | rptr = NULL; | |
500 | if (dp != NULL) | |
501 | dptr = *dp; | |
502 | else | |
503 | dptr = NULL; | |
504 | png_read_row(png_ptr, rptr, dptr); | |
505 | if (row != NULL) | |
506 | rp++; | |
507 | if (display_row != NULL) | |
508 | dp++; | |
509 | } | |
510 | } | |
511 | ||
512 | /* Read the entire image. If the image has an alpha channel or a tRNS | |
513 | * chunk, and you have called png_handle_alpha(), you will need to | |
514 | * initialize the image to the current image that PNG will be overlaying. | |
515 | * We set the num_rows again here, in case it was incorrectly set in | |
516 | * png_read_start_row() by a call to png_read_update_info() or | |
517 | * png_start_read_image() if png_set_interlace_handling() wasn't called | |
518 | * prior to either of these functions like it should have been. You can | |
519 | * only call this function once. If you desire to have an image for | |
520 | * each pass of a interlaced image, use png_read_rows() instead. | |
521 | */ | |
522 | void | |
523 | png_read_image(png_structp png_ptr, png_bytepp image) | |
524 | { | |
525 | png_uint_32 i; | |
526 | int pass, j; | |
527 | png_bytepp rp; | |
528 | ||
529 | png_debug(1, "in png_read_image\n"); | |
530 | /* save jump buffer and error functions */ | |
531 | pass = png_set_interlace_handling(png_ptr); | |
532 | ||
533 | png_ptr->num_rows = png_ptr->height; /* Make sure this is set correctly */ | |
534 | ||
535 | for (j = 0; j < pass; j++) | |
536 | { | |
537 | rp = image; | |
538 | for (i = 0; i < png_ptr->height; i++) | |
539 | { | |
540 | png_read_row(png_ptr, *rp, NULL); | |
541 | rp++; | |
542 | } | |
543 | } | |
544 | } | |
545 | ||
546 | /* Read the end of the PNG file. Will not read past the end of the | |
547 | * file, will verify the end is accurate, and will read any comments | |
548 | * or time information at the end of the file, if info is not NULL. | |
549 | */ | |
550 | void | |
551 | png_read_end(png_structp png_ptr, png_infop info_ptr) | |
552 | { | |
553 | png_byte chunk_length[4]; | |
554 | png_uint_32 length; | |
555 | ||
556 | png_debug(1, "in png_read_end\n"); | |
557 | /* save jump buffer and error functions */ | |
558 | png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ | |
559 | ||
560 | do | |
561 | { | |
562 | png_read_data(png_ptr, chunk_length, 4); | |
563 | length = png_get_uint_32(chunk_length); | |
564 | ||
565 | png_reset_crc(png_ptr); | |
566 | png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |
567 | ||
568 | png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); | |
569 | ||
570 | if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) | |
571 | png_handle_IHDR(png_ptr, info_ptr, length); | |
572 | else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
573 | { | |
574 | /* Zero length IDATs are legal after the last IDAT has been | |
575 | * read, but not after other chunks have been read. | |
576 | */ | |
577 | if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) | |
578 | png_error(png_ptr, "Too many IDAT's found"); | |
579 | else | |
580 | png_crc_finish(png_ptr, 0); | |
581 | } | |
582 | else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |
583 | png_handle_PLTE(png_ptr, info_ptr, length); | |
584 | else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |
585 | png_handle_IEND(png_ptr, info_ptr, length); | |
586 | #if defined(PNG_READ_bKGD_SUPPORTED) | |
587 | else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) | |
588 | png_handle_bKGD(png_ptr, info_ptr, length); | |
589 | #endif | |
590 | #if defined(PNG_READ_cHRM_SUPPORTED) | |
591 | else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) | |
592 | png_handle_cHRM(png_ptr, info_ptr, length); | |
593 | #endif | |
594 | #if defined(PNG_READ_gAMA_SUPPORTED) | |
595 | else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) | |
596 | png_handle_gAMA(png_ptr, info_ptr, length); | |
597 | #endif | |
598 | #if defined(PNG_READ_hIST_SUPPORTED) | |
599 | else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) | |
600 | png_handle_hIST(png_ptr, info_ptr, length); | |
601 | #endif | |
602 | #if defined(PNG_READ_oFFs_SUPPORTED) | |
603 | else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) | |
604 | png_handle_oFFs(png_ptr, info_ptr, length); | |
605 | #endif | |
606 | #if defined(PNG_READ_pCAL_SUPPORTED) | |
607 | else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) | |
608 | png_handle_pCAL(png_ptr, info_ptr, length); | |
609 | #endif | |
610 | #if defined(PNG_READ_pHYs_SUPPORTED) | |
611 | else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) | |
612 | png_handle_pHYs(png_ptr, info_ptr, length); | |
613 | #endif | |
614 | #if defined(PNG_READ_sBIT_SUPPORTED) | |
615 | else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) | |
616 | png_handle_sBIT(png_ptr, info_ptr, length); | |
617 | #endif | |
618 | #if defined(PNG_READ_sRGB_SUPPORTED) | |
619 | else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) | |
620 | png_handle_sRGB(png_ptr, info_ptr, length); | |
621 | #endif | |
622 | #if defined(PNG_READ_tEXt_SUPPORTED) | |
623 | else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) | |
624 | png_handle_tEXt(png_ptr, info_ptr, length); | |
625 | #endif | |
626 | #if defined(PNG_READ_tIME_SUPPORTED) | |
627 | else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) | |
628 | png_handle_tIME(png_ptr, info_ptr, length); | |
629 | #endif | |
630 | #if defined(PNG_READ_tRNS_SUPPORTED) | |
631 | else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) | |
632 | png_handle_tRNS(png_ptr, info_ptr, length); | |
633 | #endif | |
634 | #if defined(PNG_READ_zTXt_SUPPORTED) | |
635 | else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) | |
636 | png_handle_zTXt(png_ptr, info_ptr, length); | |
637 | #endif | |
638 | else | |
639 | png_handle_unknown(png_ptr, info_ptr, length); | |
640 | } while (!(png_ptr->mode & PNG_HAVE_IEND)); | |
641 | } | |
642 | ||
643 | /* free all memory used by the read */ | |
644 | void | |
645 | png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, | |
646 | png_infopp end_info_ptr_ptr) | |
647 | { | |
648 | png_structp png_ptr = NULL; | |
649 | png_infop info_ptr = NULL, end_info_ptr = NULL; | |
650 | ||
651 | png_debug(1, "in png_destroy_read_struct\n"); | |
652 | /* save jump buffer and error functions */ | |
653 | if (png_ptr_ptr != NULL) | |
654 | png_ptr = *png_ptr_ptr; | |
655 | ||
656 | if (info_ptr_ptr != NULL) | |
657 | info_ptr = *info_ptr_ptr; | |
658 | ||
659 | if (end_info_ptr_ptr != NULL) | |
660 | end_info_ptr = *end_info_ptr_ptr; | |
661 | ||
662 | png_read_destroy(png_ptr, info_ptr, end_info_ptr); | |
663 | ||
664 | if (info_ptr != NULL) | |
665 | { | |
666 | #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED) | |
667 | png_free(png_ptr, info_ptr->text); | |
668 | #endif | |
669 | png_destroy_struct((png_voidp)info_ptr); | |
670 | *info_ptr_ptr = (png_infop)NULL; | |
671 | } | |
672 | ||
673 | if (end_info_ptr != NULL) | |
674 | { | |
675 | #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED) | |
676 | png_free(png_ptr, end_info_ptr->text); | |
677 | #endif | |
678 | png_destroy_struct((png_voidp)end_info_ptr); | |
679 | *end_info_ptr_ptr = (png_infop)NULL; | |
680 | } | |
681 | ||
682 | if (png_ptr != NULL) | |
683 | { | |
684 | png_destroy_struct((png_voidp)png_ptr); | |
685 | *png_ptr_ptr = (png_structp)NULL; | |
686 | } | |
687 | } | |
688 | ||
689 | /* free all memory used by the read (old method) */ | |
690 | void | |
691 | png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr) | |
692 | { | |
693 | jmp_buf tmp_jmp; | |
694 | png_error_ptr error_fn; | |
695 | png_error_ptr warning_fn; | |
696 | png_voidp error_ptr; | |
697 | ||
698 | png_debug(1, "in png_read_destroy\n"); | |
699 | /* save jump buffer and error functions */ | |
700 | if (info_ptr != NULL) | |
701 | png_info_destroy(png_ptr, info_ptr); | |
702 | ||
703 | if (end_info_ptr != NULL) | |
704 | png_info_destroy(png_ptr, end_info_ptr); | |
705 | ||
706 | png_free(png_ptr, png_ptr->zbuf); | |
707 | png_free(png_ptr, png_ptr->row_buf); | |
708 | png_free(png_ptr, png_ptr->prev_row); | |
709 | #if defined(PNG_READ_DITHER_SUPPORTED) | |
710 | png_free(png_ptr, png_ptr->palette_lookup); | |
711 | png_free(png_ptr, png_ptr->dither_index); | |
712 | #endif | |
713 | #if defined(PNG_READ_GAMMA_SUPPORTED) | |
714 | png_free(png_ptr, png_ptr->gamma_table); | |
715 | #endif | |
716 | #if defined(PNG_READ_BACKGROUND_SUPPORTED) | |
717 | png_free(png_ptr, png_ptr->gamma_from_1); | |
718 | png_free(png_ptr, png_ptr->gamma_to_1); | |
719 | #endif | |
720 | if (png_ptr->flags & PNG_FLAG_FREE_PALETTE) | |
721 | png_zfree(png_ptr, png_ptr->palette); | |
722 | if (png_ptr->flags & PNG_FLAG_FREE_TRANS) | |
723 | png_free(png_ptr, png_ptr->trans); | |
724 | #if defined(PNG_READ_hIST_SUPPORTED) | |
725 | if (png_ptr->flags & PNG_FLAG_FREE_HIST) | |
726 | png_free(png_ptr, png_ptr->hist); | |
727 | #endif | |
728 | #if defined(PNG_READ_GAMMA_SUPPORTED) | |
729 | if (png_ptr->gamma_16_table != NULL) | |
730 | { | |
731 | int i; | |
732 | for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++) | |
733 | { | |
734 | png_free(png_ptr, png_ptr->gamma_16_table[i]); | |
735 | } | |
736 | } | |
737 | #endif | |
738 | #if defined(PNG_READ_BACKGROUND_SUPPORTED) | |
739 | png_free(png_ptr, png_ptr->gamma_16_table); | |
740 | if (png_ptr->gamma_16_from_1 != NULL) | |
741 | { | |
742 | int i; | |
743 | for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++) | |
744 | { | |
745 | png_free(png_ptr, png_ptr->gamma_16_from_1[i]); | |
746 | } | |
747 | } | |
748 | png_free(png_ptr, png_ptr->gamma_16_from_1); | |
749 | if (png_ptr->gamma_16_to_1 != NULL) | |
750 | { | |
751 | int i; | |
752 | for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++) | |
753 | { | |
754 | png_free(png_ptr, png_ptr->gamma_16_to_1[i]); | |
755 | } | |
756 | } | |
757 | png_free(png_ptr, png_ptr->gamma_16_to_1); | |
758 | #endif | |
759 | ||
760 | inflateEnd(&png_ptr->zstream); | |
761 | #ifdef PNG_PROGRESSIVE_READ_SUPPORTED | |
762 | png_free(png_ptr, png_ptr->save_buffer); | |
763 | #endif | |
764 | ||
765 | /* Save the important info out of the png_struct, in case it is | |
766 | * being used again. | |
767 | */ | |
768 | png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); | |
769 | ||
770 | error_fn = png_ptr->error_fn; | |
771 | warning_fn = png_ptr->warning_fn; | |
772 | error_ptr = png_ptr->error_ptr; | |
773 | ||
774 | png_memset(png_ptr, 0, sizeof (png_struct)); | |
775 | ||
776 | png_ptr->error_fn = error_fn; | |
777 | png_ptr->warning_fn = warning_fn; | |
778 | png_ptr->error_ptr = error_ptr; | |
779 | ||
780 | png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); | |
781 | } | |
782 | ||
783 | void | |
784 | png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) | |
785 | { | |
786 | png_ptr->read_row_fn = read_row_fn; | |
787 | } |