Rev 1897 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1897 | Rev 3928 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* pngwrite.c - general routines to write a PNG file |
1 | /* pngwrite.c - general routines to write a PNG file |
2 | * |
2 | * |
3 | * Last changed in libpng 1.5.1 [February 3, 2011] |
3 | * Last changed in libpng 1.6.2 [April 25, 2013] |
4 | * Copyright (c) 1998-2011 Glenn Randers-Pehrson |
4 | * Copyright (c) 1998-2013 Glenn Randers-Pehrson |
5 | * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) |
5 | * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) |
6 | * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) |
6 | * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) |
7 | * |
7 | * |
8 | * This code is released under the libpng license. |
8 | * This code is released under the libpng license. |
9 | * For conditions of distribution and use, see the disclaimer |
9 | * For conditions of distribution and use, see the disclaimer |
10 | * and license in png.h |
10 | * and license in png.h |
11 | */ |
11 | */ |
Line 12... | Line 12... | ||
12 | 12 | ||
- | 13 | #include "pngpriv.h" |
|
- | 14 | #if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) |
|
- | 15 | # include |
|
Line 13... | Line 16... | ||
13 | #include "pngpriv.h" |
16 | #endif |
Line -... | Line 17... | ||
- | 17 | ||
- | 18 | #ifdef PNG_WRITE_SUPPORTED |
|
- | 19 | ||
- | 20 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
|
- | 21 | /* Write out all the unknown chunks for the current given location */ |
|
- | 22 | static void |
|
- | 23 | write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, |
|
- | 24 | unsigned int where) |
|
- | 25 | { |
|
- | 26 | if (info_ptr->unknown_chunks_num) |
|
- | 27 | { |
|
- | 28 | png_const_unknown_chunkp up; |
|
- | 29 | ||
- | 30 | png_debug(5, "writing extra chunks"); |
|
- | 31 | ||
- | 32 | for (up = info_ptr->unknown_chunks; |
|
- | 33 | up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; |
|
- | 34 | ++up) |
|
- | 35 | if (up->location & where) |
|
- | 36 | { |
|
- | 37 | /* If per-chunk unknown chunk handling is enabled use it, otherwise |
|
- | 38 | * just write the chunks the application has set. |
|
- | 39 | */ |
|
- | 40 | #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED |
|
- | 41 | int keep = png_handle_as_unknown(png_ptr, up->name); |
|
- | 42 | ||
- | 43 | /* NOTE: this code is radically different from the read side in the |
|
- | 44 | * matter of handling an ancillary unknown chunk. In the read side |
|
- | 45 | * the default behavior is to discard it, in the code below the default |
|
- | 46 | * behavior is to write it. Critical chunks are, however, only |
|
- | 47 | * written if explicitly listed or if the default is set to write all |
|
- | 48 | * unknown chunks. |
|
- | 49 | * |
|
- | 50 | * The default handling is also slightly weird - it is not possible to |
|
- | 51 | * stop the writing of all unsafe-to-copy chunks! |
|
- | 52 | * |
|
- | 53 | * TODO: REVIEW: this would seem to be a bug. |
|
- | 54 | */ |
|
- | 55 | if (keep != PNG_HANDLE_CHUNK_NEVER && |
|
- | 56 | ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || |
|
- | 57 | keep == PNG_HANDLE_CHUNK_ALWAYS || |
|
- | 58 | (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && |
|
- | 59 | png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) |
|
- | 60 | #endif |
|
- | 61 | { |
|
- | 62 | /* TODO: review, what is wrong with a zero length unknown chunk? */ |
|
- | 63 | if (up->size == 0) |
|
- | 64 | png_warning(png_ptr, "Writing zero-length unknown chunk"); |
|
- | 65 | ||
- | 66 | png_write_chunk(png_ptr, up->name, up->data, up->size); |
|
- | 67 | } |
|
- | 68 | } |
|
- | 69 | } |
|
14 | 70 | } |
|
15 | #ifdef PNG_WRITE_SUPPORTED |
71 | #endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ |
16 | 72 | ||
17 | /* Writes all the PNG information. This is the suggested way to use the |
73 | /* Writes all the PNG information. This is the suggested way to use the |
18 | * library. If you have a new chunk to add, make a function to write it, |
74 | * library. If you have a new chunk to add, make a function to write it, |
19 | * and put it in the correct location here. If you want the chunk written |
75 | * and put it in the correct location here. If you want the chunk written |
20 | * after the image data, put it in png_write_end(). I strongly encourage |
76 | * after the image data, put it in png_write_end(). I strongly encourage |
21 | * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing |
77 | * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing |
22 | * the chunk, as that will keep the code from breaking if you want to just |
78 | * the chunk, as that will keep the code from breaking if you want to just |
23 | * write a plain PNG file. If you have long comments, I suggest writing |
79 | * write a plain PNG file. If you have long comments, I suggest writing |
24 | * them in png_write_end(), and compressing them. |
80 | * them in png_write_end(), and compressing them. |
25 | */ |
81 | */ |
26 | void PNGAPI |
82 | void PNGAPI |
Line 27... | Line 83... | ||
27 | png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) |
83 | png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) |
28 | { |
84 | { |
Line 49... | Line 105... | ||
49 | png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, |
105 | png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, |
50 | info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, |
106 | info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, |
51 | info_ptr->filter_type, |
107 | info_ptr->filter_type, |
52 | #ifdef PNG_WRITE_INTERLACING_SUPPORTED |
108 | #ifdef PNG_WRITE_INTERLACING_SUPPORTED |
53 | info_ptr->interlace_type); |
109 | info_ptr->interlace_type |
54 | #else |
110 | #else |
55 | 0); |
111 | 0 |
56 | #endif |
112 | #endif |
57 | /* The rest of these check to see if the valid field has the appropriate |
113 | ); |
- | 114 | ||
- | 115 | /* The rest of these check to see if the valid field has the appropriate |
|
58 | * flag set, and if it does, writes the chunk. |
116 | * flag set, and if it does, writes the chunk. |
59 | */ |
117 | * |
- | 118 | * 1.6.0: COLORSPACE support controls the writing of these chunks too, and |
|
- | 119 | * the chunks will be written if the WRITE routine is there and information |
|
- | 120 | * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c |
|
- | 121 | * for where the valid flags get set.) |
|
- | 122 | * |
|
- | 123 | * Under certain circumstances the colorspace can be invalidated without |
|
- | 124 | * syncing the info_struct 'valid' flags; this happens if libpng detects and |
|
- | 125 | * error and calls png_error while the color space is being set, yet the |
|
- | 126 | * application continues writing the PNG. So check the 'invalid' flag here |
|
- | 127 | * too. |
|
- | 128 | */ |
|
60 | #ifdef PNG_WRITE_gAMA_SUPPORTED |
129 | #ifdef PNG_GAMMA_SUPPORTED |
- | 130 | # ifdef PNG_WRITE_gAMA_SUPPORTED |
|
61 | if (info_ptr->valid & PNG_INFO_gAMA) |
131 | if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && |
- | 132 | (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && |
|
- | 133 | (info_ptr->valid & PNG_INFO_gAMA)) |
|
62 | png_write_gAMA_fixed(png_ptr, info_ptr->gamma); |
134 | png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); |
63 | #endif |
135 | # endif |
64 | #ifdef PNG_WRITE_sRGB_SUPPORTED |
136 | #endif |
- | 137 | ||
- | 138 | #ifdef PNG_COLORSPACE_SUPPORTED |
|
- | 139 | /* Write only one of sRGB or an ICC profile. If a profile was supplied |
|
- | 140 | * and it matches one of the known sRGB ones issue a warning. |
|
- | 141 | */ |
|
- | 142 | # ifdef PNG_WRITE_iCCP_SUPPORTED |
|
- | 143 | if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && |
|
- | 144 | (info_ptr->valid & PNG_INFO_iCCP)) |
|
- | 145 | { |
|
- | 146 | # ifdef PNG_WRITE_sRGB_SUPPORTED |
|
65 | if (info_ptr->valid & PNG_INFO_sRGB) |
147 | if (info_ptr->valid & PNG_INFO_sRGB) |
66 | png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); |
148 | png_app_warning(png_ptr, |
- | 149 | "profile matches sRGB but writing iCCP instead"); |
|
67 | #endif |
150 | # endif |
68 | 151 | ||
Line 69... | Line 152... | ||
69 | #ifdef PNG_WRITE_iCCP_SUPPORTED |
152 | png_write_iCCP(png_ptr, info_ptr->iccp_name, |
70 | if (info_ptr->valid & PNG_INFO_iCCP) |
153 | info_ptr->iccp_profile); |
- | 154 | } |
|
71 | png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, |
155 | # ifdef PNG_WRITE_sRGB_SUPPORTED |
72 | (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); |
156 | else |
73 | #endif |
157 | # endif |
- | 158 | # endif |
|
- | 159 | ||
- | 160 | # ifdef PNG_WRITE_sRGB_SUPPORTED |
|
- | 161 | if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && |
|
- | 162 | (info_ptr->valid & PNG_INFO_sRGB)) |
|
- | 163 | png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); |
|
- | 164 | # endif /* WRITE_sRGB */ |
|
- | 165 | #endif /* COLORSPACE */ |
|
- | 166 | ||
74 | #ifdef PNG_WRITE_sBIT_SUPPORTED |
167 | #ifdef PNG_WRITE_sBIT_SUPPORTED |
75 | if (info_ptr->valid & PNG_INFO_sBIT) |
168 | if (info_ptr->valid & PNG_INFO_sBIT) |
76 | png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); |
169 | png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); |
77 | #endif |
170 | #endif |
- | 171 | ||
- | 172 | #ifdef PNG_COLORSPACE_SUPPORTED |
|
78 | #ifdef PNG_WRITE_cHRM_SUPPORTED |
173 | # ifdef PNG_WRITE_cHRM_SUPPORTED |
79 | if (info_ptr->valid & PNG_INFO_cHRM) |
174 | if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && |
80 | png_write_cHRM_fixed(png_ptr, |
- | |
81 | info_ptr->x_white, info_ptr->y_white, |
175 | (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && |
82 | info_ptr->x_red, info_ptr->y_red, |
176 | (info_ptr->valid & PNG_INFO_cHRM)) |
83 | info_ptr->x_green, info_ptr->y_green, |
177 | png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); |
84 | info_ptr->x_blue, info_ptr->y_blue); |
178 | # endif |
85 | #endif |
179 | #endif |
Line 86... | Line 180... | ||
86 | 180 | ||
87 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
- | |
88 | if (info_ptr->unknown_chunks_num) |
- | |
89 | { |
- | |
90 | png_unknown_chunk *up; |
- | |
91 | - | ||
92 | png_debug(5, "writing extra chunks"); |
- | |
93 | - | ||
94 | for (up = info_ptr->unknown_chunks; |
- | |
95 | up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; |
- | |
96 | up++) |
- | |
97 | { |
- | |
98 | int keep = png_handle_as_unknown(png_ptr, up->name); |
- | |
99 | - | ||
100 | if (keep != PNG_HANDLE_CHUNK_NEVER && |
- | |
101 | up->location && !(up->location & PNG_HAVE_PLTE) && |
- | |
102 | !(up->location & PNG_HAVE_IDAT) && |
- | |
103 | ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || |
- | |
104 | (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) |
- | |
105 | { |
- | |
106 | if (up->size == 0) |
- | |
107 | png_warning(png_ptr, "Writing zero-length unknown chunk"); |
- | |
108 | 181 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
|
109 | png_write_chunk(png_ptr, up->name, up->data, up->size); |
- | |
110 | } |
- | |
111 | } |
- | |
112 | } |
182 | write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); |
- | 183 | #endif |
|
113 | #endif |
184 | |
114 | png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; |
185 | png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; |
115 | } |
186 | } |
Line 116... | Line 187... | ||
116 | } |
187 | } |
117 | 188 | ||
118 | void PNGAPI |
189 | void PNGAPI |
119 | png_write_info(png_structp png_ptr, png_infop info_ptr) |
190 | png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) |
120 | { |
191 | { |
121 | #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) |
192 | #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) |
Line 259... | Line 330... | ||
259 | } |
330 | } |
260 | #endif /* tEXt */ |
331 | #endif /* tEXt */ |
261 | 332 | ||
Line 262... | Line 333... | ||
262 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
333 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
263 | if (info_ptr->unknown_chunks_num) |
- | |
264 | { |
- | |
265 | png_unknown_chunk *up; |
- | |
266 | - | ||
267 | png_debug(5, "writing extra chunks"); |
- | |
268 | - | ||
269 | for (up = info_ptr->unknown_chunks; |
- | |
270 | up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; |
- | |
271 | up++) |
- | |
272 | { |
- | |
273 | int keep = png_handle_as_unknown(png_ptr, up->name); |
- | |
274 | if (keep != PNG_HANDLE_CHUNK_NEVER && |
- | |
275 | up->location && (up->location & PNG_HAVE_PLTE) && |
- | |
276 | !(up->location & PNG_HAVE_IDAT) && |
- | |
277 | ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || |
- | |
278 | (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) |
- | |
279 | { |
- | |
280 | png_write_chunk(png_ptr, up->name, up->data, up->size); |
334 | write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); |
281 | } |
- | |
282 | } |
- | |
283 | } |
- | |
284 | #endif |
335 | #endif |
285 | } |
336 | } |
Line 286... | Line 337... | ||
286 | 337 | ||
287 | /* Writes the end of the PNG file. If you don't want to write comments or |
338 | /* Writes the end of the PNG file. If you don't want to write comments or |
288 | * time information, you can pass NULL for info. If you already wrote these |
339 | * time information, you can pass NULL for info. If you already wrote these |
289 | * in png_write_info(), do not write them again here. If you have long |
340 | * in png_write_info(), do not write them again here. If you have long |
290 | * comments, I suggest writing them here, and compressing them. |
341 | * comments, I suggest writing them here, and compressing them. |
291 | */ |
342 | */ |
292 | void PNGAPI |
343 | void PNGAPI |
293 | png_write_end(png_structp png_ptr, png_infop info_ptr) |
344 | png_write_end(png_structrp png_ptr, png_inforp info_ptr) |
294 | { |
345 | { |
Line 295... | Line 346... | ||
295 | png_debug(1, "in png_write_end"); |
346 | png_debug(1, "in png_write_end"); |
296 | 347 | ||
Line 297... | Line 348... | ||
297 | if (png_ptr == NULL) |
348 | if (png_ptr == NULL) |
298 | return; |
349 | return; |
Line -... | Line 350... | ||
- | 350 | ||
- | 351 | if (!(png_ptr->mode & PNG_HAVE_IDAT)) |
|
- | 352 | png_error(png_ptr, "No IDATs written into file"); |
|
- | 353 | ||
- | 354 | #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED |
|
299 | 355 | if (png_ptr->num_palette_max > png_ptr->num_palette) |
|
300 | if (!(png_ptr->mode & PNG_HAVE_IDAT)) |
356 | png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); |
301 | png_error(png_ptr, "No IDATs written into file"); |
357 | #endif |
302 | 358 | ||
303 | /* See if user wants us to write information chunks */ |
359 | /* See if user wants us to write information chunks */ |
Line 366... | Line 422... | ||
366 | } |
422 | } |
367 | } |
423 | } |
368 | #endif |
424 | #endif |
369 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
425 | #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED |
370 | if (info_ptr->unknown_chunks_num) |
426 | write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); |
371 | { |
- | |
372 | png_unknown_chunk *up; |
- | |
373 | - | ||
374 | png_debug(5, "writing extra chunks"); |
- | |
375 | - | ||
376 | for (up = info_ptr->unknown_chunks; |
- | |
377 | up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; |
- | |
378 | up++) |
- | |
379 | { |
- | |
380 | int keep = png_handle_as_unknown(png_ptr, up->name); |
- | |
381 | if (keep != PNG_HANDLE_CHUNK_NEVER && |
- | |
382 | up->location && (up->location & PNG_AFTER_IDAT) && |
- | |
383 | ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || |
- | |
384 | (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) |
- | |
385 | { |
- | |
386 | png_write_chunk(png_ptr, up->name, up->data, up->size); |
- | |
387 | } |
427 | #endif |
388 | } |
- | |
389 | } |
- | |
390 | #endif |
- | |
391 | } |
428 | } |
392 | 429 | ||
Line 393... | Line 430... | ||
393 | png_ptr->mode |= PNG_AFTER_IDAT; |
430 | png_ptr->mode |= PNG_AFTER_IDAT; |
Line 408... | Line 445... | ||
408 | #endif |
445 | #endif |
409 | } |
446 | } |
410 | 447 | ||
Line 411... | Line 448... | ||
411 | #ifdef PNG_CONVERT_tIME_SUPPORTED |
448 | #ifdef PNG_CONVERT_tIME_SUPPORTED |
412 | /* "tm" structure is not supported on WindowsCE */ |
- | |
413 | void PNGAPI |
449 | void PNGAPI |
414 | png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime) |
450 | png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) |
415 | { |
451 | { |
416 | png_debug(1, "in png_convert_from_struct_tm"); |
452 | png_debug(1, "in png_convert_from_struct_tm"); |
Line 417... | Line 453... | ||
417 | 453 | ||
418 | ptime->year = (png_uint_16)(1900 + ttime->tm_year); |
454 | ptime->year = (png_uint_16)(1900 + ttime->tm_year); |
Line 439... | Line 475... | ||
439 | PNG_FUNCTION(png_structp,PNGAPI |
475 | PNG_FUNCTION(png_structp,PNGAPI |
440 | png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, |
476 | png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, |
441 | png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) |
477 | png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) |
442 | { |
478 | { |
443 | #ifdef PNG_USER_MEM_SUPPORTED |
479 | #ifndef PNG_USER_MEM_SUPPORTED |
444 | return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, |
480 | png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, |
- | 481 | error_fn, warn_fn, NULL, NULL, NULL); |
|
- | 482 | #else |
|
- | 483 | return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, |
|
445 | warn_fn, NULL, NULL, NULL)); |
484 | warn_fn, NULL, NULL, NULL); |
446 | } |
485 | } |
447 | 486 | ||
Line 448... | Line 487... | ||
448 | /* Alternate initialize png_ptr structure, and allocate any memory needed */ |
487 | /* Alternate initialize png_ptr structure, and allocate any memory needed */ |
449 | static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */ |
- | |
450 | - | ||
451 | PNG_FUNCTION(png_structp,PNGAPI |
488 | PNG_FUNCTION(png_structp,PNGAPI |
452 | png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, |
489 | png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, |
453 | png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, |
490 | png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, |
454 | png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) |
491 | png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) |
455 | { |
492 | { |
- | 493 | png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, |
|
- | 494 | error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); |
|
456 | #endif /* PNG_USER_MEM_SUPPORTED */ |
495 | #endif /* PNG_USER_MEM_SUPPORTED */ |
457 | volatile int png_cleanup_needed = 0; |
- | |
458 | #ifdef PNG_SETJMP_SUPPORTED |
- | |
459 | volatile |
- | |
460 | #endif |
- | |
461 | png_structp png_ptr; |
- | |
462 | #ifdef PNG_SETJMP_SUPPORTED |
- | |
463 | #ifdef USE_FAR_KEYWORD |
- | |
464 | jmp_buf png_jmpbuf; |
- | |
465 | #endif |
- | |
466 | #endif |
- | |
467 | int i; |
- | |
468 | - | ||
469 | png_debug(1, "in png_create_write_struct"); |
- | |
470 | - | ||
471 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
472 | png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, |
- | |
473 | (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); |
- | |
474 | #else |
- | |
475 | png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); |
- | |
476 | #endif /* PNG_USER_MEM_SUPPORTED */ |
- | |
477 | if (png_ptr == NULL) |
496 | if (png_ptr != NULL) |
478 | return (NULL); |
- | |
479 | - | ||
480 | /* Added at libpng-1.2.6 */ |
- | |
481 | #ifdef PNG_SET_USER_LIMITS_SUPPORTED |
- | |
482 | png_ptr->user_width_max = PNG_USER_WIDTH_MAX; |
- | |
483 | png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; |
- | |
484 | #endif |
- | |
485 | - | ||
486 | #ifdef PNG_SETJMP_SUPPORTED |
- | |
487 | /* Applications that neglect to set up their own setjmp() and then |
- | |
488 | encounter a png_error() will longjmp here. Since the jmpbuf is |
- | |
489 | then meaningless we abort instead of returning. */ |
- | |
490 | #ifdef USE_FAR_KEYWORD |
- | |
491 | if (setjmp(png_jmpbuf)) |
- | |
492 | #else |
- | |
493 | if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ |
- | |
494 | #endif |
- | |
495 | #ifdef USE_FAR_KEYWORD |
- | |
496 | png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf)); |
- | |
497 | #endif |
- | |
498 | PNG_ABORT(); |
- | |
499 | #endif |
- | |
500 | - | ||
501 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
502 | png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); |
- | |
503 | #endif /* PNG_USER_MEM_SUPPORTED */ |
- | |
504 | png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); |
- | |
505 | - | ||
506 | if (user_png_ver) |
- | |
507 | { |
- | |
508 | i = 0; |
- | |
509 | do |
- | |
510 | { |
- | |
511 | if (user_png_ver[i] != png_libpng_ver[i]) |
- | |
512 | png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; |
- | |
513 | } while (png_libpng_ver[i++]); |
- | |
514 | } |
- | |
515 | - | ||
516 | if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) |
- | |
517 | { |
497 | { |
518 | /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so |
- | |
519 | * we must recompile any applications that use any older library version. |
498 | /* Set the zlib control values to defaults; they can be overridden by the |
520 | * For versions after libpng 1.0, we will be compatible, so we need |
499 | * application after the struct has been created. |
521 | * only check the first digit. |
- | |
522 | */ |
500 | */ |
523 | if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || |
501 | png_ptr->zbuffer_size = PNG_ZBUF_SIZE; |
524 | (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || |
- | |
525 | (user_png_ver[0] == '0' && user_png_ver[2] < '9')) |
- | |
526 | { |
- | |
527 | #ifdef PNG_CONSOLE_IO_SUPPORTED |
- | |
528 | char msg[80]; |
- | |
Line 529... | Line -... | ||
529 | - | ||
530 | if (user_png_ver) |
- | |
531 | { |
- | |
532 | png_snprintf2(msg, 80, |
502 | |
533 | "Application built with libpng-%.20s" |
503 | /* The 'zlib_strategy' setting is irrelevant because png_default_claim in |
534 | " but running with %.20s", |
- | |
535 | user_png_ver, |
- | |
536 | png_libpng_ver); |
504 | * pngwutil.c defaults it according to whether or not filters will be |
537 | png_warning(png_ptr, msg); |
505 | * used, and ignores this setting. |
538 | } |
- | |
539 | #else |
506 | */ |
540 | png_warning(png_ptr, |
507 | png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; |
541 | "Incompatible libpng version in application and library"); |
- | |
542 | #endif |
508 | png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; |
543 | #ifdef PNG_ERROR_NUMBERS_SUPPORTED |
509 | png_ptr->zlib_mem_level = 8; |
544 | png_ptr->flags = 0; |
- | |
545 | #endif |
510 | png_ptr->zlib_window_bits = 15; |
546 | png_cleanup_needed = 1; |
- | |
547 | } |
- | |
Line -... | Line 511... | ||
- | 511 | png_ptr->zlib_method = 8; |
|
- | 512 | ||
- | 513 | #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED |
|
548 | } |
514 | png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; |
549 | 515 | png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; |
|
- | 516 | png_ptr->zlib_text_mem_level = 8; |
|
- | 517 | png_ptr->zlib_text_window_bits = 15; |
|
Line -... | Line 518... | ||
- | 518 | png_ptr->zlib_text_method = 8; |
|
- | 519 | #endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ |
|
- | 520 | ||
550 | /* Initialize zbuf - compression buffer */ |
521 | /* This is a highly dubious configuration option; by default it is off, |
551 | png_ptr->zbuf_size = PNG_ZBUF_SIZE; |
522 | * but it may be appropriate for private builds that are testing |
552 | 523 | * extensions not conformant to the current specification, or of |
|
553 | if (!png_cleanup_needed) |
524 | * applications that must not fail to write at all costs! |
554 | { |
525 | */ |
555 | png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, |
526 | #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED |
556 | png_ptr->zbuf_size); |
527 | png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; |
- | 528 | /* In stable builds only warn if an application error can be completely |
|
Line 557... | Line -... | ||
557 | if (png_ptr->zbuf == NULL) |
- | |
558 | png_cleanup_needed = 1; |
- | |
559 | } |
529 | * handled. |
560 | 530 | */ |
|
561 | if (png_cleanup_needed) |
531 | #endif |
562 | { |
- | |
563 | /* Clean up PNG structure and deallocate any memory. */ |
- | |
564 | png_free(png_ptr, png_ptr->zbuf); |
532 | |
565 | png_ptr->zbuf = NULL; |
- | |
566 | #ifdef PNG_USER_MEM_SUPPORTED |
533 | /* App warnings are warnings in release (or release candidate) builds but |
567 | png_destroy_struct_2((png_voidp)png_ptr, |
534 | * are errors during development. |
568 | (png_free_ptr)free_fn, (png_voidp)mem_ptr); |
- | |
569 | #else |
- | |
Line -... | Line 535... | ||
- | 535 | */ |
|
- | 536 | #if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC |
|
- | 537 | png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; |
|
- | 538 | #endif |
|
570 | png_destroy_struct((png_voidp)png_ptr); |
539 | |
- | 540 | /* TODO: delay this, it can be done in png_init_io() (if the app doesn't |
|
Line 571... | Line -... | ||
571 | #endif |
- | |
572 | return (NULL); |
- | |
573 | } |
- | |
574 | - | ||
575 | png_set_write_fn(png_ptr, NULL, NULL, NULL); |
541 | * do it itself) avoiding setting the default function if it is not |
576 | 542 | * required. |
|
Line 577... | Line 543... | ||
577 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED |
543 | */ |
578 | png_reset_filter_heuristics(png_ptr); |
544 | png_set_write_fn(png_ptr, NULL, NULL, NULL); |
579 | #endif |
545 | } |
580 | 546 | ||
581 | return (png_ptr); |
547 | return png_ptr; |
582 | } |
548 | } |
583 | 549 | ||
584 | 550 | ||
585 | /* Write a few rows of image data. If the image is interlaced, |
551 | /* Write a few rows of image data. If the image is interlaced, |
586 | * either you will have to write the 7 sub images, or, if you |
552 | * either you will have to write the 7 sub images, or, if you |
587 | * have called png_set_interlace_handling(), you will have to |
553 | * have called png_set_interlace_handling(), you will have to |
Line 609... | Line 575... | ||
609 | /* Write the image. You only need to call this function once, even |
575 | /* Write the image. You only need to call this function once, even |
610 | * if you are writing an interlaced image. |
576 | * if you are writing an interlaced image. |
611 | */ |
577 | */ |
612 | void PNGAPI |
578 | void PNGAPI |
613 | png_write_image(png_structp png_ptr, png_bytepp image) |
579 | png_write_image(png_structrp png_ptr, png_bytepp image) |
614 | { |
580 | { |
615 | png_uint_32 i; /* row index */ |
581 | png_uint_32 i; /* row index */ |
616 | int pass, num_pass; /* pass variables */ |
582 | int pass, num_pass; /* pass variables */ |
617 | png_bytepp rp; /* points to current row */ |
583 | png_bytepp rp; /* points to current row */ |
Line 641... | Line 607... | ||
641 | } |
607 | } |
642 | 608 | ||
Line 643... | Line 609... | ||
643 | /* Called by user to write a row of image data */ |
609 | /* Called by user to write a row of image data */ |
644 | void PNGAPI |
610 | void PNGAPI |
645 | png_write_row(png_structp png_ptr, png_const_bytep row) |
611 | png_write_row(png_structrp png_ptr, png_const_bytep row) |
646 | { |
612 | { |
- | 613 | /* 1.5.6: moved from png_struct to be a local structure: */ |
|
- | 614 | png_row_info row_info; |
|
- | 615 | ||
647 | if (png_ptr == NULL) |
616 | if (png_ptr == NULL) |
648 | return; |
617 | return; |
Line 649... | Line 618... | ||
649 | 618 | ||
650 | png_debug2(1, "in png_write_row (row %u, pass %d)", |
619 | png_debug2(1, "in png_write_row (row %u, pass %d)", |
Line 766... | Line 735... | ||
766 | } |
735 | } |
767 | #endif |
736 | #endif |
768 | 737 | ||
Line 769... | Line 738... | ||
769 | /* Set up row info for transformations */ |
738 | /* Set up row info for transformations */ |
770 | png_ptr->row_info.color_type = png_ptr->color_type; |
739 | row_info.color_type = png_ptr->color_type; |
771 | png_ptr->row_info.width = png_ptr->usr_width; |
740 | row_info.width = png_ptr->usr_width; |
772 | png_ptr->row_info.channels = png_ptr->usr_channels; |
741 | row_info.channels = png_ptr->usr_channels; |
773 | png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; |
742 | row_info.bit_depth = png_ptr->usr_bit_depth; |
774 | png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * |
743 | row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); |
775 | png_ptr->row_info.channels); |
- | |
776 | - | ||
777 | png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, |
744 | row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); |
778 | png_ptr->row_info.width); |
- | |
779 | 745 | ||
780 | png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); |
746 | png_debug1(3, "row_info->color_type = %d", row_info.color_type); |
781 | png_debug1(3, "row_info->width = %u", png_ptr->row_info.width); |
747 | png_debug1(3, "row_info->width = %u", row_info.width); |
782 | png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); |
748 | png_debug1(3, "row_info->channels = %d", row_info.channels); |
783 | png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); |
749 | png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); |
784 | png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); |
750 | png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); |
785 | png_debug1(3, "row_info->rowbytes = %lu", |
751 | png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); |
786 | (unsigned long)png_ptr->row_info.rowbytes); |
- | |
Line 787... | Line 752... | ||
787 | 752 | ||
788 | /* Copy user's row into buffer, leaving room for filter byte. */ |
753 | /* Copy user's row into buffer, leaving room for filter byte. */ |
Line 789... | Line 754... | ||
789 | png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes); |
754 | memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); |
790 | 755 | ||
791 | #ifdef PNG_WRITE_INTERLACING_SUPPORTED |
756 | #ifdef PNG_WRITE_INTERLACING_SUPPORTED |
792 | /* Handle interlacing */ |
757 | /* Handle interlacing */ |
793 | if (png_ptr->interlaced && png_ptr->pass < 6 && |
758 | if (png_ptr->interlaced && png_ptr->pass < 6 && |
794 | (png_ptr->transformations & PNG_INTERLACE)) |
759 | (png_ptr->transformations & PNG_INTERLACE)) |
795 | { |
- | |
796 | png_do_write_interlace(&(png_ptr->row_info), |
760 | { |
797 | png_ptr->row_buf + 1, png_ptr->pass); |
761 | png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); |
798 | /* This should always get caught above, but still ... */ |
762 | /* This should always get caught above, but still ... */ |
799 | if (!(png_ptr->row_info.width)) |
763 | if (!(row_info.width)) |
800 | { |
764 | { |
801 | png_write_finish_row(png_ptr); |
765 | png_write_finish_row(png_ptr); |
802 | return; |
766 | return; |
803 | } |
767 | } |
Line -... | Line 768... | ||
- | 768 | } |
|
804 | } |
769 | #endif |
805 | #endif |
770 | |
806 | 771 | #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED |
|
- | 772 | /* Handle other transformations */ |
|
- | 773 | if (png_ptr->transformations) |
|
- | 774 | png_do_write_transformations(png_ptr, &row_info); |
|
- | 775 | #endif |
|
- | 776 | ||
- | 777 | /* At this point the row_info pixel depth must match the 'transformed' depth, |
|
- | 778 | * which is also the output depth. |
|
- | 779 | */ |
|
Line 807... | Line 780... | ||
807 | /* Handle other transformations */ |
780 | if (row_info.pixel_depth != png_ptr->pixel_depth || |
808 | if (png_ptr->transformations) |
781 | row_info.pixel_depth != png_ptr->transformed_pixel_depth) |
809 | png_do_write_transformations(png_ptr); |
782 | png_error(png_ptr, "internal write transform logic error"); |
810 | 783 | ||
Line 821... | Line 794... | ||
821 | if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && |
794 | if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && |
822 | (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) |
795 | (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) |
823 | { |
796 | { |
824 | /* Intrapixel differencing */ |
797 | /* Intrapixel differencing */ |
825 | png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); |
798 | png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); |
826 | } |
799 | } |
827 | #endif |
800 | #endif |
828 | 801 | ||
Line -... | Line 802... | ||
- | 802 | /* Added at libpng-1.5.10 */ |
|
- | 803 | #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED |
|
- | 804 | /* Check for out-of-range palette index */ |
|
- | 805 | if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && |
|
- | 806 | png_ptr->num_palette_max >= 0) |
|
- | 807 | png_do_check_palette_indexes(png_ptr, &row_info); |
|
- | 808 | #endif |
|
- | 809 | ||
829 | /* Find a filter if necessary, filter the row and write it out. */ |
810 | /* Find a filter if necessary, filter the row and write it out. */ |
830 | png_write_find_filter(png_ptr, &(png_ptr->row_info)); |
811 | png_write_find_filter(png_ptr, &row_info); |
Line 831... | Line 812... | ||
831 | 812 | ||
832 | if (png_ptr->write_row_fn != NULL) |
813 | if (png_ptr->write_row_fn != NULL) |
833 | (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); |
814 | (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); |
Line 834... | Line 815... | ||
834 | } |
815 | } |
835 | 816 | ||
836 | #ifdef PNG_WRITE_FLUSH_SUPPORTED |
817 | #ifdef PNG_WRITE_FLUSH_SUPPORTED |
837 | /* Set the automatic flush interval or 0 to turn flushing off */ |
818 | /* Set the automatic flush interval or 0 to turn flushing off */ |
838 | void PNGAPI |
819 | void PNGAPI |
839 | png_set_flush(png_structp png_ptr, int nrows) |
820 | png_set_flush(png_structrp png_ptr, int nrows) |
Line 840... | Line 821... | ||
840 | { |
821 | { |
841 | png_debug(1, "in png_set_flush"); |
822 | png_debug(1, "in png_set_flush"); |
Line 847... | Line 828... | ||
847 | } |
828 | } |
848 | 829 | ||
Line 849... | Line 830... | ||
849 | /* Flush the current output buffers now */ |
830 | /* Flush the current output buffers now */ |
850 | void PNGAPI |
831 | void PNGAPI |
851 | png_write_flush(png_structp png_ptr) |
832 | png_write_flush(png_structrp png_ptr) |
852 | { |
833 | { |
853 | int wrote_IDAT; |
- | |
854 | - | ||
855 | png_debug(1, "in png_write_flush"); |
834 | png_debug(1, "in png_write_flush"); |
Line 856... | Line 835... | ||
856 | 835 | ||
857 | if (png_ptr == NULL) |
836 | if (png_ptr == NULL) |
Line 858... | Line 837... | ||
858 | return; |
837 | return; |
859 | 838 | ||
860 | /* We have already written out all of the data */ |
839 | /* We have already written out all of the data */ |
Line 861... | Line -... | ||
861 | if (png_ptr->row_number >= png_ptr->num_rows) |
- | |
862 | return; |
- | |
863 | - | ||
864 | do |
- | |
865 | { |
- | |
866 | int ret; |
840 | if (png_ptr->row_number >= png_ptr->num_rows) |
867 | - | ||
868 | /* Compress the data */ |
- | |
869 | ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); |
- | |
870 | wrote_IDAT = 0; |
- | |
871 | - | ||
872 | /* Check for compression errors */ |
- | |
873 | if (ret != Z_OK) |
- | |
874 | { |
- | |
875 | if (png_ptr->zstream.msg != NULL) |
- | |
876 | png_error(png_ptr, png_ptr->zstream.msg); |
- | |
877 | - | ||
878 | else |
- | |
879 | png_error(png_ptr, "zlib error"); |
- | |
880 | } |
- | |
881 | - | ||
882 | if (!(png_ptr->zstream.avail_out)) |
- | |
883 | { |
- | |
884 | /* Write the IDAT and reset the zlib output buffer */ |
- | |
885 | png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); |
- | |
886 | png_ptr->zstream.next_out = png_ptr->zbuf; |
- | |
887 | png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; |
- | |
888 | wrote_IDAT = 1; |
- | |
889 | } |
- | |
890 | } while (wrote_IDAT == 1); |
- | |
891 | - | ||
892 | /* If there is any data left to be output, write it into a new IDAT */ |
- | |
893 | if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) |
- | |
894 | { |
- | |
895 | /* Write the IDAT and reset the zlib output buffer */ |
- | |
896 | png_write_IDAT(png_ptr, png_ptr->zbuf, |
- | |
897 | png_ptr->zbuf_size - png_ptr->zstream.avail_out); |
- | |
898 | png_ptr->zstream.next_out = png_ptr->zbuf; |
841 | return; |
899 | png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; |
842 | |
900 | } |
843 | png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); |
901 | png_ptr->flush_rows = 0; |
844 | png_ptr->flush_rows = 0; |
Line 902... | Line -... | ||
902 | png_flush(png_ptr); |
- | |
903 | } |
- | |
904 | #endif /* PNG_WRITE_FLUSH_SUPPORTED */ |
- | |
905 | - | ||
906 | /* Free all memory used by the write */ |
- | |
907 | void PNGAPI |
- | |
908 | png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) |
- | |
909 | { |
- | |
910 | png_structp png_ptr = NULL; |
- | |
911 | png_infop info_ptr = NULL; |
- | |
912 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
913 | png_free_ptr free_fn = NULL; |
- | |
914 | png_voidp mem_ptr = NULL; |
- | |
915 | #endif |
- | |
916 | - | ||
917 | png_debug(1, "in png_destroy_write_struct"); |
- | |
918 | - | ||
919 | if (png_ptr_ptr != NULL) |
- | |
920 | { |
- | |
921 | png_ptr = *png_ptr_ptr; |
- | |
922 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
923 | free_fn = png_ptr->free_fn; |
- | |
924 | mem_ptr = png_ptr->mem_ptr; |
- | |
925 | #endif |
- | |
926 | } |
- | |
927 | - | ||
928 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
929 | if (png_ptr != NULL) |
- | |
930 | { |
- | |
931 | free_fn = png_ptr->free_fn; |
- | |
932 | mem_ptr = png_ptr->mem_ptr; |
- | |
933 | } |
- | |
934 | #endif |
- | |
935 | - | ||
936 | if (info_ptr_ptr != NULL) |
- | |
937 | info_ptr = *info_ptr_ptr; |
- | |
938 | - | ||
939 | if (info_ptr != NULL) |
- | |
940 | { |
- | |
941 | if (png_ptr != NULL) |
845 | png_flush(png_ptr); |
942 | { |
- | |
943 | png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); |
- | |
944 | - | ||
945 | #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED |
- | |
946 | if (png_ptr->num_chunk_list) |
- | |
947 | { |
- | |
948 | png_free(png_ptr, png_ptr->chunk_list); |
- | |
949 | png_ptr->num_chunk_list = 0; |
- | |
950 | } |
- | |
951 | #endif |
846 | } |
952 | } |
- | |
953 | - | ||
954 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
955 | png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, |
847 | #endif /* PNG_WRITE_FLUSH_SUPPORTED */ |
956 | (png_voidp)mem_ptr); |
- | |
957 | #else |
- | |
Line -... | Line 848... | ||
- | 848 | ||
- | 849 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED |
|
958 | png_destroy_struct((png_voidp)info_ptr); |
850 | static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ |
959 | #endif |
851 | #endif |
960 | *info_ptr_ptr = NULL; |
- | |
961 | } |
- | |
962 | - | ||
963 | if (png_ptr != NULL) |
- | |
964 | { |
- | |
965 | png_write_destroy(png_ptr); |
- | |
966 | #ifdef PNG_USER_MEM_SUPPORTED |
- | |
967 | png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, |
- | |
968 | (png_voidp)mem_ptr); |
- | |
969 | #else |
- | |
970 | png_destroy_struct((png_voidp)png_ptr); |
- | |
971 | #endif |
- | |
972 | *png_ptr_ptr = NULL; |
- | |
973 | } |
- | |
974 | } |
- | |
975 | - | ||
976 | - | ||
977 | /* Free any memory used in png_ptr struct (old method) */ |
- | |
978 | void /* PRIVATE */ |
- | |
979 | png_write_destroy(png_structp png_ptr) |
- | |
980 | { |
- | |
981 | #ifdef PNG_SETJMP_SUPPORTED |
- | |
982 | jmp_buf tmp_jmp; /* Save jump buffer */ |
- | |
983 | #endif |
- | |
984 | png_error_ptr error_fn; |
- | |
985 | png_error_ptr warning_fn; |
- | |
986 | png_voidp error_ptr; |
852 | |
Line 987... | Line 853... | ||
987 | #ifdef PNG_USER_MEM_SUPPORTED |
853 | /* Free any memory used in png_ptr struct without freeing the struct itself. */ |
- | 854 | static void |
|
988 | png_free_ptr free_fn; |
855 | png_write_destroy(png_structrp png_ptr) |
Line 989... | Line 856... | ||
989 | #endif |
856 | { |
990 | 857 | png_debug(1, "in png_write_destroy"); |
|
991 | png_debug(1, "in png_write_destroy"); |
858 | |
992 | 859 | /* Free any memory zlib uses */ |
|
993 | /* Free any memory zlib uses */ |
860 | if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) |
994 | deflateEnd(&png_ptr->zstream); |
861 | deflateEnd(&png_ptr->zstream); |
995 | 862 | ||
996 | /* Free our memory. png_free checks NULL for us. */ |
863 | /* Free our memory. png_free checks NULL for us. */ |
997 | png_free(png_ptr, png_ptr->zbuf); |
864 | png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); |
998 | png_free(png_ptr, png_ptr->row_buf); |
865 | png_free(png_ptr, png_ptr->row_buf); |
Line 999... | Line -... | ||
999 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
- | |
1000 | png_free(png_ptr, png_ptr->prev_row); |
- | |
1001 | png_free(png_ptr, png_ptr->sub_row); |
- | |
1002 | png_free(png_ptr, png_ptr->up_row); |
- | |
1003 | png_free(png_ptr, png_ptr->avg_row); |
866 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
1004 | png_free(png_ptr, png_ptr->paeth_row); |
867 | png_free(png_ptr, png_ptr->prev_row); |
1005 | #endif |
868 | png_free(png_ptr, png_ptr->sub_row); |
1006 | 869 | png_free(png_ptr, png_ptr->up_row); |
|
1007 | #ifdef PNG_TIME_RFC1123_SUPPORTED |
870 | png_free(png_ptr, png_ptr->avg_row); |
1008 | png_free(png_ptr, png_ptr->time_buffer); |
871 | png_free(png_ptr, png_ptr->paeth_row); |
Line 1009... | Line 872... | ||
1009 | #endif |
872 | #endif |
1010 | - | ||
1011 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED |
873 | |
1012 | /* Use this to save a little code space, it doesn't free the filter_costs */ |
874 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED |
Line 1013... | Line -... | ||
1013 | png_reset_filter_heuristics(png_ptr); |
- | |
1014 | png_free(png_ptr, png_ptr->filter_costs); |
875 | /* Use this to save a little code space, it doesn't free the filter_costs */ |
1015 | png_free(png_ptr, png_ptr->inv_filter_costs); |
876 | png_reset_filter_heuristics(png_ptr); |
1016 | #endif |
- | |
1017 | 877 | png_free(png_ptr, png_ptr->filter_costs); |
|
1018 | #ifdef PNG_SETJMP_SUPPORTED |
878 | png_free(png_ptr, png_ptr->inv_filter_costs); |
- | 879 | #endif |
|
Line -... | Line 880... | ||
- | 880 | ||
- | 881 | #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED |
|
- | 882 | png_free(png_ptr, png_ptr->chunk_list); |
|
- | 883 | #endif |
|
- | 884 | ||
- | 885 | /* The error handling and memory handling information is left intact at this |
|
- | 886 | * point: the jmp_buf may still have to be freed. See png_destroy_png_struct |
|
- | 887 | * for how this happens. |
|
- | 888 | */ |
|
- | 889 | } |
|
1019 | /* Reset structure */ |
890 | |
Line 1020... | Line 891... | ||
1020 | png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf)); |
891 | /* Free all memory used by the write. |
1021 | #endif |
892 | * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for |
1022 | 893 | * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free |
|
1023 | error_fn = png_ptr->error_fn; |
- | |
1024 | warning_fn = png_ptr->warning_fn; |
- | |
1025 | error_ptr = png_ptr->error_ptr; |
- | |
Line -... | Line 894... | ||
- | 894 | * the passed in info_structs but it would quietly fail to free any of the data |
|
- | 895 | * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it |
|
- | 896 | * has no png_ptr.) |
|
- | 897 | */ |
|
1026 | #ifdef PNG_USER_MEM_SUPPORTED |
898 | void PNGAPI |
- | 899 | png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) |
|
1027 | free_fn = png_ptr->free_fn; |
900 | { |
1028 | #endif |
901 | png_debug(1, "in png_destroy_write_struct"); |
- | 902 | ||
1029 | 903 | if (png_ptr_ptr != NULL) |
|
Line 1030... | Line 904... | ||
1030 | png_memset(png_ptr, 0, png_sizeof(png_struct)); |
904 | { |
1031 | 905 | png_structrp png_ptr = *png_ptr_ptr; |
|
1032 | png_ptr->error_fn = error_fn; |
906 | |
1033 | png_ptr->warning_fn = warning_fn; |
907 | if (png_ptr != NULL) /* added in libpng 1.6.0 */ |
1034 | png_ptr->error_ptr = error_ptr; |
908 | { |
Line 1035... | Line 909... | ||
1035 | #ifdef PNG_USER_MEM_SUPPORTED |
909 | png_destroy_info_struct(png_ptr, info_ptr_ptr); |
1036 | png_ptr->free_fn = free_fn; |
910 | |
Line 1062... | Line 936... | ||
1062 | { |
936 | { |
1063 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
937 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
1064 | case 5: |
938 | case 5: |
1065 | case 6: |
939 | case 6: |
1066 | case 7: png_warning(png_ptr, "Unknown row filter for method 0"); |
940 | case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); |
1067 | #endif /* PNG_WRITE_FILTER_SUPPORTED */ |
941 | /* FALL THROUGH */ |
- | 942 | #endif /* PNG_WRITE_FILTER_SUPPORTED */ |
|
1068 | case PNG_FILTER_VALUE_NONE: |
943 | case PNG_FILTER_VALUE_NONE: |
1069 | png_ptr->do_filter = PNG_FILTER_NONE; break; |
944 | png_ptr->do_filter = PNG_FILTER_NONE; break; |
1070 | 945 | ||
Line 1071... | Line 946... | ||
1071 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
946 | #ifdef PNG_WRITE_FILTER_SUPPORTED |
Line 1084... | Line 959... | ||
1084 | default: |
959 | default: |
1085 | png_ptr->do_filter = (png_byte)filters; break; |
960 | png_ptr->do_filter = (png_byte)filters; break; |
1086 | #else |
961 | #else |
1087 | default: |
962 | default: |
1088 | png_warning(png_ptr, "Unknown row filter for method 0"); |
963 | png_app_error(png_ptr, "Unknown row filter for method 0"); |
1089 | #endif /* PNG_WRITE_FILTER_SUPPORTED */ |
964 | #endif /* PNG_WRITE_FILTER_SUPPORTED */ |
1090 | } |
965 | } |
Line 1091... | Line 966... | ||
1091 | 966 | ||
1092 | /* If we have allocated the row_buf, this means we have already started |
967 | /* If we have allocated the row_buf, this means we have already started |
Line 1175... | Line 1050... | ||
1175 | * filtered data going to zlib more consistent, hopefully resulting in |
1050 | * filtered data going to zlib more consistent, hopefully resulting in |
1176 | * better compression. |
1051 | * better compression. |
1177 | */ |
1052 | */ |
1178 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ |
1053 | #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ |
1179 | /* Conveneince reset API. */ |
1054 | /* Convenience reset API. */ |
1180 | static void |
1055 | static void |
1181 | png_reset_filter_heuristics(png_structp png_ptr) |
1056 | png_reset_filter_heuristics(png_structrp png_ptr) |
1182 | { |
1057 | { |
1183 | /* Clear out any old values in the 'weights' - this must be done because if |
1058 | /* Clear out any old values in the 'weights' - this must be done because if |
1184 | * the app calls set_filter_heuristics multiple times with different |
1059 | * the app calls set_filter_heuristics multiple times with different |
1185 | * 'num_weights' values we would otherwise potentially have wrong sized |
1060 | * 'num_weights' values we would otherwise potentially have wrong sized |
1186 | * arrays. |
1061 | * arrays. |
1187 | */ |
1062 | */ |
Line 1210... | Line 1085... | ||
1210 | /* Leave the filter_costs - this array is fixed size. */ |
1085 | /* Leave the filter_costs - this array is fixed size. */ |
1211 | } |
1086 | } |
Line 1212... | Line 1087... | ||
1212 | 1087 | ||
1213 | static int |
1088 | static int |
1214 | png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, |
1089 | png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, |
1215 | int num_weights) |
1090 | int num_weights) |
1216 | { |
1091 | { |
1217 | if (png_ptr == NULL) |
1092 | if (png_ptr == NULL) |
Line 1230... | Line 1105... | ||
1230 | 1105 | ||
Line 1231... | Line 1106... | ||
1231 | if (num_weights > 0) |
1106 | if (num_weights > 0) |
1232 | { |
1107 | { |
1233 | png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, |
1108 | png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, |
1234 | (png_uint_32)(png_sizeof(png_byte) * num_weights)); |
1109 | (png_uint_32)((sizeof (png_byte)) * num_weights)); |
Line 1235... | Line 1110... | ||
1235 | 1110 | ||
1236 | /* To make sure that the weighting starts out fairly */ |
1111 | /* To make sure that the weighting starts out fairly */ |
1237 | for (i = 0; i < num_weights; i++) |
1112 | for (i = 0; i < num_weights; i++) |
1238 | { |
1113 | { |
1239 | png_ptr->prev_filters[i] = 255; |
1114 | png_ptr->prev_filters[i] = 255; |
Line 1240... | Line 1115... | ||
1240 | } |
1115 | } |
1241 | 1116 | ||
Line 1242... | Line 1117... | ||
1242 | png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, |
1117 | png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, |
1243 | (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); |
1118 | (png_uint_32)((sizeof (png_uint_16)) * num_weights)); |
Line 1244... | Line 1119... | ||
1244 | 1119 | ||
1245 | png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, |
1120 | png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, |
1246 | (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); |
1121 | (png_uint_32)((sizeof (png_uint_16)) * num_weights)); |
1247 | 1122 | ||
Line 1260... | Line 1135... | ||
1260 | */ |
1135 | */ |
1261 | if (png_ptr->filter_costs == NULL) |
1136 | if (png_ptr->filter_costs == NULL) |
1262 | { |
1137 | { |
1263 | png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, |
1138 | png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, |
1264 | (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); |
1139 | (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); |
1265 | 1140 | ||
Line 1266... | Line 1141... | ||
1266 | png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, |
1141 | png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, |
1267 | (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); |
1142 | (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); |
1268 | } |
1143 | } |
Line 1269... | Line 1144... | ||
1269 | 1144 | ||
1270 | for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) |
1145 | for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) |
1271 | { |
1146 | { |
Line 1293... | Line 1168... | ||
1293 | 1168 | ||
Line 1294... | Line 1169... | ||
1294 | /* Provide floating and fixed point APIs */ |
1169 | /* Provide floating and fixed point APIs */ |
1295 | #ifdef PNG_FLOATING_POINT_SUPPORTED |
1170 | #ifdef PNG_FLOATING_POINT_SUPPORTED |
1296 | void PNGAPI |
1171 | void PNGAPI |
1297 | png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, |
1172 | png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, |
1298 | int num_weights, png_const_doublep filter_weights, |
1173 | int num_weights, png_const_doublep filter_weights, |
1299 | png_const_doublep filter_costs) |
1174 | png_const_doublep filter_costs) |
1300 | { |
1175 | { |
1301 | png_debug(1, "in png_set_filter_heuristics"); |
1176 | png_debug(1, "in png_set_filter_heuristics"); |
Line 1348... | Line 1223... | ||
1348 | #endif /* FLOATING_POINT */ |
1223 | #endif /* FLOATING_POINT */ |
1349 | 1224 | ||
Line 1350... | Line 1225... | ||
1350 | #ifdef PNG_FIXED_POINT_SUPPORTED |
1225 | #ifdef PNG_FIXED_POINT_SUPPORTED |
1351 | void PNGAPI |
1226 | void PNGAPI |
1352 | png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method, |
1227 | png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, |
1353 | int num_weights, png_const_fixed_point_p filter_weights, |
1228 | int num_weights, png_const_fixed_point_p filter_weights, |
1354 | png_const_fixed_point_p filter_costs) |
1229 | png_const_fixed_point_p filter_costs) |
1355 | { |
1230 | { |
1356 | png_debug(1, "in png_set_filter_heuristics_fixed"); |
1231 | png_debug(1, "in png_set_filter_heuristics_fixed"); |
Line 1414... | Line 1289... | ||
1414 | #endif /* FIXED_POINT */ |
1289 | #endif /* FIXED_POINT */ |
1415 | #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ |
1290 | #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ |
1416 | 1291 | ||
Line 1417... | Line 1292... | ||
1417 | void PNGAPI |
1292 | void PNGAPI |
1418 | png_set_compression_level(png_structp png_ptr, int level) |
1293 | png_set_compression_level(png_structrp png_ptr, int level) |
1419 | { |
1294 | { |
1420 | png_debug(1, "in png_set_compression_level"); |
1295 | png_debug(1, "in png_set_compression_level"); |
Line 1421... | Line 1296... | ||
1421 | 1296 | ||
1422 | if (png_ptr == NULL) |
1297 | if (png_ptr == NULL) |
Line 1423... | Line -... | ||
1423 | return; |
- | |
1424 | 1298 | return; |
|
1425 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; |
1299 | |
Line 1426... | Line 1300... | ||
1426 | png_ptr->zlib_level = level; |
1300 | png_ptr->zlib_level = level; |
1427 | } |
1301 | } |
1428 | 1302 | ||
1429 | void PNGAPI |
1303 | void PNGAPI |
Line 1430... | Line 1304... | ||
1430 | png_set_compression_mem_level(png_structp png_ptr, int mem_level) |
1304 | png_set_compression_mem_level(png_structrp png_ptr, int mem_level) |
1431 | { |
1305 | { |
Line 1432... | Line -... | ||
1432 | png_debug(1, "in png_set_compression_mem_level"); |
- | |
1433 | 1306 | png_debug(1, "in png_set_compression_mem_level"); |
|
1434 | if (png_ptr == NULL) |
1307 | |
Line 1435... | Line 1308... | ||
1435 | return; |
1308 | if (png_ptr == NULL) |
1436 | 1309 | return; |
|
1437 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; |
1310 | |
1438 | png_ptr->zlib_mem_level = mem_level; |
1311 | png_ptr->zlib_mem_level = mem_level; |
Line 1439... | Line 1312... | ||
1439 | } |
1312 | } |
1440 | 1313 | ||
Line -... | Line 1314... | ||
- | 1314 | void PNGAPI |
|
- | 1315 | png_set_compression_strategy(png_structrp png_ptr, int strategy) |
|
1441 | void PNGAPI |
1316 | { |
1442 | png_set_compression_strategy(png_structp png_ptr, int strategy) |
1317 | png_debug(1, "in png_set_compression_strategy"); |
1443 | { |
1318 | |
Line -... | Line 1319... | ||
- | 1319 | if (png_ptr == NULL) |
|
- | 1320 | return; |
|
- | 1321 | ||
1444 | png_debug(1, "in png_set_compression_strategy"); |
1322 | /* The flag setting here prevents the libpng dynamic selection of strategy. |
1445 | 1323 | */ |
|
1446 | if (png_ptr == NULL) |
1324 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; |
1447 | return; |
1325 | png_ptr->zlib_strategy = strategy; |
1448 | 1326 | } |
|
Line -... | Line 1327... | ||
- | 1327 | ||
- | 1328 | /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a |
|
- | 1329 | * smaller value of window_bits if it can do so safely. |
|
- | 1330 | */ |
|
- | 1331 | void PNGAPI |
|
- | 1332 | png_set_compression_window_bits(png_structrp png_ptr, int window_bits) |
|
1449 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; |
1333 | { |
- | 1334 | if (png_ptr == NULL) |
|
1450 | png_ptr->zlib_strategy = strategy; |
1335 | return; |
- | 1336 | ||
- | 1337 | /* Prior to 1.6.0 this would warn but then set the window_bits value, this |
|
Line 1451... | Line 1338... | ||
1451 | } |
1338 | * meant that negative window bits values could be selected which would cause |
1452 | - | ||
1453 | void PNGAPI |
- | |
1454 | png_set_compression_window_bits(png_structp png_ptr, int window_bits) |
- | |
1455 | { |
- | |
1456 | if (png_ptr == NULL) |
- | |
1457 | return; |
1339 | * libpng to write a non-standard PNG file with raw deflate or gzip |
1458 | 1340 | * compressed IDAT or ancillary chunks. Such files can be read and there is |
|
1459 | if (window_bits > 15) |
1341 | * no warning on read, so this seems like a very bad idea. |
1460 | png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); |
1342 | */ |
Line 1461... | Line -... | ||
1461 | - | ||
1462 | else if (window_bits < 8) |
- | |
1463 | png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); |
1343 | if (window_bits > 15) |
1464 | 1344 | { |
|
Line 1465... | Line 1345... | ||
1465 | #ifndef WBITS_8_OK |
1345 | png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); |
1466 | /* Avoid libpng bug with 256-byte windows */ |
1346 | window_bits = 15; |
1467 | if (window_bits == 8) |
1347 | } |
1468 | { |
1348 | |
Line 1469... | Line 1349... | ||
1469 | png_warning(png_ptr, "Compression window is being reset to 512"); |
1349 | else if (window_bits < 8) |
1470 | window_bits = 9; |
1350 | { |
Line -... | Line 1351... | ||
- | 1351 | png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); |
|
- | 1352 | window_bits = 8; |
|
- | 1353 | } |
|
1471 | } |
1354 | |
1472 | 1355 | png_ptr->zlib_window_bits = window_bits; |
|
Line 1473... | Line -... | ||
1473 | #endif |
- | |
1474 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; |
1356 | } |
1475 | png_ptr->zlib_window_bits = window_bits; |
1357 | |
Line -... | Line 1358... | ||
- | 1358 | void PNGAPI |
|
- | 1359 | png_set_compression_method(png_structrp png_ptr, int method) |
|
- | 1360 | { |
|
- | 1361 | png_debug(1, "in png_set_compression_method"); |
|
- | 1362 | ||
- | 1363 | if (png_ptr == NULL) |
|
- | 1364 | return; |
|
- | 1365 | ||
- | 1366 | /* This would produce an invalid PNG file if it worked, but it doesn't and |
|
- | 1367 | * deflate will fault it, so it is harmless to just warn here. |
|
- | 1368 | */ |
|
- | 1369 | if (method != 8) |
|
- | 1370 | png_warning(png_ptr, "Only compression method 8 is supported by PNG"); |
|
- | 1371 | ||
- | 1372 | png_ptr->zlib_method = method; |
|
- | 1373 | } |
|
- | 1374 | ||
- | 1375 | /* The following were added to libpng-1.5.4 */ |
|
- | 1376 | #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED |
|
- | 1377 | void PNGAPI |
|
- | 1378 | png_set_text_compression_level(png_structrp png_ptr, int level) |
|
- | 1379 | { |
|
- | 1380 | png_debug(1, "in png_set_text_compression_level"); |
|
- | 1381 | ||
- | 1382 | if (png_ptr == NULL) |
|
- | 1383 | return; |
|
- | 1384 | ||
- | 1385 | png_ptr->zlib_text_level = level; |
|
- | 1386 | } |
|
- | 1387 | ||
- | 1388 | void PNGAPI |
|
- | 1389 | png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) |
|
- | 1390 | { |
|
- | 1391 | png_debug(1, "in png_set_text_compression_mem_level"); |
|
- | 1392 | ||
- | 1393 | if (png_ptr == NULL) |
|
- | 1394 | return; |
|
- | 1395 | ||
- | 1396 | png_ptr->zlib_text_mem_level = mem_level; |
|
- | 1397 | } |
|
- | 1398 | ||
- | 1399 | void PNGAPI |
|
- | 1400 | png_set_text_compression_strategy(png_structrp png_ptr, int strategy) |
|
- | 1401 | { |
|
- | 1402 | png_debug(1, "in png_set_text_compression_strategy"); |
|
- | 1403 | ||
- | 1404 | if (png_ptr == NULL) |
|
- | 1405 | return; |
|
- | 1406 | ||
- | 1407 | png_ptr->zlib_text_strategy = strategy; |
|
- | 1408 | } |
|
- | 1409 | ||
- | 1410 | /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a |
|
- | 1411 | * smaller value of window_bits if it can do so safely. |
|
- | 1412 | */ |
|
- | 1413 | void PNGAPI |
|
- | 1414 | png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) |
|
- | 1415 | { |
|
- | 1416 | if (png_ptr == NULL) |
|
1476 | } |
1417 | return; |
- | 1418 | ||
- | 1419 | if (window_bits > 15) |
|
- | 1420 | { |
|
- | 1421 | png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); |
|
- | 1422 | window_bits = 15; |
|
- | 1423 | } |
|
- | 1424 | ||
- | 1425 | else if (window_bits < 8) |
|
- | 1426 | { |
|
- | 1427 | png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); |
|
- | 1428 | window_bits = 8; |
|
- | 1429 | } |
|
- | 1430 | ||
- | 1431 | png_ptr->zlib_text_window_bits = window_bits; |
|
- | 1432 | } |
|
- | 1433 | ||
1477 | 1434 | void PNGAPI |
|
1478 | void PNGAPI |
1435 | png_set_text_compression_method(png_structrp png_ptr, int method) |
1479 | png_set_compression_method(png_structp png_ptr, int method) |
1436 | { |
1480 | { |
1437 | png_debug(1, "in png_set_text_compression_method"); |
Line 1481... | Line 1438... | ||
1481 | png_debug(1, "in png_set_compression_method"); |
1438 | |
1482 | 1439 | if (png_ptr == NULL) |
|
Line 1483... | Line 1440... | ||
1483 | if (png_ptr == NULL) |
1440 | return; |
1484 | return; |
1441 | |
1485 | 1442 | if (method != 8) |
|
1486 | if (method != 8) |
1443 | png_warning(png_ptr, "Only compression method 8 is supported by PNG"); |
1487 | png_warning(png_ptr, "Only compression method 8 is supported by PNG"); |
1444 | |
1488 | 1445 | png_ptr->zlib_text_method = method; |
|
Line 1489... | Line 1446... | ||
1489 | png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; |
1446 | } |
Line 1516... | Line 1473... | ||
1516 | 1473 | ||
Line 1517... | Line 1474... | ||
1517 | 1474 | ||
1518 | #ifdef PNG_INFO_IMAGE_SUPPORTED |
1475 | #ifdef PNG_INFO_IMAGE_SUPPORTED |
1519 | void PNGAPI |
1476 | void PNGAPI |
1520 | png_write_png(png_structp png_ptr, png_infop info_ptr, |
1477 | png_write_png(png_structrp png_ptr, png_inforp info_ptr, |
1521 | int transforms, voidp params) |
1478 | int transforms, voidp params) |
1522 | { |
1479 | { |
1523 | if (png_ptr == NULL || info_ptr == NULL) |
1480 | if (png_ptr == NULL || info_ptr == NULL) |
Line 1555... | Line 1512... | ||
1555 | png_set_swap_alpha(png_ptr); |
1512 | png_set_swap_alpha(png_ptr); |
1556 | #endif |
1513 | #endif |
1557 | 1514 | ||
Line 1558... | Line 1515... | ||
1558 | #ifdef PNG_WRITE_FILLER_SUPPORTED |
1515 | #ifdef PNG_WRITE_FILLER_SUPPORTED |
1559 | /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ |
1516 | /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ |
1560 | if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) |
1517 | if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) |
1561 | png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); |
1518 | png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); |
Line 1562... | Line 1519... | ||
1562 | 1519 | ||
1563 | else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) |
1520 | else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) |
Line 1600... | Line 1557... | ||
1600 | PNG_UNUSED(transforms) /* Quiet compiler warnings */ |
1557 | PNG_UNUSED(transforms) /* Quiet compiler warnings */ |
1601 | PNG_UNUSED(params) |
1558 | PNG_UNUSED(params) |
1602 | } |
1559 | } |
1603 | #endif |
1560 | #endif |
- | 1561 | ||
- | 1562 | ||
- | 1563 | #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED |
|
- | 1564 | #ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ |
|
- | 1565 | /* Initialize the write structure - general purpose utility. */ |
|
- | 1566 | static int |
|
- | 1567 | png_image_write_init(png_imagep image) |
|
- | 1568 | { |
|
- | 1569 | png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, |
|
- | 1570 | png_safe_error, png_safe_warning); |
|
- | 1571 | ||
- | 1572 | if (png_ptr != NULL) |
|
- | 1573 | { |
|
- | 1574 | png_infop info_ptr = png_create_info_struct(png_ptr); |
|
- | 1575 | ||
- | 1576 | if (info_ptr != NULL) |
|
- | 1577 | { |
|
- | 1578 | png_controlp control = png_voidcast(png_controlp, |
|
- | 1579 | png_malloc_warn(png_ptr, (sizeof *control))); |
|
- | 1580 | ||
- | 1581 | if (control != NULL) |
|
- | 1582 | { |
|
- | 1583 | memset(control, 0, (sizeof *control)); |
|
- | 1584 | ||
- | 1585 | control->png_ptr = png_ptr; |
|
- | 1586 | control->info_ptr = info_ptr; |
|
- | 1587 | control->for_write = 1; |
|
- | 1588 | ||
- | 1589 | image->opaque = control; |
|
- | 1590 | return 1; |
|
- | 1591 | } |
|
- | 1592 | ||
- | 1593 | /* Error clean up */ |
|
- | 1594 | png_destroy_info_struct(png_ptr, &info_ptr); |
|
- | 1595 | } |
|
- | 1596 | ||
- | 1597 | png_destroy_write_struct(&png_ptr, NULL); |
|
- | 1598 | } |
|
- | 1599 | ||
- | 1600 | return png_image_error(image, "png_image_write_: out of memory"); |
|
- | 1601 | } |
|
- | 1602 | ||
- | 1603 | /* Arguments to png_image_write_main: */ |
|
- | 1604 | typedef struct |
|
- | 1605 | { |
|
- | 1606 | /* Arguments: */ |
|
- | 1607 | png_imagep image; |
|
- | 1608 | png_const_voidp buffer; |
|
- | 1609 | png_int_32 row_stride; |
|
- | 1610 | png_const_voidp colormap; |
|
- | 1611 | int convert_to_8bit; |
|
- | 1612 | /* Local variables: */ |
|
- | 1613 | png_const_voidp first_row; |
|
- | 1614 | ptrdiff_t row_bytes; |
|
- | 1615 | png_voidp local_row; |
|
- | 1616 | } png_image_write_control; |
|
- | 1617 | ||
- | 1618 | /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to |
|
- | 1619 | * do any necessary byte swapping. The component order is defined by the |
|
- | 1620 | * png_image format value. |
|
- | 1621 | */ |
|
- | 1622 | static int |
|
- | 1623 | png_write_image_16bit(png_voidp argument) |
|
- | 1624 | { |
|
- | 1625 | png_image_write_control *display = png_voidcast(png_image_write_control*, |
|
- | 1626 | argument); |
|
- | 1627 | png_imagep image = display->image; |
|
- | 1628 | png_structrp png_ptr = image->opaque->png_ptr; |
|
- | 1629 | ||
- | 1630 | png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, |
|
- | 1631 | display->first_row); |
|
- | 1632 | png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); |
|
- | 1633 | png_uint_16p row_end; |
|
- | 1634 | const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; |
|
- | 1635 | int aindex = 0; |
|
- | 1636 | png_uint_32 y = image->height; |
|
- | 1637 | ||
- | 1638 | if (image->format & PNG_FORMAT_FLAG_ALPHA) |
|
- | 1639 | { |
|
- | 1640 | if (image->format & PNG_FORMAT_FLAG_AFIRST) |
|
- | 1641 | { |
|
- | 1642 | aindex = -1; |
|
- | 1643 | ++input_row; /* To point to the first component */ |
|
- | 1644 | ++output_row; |
|
- | 1645 | } |
|
- | 1646 | ||
- | 1647 | else |
|
- | 1648 | aindex = channels; |
|
- | 1649 | } |
|
- | 1650 | ||
- | 1651 | else |
|
- | 1652 | png_error(png_ptr, "png_write_image: internal call error"); |
|
- | 1653 | ||
- | 1654 | /* Work out the output row end and count over this, note that the increment |
|
- | 1655 | * above to 'row' means that row_end can actually be beyond the end of the |
|
- | 1656 | * row; this is correct. |
|
- | 1657 | */ |
|
- | 1658 | row_end = output_row + image->width * (channels+1); |
|
- | 1659 | ||
- | 1660 | while (y-- > 0) |
|
- | 1661 | { |
|
- | 1662 | png_const_uint_16p in_ptr = input_row; |
|
- | 1663 | png_uint_16p out_ptr = output_row; |
|
- | 1664 | ||
- | 1665 | while (out_ptr < row_end) |
|
- | 1666 | { |
|
- | 1667 | const png_uint_16 alpha = in_ptr[aindex]; |
|
- | 1668 | png_uint_32 reciprocal = 0; |
|
- | 1669 | int c; |
|
- | 1670 | ||
- | 1671 | out_ptr[aindex] = alpha; |
|
- | 1672 | ||
- | 1673 | /* Calculate a reciprocal. The correct calculation is simply |
|
- | 1674 | * component/alpha*65535 << 15. (I.e. 15 bits of precision); this |
|
- | 1675 | * allows correct rounding by adding .5 before the shift. 'reciprocal' |
|
- | 1676 | * is only initialized when required. |
|
- | 1677 | */ |
|
- | 1678 | if (alpha > 0 && alpha < 65535) |
|
- | 1679 | reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; |
|
- | 1680 | ||
- | 1681 | c = channels; |
|
- | 1682 | do /* always at least one channel */ |
|
- | 1683 | { |
|
- | 1684 | png_uint_16 component = *in_ptr++; |
|
- | 1685 | ||
- | 1686 | /* The following gives 65535 for an alpha of 0, which is fine, |
|
- | 1687 | * otherwise if 0/0 is represented as some other value there is more |
|
- | 1688 | * likely to be a discontinuity which will probably damage |
|
- | 1689 | * compression when moving from a fully transparent area to a |
|
- | 1690 | * nearly transparent one. (The assumption here is that opaque |
|
- | 1691 | * areas tend not to be 0 intensity.) |
|
- | 1692 | */ |
|
- | 1693 | if (component >= alpha) |
|
- | 1694 | component = 65535; |
|
- | 1695 | ||
- | 1696 | /* component |
|
- | 1697 | * component*reciprocal is less than 2^31. |
|
- | 1698 | */ |
|
- | 1699 | else if (component > 0 && alpha < 65535) |
|
- | 1700 | { |
|
- | 1701 | png_uint_32 calc = component * reciprocal; |
|
- | 1702 | calc += 16384; /* round to nearest */ |
|
- | 1703 | component = (png_uint_16)(calc >> 15); |
|
- | 1704 | } |
|
- | 1705 | ||
- | 1706 | *out_ptr++ = component; |
|
- | 1707 | } |
|
- | 1708 | while (--c > 0); |
|
- | 1709 | ||
- | 1710 | /* Skip to next component (skip the intervening alpha channel) */ |
|
- | 1711 | ++in_ptr; |
|
- | 1712 | ++out_ptr; |
|
- | 1713 | } |
|
- | 1714 | ||
- | 1715 | png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); |
|
- | 1716 | input_row += display->row_bytes/(sizeof (png_uint_16)); |
|
- | 1717 | } |
|
- | 1718 | ||
- | 1719 | return 1; |
|
- | 1720 | } |
|
- | 1721 | ||
- | 1722 | /* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel |
|
- | 1723 | * is present it must be removed from the components, the components are then |
|
- | 1724 | * written in sRGB encoding. No components are added or removed. |
|
- | 1725 | * |
|
- | 1726 | * Calculate an alpha reciprocal to reverse pre-multiplication. As above the |
|
- | 1727 | * calculation can be done to 15 bits of accuracy; however, the output needs to |
|
- | 1728 | * be scaled in the range 0..255*65535, so include that scaling here. |
|
- | 1729 | */ |
|
- | 1730 | #define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) |
|
- | 1731 | ||
- | 1732 | static png_byte |
|
- | 1733 | png_unpremultiply(png_uint_32 component, png_uint_32 alpha, |
|
- | 1734 | png_uint_32 reciprocal/*from the above macro*/) |
|
- | 1735 | { |
|
- | 1736 | /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 |
|
- | 1737 | * is represented as some other value there is more likely to be a |
|
- | 1738 | * discontinuity which will probably damage compression when moving from a |
|
- | 1739 | * fully transparent area to a nearly transparent one. (The assumption here |
|
- | 1740 | * is that opaque areas tend not to be 0 intensity.) |
|
- | 1741 | * |
|
- | 1742 | * There is a rounding problem here; if alpha is less than 128 it will end up |
|
- | 1743 | * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the |
|
- | 1744 | * output change for this too. |
|
- | 1745 | */ |
|
- | 1746 | if (component >= alpha || alpha < 128) |
|
- | 1747 | return 255; |
|
- | 1748 | ||
- | 1749 | /* component |
|
- | 1750 | * component*reciprocal is less than 2^31. |
|
- | 1751 | */ |
|
- | 1752 | else if (component > 0) |
|
- | 1753 | { |
|
- | 1754 | /* The test is that alpha/257 (rounded) is less than 255, the first value |
|
- | 1755 | * that becomes 255 is 65407. |
|
- | 1756 | * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, |
|
- | 1757 | * be exact!) [Could also test reciprocal != 0] |
|
- | 1758 | */ |
|
- | 1759 | if (alpha < 65407) |
|
- | 1760 | { |
|
- | 1761 | component *= reciprocal; |
|
- | 1762 | component += 64; /* round to nearest */ |
|
- | 1763 | component >>= 7; |
|
- | 1764 | } |
|
- | 1765 | ||
- | 1766 | else |
|
- | 1767 | component *= 255; |
|
- | 1768 | ||
- | 1769 | /* Convert the component to sRGB. */ |
|
- | 1770 | return (png_byte)PNG_sRGB_FROM_LINEAR(component); |
|
- | 1771 | } |
|
- | 1772 | ||
- | 1773 | else |
|
- | 1774 | return 0; |
|
- | 1775 | } |
|
- | 1776 | ||
- | 1777 | static int |
|
- | 1778 | png_write_image_8bit(png_voidp argument) |
|
- | 1779 | { |
|
- | 1780 | png_image_write_control *display = png_voidcast(png_image_write_control*, |
|
- | 1781 | argument); |
|
- | 1782 | png_imagep image = display->image; |
|
- | 1783 | png_structrp png_ptr = image->opaque->png_ptr; |
|
- | 1784 | ||
- | 1785 | png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, |
|
- | 1786 | display->first_row); |
|
- | 1787 | png_bytep output_row = png_voidcast(png_bytep, display->local_row); |
|
- | 1788 | png_uint_32 y = image->height; |
|
- | 1789 | const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; |
|
- | 1790 | ||
- | 1791 | if (image->format & PNG_FORMAT_FLAG_ALPHA) |
|
- | 1792 | { |
|
- | 1793 | png_bytep row_end; |
|
- | 1794 | int aindex; |
|
- | 1795 | ||
- | 1796 | if (image->format & PNG_FORMAT_FLAG_AFIRST) |
|
- | 1797 | { |
|
- | 1798 | aindex = -1; |
|
- | 1799 | ++input_row; /* To point to the first component */ |
|
- | 1800 | ++output_row; |
|
- | 1801 | } |
|
- | 1802 | ||
- | 1803 | else |
|
- | 1804 | aindex = channels; |
|
- | 1805 | ||
- | 1806 | /* Use row_end in place of a loop counter: */ |
|
- | 1807 | row_end = output_row + image->width * (channels+1); |
|
- | 1808 | ||
- | 1809 | while (y-- > 0) |
|
- | 1810 | { |
|
- | 1811 | png_const_uint_16p in_ptr = input_row; |
|
- | 1812 | png_bytep out_ptr = output_row; |
|
- | 1813 | ||
- | 1814 | while (out_ptr < row_end) |
|
- | 1815 | { |
|
- | 1816 | png_uint_16 alpha = in_ptr[aindex]; |
|
- | 1817 | png_byte alphabyte = (png_byte)PNG_DIV257(alpha); |
|
- | 1818 | png_uint_32 reciprocal = 0; |
|
- | 1819 | int c; |
|
- | 1820 | ||
- | 1821 | /* Scale and write the alpha channel. */ |
|
- | 1822 | out_ptr[aindex] = alphabyte; |
|
- | 1823 | ||
- | 1824 | if (alphabyte > 0 && alphabyte < 255) |
|
- | 1825 | reciprocal = UNP_RECIPROCAL(alpha); |
|
- | 1826 | ||
- | 1827 | c = channels; |
|
- | 1828 | do /* always at least one channel */ |
|
- | 1829 | *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); |
|
- | 1830 | while (--c > 0); |
|
- | 1831 | ||
- | 1832 | /* Skip to next component (skip the intervening alpha channel) */ |
|
- | 1833 | ++in_ptr; |
|
- | 1834 | ++out_ptr; |
|
- | 1835 | } /* while out_ptr < row_end */ |
|
- | 1836 | ||
- | 1837 | png_write_row(png_ptr, png_voidcast(png_const_bytep, |
|
- | 1838 | display->local_row)); |
|
- | 1839 | input_row += display->row_bytes/(sizeof (png_uint_16)); |
|
- | 1840 | } /* while y */ |
|
- | 1841 | } |
|
- | 1842 | ||
- | 1843 | else |
|
- | 1844 | { |
|
- | 1845 | /* No alpha channel, so the row_end really is the end of the row and it |
|
- | 1846 | * is sufficient to loop over the components one by one. |
|
- | 1847 | */ |
|
- | 1848 | png_bytep row_end = output_row + image->width * channels; |
|
- | 1849 | ||
- | 1850 | while (y-- > 0) |
|
- | 1851 | { |
|
- | 1852 | png_const_uint_16p in_ptr = input_row; |
|
- | 1853 | png_bytep out_ptr = output_row; |
|
- | 1854 | ||
- | 1855 | while (out_ptr < row_end) |
|
- | 1856 | { |
|
- | 1857 | png_uint_32 component = *in_ptr++; |
|
- | 1858 | ||
- | 1859 | component *= 255; |
|
- | 1860 | *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); |
|
- | 1861 | } |
|
- | 1862 | ||
- | 1863 | png_write_row(png_ptr, output_row); |
|
- | 1864 | input_row += display->row_bytes/(sizeof (png_uint_16)); |
|
- | 1865 | } |
|
- | 1866 | } |
|
- | 1867 | ||
- | 1868 | return 1; |
|
- | 1869 | } |
|
- | 1870 | ||
- | 1871 | static void |
|
- | 1872 | png_image_set_PLTE(png_image_write_control *display) |
|
- | 1873 | { |
|
- | 1874 | const png_imagep image = display->image; |
|
- | 1875 | const void *cmap = display->colormap; |
|
- | 1876 | const int entries = image->colormap_entries > 256 ? 256 : |
|
- | 1877 | (int)image->colormap_entries; |
|
- | 1878 | ||
- | 1879 | /* NOTE: the caller must check for cmap != NULL and entries != 0 */ |
|
- | 1880 | const png_uint_32 format = image->format; |
|
- | 1881 | const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); |
|
- | 1882 | ||
- | 1883 | # ifdef PNG_FORMAT_BGR_SUPPORTED |
|
- | 1884 | const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && |
|
- | 1885 | (format & PNG_FORMAT_FLAG_ALPHA) != 0; |
|
- | 1886 | # else |
|
- | 1887 | # define afirst 0 |
|
- | 1888 | # endif |
|
- | 1889 | ||
- | 1890 | # ifdef PNG_FORMAT_BGR_SUPPORTED |
|
- | 1891 | const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; |
|
- | 1892 | # else |
|
- | 1893 | # define bgr 0 |
|
- | 1894 | # endif |
|
- | 1895 | ||
- | 1896 | int i, num_trans; |
|
- | 1897 | png_color palette[256]; |
|
- | 1898 | png_byte tRNS[256]; |
|
- | 1899 | ||
- | 1900 | memset(tRNS, 255, (sizeof tRNS)); |
|
- | 1901 | memset(palette, 0, (sizeof palette)); |
|
- | 1902 | ||
- | 1903 | for (i=num_trans=0; i |
|
- | 1904 | { |
|
- | 1905 | /* This gets automatically converted to sRGB with reversal of the |
|
- | 1906 | * pre-multiplication if the color-map has an alpha channel. |
|
- | 1907 | */ |
|
- | 1908 | if (format & PNG_FORMAT_FLAG_LINEAR) |
|
- | 1909 | { |
|
- | 1910 | png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap); |
|
- | 1911 | ||
- | 1912 | entry += i * channels; |
|
- | 1913 | ||
- | 1914 | if (channels & 1) /* no alpha */ |
|
- | 1915 | { |
|
- | 1916 | if (channels >= 3) /* RGB */ |
|
- | 1917 | { |
|
- | 1918 | palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * |
|
- | 1919 | entry[(2 ^ bgr)]); |
|
- | 1920 | palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * |
|
- | 1921 | entry[1]); |
|
- | 1922 | palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * |
|
- | 1923 | entry[bgr]); |
|
- | 1924 | } |
|
- | 1925 | ||
- | 1926 | else /* Gray */ |
|
- | 1927 | palette[i].blue = palette[i].red = palette[i].green = |
|
- | 1928 | (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); |
|
- | 1929 | } |
|
- | 1930 | ||
- | 1931 | else /* alpha */ |
|
- | 1932 | { |
|
- | 1933 | png_uint_16 alpha = entry[afirst ? 0 : channels-1]; |
|
- | 1934 | png_byte alphabyte = (png_byte)PNG_DIV257(alpha); |
|
- | 1935 | png_uint_32 reciprocal = 0; |
|
- | 1936 | ||
- | 1937 | /* Calculate a reciprocal, as in the png_write_image_8bit code above |
|
- | 1938 | * this is designed to produce a value scaled to 255*65535 when |
|
- | 1939 | * divided by 128 (i.e. asr 7). |
|
- | 1940 | */ |
|
- | 1941 | if (alphabyte > 0 && alphabyte < 255) |
|
- | 1942 | reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; |
|
- | 1943 | ||
- | 1944 | tRNS[i] = alphabyte; |
|
- | 1945 | if (alphabyte < 255) |
|
- | 1946 | num_trans = i+1; |
|
- | 1947 | ||
- | 1948 | if (channels >= 3) /* RGB */ |
|
- | 1949 | { |
|
- | 1950 | palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], |
|
- | 1951 | alpha, reciprocal); |
|
- | 1952 | palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, |
|
- | 1953 | reciprocal); |
|
- | 1954 | palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, |
|
- | 1955 | reciprocal); |
|
- | 1956 | } |
|
- | 1957 | ||
- | 1958 | else /* gray */ |
|
- | 1959 | palette[i].blue = palette[i].red = palette[i].green = |
|
- | 1960 | png_unpremultiply(entry[afirst], alpha, reciprocal); |
|
- | 1961 | } |
|
- | 1962 | } |
|
- | 1963 | ||
- | 1964 | else /* Color-map has sRGB values */ |
|
- | 1965 | { |
|
- | 1966 | png_const_bytep entry = png_voidcast(png_const_bytep, cmap); |
|
- | 1967 | ||
- | 1968 | entry += i * channels; |
|
- | 1969 | ||
- | 1970 | switch (channels) |
|
- | 1971 | { |
|
- | 1972 | case 4: |
|
- | 1973 | tRNS[i] = entry[afirst ? 0 : 3]; |
|
- | 1974 | if (tRNS[i] < 255) |
|
- | 1975 | num_trans = i+1; |
|
- | 1976 | /* FALL THROUGH */ |
|
- | 1977 | case 3: |
|
- | 1978 | palette[i].blue = entry[afirst + (2 ^ bgr)]; |
|
- | 1979 | palette[i].green = entry[afirst + 1]; |
|
- | 1980 | palette[i].red = entry[afirst + bgr]; |
|
- | 1981 | break; |
|
- | 1982 | ||
- | 1983 | case 2: |
|
- | 1984 | tRNS[i] = entry[1 ^ afirst]; |
|
- | 1985 | if (tRNS[i] < 255) |
|
- | 1986 | num_trans = i+1; |
|
- | 1987 | /* FALL THROUGH */ |
|
- | 1988 | case 1: |
|
- | 1989 | palette[i].blue = palette[i].red = palette[i].green = |
|
- | 1990 | entry[afirst]; |
|
- | 1991 | break; |
|
- | 1992 | ||
- | 1993 | default: |
|
- | 1994 | break; |
|
- | 1995 | } |
|
- | 1996 | } |
|
- | 1997 | } |
|
- | 1998 | ||
- | 1999 | # ifdef afirst |
|
- | 2000 | # undef afirst |
|
- | 2001 | # endif |
|
- | 2002 | # ifdef bgr |
|
- | 2003 | # undef bgr |
|
- | 2004 | # endif |
|
- | 2005 | ||
- | 2006 | png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, |
|
- | 2007 | entries); |
|
- | 2008 | ||
- | 2009 | if (num_trans > 0) |
|
- | 2010 | png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, |
|
- | 2011 | num_trans, NULL); |
|
- | 2012 | ||
- | 2013 | image->colormap_entries = entries; |
|
- | 2014 | } |
|
- | 2015 | ||
- | 2016 | static int |
|
- | 2017 | png_image_write_main(png_voidp argument) |
|
- | 2018 | { |
|
- | 2019 | png_image_write_control *display = png_voidcast(png_image_write_control*, |
|
- | 2020 | argument); |
|
- | 2021 | png_imagep image = display->image; |
|
- | 2022 | png_structrp png_ptr = image->opaque->png_ptr; |
|
- | 2023 | png_inforp info_ptr = image->opaque->info_ptr; |
|
- | 2024 | png_uint_32 format = image->format; |
|
- | 2025 | ||
- | 2026 | int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; |
|
- | 2027 | int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ |
|
- | 2028 | int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; |
|
- | 2029 | int write_16bit = linear && !colormap && !display->convert_to_8bit; |
|
- | 2030 | ||
- | 2031 | # ifdef PNG_BENIGN_ERRORS_SUPPORTED |
|
- | 2032 | /* Make sure we error out on any bad situation */ |
|
- | 2033 | png_set_benign_errors(png_ptr, 0/*error*/); |
|
- | 2034 | # endif |
|
- | 2035 | ||
- | 2036 | /* Default the 'row_stride' parameter if required. */ |
|
- | 2037 | if (display->row_stride == 0) |
|
- | 2038 | display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); |
|
- | 2039 | ||
- | 2040 | /* Set the required transforms then write the rows in the correct order. */ |
|
- | 2041 | if (format & PNG_FORMAT_FLAG_COLORMAP) |
|
- | 2042 | { |
|
- | 2043 | if (display->colormap != NULL && image->colormap_entries > 0) |
|
- | 2044 | { |
|
- | 2045 | png_uint_32 entries = image->colormap_entries; |
|
- | 2046 | ||
- | 2047 | png_set_IHDR(png_ptr, info_ptr, image->width, image->height, |
|
- | 2048 | entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), |
|
- | 2049 | PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, |
|
- | 2050 | PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); |
|
- | 2051 | ||
- | 2052 | png_image_set_PLTE(display); |
|
- | 2053 | } |
|
- | 2054 | ||
- | 2055 | else |
|
- | 2056 | png_error(image->opaque->png_ptr, |
|
- | 2057 | "no color-map for color-mapped image"); |
|
- | 2058 | } |
|
- | 2059 | ||
- | 2060 | else |
|
- | 2061 | png_set_IHDR(png_ptr, info_ptr, image->width, image->height, |
|
- | 2062 | write_16bit ? 16 : 8, |
|
- | 2063 | ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + |
|
- | 2064 | ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), |
|
- | 2065 | PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); |
|
- | 2066 | ||
- | 2067 | /* Counter-intuitively the data transformations must be called *after* |
|
- | 2068 | * png_write_info, not before as in the read code, but the 'set' functions |
|
- | 2069 | * must still be called before. Just set the color space information, never |
|
- | 2070 | * write an interlaced image. |
|
- | 2071 | */ |
|
- | 2072 | ||
- | 2073 | if (write_16bit) |
|
- | 2074 | { |
|
- | 2075 | /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ |
|
- | 2076 | png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); |
|
- | 2077 | ||
- | 2078 | if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) |
|
- | 2079 | png_set_cHRM_fixed(png_ptr, info_ptr, |
|
- | 2080 | /* color x y */ |
|
- | 2081 | /* white */ 31270, 32900, |
|
- | 2082 | /* red */ 64000, 33000, |
|
- | 2083 | /* green */ 30000, 60000, |
|
- | 2084 | /* blue */ 15000, 6000 |
|
- | 2085 | ); |
|
- | 2086 | } |
|
- | 2087 | ||
- | 2088 | else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) |
|
- | 2089 | png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); |
|
- | 2090 | ||
- | 2091 | /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit |
|
- | 2092 | * space must still be gamma encoded. |
|
- | 2093 | */ |
|
- | 2094 | else |
|
- | 2095 | png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); |
|
- | 2096 | ||
- | 2097 | /* Write the file header. */ |
|
- | 2098 | png_write_info(png_ptr, info_ptr); |
|
- | 2099 | ||
- | 2100 | /* Now set up the data transformations (*after* the header is written), |
|
- | 2101 | * remove the handled transformations from the 'format' flags for checking. |
|
- | 2102 | * |
|
- | 2103 | * First check for a little endian system if writing 16 bit files. |
|
- | 2104 | */ |
|
- | 2105 | if (write_16bit) |
|
- | 2106 | { |
|
- | 2107 | PNG_CONST png_uint_16 le = 0x0001; |
|
- | 2108 | ||
- | 2109 | if (*(png_const_bytep)&le) |
|
- | 2110 | png_set_swap(png_ptr); |
|
- | 2111 | } |
|
- | 2112 | ||
- | 2113 | # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED |
|
- | 2114 | if (format & PNG_FORMAT_FLAG_BGR) |
|
- | 2115 | { |
|
- | 2116 | if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0) |
|
- | 2117 | png_set_bgr(png_ptr); |
|
- | 2118 | format &= ~PNG_FORMAT_FLAG_BGR; |
|
- | 2119 | } |
|
- | 2120 | # endif |
|
- | 2121 | ||
- | 2122 | # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED |
|
- | 2123 | if (format & PNG_FORMAT_FLAG_AFIRST) |
|
- | 2124 | { |
|
- | 2125 | if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0) |
|
- | 2126 | png_set_swap_alpha(png_ptr); |
|
- | 2127 | format &= ~PNG_FORMAT_FLAG_AFIRST; |
|
- | 2128 | } |
|
- | 2129 | # endif |
|
- | 2130 | ||
- | 2131 | /* If there are 16 or fewer color-map entries we wrote a lower bit depth |
|
- | 2132 | * above, but the application data is still byte packed. |
|
- | 2133 | */ |
|
- | 2134 | if (colormap && image->colormap_entries <= 16) |
|
- | 2135 | png_set_packing(png_ptr); |
|
- | 2136 | ||
- | 2137 | /* That should have handled all (both) the transforms. */ |
|
- | 2138 | if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | |
|
- | 2139 | PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) |
|
- | 2140 | png_error(png_ptr, "png_write_image: unsupported transformation"); |
|
- | 2141 | ||
- | 2142 | { |
|
- | 2143 | png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); |
|
- | 2144 | ptrdiff_t row_bytes = display->row_stride; |
|
- | 2145 | ||
- | 2146 | if (linear) |
|
- | 2147 | row_bytes *= (sizeof (png_uint_16)); |
|
- | 2148 | ||
- | 2149 | if (row_bytes < 0) |
|
- | 2150 | row += (image->height-1) * (-row_bytes); |
|
- | 2151 | ||
- | 2152 | display->first_row = row; |
|
- | 2153 | display->row_bytes = row_bytes; |
|
- | 2154 | } |
|
- | 2155 | ||
- | 2156 | /* Apply 'fast' options if the flag is set. */ |
|
- | 2157 | if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) |
|
- | 2158 | { |
|
- | 2159 | png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); |
|
- | 2160 | /* NOTE: determined by experiment using pngstest, this reflects some |
|
- | 2161 | * balance between the time to write the image once and the time to read |
|
- | 2162 | * it about 50 times. The speed-up in pngstest was about 10-20% of the |
|
- | 2163 | * total (user) time on a heavily loaded system. |
|
- | 2164 | */ |
|
- | 2165 | png_set_compression_level(png_ptr, 3); |
|
- | 2166 | } |
|
- | 2167 | ||
- | 2168 | /* Check for the cases that currently require a pre-transform on the row |
|
- | 2169 | * before it is written. This only applies when the input is 16-bit and |
|
- | 2170 | * either there is an alpha channel or it is converted to 8-bit. |
|
- | 2171 | */ |
|
- | 2172 | if ((linear && alpha) || (!colormap && display->convert_to_8bit)) |
|
- | 2173 | { |
|
- | 2174 | png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, |
|
- | 2175 | png_get_rowbytes(png_ptr, info_ptr))); |
|
- | 2176 | int result; |
|
- | 2177 | ||
- | 2178 | display->local_row = row; |
|
- | 2179 | if (write_16bit) |
|
- | 2180 | result = png_safe_execute(image, png_write_image_16bit, display); |
|
- | 2181 | else |
|
- | 2182 | result = png_safe_execute(image, png_write_image_8bit, display); |
|
- | 2183 | display->local_row = NULL; |
|
- | 2184 | ||
- | 2185 | png_free(png_ptr, row); |
|
- | 2186 | ||
- | 2187 | /* Skip the 'write_end' on error: */ |
|
- | 2188 | if (!result) |
|
- | 2189 | return 0; |
|
- | 2190 | } |
|
- | 2191 | ||
- | 2192 | /* Otherwise this is the case where the input is in a format currently |
|
- | 2193 | * supported by the rest of the libpng write code; call it directly. |
|
- | 2194 | */ |
|
- | 2195 | else |
|
- | 2196 | { |
|
- | 2197 | png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); |
|
- | 2198 | ptrdiff_t row_bytes = display->row_bytes; |
|
- | 2199 | png_uint_32 y = image->height; |
|
- | 2200 | ||
- | 2201 | while (y-- > 0) |
|
- | 2202 | { |
|
- | 2203 | png_write_row(png_ptr, row); |
|
- | 2204 | row += row_bytes; |
|
- | 2205 | } |
|
- | 2206 | } |
|
- | 2207 | ||
- | 2208 | png_write_end(png_ptr, info_ptr); |
|
- | 2209 | return 1; |
|
- | 2210 | } |
|
- | 2211 | ||
- | 2212 | int PNGAPI |
|
- | 2213 | png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, |
|
- | 2214 | const void *buffer, png_int_32 row_stride, const void *colormap) |
|
- | 2215 | { |
|
- | 2216 | /* Write the image to the given (FILE*). */ |
|
- | 2217 | if (image != NULL && image->version == PNG_IMAGE_VERSION) |
|
- | 2218 | { |
|
- | 2219 | if (file != NULL) |
|
- | 2220 | { |
|
- | 2221 | if (png_image_write_init(image)) |
|
- | 2222 | { |
|
- | 2223 | png_image_write_control display; |
|
- | 2224 | int result; |
|
- | 2225 | ||
- | 2226 | /* This is slightly evil, but png_init_io doesn't do anything other |
|
- | 2227 | * than this and we haven't changed the standard IO functions so |
|
- | 2228 | * this saves a 'safe' function. |
|
- | 2229 | */ |
|
- | 2230 | image->opaque->png_ptr->io_ptr = file; |
|
- | 2231 | ||
- | 2232 | memset(&display, 0, (sizeof display)); |
|
- | 2233 | display.image = image; |
|
- | 2234 | display.buffer = buffer; |
|
- | 2235 | display.row_stride = row_stride; |
|
- | 2236 | display.colormap = colormap; |
|
- | 2237 | display.convert_to_8bit = convert_to_8bit; |
|
- | 2238 | ||
- | 2239 | result = png_safe_execute(image, png_image_write_main, &display); |
|
- | 2240 | png_image_free(image); |
|
- | 2241 | return result; |
|
- | 2242 | } |
|
- | 2243 | ||
- | 2244 | else |
|
- | 2245 | return 0; |
|
- | 2246 | } |
|
- | 2247 | ||
- | 2248 | else |
|
- | 2249 | return png_image_error(image, |
|
- | 2250 | "png_image_write_to_stdio: invalid argument"); |
|
- | 2251 | } |
|
- | 2252 | ||
- | 2253 | else if (image != NULL) |
|
- | 2254 | return png_image_error(image, |
|
- | 2255 | "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); |
|
- | 2256 | ||
- | 2257 | else |
|
- | 2258 | return 0; |
|
- | 2259 | } |
|
- | 2260 | ||
- | 2261 | int PNGAPI |
|
- | 2262 | png_image_write_to_file(png_imagep image, const char *file_name, |
|
- | 2263 | int convert_to_8bit, const void *buffer, png_int_32 row_stride, |
|
- | 2264 | const void *colormap) |
|
- | 2265 | { |
|
- | 2266 | /* Write the image to the named file. */ |
|
- | 2267 | if (image != NULL && image->version == PNG_IMAGE_VERSION) |
|
- | 2268 | { |
|
- | 2269 | if (file_name != NULL) |
|
- | 2270 | { |
|
- | 2271 | FILE *fp = fopen(file_name, "wb"); |
|
- | 2272 | ||
- | 2273 | if (fp != NULL) |
|
- | 2274 | { |
|
- | 2275 | if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, |
|
- | 2276 | row_stride, colormap)) |
|
- | 2277 | { |
|
- | 2278 | int error; /* from fflush/fclose */ |
|
- | 2279 | ||
- | 2280 | /* Make sure the file is flushed correctly. */ |
|
- | 2281 | if (fflush(fp) == 0 && ferror(fp) == 0) |
|
- | 2282 | { |
|
- | 2283 | if (fclose(fp) == 0) |
|
- | 2284 | return 1; |
|
- | 2285 | ||
- | 2286 | error = errno; /* from fclose */ |
|
- | 2287 | } |
|
- | 2288 | ||
- | 2289 | else |
|
- | 2290 | { |
|
- | 2291 | error = errno; /* from fflush or ferror */ |
|
- | 2292 | (void)fclose(fp); |
|
- | 2293 | } |
|
- | 2294 | ||
- | 2295 | (void)remove(file_name); |
|
- | 2296 | /* The image has already been cleaned up; this is just used to |
|
- | 2297 | * set the error (because the original write succeeded). |
|
- | 2298 | */ |
|
- | 2299 | return png_image_error(image, strerror(error)); |
|
- | 2300 | } |
|
- | 2301 | ||
- | 2302 | else |
|
- | 2303 | { |
|
- | 2304 | /* Clean up: just the opened file. */ |
|
- | 2305 | (void)fclose(fp); |
|
- | 2306 | (void)remove(file_name); |
|
- | 2307 | return 0; |
|
- | 2308 | } |
|
- | 2309 | } |
|
- | 2310 | ||
- | 2311 | else |
|
- | 2312 | return png_image_error(image, strerror(errno)); |
|
- | 2313 | } |
|
- | 2314 | ||
- | 2315 | else |
|
- | 2316 | return png_image_error(image, |
|
- | 2317 | "png_image_write_to_file: invalid argument"); |
|
- | 2318 | } |
|
- | 2319 | ||
- | 2320 | else if (image != NULL) |
|
- | 2321 | return png_image_error(image, |
|
- | 2322 | "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); |
|
- | 2323 | ||
- | 2324 | else |
|
- | 2325 | return 0; |
|
- | 2326 | } |
|
- | 2327 | #endif /* PNG_STDIO_SUPPORTED */ |
|
- | 2328 | #endif /* SIMPLIFIED_WRITE */ |
|
1604 | #endif /* PNG_WRITE_SUPPORTED */>=>>=>>>=>>>>>>>>>>>>>>>>>>>(int)info_ptr->> |
2329 | #endif /* PNG_WRITE_SUPPORTED */>=>>>>7)+(alpha><7)+(alpha>>>>>>>>7)+(alpha><7)+(alpha>>15)+(alpha><15)+(alpha>>><>>>=>>=>>=>>>=>>>>>>>>>>>>>>>>(int)info_ptr->> |