/src/graphicsmagick/coders/png.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % PPPP N N GGGG % |
15 | | % P P NN N G % |
16 | | % PPPP N N N G GG % |
17 | | % P N NN G G % |
18 | | % P N N GGG % |
19 | | % % |
20 | | % % |
21 | | % Read/Write Portable Network Graphics Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % Glenn Randers-Pehrson % |
27 | | % November 1997 % |
28 | | % % |
29 | | % % |
30 | | % % |
31 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
32 | | % |
33 | | % |
34 | | */ |
35 | | |
36 | | /* GraphicsMagick differences */ |
37 | | |
38 | | #if !defined(RGBColorMatchExact) |
39 | | /* Similar to ColorMatch() but with value argument rather than pointer */ |
40 | | #define RGBColorMatchExact(color,target) \ |
41 | 57.4k | (((color).red == (target).red) && \ |
42 | 57.4k | ((color).green == (target).green) && \ |
43 | 57.4k | ((color).blue == (target).blue)) |
44 | | #endif /* if !defined(RGBColorMatchExact) */ |
45 | | |
46 | | /* |
47 | | Include declarations. |
48 | | */ |
49 | | #include "magick/studio.h" |
50 | | #include "magick/analyze.h" |
51 | | #include "magick/attribute.h" |
52 | | #include "magick/blob.h" |
53 | | #include "magick/channel.h" |
54 | | #include "magick/color.h" |
55 | | #include "magick/colormap.h" |
56 | | #include "magick/constitute.h" |
57 | | #include "magick/enhance.h" |
58 | | #include "magick/log.h" |
59 | | #include "magick/magick.h" |
60 | | #include "magick/monitor.h" |
61 | | #include "magick/pixel_cache.h" |
62 | | #include "magick/profile.h" |
63 | | #include "magick/quantize.h" |
64 | | #include "magick/resource.h" |
65 | | #include "magick/semaphore.h" |
66 | | #include "magick/static.h" |
67 | | #include "magick/tempfile.h" |
68 | | #include "magick/transform.h" |
69 | | #include "magick/utility.h" |
70 | | #include "magick/version.h" |
71 | | #include "magick/static.h" |
72 | | #if defined(HasPNG) |
73 | | |
74 | | /* Suppress libpng pedantic warnings */ |
75 | | #define PNG_DEPRECATED /* Use of this function is deprecated */ |
76 | | #define PNG_USE_RESULT /* The result of this function must be checked */ |
77 | | #define PNG_NORETURN /* This function does not return */ |
78 | | /* #define PNG_ALLOCATED */ /* The result of the function is new memory */ |
79 | | #define PNG_DEPSTRUCT /* access to this struct member is deprecated */ |
80 | | |
81 | | #include "png.h" |
82 | | #include "zlib.h" |
83 | | #if defined(HasLCMS) |
84 | | # if defined(HAVE_LCMS2_LCMS2_H) |
85 | | # include <lcms2/lcms2.h> |
86 | | # elif defined(HAVE_LCMS2_H) |
87 | | # include <lcms2.h> |
88 | | # else |
89 | | # error "LCMS 2 header missing!" |
90 | | # endif |
91 | | #endif |
92 | | |
93 | | |
94 | | #if PNG_LIBPNG_VER > 10011 |
95 | | /* |
96 | | Optional declarations. Define or undefine them as you like. |
97 | | */ |
98 | | |
99 | | /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */ |
100 | | |
101 | | /* |
102 | | Features under construction. Define these to work on them. |
103 | | */ |
104 | | #undef MNG_OBJECT_BUFFERS |
105 | | #undef MNG_BASI_SUPPORTED |
106 | | #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */ |
107 | | #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */ |
108 | | #define GMPNG_BUILD_PALETTE /* This works as of 5.4.3. */ |
109 | | #if defined(HasJPEG) |
110 | | # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */ |
111 | | #endif |
112 | | |
113 | | /* |
114 | | Establish thread safety. |
115 | | setjmp/longjmp is claimed to be safe on these platforms: |
116 | | setjmp/longjmp is alleged to be unsafe on these platforms: |
117 | | */ |
118 | | #ifdef PNG_SETJMP_SUPPORTED |
119 | | # ifndef SETJMP_IS_THREAD_SAFE |
120 | | # define GMPNG_SETJMP_NOT_THREAD_SAFE |
121 | | # endif |
122 | | |
123 | | # if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
124 | | static SemaphoreInfo |
125 | | *png_semaphore = (SemaphoreInfo *) NULL; |
126 | | # endif |
127 | | #endif |
128 | | |
129 | | /* |
130 | | This is temporary until I set up malloc'ed object attributes array. |
131 | | Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but |
132 | | waste more memory. |
133 | | */ |
134 | 395M | #define MNG_MAX_OBJECTS 256 |
135 | | |
136 | | /* |
137 | | If this is not defined, spec is interpreted strictly. If it is |
138 | | defined, an attempt will be made to recover from some errors, |
139 | | including |
140 | | o global PLTE too short |
141 | | */ |
142 | | #undef MNG_LOOSE |
143 | | |
144 | | /* |
145 | | Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure |
146 | | it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work |
147 | | with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8, |
148 | | PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in |
149 | | libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here. |
150 | | PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and |
151 | | will be enabled by default in libpng-1.2.0. |
152 | | */ |
153 | | #ifdef PNG_MNG_FEATURES_SUPPORTED |
154 | | # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
155 | | # define PNG_READ_EMPTY_PLTE_SUPPORTED |
156 | | # endif |
157 | | # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
158 | | # define PNG_WRITE_EMPTY_PLTE_SUPPORTED |
159 | | # endif |
160 | | #endif |
161 | | |
162 | | /* |
163 | | Maximum valid unsigned long in PNG/MNG chunks is (2^31)-1 |
164 | | This macro is only defined in libpng-1.0.3a and later. |
165 | | */ |
166 | | #ifndef PNG_MAX_UINT |
167 | 136M | #define PNG_MAX_UINT (png_uint_32) 0x7fffffffL |
168 | | #endif |
169 | | |
170 | | /* |
171 | | Constant strings for known chunk types. If you need to add a chunk, |
172 | | add a string holding the name here. To make the code more |
173 | | portable, we use ASCII numbers like this, not characters. |
174 | | */ |
175 | | |
176 | | static png_byte const mng_MHDR[5]={ 77, 72, 68, 82, '\0'}; |
177 | | static png_byte const mng_BACK[5]={ 66, 65, 67, 75, '\0'}; |
178 | | static png_byte const mng_BASI[5]={ 66, 65, 83, 73, '\0'}; |
179 | | static png_byte const mng_CLIP[5]={ 67, 76, 73, 80, '\0'}; |
180 | | static png_byte const mng_CLON[5]={ 67, 76, 79, 78, '\0'}; |
181 | | static png_byte const mng_DEFI[5]={ 68, 69, 70, 73, '\0'}; |
182 | | static png_byte const mng_DHDR[5]={ 68, 72, 68, 82, '\0'}; |
183 | | static png_byte const mng_DISC[5]={ 68, 73, 83, 67, '\0'}; |
184 | | static png_byte const mng_ENDL[5]={ 69, 78, 68, 76, '\0'}; |
185 | | static png_byte const mng_FRAM[5]={ 70, 82, 65, 77, '\0'}; |
186 | | static png_byte const mng_IEND[5]={ 73, 69, 78, 68, '\0'}; |
187 | | static png_byte const mng_IHDR[5]={ 73, 72, 68, 82, '\0'}; |
188 | | static png_byte const mng_JHDR[5]={ 74, 72, 68, 82, '\0'}; |
189 | | static png_byte const mng_LOOP[5]={ 76, 79, 79, 80, '\0'}; |
190 | | static png_byte const mng_MAGN[5]={ 77, 65, 71, 78, '\0'}; |
191 | | static png_byte const mng_MEND[5]={ 77, 69, 78, 68, '\0'}; |
192 | | static png_byte const mng_MOVE[5]={ 77, 79, 86, 69, '\0'}; |
193 | | static png_byte const mng_PAST[5]={ 80, 65, 83, 84, '\0'}; |
194 | | static png_byte const mng_PLTE[5]={ 80, 76, 84, 69, '\0'}; |
195 | | static png_byte const mng_SAVE[5]={ 83, 65, 86, 69, '\0'}; |
196 | | static png_byte const mng_SEEK[5]={ 83, 69, 69, 75, '\0'}; |
197 | | static png_byte const mng_SHOW[5]={ 83, 72, 79, 87, '\0'}; |
198 | | static png_byte const mng_TERM[5]={ 84, 69, 82, 77, '\0'}; |
199 | | static png_byte const mng_bKGD[5]={ 98, 75, 71, 68, '\0'}; |
200 | | static png_byte const mng_caNv[5]={ 99, 97, 78, 118, '\0'}; |
201 | | static png_byte const mng_cHRM[5]={ 99, 72, 82, 77, '\0'}; |
202 | | static png_byte const mng_eXIf[5]={101, 88, 73, 102, '\0'}; |
203 | | static png_byte const mng_gAMA[5]={103, 65, 77, 65, '\0'}; |
204 | | static png_byte const mng_iCCP[5]={105, 67, 67, 80, '\0'}; |
205 | | static png_byte const mng_nEED[5]={110, 69, 69, 68, '\0'}; |
206 | | static png_byte const mng_orNT[5]={111, 114, 78, 84, '\0'}; |
207 | | static png_byte const mng_pHYg[5]={112, 72, 89, 103, '\0'}; |
208 | | static png_byte const mng_pHYs[5]={112, 72, 89, 115, '\0'}; |
209 | | static png_byte const mng_sBIT[5]={115, 66, 73, 84, '\0'}; |
210 | | static png_byte const mng_sRGB[5]={115, 82, 71, 66, '\0'}; |
211 | | static png_byte const mng_tRNS[5]={116, 82, 78, 83, '\0'}; |
212 | | |
213 | | #if defined(JNG_SUPPORTED) |
214 | | static png_byte const mng_IDAT[5]={ 73, 68, 65, 84, '\0'}; |
215 | | static png_byte const mng_JDAT[5]={ 74, 68, 65, 84, '\0'}; |
216 | | static png_byte const mng_JDAA[5]={ 74, 68, 65, 65, '\0'}; |
217 | | static png_byte const mng_JdAA[5]={ 74, 100, 65, 65, '\0'}; |
218 | | static png_byte const mng_JSEP[5]={ 74, 83, 69, 80, '\0'}; |
219 | | static png_byte const mng_oFFs[5]={111, 70, 70, 115, '\0'}; |
220 | | #endif |
221 | | |
222 | | /* |
223 | | static png_byte const mng_hIST[5]={104, 73, 83, 84, '\0'}; |
224 | | static png_byte const mng_iCCP[5]={105, 67, 67, 80, '\0'}; |
225 | | static png_byte const mng_iTXt[5]={105, 84, 88, 116, '\0'}; |
226 | | static png_byte const mng_sPLT[5]={115, 80, 76, 84, '\0'}; |
227 | | static png_byte const mng_tEXt[5]={116, 69, 88, 116, '\0'}; |
228 | | static png_byte const mng_tIME[5]={116, 73, 77, 69, '\0'}; |
229 | | static png_byte const mng_zTXt[5]={122, 84, 88, 116, '\0'}; |
230 | | */ |
231 | | |
232 | | typedef struct _UShortPixelPacket |
233 | | { |
234 | | unsigned short |
235 | | red, |
236 | | green, |
237 | | blue, |
238 | | opacity, |
239 | | index; |
240 | | } UShortPixelPacket; |
241 | | |
242 | | typedef struct _MngBox |
243 | | { |
244 | | long |
245 | | left, |
246 | | right, |
247 | | top, |
248 | | bottom; |
249 | | } MngBox; |
250 | | |
251 | | typedef struct _MngPair |
252 | | { |
253 | | volatile long |
254 | | a, |
255 | | b; |
256 | | } MngPair; |
257 | | |
258 | | #ifdef MNG_OBJECT_BUFFERS |
259 | | typedef struct _MngBuffer |
260 | | { |
261 | | |
262 | | unsigned long |
263 | | height, |
264 | | width; |
265 | | |
266 | | Image |
267 | | *image; |
268 | | |
269 | | png_color |
270 | | plte[256]; |
271 | | |
272 | | int |
273 | | reference_count; |
274 | | |
275 | | unsigned char |
276 | | alpha_sample_depth, |
277 | | compression_method, |
278 | | color_type, |
279 | | concrete, |
280 | | filter_method, |
281 | | frozen, |
282 | | image_type, |
283 | | interlace_method, |
284 | | pixel_sample_depth, |
285 | | plte_length, |
286 | | sample_depth, |
287 | | viewable; |
288 | | } MngBuffer; |
289 | | #endif |
290 | | |
291 | | typedef struct _MngInfo |
292 | | { |
293 | | |
294 | | #ifdef MNG_OBJECT_BUFFERS |
295 | | MngBuffer |
296 | | *ob[MNG_MAX_OBJECTS]; |
297 | | #endif |
298 | | |
299 | | Image * |
300 | | image; |
301 | | |
302 | | RectangleInfo |
303 | | page; |
304 | | |
305 | | int |
306 | | adjoin, |
307 | | #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
308 | | bytes_in_read_buffer, |
309 | | found_empty_plte, |
310 | | #endif |
311 | | equal_backgrounds, |
312 | | equal_chrms, |
313 | | equal_gammas, |
314 | | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
315 | | defined(PNG_MNG_FEATURES_SUPPORTED) |
316 | | equal_palettes, |
317 | | #endif |
318 | | equal_physs, |
319 | | equal_srgbs, |
320 | | framing_mode, |
321 | | have_global_bkgd, |
322 | | have_global_chrm, |
323 | | have_global_gama, |
324 | | have_global_phys, |
325 | | have_global_sbit, |
326 | | have_global_srgb, |
327 | | have_saved_bkgd_index, |
328 | | have_write_global_chrm, |
329 | | have_write_global_gama, |
330 | | have_write_global_plte, |
331 | | have_write_global_srgb, |
332 | | need_fram, |
333 | | object_id, |
334 | | old_framing_mode, |
335 | | saved_bkgd_index; |
336 | | |
337 | | int |
338 | | new_number_colors; |
339 | | |
340 | | long |
341 | | image_found, |
342 | | loop_count[256], |
343 | | loop_iteration[256], |
344 | | scenes_found, |
345 | | x_off[MNG_MAX_OBJECTS], |
346 | | y_off[MNG_MAX_OBJECTS]; |
347 | | |
348 | | MngBox |
349 | | clip, |
350 | | frame, |
351 | | image_box, |
352 | | object_clip[MNG_MAX_OBJECTS]; |
353 | | |
354 | | unsigned char |
355 | | /* These flags could be combined into one byte */ |
356 | | exists[MNG_MAX_OBJECTS], |
357 | | frozen[MNG_MAX_OBJECTS], |
358 | | loop_active[256], |
359 | | invisible[MNG_MAX_OBJECTS], |
360 | | viewable[MNG_MAX_OBJECTS]; |
361 | | |
362 | | ExtendedSignedIntegralType |
363 | | loop_jump[256]; |
364 | | |
365 | | png_colorp |
366 | | global_plte; |
367 | | |
368 | | png_color_8 |
369 | | global_sbit; |
370 | | |
371 | | png_byte |
372 | | #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
373 | | read_buffer[8], |
374 | | #endif |
375 | | global_trns[256]; |
376 | | |
377 | | float |
378 | | global_gamma; |
379 | | |
380 | | ChromaticityInfo |
381 | | global_chrm; |
382 | | |
383 | | RenderingIntent |
384 | | global_srgb_intent; |
385 | | |
386 | | unsigned long |
387 | | delay, |
388 | | global_plte_length, |
389 | | global_trns_length, |
390 | | global_x_pixels_per_unit, |
391 | | global_y_pixels_per_unit, |
392 | | mng_width, |
393 | | mng_height, |
394 | | ticks_per_second; |
395 | | |
396 | | unsigned int |
397 | | IsPalette, |
398 | | global_phys_unit_type, |
399 | | basi_warning, |
400 | | clon_warning, |
401 | | dhdr_warning, |
402 | | jhdr_warning, |
403 | | magn_warning, |
404 | | past_warning, |
405 | | phyg_warning, |
406 | | phys_warning, |
407 | | sbit_warning, |
408 | | show_warning, |
409 | | mng_type, |
410 | | write_mng, |
411 | | write_png_colortype, |
412 | | write_png_depth, |
413 | | write_png8, |
414 | | write_png24, |
415 | | write_png32, |
416 | | write_png48, |
417 | | write_png64; |
418 | | |
419 | | #ifdef MNG_BASI_SUPPORTED |
420 | | unsigned long |
421 | | basi_width, |
422 | | basi_height; |
423 | | |
424 | | unsigned int |
425 | | basi_depth, |
426 | | basi_color_type, |
427 | | basi_compression_method, |
428 | | basi_filter_type, |
429 | | basi_interlace_method, |
430 | | basi_red, |
431 | | basi_green, |
432 | | basi_blue, |
433 | | basi_alpha, |
434 | | basi_viewable; |
435 | | #endif |
436 | | |
437 | | png_uint_16 |
438 | | magn_first, |
439 | | magn_last, |
440 | | magn_mb, |
441 | | magn_ml, |
442 | | magn_mr, |
443 | | magn_mt, |
444 | | magn_mx, |
445 | | magn_my, |
446 | | magn_methx, |
447 | | magn_methy; |
448 | | |
449 | | PixelPacket |
450 | | mng_global_bkgd; |
451 | | |
452 | | unsigned char |
453 | | *png_pixels; |
454 | | |
455 | | Quantum |
456 | | *quantum_scanline; |
457 | | |
458 | | } MngInfo; |
459 | | #endif /* VER */ |
460 | | |
461 | | /* |
462 | | Forward declarations. |
463 | | */ |
464 | | static unsigned int |
465 | | WritePNGImage(const ImageInfo *,Image *); |
466 | | static unsigned int |
467 | | WriteMNGImage(const ImageInfo *,Image *); |
468 | | #if defined(JNG_SUPPORTED) |
469 | | static unsigned int |
470 | | WriteJNGImage(const ImageInfo *,Image *); |
471 | | #endif |
472 | | static const char* PngColorTypeToString(const unsigned int color_type) |
473 | 0 | { |
474 | 0 | const char |
475 | 0 | *result = "Unknown"; |
476 | |
|
477 | 0 | switch (color_type) |
478 | 0 | { |
479 | 0 | case PNG_COLOR_TYPE_GRAY: |
480 | 0 | result = "Gray"; |
481 | 0 | break; |
482 | 0 | case PNG_COLOR_TYPE_GRAY_ALPHA: |
483 | 0 | result = "Gray+Alpha"; |
484 | 0 | break; |
485 | 0 | case PNG_COLOR_TYPE_PALETTE: |
486 | 0 | result = "Palette"; |
487 | 0 | break; |
488 | 0 | case PNG_COLOR_TYPE_RGB: |
489 | 0 | result = "RGB"; |
490 | 0 | break; |
491 | 0 | case PNG_COLOR_TYPE_RGB_ALPHA: |
492 | 0 | result = "RGB+Alpha"; |
493 | 0 | break; |
494 | 0 | } |
495 | | |
496 | 0 | return result; |
497 | 0 | } |
498 | | #endif /* HasPNG */ |
499 | | |
500 | | /* |
501 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
502 | | % % |
503 | | % % |
504 | | % % |
505 | | % I s M N G % |
506 | | % % |
507 | | % % |
508 | | % % |
509 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
510 | | % |
511 | | % Method IsMNG returns True if the image format type, identified by the |
512 | | % magick string, is MNG. |
513 | | % |
514 | | % The format of the IsMNG method is: |
515 | | % |
516 | | % unsigned int IsMNG(const unsigned char *magick,const size_t length) |
517 | | % |
518 | | % A description of each parameter follows: |
519 | | % |
520 | | % o status: Method IsMNG returns True if the image format type is MNG. |
521 | | % |
522 | | % o magick: This string is generally the first few bytes of an image file |
523 | | % or blob. |
524 | | % |
525 | | % o length: Specifies the length of the magick string. |
526 | | % |
527 | | % |
528 | | */ |
529 | | static MagickPassFail IsMNG(const unsigned char *magick,const size_t length) |
530 | 0 | { |
531 | 0 | if (length < 8) |
532 | 0 | return(MagickFail); |
533 | 0 | if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0) |
534 | 0 | return(MagickPass); |
535 | 0 | return(MagickFail); |
536 | 0 | } |
537 | | |
538 | | /* |
539 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
540 | | % % |
541 | | % % |
542 | | % % |
543 | | % I s J N G % |
544 | | % % |
545 | | % % |
546 | | % % |
547 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
548 | | % |
549 | | % Method IsJNG returns True if the image format type, identified by the |
550 | | % magick string, is JNG. |
551 | | % |
552 | | % The format of the IsJNG method is: |
553 | | % |
554 | | % unsigned int IsJNG(const unsigned char *magick,const size_t length) |
555 | | % |
556 | | % A description of each parameter follows: |
557 | | % |
558 | | % o status: Method IsJNG returns True if the image format type is JNG. |
559 | | % |
560 | | % o magick: This string is generally the first few bytes of an image file |
561 | | % or blob. |
562 | | % |
563 | | % o length: Specifies the length of the magick string. |
564 | | % |
565 | | % |
566 | | */ |
567 | | static MagickPassFail IsJNG(const unsigned char *magick,const size_t length) |
568 | 0 | { |
569 | 0 | if (length < 8) |
570 | 0 | return(MagickFail); |
571 | 0 | if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0) |
572 | 0 | return(MagickPass); |
573 | 0 | return(MagickFail); |
574 | 0 | } |
575 | | |
576 | | /* |
577 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
578 | | % % |
579 | | % % |
580 | | % % |
581 | | % I s P N G % |
582 | | % % |
583 | | % % |
584 | | % % |
585 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
586 | | % |
587 | | % Method IsPNG returns True if the image format type, identified by the |
588 | | % magick string, is PNG. |
589 | | % |
590 | | % The format of the IsPNG method is: |
591 | | % |
592 | | % unsigned int IsPNG(const unsigned char *magick,const size_t length) |
593 | | % |
594 | | % A description of each parameter follows: |
595 | | % |
596 | | % o status: Method IsPNG returns True if the image format type is PNG. |
597 | | % |
598 | | % o magick: This string is generally the first few bytes of an image file |
599 | | % or blob. |
600 | | % |
601 | | % o length: Specifies the length of the magick string. |
602 | | % |
603 | | % |
604 | | */ |
605 | | static MagickPassFail IsPNG(const unsigned char *magick,const size_t length) |
606 | 0 | { |
607 | 0 | if (length < 8) |
608 | 0 | return(MagickFail); |
609 | 0 | if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0) |
610 | 0 | return(MagickPass); |
611 | 0 | return(MagickFail); |
612 | 0 | } |
613 | | |
614 | | #if defined(HasPNG) |
615 | | #if defined(__cplusplus) || defined(c_plusplus) |
616 | | extern "C" { |
617 | | #endif |
618 | | |
619 | | #if (PNG_LIBPNG_VER > 10011) |
620 | | static size_t WriteBlobMSBULong(Image *image,const unsigned long value) |
621 | 123k | { |
622 | 123k | unsigned char |
623 | 123k | buffer[4]; |
624 | | |
625 | 123k | assert(image != (Image *) NULL); |
626 | 123k | assert(image->signature == MagickSignature); |
627 | 123k | buffer[0]=(unsigned char) (value >> 24); |
628 | 123k | buffer[1]=(unsigned char) (value >> 16); |
629 | 123k | buffer[2]=(unsigned char) (value >> 8); |
630 | 123k | buffer[3]=(unsigned char) value; |
631 | 123k | return(WriteBlob(image,4,buffer)); |
632 | 123k | } |
633 | | |
634 | | static void PNGLong(png_bytep p,png_uint_32 value) |
635 | 24.2k | { |
636 | 24.2k | *p++=(png_byte) ((value >> 24) & 0xff); |
637 | 24.2k | *p++=(png_byte) ((value >> 16) & 0xff); |
638 | 24.2k | *p++=(png_byte) ((value >> 8) & 0xff); |
639 | 24.2k | *p++=(png_byte) (value & 0xff); |
640 | 24.2k | } |
641 | | |
642 | | static void PNGsLong(png_bytep p,png_int_32 value) |
643 | 2.95k | { |
644 | 2.95k | *p++=(png_byte) ((value >> 24) & 0xff); |
645 | 2.95k | *p++=(png_byte) ((value >> 16) & 0xff); |
646 | 2.95k | *p++=(png_byte) ((value >> 8) & 0xff); |
647 | 2.95k | *p++=(png_byte) (value & 0xff); |
648 | 2.95k | } |
649 | | |
650 | | static void PNGShort(png_bytep p,png_uint_16 value) |
651 | 0 | { |
652 | 0 | *p++=(png_byte) ((value >> 8) & 0xff); |
653 | 0 | *p++=(png_byte) (value & 0xff); |
654 | 0 | } |
655 | | |
656 | | static void PNGType(png_bytep p,png_byte const * type) |
657 | 61.7k | { |
658 | 61.7k | (void) memcpy(p,type,4*sizeof(png_byte)); |
659 | 61.7k | } |
660 | | |
661 | | static void LogPNGChunk(int logging, png_byte const * type, size_t length) |
662 | 61.7k | { |
663 | 61.7k | if (logging) |
664 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
665 | 0 | " Writing %c%c%c%c chunk, length: %" MAGICK_SIZE_T_F "u", |
666 | 0 | type[0],type[1],type[2],type[3],(MAGICK_SIZE_T) length); |
667 | 61.7k | } |
668 | | #endif /* PNG_LIBPNG_VER > 10011 */ |
669 | | |
670 | | #if defined(__cplusplus) || defined(c_plusplus) |
671 | | } |
672 | | #endif |
673 | | |
674 | | /* |
675 | | Use a macro to report exceptions (rather than calling libpng's |
676 | | png_error()) for exceptions thrown from this module. |
677 | | |
678 | | This provides useful file/line information as well as allowing code |
679 | | analyzers to have a more accurate idea of what is going on. |
680 | | */ |
681 | | #undef png_error |
682 | | #define png_error(png_ptr,error_message) \ |
683 | 14.7k | do \ |
684 | 14.7k | { \ |
685 | 14.7k | Image * \ |
686 | 14.7k | _image; \ |
687 | 14.7k | \ |
688 | 14.7k | _image=(Image *) png_get_error_ptr(png_ptr); \ |
689 | 14.7k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), \ |
690 | 14.7k | " error: %.1024s", error_message); \ |
691 | 14.7k | (void) ThrowException2(&_image->exception,CoderError, \ |
692 | 14.7k | error_message,_image->filename); \ |
693 | 14.7k | longjmp(png_jmpbuf(png_ptr),1); \ |
694 | 14.7k | } while(0) |
695 | | |
696 | | #if PNG_LIBPNG_VER > 10011 |
697 | | /* |
698 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
699 | | % % |
700 | | % % |
701 | | % % |
702 | | % R e a d P N G I m a g e % |
703 | | % % |
704 | | % % |
705 | | % % |
706 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
707 | | % |
708 | | % Method ReadPNGImage reads a Portable Network Graphics (PNG) or |
709 | | % Multiple-image Network Graphics (MNG) image file and returns it. It |
710 | | % allocates the memory necessary for the new Image structure and returns a |
711 | | % pointer to the new image or set of images. |
712 | | % |
713 | | % MNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu. |
714 | | % |
715 | | % The format of the ReadPNGImage method is: |
716 | | % |
717 | | % Image *ReadPNGImage(const ImageInfo *image_info, |
718 | | % ExceptionInfo *exception) |
719 | | % |
720 | | % A description of each parameter follows: |
721 | | % |
722 | | % o image: Method ReadPNGImage returns a pointer to the image after |
723 | | % reading. A null image is returned if there is a memory shortage or |
724 | | % if the image cannot be read. |
725 | | % |
726 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
727 | | % |
728 | | % o exception: return any errors or warnings in this structure. |
729 | | % |
730 | | % To do, more or less in chronological order (as of version 5.5.2, |
731 | | % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage): |
732 | | % |
733 | | % Get 16-bit cheap transparency working. |
734 | | % |
735 | | % (At this point, PNG decoding is supposed to be in full MNG-LC compliance) |
736 | | % |
737 | | % Preserve all unknown and not-yet-handled known chunks found in input |
738 | | % PNG file and copy them into output PNG files according to the PNG |
739 | | % copying rules. |
740 | | % |
741 | | % (At this point, PNG encoding should be in full MNG compliance) |
742 | | % |
743 | | % Provide options for choice of background to use when the MNG BACK |
744 | | % chunk is not present or is not mandatory (i.e., leave transparent, |
745 | | % user specified, MNG BACK, PNG bKGD) |
746 | | % |
747 | | % Implement LOOP/ENDL [done, but could do discretionary loops more |
748 | | % efficiently by linking in the duplicate frames.]. |
749 | | % |
750 | | % Decode and act on the MHDR simplicity profile (offer option to reject |
751 | | % files or attempt to process them anyway when the profile isn't LC or VLC). |
752 | | % |
753 | | % Upgrade to full MNG without Delta-PNG. |
754 | | % |
755 | | % o BACK [done a while ago except for background image ID] |
756 | | % o MOVE [done 15 May 1999] |
757 | | % o CLIP [done 15 May 1999] |
758 | | % o DISC [done 19 May 1999] |
759 | | % o SAVE [partially done 19 May 1999 (marks objects frozen)] |
760 | | % o SEEK [partially done 19 May 1999 (discard function only)] |
761 | | % o SHOW |
762 | | % o PAST |
763 | | % o BASI |
764 | | % o MNG-level tEXt/iTXt/zTXt |
765 | | % o pHYg |
766 | | % o pHYs |
767 | | % o sBIT |
768 | | % o bKGD |
769 | | % o iTXt (wait for libpng implementation). |
770 | | % |
771 | | % Use the scene signature to discover when an identical scene is |
772 | | % being reused, and just point to the original image->pixels instead |
773 | | % of storing another set of pixels. This is not specific to MNG |
774 | | % but could be applied generally. |
775 | | % |
776 | | % Upgrade to full MNG with Delta-PNG. |
777 | | % |
778 | | % JNG tEXt/iTXt/zTXt |
779 | | % |
780 | | % We will not attempt to read files containing the CgBI chunk. |
781 | | % They are really Xcode files meant for display on the iPhone. |
782 | | % These are not valid PNG files and it is impossible to recover |
783 | | % the original PNG from files that have been converted to Xcode-PNG, |
784 | | % since irretrievable loss of color data has occurred due to the |
785 | | % use of premultiplied alpha. |
786 | | */ |
787 | | |
788 | | #if defined(__cplusplus) || defined(c_plusplus) |
789 | | extern "C" { |
790 | | #endif |
791 | | |
792 | | /* |
793 | | Compute a distance vector between two colors (0-3.0) |
794 | | */ |
795 | | static double DistanceVector(const PixelPacket *a, const PixelPacket *b) |
796 | 852k | { |
797 | 852k | double |
798 | 852k | difference, |
799 | 852k | distance, |
800 | 852k | distance_squared; |
801 | | |
802 | 852k | difference=(a->red-(double) b->red)/MaxRGBDouble; |
803 | 852k | distance_squared=(difference*difference); |
804 | | |
805 | 852k | difference=(a->green-(double) b->green)/MaxRGBDouble; |
806 | 852k | distance_squared+=(difference*difference); |
807 | | |
808 | 852k | difference=(a->blue-(double) b->blue)/MaxRGBDouble; |
809 | 852k | distance_squared+=(difference*difference); |
810 | 852k | distance=sqrt(distance_squared); |
811 | 852k | return distance; |
812 | 852k | } |
813 | | |
814 | | /* |
815 | | This is the function that does the actual reading of data. It is |
816 | | the same as the one supplied in libpng, except that it receives the |
817 | | datastream from the ReadBlob() function instead of standard input. |
818 | | */ |
819 | | static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length) |
820 | 6.31M | { |
821 | 6.31M | Image |
822 | 6.31M | *image; |
823 | | |
824 | 6.31M | image=(Image *) png_get_io_ptr(png_ptr); |
825 | 6.31M | if (length > 0) |
826 | 6.31M | { |
827 | 6.31M | size_t |
828 | 6.31M | check; |
829 | | |
830 | 6.31M | if (length > 0x7fffffff) |
831 | 0 | png_warning(png_ptr, "chunk length > 2G"); |
832 | 6.31M | check=ReadBlob(image, length,(char *) data); |
833 | 6.31M | if (check != length) |
834 | 56.0k | { |
835 | 56.0k | char |
836 | 56.0k | msg[MaxTextExtent]; |
837 | | |
838 | 56.0k | (void) snprintf(msg,sizeof(msg),"Expected %" MAGICK_SIZE_T_F "u bytes;" |
839 | 56.0k | " found %" MAGICK_SIZE_T_F "u bytes", |
840 | 56.0k | (MAGICK_SIZE_T) length,(MAGICK_SIZE_T) check); |
841 | 56.0k | png_warning(png_ptr,msg); |
842 | 56.0k | png_error(png_ptr,"Read Exception"); |
843 | 56.0k | } |
844 | 6.31M | } |
845 | 6.31M | } |
846 | | |
847 | | #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \ |
848 | | !defined(PNG_MNG_FEATURES_SUPPORTED) |
849 | | /* We use mng_get_data() instead of png_get_data() if we have a libpng |
850 | | * older than libpng-1.0.3a, which was the first to allow the empty |
851 | | * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was |
852 | | * ifdef'ed out. Earlier versions would crash if the bKGD chunk was |
853 | | * encountered after an empty PLTE, so we have to look ahead for bKGD |
854 | | * chunks and remove them from the datastream that is passed to libpng, |
855 | | * and store their contents for later use. |
856 | | */ |
857 | | static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length) |
858 | | { |
859 | | MngInfo |
860 | | *mng_info; |
861 | | |
862 | | Image |
863 | | *image; |
864 | | |
865 | | png_size_t |
866 | | check; |
867 | | |
868 | | register long |
869 | | i; |
870 | | |
871 | | i=0; |
872 | | mng_info=(MngInfo *) png_get_io_ptr(png_ptr); |
873 | | image=(Image *) mng_info->image; |
874 | | while (mng_info->bytes_in_read_buffer && length) |
875 | | { |
876 | | data[i]=mng_info->read_buffer[i]; |
877 | | mng_info->bytes_in_read_buffer--; |
878 | | length--; |
879 | | i++; |
880 | | } |
881 | | if (length) |
882 | | { |
883 | | check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data); |
884 | | if (check != length) |
885 | | png_error(png_ptr,"Read Exception"); |
886 | | if (length == 4) |
887 | | { |
888 | | if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && |
889 | | (data[3] == 0)) |
890 | | { |
891 | | check=(png_size_t) ReadBlob(image,(size_t) length, |
892 | | (char *) mng_info->read_buffer); |
893 | | if (check != length) |
894 | | png_error(png_ptr,"Read Exception"); |
895 | | mng_info->read_buffer[4]=0; |
896 | | mng_info->bytes_in_read_buffer=4; |
897 | | if (!memcmp(mng_info->read_buffer,mng_PLTE,4)) |
898 | | mng_info->found_empty_plte=MagickTrue; |
899 | | if (!memcmp(mng_info->read_buffer,mng_IEND,4)) |
900 | | { |
901 | | mng_info->found_empty_plte=MagickFalse; |
902 | | mng_info->have_saved_bkgd_index=MagickFalse; |
903 | | } |
904 | | } |
905 | | if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && |
906 | | (data[3] == 1)) |
907 | | { |
908 | | check=(png_size_t) ReadBlob(image,(size_t) length, |
909 | | (char *) mng_info->read_buffer); |
910 | | if (check != length) |
911 | | png_error(png_ptr,"Read Exception"); |
912 | | mng_info->read_buffer[4]=0; |
913 | | mng_info->bytes_in_read_buffer=4; |
914 | | if (!memcmp(mng_info->read_buffer,mng_bKGD,4)) |
915 | | if (mng_info->found_empty_plte) |
916 | | { |
917 | | /* |
918 | | Skip the bKGD data byte and CRC. |
919 | | */ |
920 | | check=(png_size_t) |
921 | | ReadBlob(image,5,(char *) mng_info->read_buffer); |
922 | | if (check != 5) |
923 | | png_error(png_ptr,"Read Exception"); |
924 | | check=(png_size_t) ReadBlob(image,(size_t) length, |
925 | | (char *) |
926 | | mng_info->read_buffer); |
927 | | if (check != length) |
928 | | png_error(png_ptr,"Read Exception"); |
929 | | mng_info->saved_bkgd_index=mng_info->read_buffer[0]; |
930 | | mng_info->have_saved_bkgd_index=MagickTrue; |
931 | | mng_info->bytes_in_read_buffer=0; |
932 | | } |
933 | | } |
934 | | } |
935 | | } |
936 | | } |
937 | | #endif |
938 | | |
939 | | static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length) |
940 | 663k | { |
941 | 663k | Image |
942 | 663k | *image; |
943 | | |
944 | 663k | image=(Image *) png_get_io_ptr(png_ptr); |
945 | 663k | if (length) |
946 | 646k | { |
947 | 646k | png_size_t |
948 | 646k | check; |
949 | | |
950 | 646k | check=(png_size_t) WriteBlob(image,(unsigned long) length,(char *) data); |
951 | 646k | if (check != length) |
952 | 1 | png_error(png_ptr,"WriteBlob Failed"); |
953 | 646k | } |
954 | 663k | } |
955 | | |
956 | | static void png_flush_data(png_structp png_ptr) |
957 | 0 | { |
958 | 0 | ARG_NOT_USED(png_ptr); |
959 | | |
960 | | /* There is currently no safe API to "flush" a blob. */ |
961 | | #if 0 |
962 | | Image |
963 | | *image; |
964 | | |
965 | | image=(Image *) png_get_io_ptr(png_ptr); |
966 | | (void) SyncBlob(image); |
967 | | #endif |
968 | 0 | } |
969 | | |
970 | | #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
971 | | static int PalettesAreEqual(Image *a,Image *b) |
972 | 6.28k | { |
973 | 6.28k | long |
974 | 6.28k | i; |
975 | | |
976 | 6.28k | if ((a == (Image *) NULL) || (b == (Image *) NULL)) |
977 | 82 | return(MagickFail); |
978 | 6.20k | if (a->storage_class!=PseudoClass || b->storage_class!=PseudoClass) |
979 | 0 | return(MagickFail); |
980 | 6.20k | if (a->colors != b->colors) |
981 | 0 | return(MagickFail); |
982 | 11.7k | for (i=0; i < (long) a->colors; i++) |
983 | 6.20k | { |
984 | 6.20k | if ((a->colormap[i].red != b->colormap[i].red) || |
985 | 5.96k | (a->colormap[i].green != b->colormap[i].green) || |
986 | 5.85k | (a->colormap[i].blue != b->colormap[i].blue)) |
987 | 669 | return(MagickFail); |
988 | 6.20k | } |
989 | 5.53k | return((int) MagickTrue); |
990 | 6.20k | } |
991 | | #endif |
992 | | |
993 | | static void MngInfoDiscardObject(MngInfo *mng_info,int i) |
994 | 138M | { |
995 | 138M | if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) && |
996 | 138M | mng_info->exists[i] && !mng_info->frozen[i]) |
997 | 26.6k | { |
998 | | #ifdef MNG_OBJECT_BUFFERS |
999 | | if (mng_info->ob[i] != (MngBuffer *) NULL) |
1000 | | { |
1001 | | if (mng_info->ob[i]->reference_count > 0) |
1002 | | mng_info->ob[i]->reference_count--; |
1003 | | if (mng_info->ob[i]->reference_count == 0) |
1004 | | { |
1005 | | if (mng_info->ob[i]->image != (Image *) NULL) |
1006 | | { |
1007 | | DestroyImage(mng_info->ob[i]->image); |
1008 | | mng_info->ob[i]->image=(Image *) NULL; |
1009 | | } |
1010 | | MagickFreeMemory(mng_info->ob[i]); |
1011 | | } |
1012 | | } |
1013 | | mng_info->ob[i]=(MngBuffer *) NULL; |
1014 | | #endif |
1015 | 26.6k | mng_info->exists[i]=MagickFalse; |
1016 | 26.6k | mng_info->invisible[i]=MagickFalse; |
1017 | 26.6k | mng_info->viewable[i]=MagickFalse; |
1018 | 26.6k | mng_info->frozen[i]=MagickFalse; |
1019 | 26.6k | mng_info->x_off[i]=0; |
1020 | 26.6k | mng_info->y_off[i]=0; |
1021 | 26.6k | mng_info->object_clip[i].left=0; |
1022 | 26.6k | mng_info->object_clip[i].right=PNG_MAX_UINT; |
1023 | 26.6k | mng_info->object_clip[i].top=0; |
1024 | 26.6k | mng_info->object_clip[i].bottom=PNG_MAX_UINT; |
1025 | 26.6k | } |
1026 | 138M | } |
1027 | | |
1028 | | static void MngInfoFreeStruct(MngInfo *mng_info,int *have_mng_structure) |
1029 | 531k | { |
1030 | 531k | if (*have_mng_structure && (mng_info != (MngInfo *) NULL)) |
1031 | 531k | { |
1032 | 531k | register long |
1033 | 531k | i; |
1034 | | |
1035 | 135M | for (i=1; i < MNG_MAX_OBJECTS; i++) |
1036 | 135M | MngInfoDiscardObject(mng_info,i); |
1037 | 531k | mng_info->image=(Image *)NULL; |
1038 | 531k | MagickFreeMemory(mng_info->global_plte); |
1039 | 531k | MagickFreeMemory(mng_info); |
1040 | 531k | *have_mng_structure=MagickFalse; |
1041 | 531k | } |
1042 | 531k | } |
1043 | | |
1044 | | static MngBox mng_minimum_box(MngBox box1,MngBox box2) |
1045 | 159k | { |
1046 | 159k | MngBox |
1047 | 159k | box; |
1048 | | |
1049 | 159k | box=box1; |
1050 | 159k | if (box.left < box2.left) |
1051 | 1.11k | box.left=box2.left; |
1052 | 159k | if (box.top < box2.top) |
1053 | 8.77k | box.top=box2.top; |
1054 | 159k | if (box.right > box2.right) |
1055 | 65.9k | box.right=box2.right; |
1056 | 159k | if (box.bottom > box2.bottom) |
1057 | 65.2k | box.bottom=box2.bottom; |
1058 | 159k | return box; |
1059 | 159k | } |
1060 | | |
1061 | | static long mng_get_long(unsigned char *p) |
1062 | 1.07M | { |
1063 | 1.07M | return ((long) (((magick_uint32_t) p[0] << 24) | |
1064 | 1.07M | ((magick_uint32_t) p[1] << 16) | |
1065 | 1.07M | ((magick_uint32_t) p[2] << 8) | |
1066 | 1.07M | (magick_uint32_t) p[3])); |
1067 | 1.07M | } |
1068 | | |
1069 | | static MngBox mng_read_box(MngBox previous_box,char delta_type, |
1070 | | unsigned char *p) |
1071 | 104k | { |
1072 | 104k | MngBox |
1073 | 104k | box; |
1074 | | |
1075 | | /* |
1076 | | Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk. |
1077 | | */ |
1078 | 104k | box.left = mng_get_long(p); |
1079 | 104k | box.right = mng_get_long(&p[4]); |
1080 | 104k | box.top = mng_get_long(&p[8]); |
1081 | 104k | box.bottom= mng_get_long(&p[12]); |
1082 | 104k | if (delta_type != 0) |
1083 | 50.1k | { |
1084 | 50.1k | box.left+=previous_box.left; |
1085 | 50.1k | box.right+=previous_box.right; |
1086 | 50.1k | box.top+=previous_box.top; |
1087 | 50.1k | box.bottom+=previous_box.bottom; |
1088 | 50.1k | } |
1089 | 104k | return(box); |
1090 | 104k | } |
1091 | | |
1092 | | static MngPair mng_read_pair(MngPair previous_pair,int delta_type, |
1093 | | unsigned char *p) |
1094 | 787 | { |
1095 | 787 | MngPair |
1096 | 787 | pair; |
1097 | | /* |
1098 | | Read two longs from CLON, MOVE or PAST chunk |
1099 | | */ |
1100 | 787 | pair.a= mng_get_long(p); |
1101 | 787 | pair.b= mng_get_long(&p[4]); |
1102 | | |
1103 | 787 | if (delta_type != 0) |
1104 | 324 | { |
1105 | 324 | pair.a+=previous_pair.a; |
1106 | 324 | pair.b+=previous_pair.b; |
1107 | 324 | } |
1108 | 787 | return(pair); |
1109 | 787 | } |
1110 | | |
1111 | | static void PNGErrorHandler(png_struct *ping,png_const_charp message) MAGICK_FUNC_NORETURN; |
1112 | | |
1113 | | static void PNGErrorHandler(png_struct *ping,png_const_charp message) |
1114 | 165k | { |
1115 | 165k | Image |
1116 | 165k | *image; |
1117 | | |
1118 | 165k | image=(Image *) png_get_error_ptr(ping); |
1119 | 165k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1120 | 165k | " libpng-%.1024s error: %.1024s", |
1121 | 165k | PNG_LIBPNG_VER_STRING, message); |
1122 | 165k | (void) ThrowException2(&image->exception,CoderError,message,image->filename); |
1123 | | #if (PNG_LIBPNG_VER < 10500) |
1124 | | longjmp(ping->jmpbuf,1); |
1125 | | #else |
1126 | 165k | png_longjmp(ping,1); |
1127 | 165k | #endif |
1128 | 165k | SignalHandlerExit(EXIT_FAILURE); /* Avoid GCC warning about non-exit function which does exit */ |
1129 | 165k | } |
1130 | | |
1131 | | static void PNGWarningHandler(png_struct *ping,png_const_charp message) |
1132 | 2.09M | { |
1133 | 2.09M | Image |
1134 | 2.09M | *image; |
1135 | | |
1136 | 2.09M | if (LocaleCompare(message, "Missing PLTE before tRNS") == 0) |
1137 | 0 | png_error(ping, message); |
1138 | 2.09M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1139 | 2.09M | " libpng-%.1024s warning: %.1024s", |
1140 | 2.09M | PNG_LIBPNG_VER_STRING, message); |
1141 | 2.09M | image=(Image *) png_get_error_ptr(ping); |
1142 | 2.09M | errno=0; |
1143 | 2.09M | (void) ThrowException2(&image->exception,CoderWarning,message, |
1144 | 2.09M | image->filename); |
1145 | 2.09M | } |
1146 | | |
1147 | | #ifdef PNG_USER_MEM_SUPPORTED |
1148 | | #if PNG_LIBPNG_VER >= 14000 |
1149 | | static png_voidp png_IM_malloc(png_structp png_ptr,png_alloc_size_t size) |
1150 | | #else |
1151 | | static png_voidp png_IM_malloc(png_structp png_ptr,png_size_t size) |
1152 | | #endif |
1153 | 4.29M | { |
1154 | 4.29M | (void) png_ptr; |
1155 | 4.29M | return MagickAllocateMemory(png_voidp,(size_t) size); |
1156 | 4.29M | } |
1157 | | |
1158 | | /* |
1159 | | Free a pointer. It is removed from the list at the same time. |
1160 | | */ |
1161 | | static void png_IM_free(png_structp png_ptr,png_voidp ptr) |
1162 | 4.29M | { |
1163 | 4.29M | (void) png_ptr; |
1164 | 4.29M | MagickFreeMemory(ptr); |
1165 | 4.29M | return; |
1166 | 4.29M | } |
1167 | | #endif |
1168 | | |
1169 | | #if defined(__cplusplus) || defined(c_plusplus) |
1170 | | } |
1171 | | #endif |
1172 | | |
1173 | | static MagickPassFail |
1174 | | png_read_raw_profile(Image *image, const ImageInfo *image_info, |
1175 | | png_textp text,long ii,ExceptionInfo *exception) |
1176 | 29.7k | { |
1177 | 29.7k | char |
1178 | 29.7k | profile_description[MaxTextExtent], |
1179 | 29.7k | profile_name[MaxTextExtent]; |
1180 | | |
1181 | 29.7k | unsigned char |
1182 | 29.7k | *info; |
1183 | | |
1184 | 29.7k | register size_t |
1185 | 29.7k | i; |
1186 | | |
1187 | 29.7k | size_t |
1188 | 29.7k | length, |
1189 | 29.7k | nibbles; |
1190 | | |
1191 | 29.7k | long |
1192 | 29.7k | length_s; |
1193 | | |
1194 | 29.7k | register unsigned char |
1195 | 29.7k | *dp; |
1196 | | |
1197 | 29.7k | register png_charp |
1198 | 29.7k | sp; |
1199 | | |
1200 | 29.7k | png_charp |
1201 | 29.7k | ep; |
1202 | | |
1203 | 29.7k | static const unsigned char |
1204 | 29.7k | unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, |
1205 | 29.7k | 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, |
1206 | 29.7k | 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0, |
1207 | 29.7k | 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, |
1208 | 29.7k | 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12, |
1209 | 29.7k | 13,14,15}; |
1210 | | |
1211 | 29.7k | if (image->logging) |
1212 | 29.7k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1213 | 29.7k | " Read raw profile[%ld]",ii); |
1214 | | |
1215 | 29.7k | sp=text[ii].text+1; |
1216 | 29.7k | ep=text[ii].text+text[ii].text_length; |
1217 | 29.7k | if (ep <= sp) |
1218 | 38 | { |
1219 | 38 | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1220 | 38 | return MagickFail; |
1221 | 38 | } |
1222 | | /* look for newline */ |
1223 | 230k | while ((sp < ep) && (*sp != '\n')) |
1224 | 200k | sp++; |
1225 | 29.7k | if (sp == ep) |
1226 | 3.02k | { |
1227 | 3.02k | if (image->logging) |
1228 | 3.02k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1229 | 3.02k | " Failed to find new-line in raw profile"); |
1230 | 3.02k | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1231 | 3.02k | return MagickFail; |
1232 | 3.02k | } |
1233 | | /* look for length */ |
1234 | 74.7k | while ((sp < ep) && (*sp == '\0' || *sp == ' ' || *sp == '\n')) |
1235 | 48.0k | sp++; |
1236 | 26.7k | if (sp == ep) |
1237 | 71 | { |
1238 | 71 | if (image->logging) |
1239 | 71 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1240 | 71 | " Failed to find raw profile length!"); |
1241 | 71 | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1242 | 71 | return MagickFail; |
1243 | 71 | } |
1244 | 26.6k | length_s = MagickAtoL(sp); |
1245 | 26.6k | if ((length_s <= 0) || (length_s >= (ep-sp))) |
1246 | 5.88k | { |
1247 | 5.88k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1248 | 5.88k | "invalid profile length %ld", length_s); |
1249 | 5.88k | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1250 | 5.88k | return (MagickFail); |
1251 | 5.88k | } |
1252 | 20.7k | length=(size_t) length_s; |
1253 | 223k | while ((sp < ep) && (*sp != ' ' && *sp != '\n')) |
1254 | 202k | sp++; |
1255 | 20.7k | if (sp == ep) |
1256 | 5.97k | { |
1257 | 5.97k | if (image->logging) |
1258 | 5.97k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1259 | 5.97k | " End of text while looking for start of hex-encoded profile"); |
1260 | 5.97k | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1261 | 5.97k | return MagickFail; |
1262 | 5.97k | } |
1263 | | /* allocate space */ |
1264 | 14.7k | if ((length == 0) || ((magick_uintptr_t) (ep-sp) <= length*2)) |
1265 | 50 | { |
1266 | 50 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1267 | 50 | "invalid profile length %" MAGICK_SIZE_T_F "u", (MAGICK_SIZE_T) length); |
1268 | 50 | ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename); |
1269 | 50 | return (MagickFail); |
1270 | 50 | } |
1271 | 14.7k | info=MagickAllocateMemory(unsigned char *,length); |
1272 | 14.7k | if (info == (unsigned char *) NULL) |
1273 | 0 | { |
1274 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1275 | 0 | "Unable to copy profile"); |
1276 | 0 | return (MagickFail); |
1277 | 0 | } |
1278 | | /* copy profile, skipping white space and column 1 "=" signs */ |
1279 | 14.7k | dp=info; |
1280 | 14.7k | nibbles=length*2; |
1281 | 225k | for (i=0; i < nibbles; i++) |
1282 | 212k | { |
1283 | 422k | while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f') |
1284 | 211k | { |
1285 | 211k | if (*sp == '\0') |
1286 | 1.24k | { |
1287 | 1.24k | MagickFreeMemory(info); |
1288 | 1.24k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1289 | 1.24k | "ran out of profile data"); |
1290 | 1.24k | return (MagickFail); |
1291 | 1.24k | } |
1292 | 210k | sp++; |
1293 | 210k | } |
1294 | 211k | if (i%2 == 0) |
1295 | 105k | *dp=16*unhex[(int) *sp++]; |
1296 | 105k | else |
1297 | 105k | (*dp++)+=unhex[(int) *sp++]; |
1298 | 211k | } |
1299 | | |
1300 | | /* We have already read "Raw profile type " */ |
1301 | 13.5k | if(!memcmp(&text[ii].key[17], "iptc\0",5)) |
1302 | 659 | { |
1303 | 659 | strlcpy(profile_name,"IPTC",sizeof(profile_name)); |
1304 | 659 | strlcpy(profile_description,"IPTC profile.",sizeof(profile_description)); |
1305 | 659 | } |
1306 | 12.8k | else if (!memcmp(&text[ii].key[17], "icm\0",4)) |
1307 | 910 | { |
1308 | 910 | strlcpy(profile_name,"ICM",sizeof(profile_name)); |
1309 | 910 | strlcpy(profile_description,"ICM (ICCP) profile.", |
1310 | 910 | sizeof(profile_description)); |
1311 | 910 | } |
1312 | 11.9k | else |
1313 | 11.9k | { |
1314 | 11.9k | strlcpy(profile_name,&text[ii].key[17],sizeof(profile_name)); |
1315 | 11.9k | LocaleUpper(profile_name); |
1316 | 11.9k | strlcpy(profile_description,"generic profile, type ", |
1317 | 11.9k | sizeof(profile_description)); |
1318 | 11.9k | strlcat(profile_description,&text[ii].key[17], |
1319 | 11.9k | sizeof(profile_description)); |
1320 | 11.9k | } |
1321 | 13.5k | if (image_info->verbose) |
1322 | 0 | (void) printf(" Found a %.1024s\n",profile_description); |
1323 | 13.5k | if(SetImageProfile(image,profile_name,info,length) == MagickFail) |
1324 | 0 | { |
1325 | 0 | MagickFreeMemory(info); |
1326 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1327 | 0 | "unable to copy profile"); |
1328 | 0 | return MagickFail; |
1329 | 0 | } |
1330 | 13.5k | MagickFreeMemory(info); |
1331 | 13.5k | return MagickTrue; |
1332 | 13.5k | } |
1333 | | |
1334 | | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) |
1335 | | |
1336 | | static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) |
1337 | 429k | { |
1338 | 429k | Image |
1339 | 429k | *image; |
1340 | | |
1341 | | |
1342 | | /* The unknown chunk structure contains the chunk data: |
1343 | | png_byte name[5]; |
1344 | | png_byte *data; |
1345 | | png_size_t size; |
1346 | | |
1347 | | Note that libpng has already taken care of the CRC handling. |
1348 | | |
1349 | | Returns one of the following: |
1350 | | return(-n); An error occurred; png_chunk_error will be called. |
1351 | | return(0); The chunk was not handled, the chunk will be discarded |
1352 | | unless png_set_keep_unknown_chunks has been used to set |
1353 | | a 'keep' behavior for this particular chunk, in which |
1354 | | case that will be used. A critical chunk will cause an |
1355 | | error at this point unless it is to be saved. |
1356 | | return(n); The chunk was handled, libpng will ignore/discard it. |
1357 | | */ |
1358 | | |
1359 | 429k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1360 | 429k | " read_user_chunk: found %c%c%c%c chunk with size" |
1361 | 429k | " %" MAGICK_SIZE_T_F "u", |
1362 | 429k | chunk->name[0],chunk->name[1], |
1363 | 429k | chunk->name[2],chunk->name[3], |
1364 | 429k | (MAGICK_SIZE_T) chunk->size); |
1365 | | |
1366 | 429k | if (chunk->name[0] == 101 && |
1367 | 120k | (chunk->name[1] == 88 || chunk->name[1] == 120 ) && |
1368 | 106k | chunk->name[2] == 73 && |
1369 | 101k | chunk->name[3] == 102) |
1370 | 66.2k | { |
1371 | | /* process eXIf or exIf chunk */ |
1372 | | |
1373 | 66.2k | unsigned char |
1374 | 66.2k | *profile; |
1375 | | |
1376 | 66.2k | unsigned char |
1377 | 66.2k | *p; |
1378 | | |
1379 | 66.2k | png_byte |
1380 | 66.2k | *s; |
1381 | | |
1382 | 66.2k | size_t |
1383 | 66.2k | i; |
1384 | | |
1385 | 66.2k | const size_t app1_hdr_size = MAGICK_JPEG_APP1_EXIF_HEADER_SIZE; |
1386 | | |
1387 | 66.2k | image=(Image *) png_get_user_chunk_ptr(ping); |
1388 | | |
1389 | 66.2k | if (image->logging) |
1390 | 66.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1391 | 66.2k | " recognized eXIf chunk"); |
1392 | | |
1393 | 66.2k | profile=MagickAllocateMemory(unsigned char *,chunk->size+app1_hdr_size); |
1394 | | |
1395 | 66.2k | if (profile == (unsigned char *) NULL) |
1396 | 0 | { |
1397 | 0 | ThrowException(&image->exception,ResourceLimitError, |
1398 | 0 | MemoryAllocationFailed,image->filename); |
1399 | 0 | return -1; |
1400 | 0 | } |
1401 | | |
1402 | 66.2k | p=profile; |
1403 | | |
1404 | | /* Stored profile should start with JPEG APP1 "Exif\0\0" header */ |
1405 | 66.2k | (void) memcpy(p,MAGICK_JPEG_APP1_EXIF_HEADER,app1_hdr_size); |
1406 | 66.2k | p += app1_hdr_size; |
1407 | | |
1408 | 66.2k | i=0; |
1409 | 66.2k | s=chunk->data; |
1410 | | |
1411 | 66.2k | if (chunk->size > app1_hdr_size && |
1412 | 17.5k | (memcmp((const void *) s,(const void *) MAGICK_JPEG_APP1_EXIF_HEADER, |
1413 | 17.5k | app1_hdr_size) == 0)) |
1414 | 1.97k | { |
1415 | | /* |
1416 | | Skip over "Exif\0\0" if already present |
1417 | | */ |
1418 | 1.97k | i=app1_hdr_size; |
1419 | 1.97k | s += app1_hdr_size; |
1420 | 1.97k | } |
1421 | | |
1422 | | /* copy chunk->data to profile */ |
1423 | | /* It is documented that the first four bytes of eXIf profile |
1424 | | should be '73 73 42 0' or '77 77 0 42' */ |
1425 | 9.76M | for (; i<chunk->size; i++) |
1426 | 9.69M | *p++ = *s++; |
1427 | | |
1428 | 66.2k | (void) SetImageProfile(image,"exif", |
1429 | 66.2k | (const unsigned char *)profile, p-profile); |
1430 | 66.2k | MagickFreeMemory(profile) |
1431 | | |
1432 | 66.2k | return(1); |
1433 | 66.2k | } |
1434 | | |
1435 | | /* orNT */ |
1436 | 363k | if (chunk->name[0] == 111 && |
1437 | 96.2k | chunk->name[1] == 114 && |
1438 | 85.4k | chunk->name[2] == 78 && |
1439 | 73.7k | chunk->name[3] == 84) |
1440 | 69.9k | { |
1441 | | /* recognized orNT */ |
1442 | 69.9k | if (chunk->size != 1) |
1443 | 219 | return(-1); /* Error return */ |
1444 | | |
1445 | 69.7k | image=(Image *) png_get_user_chunk_ptr(ping); |
1446 | 69.7k | if (chunk->data[0] < 9) |
1447 | 64.9k | image->orientation = (OrientationType) chunk->data[0]; |
1448 | 4.85k | else |
1449 | 4.85k | image->orientation = UndefinedOrientation; |
1450 | 69.7k | return(1); |
1451 | 69.9k | } |
1452 | | |
1453 | | /* caNv */ |
1454 | 293k | if (chunk->name[0] == 99 && |
1455 | 76.6k | chunk->name[1] == 97 && |
1456 | 38.3k | chunk->name[2] == 78 && |
1457 | 25.2k | chunk->name[3] == 118) |
1458 | 3.47k | { |
1459 | | /* recognized caNv */ |
1460 | | |
1461 | 3.47k | if (chunk->size != 16) |
1462 | 360 | return(-1); /* Error return */ |
1463 | | |
1464 | 3.11k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1465 | 3.11k | " recognized caNv chunk"); |
1466 | | |
1467 | 3.11k | image=(Image *) png_get_user_chunk_ptr(ping); |
1468 | | |
1469 | 3.11k | image->page.width=(size_t) mng_get_long(chunk->data); |
1470 | 3.11k | image->page.height=(size_t) mng_get_long(&chunk->data[4]); |
1471 | 3.11k | image->page.x=(size_t) mng_get_long(&chunk->data[8]); |
1472 | 3.11k | image->page.y=(size_t) mng_get_long(&chunk->data[12]); |
1473 | | |
1474 | 3.11k | return(1); |
1475 | 3.47k | } |
1476 | | |
1477 | 289k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1478 | 289k | " unrecognized user chunk: %s", chunk->name); |
1479 | | |
1480 | 289k | return(0); /* Did not recognize */ |
1481 | 293k | } |
1482 | | #endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */ |
1483 | | |
1484 | | /* |
1485 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1486 | | % % |
1487 | | % % |
1488 | | % % |
1489 | | % R e a d O n e P N G I m a g e % |
1490 | | % % |
1491 | | % % |
1492 | | % % |
1493 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1494 | | % |
1495 | | % Method ReadOnePNGImage reads a Portable Network Graphics (PNG) image file |
1496 | | % (minus the 8-byte signature) and returns it. It allocates the memory |
1497 | | % necessary for the new Image structure and returns a pointer to the new |
1498 | | % image. |
1499 | | % |
1500 | | % The format of the ReadOnePNGImage method is: |
1501 | | % |
1502 | | % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info, |
1503 | | % ExceptionInfo *exception) |
1504 | | % |
1505 | | % A description of each parameter follows: |
1506 | | % |
1507 | | % o image: Method ReadOnePNGImage returns a pointer to the image after |
1508 | | % reading. A null image is returned if there is a memory shortage or |
1509 | | % if the image cannot be read. |
1510 | | % |
1511 | | % o mng_info: Specifies a pointer to a MngInfo structure. |
1512 | | % |
1513 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1514 | | % |
1515 | | % o exception: return any errors or warnings in this structure. |
1516 | | % |
1517 | | */ |
1518 | | static Image *ReadOnePNGImage(MngInfo *mng_info, |
1519 | | const ImageInfo *image_info, |
1520 | | ExceptionInfo *exception) |
1521 | 332k | { |
1522 | | /* Read one PNG image */ |
1523 | | |
1524 | 332k | Image |
1525 | 332k | *image; |
1526 | | |
1527 | 332k | png_info |
1528 | 332k | *end_info, |
1529 | 332k | *ping_info; |
1530 | | |
1531 | 332k | png_struct |
1532 | 332k | *ping; |
1533 | | |
1534 | 332k | png_textp |
1535 | 332k | text; |
1536 | | |
1537 | 332k | png_bytep |
1538 | 332k | ping_trans_alpha = (png_bytep) NULL; |
1539 | | |
1540 | 332k | size_t |
1541 | 332k | length, |
1542 | 332k | ping_rowbytes, |
1543 | 332k | row_offset; |
1544 | | |
1545 | 332k | unsigned int |
1546 | 332k | ping_file_depth; |
1547 | | |
1548 | 332k | int |
1549 | 332k | logging, |
1550 | 332k | num_text, |
1551 | 332k | num_passes, |
1552 | 332k | pass, |
1553 | 332k | ping_bit_depth, |
1554 | 332k | ping_colortype, |
1555 | 332k | ping_interlace_method, |
1556 | 332k | ping_compression_method, |
1557 | 332k | ping_filter_method, |
1558 | 332k | ping_num_trans=0; |
1559 | | |
1560 | 332k | LongPixelPacket |
1561 | 332k | transparent_color; |
1562 | | |
1563 | 332k | png_color_16p |
1564 | 332k | ping_background = (png_color_16p) NULL, |
1565 | 332k | ping_trans_color = (png_color_16p) NULL; |
1566 | | |
1567 | 332k | png_uint_32 |
1568 | 332k | ping_width, |
1569 | 332k | ping_height; |
1570 | | |
1571 | 332k | long |
1572 | 332k | y; |
1573 | | |
1574 | 332k | register IndexPacket |
1575 | 332k | *indexes; |
1576 | | |
1577 | 332k | register long |
1578 | 332k | i, |
1579 | 332k | x; |
1580 | | |
1581 | 332k | register PixelPacket |
1582 | 332k | *q; |
1583 | | |
1584 | 332k | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) |
1585 | 332k | static const png_byte unused_chunks[]= |
1586 | 332k | { |
1587 | 332k | 104, 73, 83, 84, '\0', /* hIST */ |
1588 | 332k | 105, 84, 88, 116, '\0', /* iTXt */ |
1589 | 332k | 112, 67, 65, 76, '\0', /* pCAL */ |
1590 | 332k | 115, 67, 65, 76, '\0', /* sCAL */ |
1591 | 332k | 115, 80, 76, 84, '\0', /* sPLT */ |
1592 | 332k | 116, 73, 77, 69, '\0', /* tIME */ |
1593 | 332k | #ifdef PNG_READ_eXIf_SUPPORTED /* Enforce custom eXIf processing to override default one. */ |
1594 | 332k | 101, 88, 73, 102, '\0', /* eXIf*/ |
1595 | 332k | #endif |
1596 | 332k | #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */ |
1597 | | /* ignore the APNG chunks */ |
1598 | 332k | 97, 99, 84, 76, '\0', /* acTL */ |
1599 | 332k | 102, 99, 84, 76, '\0', /* fcTL */ |
1600 | 332k | 102, 100, 65, 84, '\0', /* fdAT */ |
1601 | 332k | #endif |
1602 | 332k | }; |
1603 | 332k | #endif |
1604 | | |
1605 | 332k | logging=LogMagickEvent(CoderEvent,GetMagickModule(), |
1606 | 332k | " enter ReadOnePNGImage()"); |
1607 | | |
1608 | | /* Set to an out-of-range color unless tRNS chunk is present */ |
1609 | 332k | transparent_color.red=65537; |
1610 | 332k | transparent_color.green=65537; |
1611 | 332k | transparent_color.blue=65537; |
1612 | 332k | transparent_color.opacity=65537; |
1613 | | |
1614 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
1615 | | LockSemaphoreInfo(png_semaphore); |
1616 | | #endif |
1617 | | |
1618 | | #if (PNG_LIBPNG_VER < 10012) |
1619 | | if (image_info->verbose) |
1620 | | printf("Your PNG library (libpng-%s) is rather old.\n", |
1621 | | PNG_LIBPNG_VER_STRING); |
1622 | | #endif |
1623 | | |
1624 | 332k | image=mng_info->image; |
1625 | | |
1626 | | /* |
1627 | | Allocate the PNG structures |
1628 | | */ |
1629 | 332k | #ifdef PNG_USER_MEM_SUPPORTED |
1630 | 332k | ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image, |
1631 | 332k | PNGErrorHandler,PNGWarningHandler, NULL, |
1632 | 332k | (png_malloc_ptr) png_IM_malloc, |
1633 | 332k | (png_free_ptr) png_IM_free); |
1634 | | #else |
1635 | | ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image, |
1636 | | PNGErrorHandler,PNGWarningHandler); |
1637 | | #endif |
1638 | 332k | if (ping == (png_struct *) NULL) |
1639 | 0 | { |
1640 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
1641 | | UnlockSemaphoreInfo(png_semaphore); |
1642 | | #endif |
1643 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1644 | 0 | } |
1645 | | |
1646 | 332k | png_set_crc_action(ping, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); |
1647 | | |
1648 | 332k | mng_info->png_pixels=(unsigned char *) NULL; |
1649 | 332k | mng_info->quantum_scanline=(Quantum *) NULL; |
1650 | | |
1651 | 332k | if (setjmp(png_jmpbuf(ping))) |
1652 | 221k | { |
1653 | | /* |
1654 | | PNG image is corrupt. |
1655 | | */ |
1656 | 221k | png_destroy_read_struct(&ping,&ping_info,&end_info); |
1657 | 221k | MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline); |
1658 | 221k | MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels); |
1659 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
1660 | | UnlockSemaphoreInfo(png_semaphore); |
1661 | | #endif |
1662 | 221k | if (logging) |
1663 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1664 | 0 | " exit ReadOnePNGImage() with error."); |
1665 | 221k | if (image != (Image *) NULL) |
1666 | 221k | { |
1667 | 221k | if (image->exception.severity > exception->severity) |
1668 | 63.1k | CopyException(exception,&image->exception); |
1669 | 221k | image->columns=0; |
1670 | 221k | } |
1671 | 221k | if (image) |
1672 | 221k | { |
1673 | | /* Image is part of mng_info->image list (see above) */ |
1674 | 221k | DestroyImageList(image); |
1675 | 221k | image=(Image *) NULL; |
1676 | 221k | mng_info->image=(Image *) NULL; |
1677 | 221k | } |
1678 | | /* We are not aware that the following case ever happens */ |
1679 | 221k | if (mng_info->image) |
1680 | 0 | { |
1681 | 0 | DestroyImageList(mng_info->image); |
1682 | 0 | mng_info->image=(Image *) NULL; |
1683 | 0 | } |
1684 | 221k | return(image); |
1685 | 221k | } |
1686 | | |
1687 | | /* { From here through end of ReadOnePNGImage(), use png_error(), not Throw() */ |
1688 | | |
1689 | 111k | ping_info=png_create_info_struct(ping); |
1690 | 111k | if (ping_info == (png_info *) NULL) |
1691 | 0 | { |
1692 | 0 | png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL); |
1693 | 0 | png_error(ping,"Could not allocate PNG info struct"); |
1694 | 0 | } |
1695 | | |
1696 | 111k | end_info=png_create_info_struct(ping); |
1697 | 111k | if (end_info == (png_info *) NULL) |
1698 | 0 | { |
1699 | 0 | png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL); |
1700 | 0 | png_error(ping,"Could not allocate PNG end_info struct"); |
1701 | 0 | } |
1702 | | |
1703 | 111k | #ifdef PNG_BENIGN_ERRORS_SUPPORTED |
1704 | | /* Allow benign errors */ |
1705 | 111k | png_set_benign_errors(ping, 1); |
1706 | 111k | #endif |
1707 | | |
1708 | | /* Default to using libpng's limit (PNG_USER_CHUNK_MALLOC_MAX == |
1709 | | 8000000) on chunk size */ |
1710 | 111k | #ifdef PNG_SET_USER_LIMITS_SUPPORTED |
1711 | | /* Reject images with too many rows or columns */ |
1712 | 111k | png_set_user_limits(ping, |
1713 | 111k | (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)), |
1714 | 111k | (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(HeightResource))); |
1715 | | /* Allow specifying a different chunk size limit than the |
1716 | | PNG_USER_CHUNK_MALLOC_MAX baked into libpng */ |
1717 | 111k | # if PNG_LIBPNG_VER >= 10401 /* png_set_chunk_malloc_max was added in 1.4.1 */ |
1718 | 111k | { |
1719 | 111k | const char *chunk_malloc_max_str; |
1720 | 111k | if ((chunk_malloc_max_str=AccessDefinition(image_info,"png","chunk-malloc-max"))) |
1721 | 0 | { |
1722 | 0 | unsigned long chunk_malloc_max; |
1723 | 0 | if (MagickAtoULChk(chunk_malloc_max_str, &chunk_malloc_max) == MagickPass) |
1724 | 0 | { |
1725 | 0 | png_set_chunk_malloc_max(ping, chunk_malloc_max); |
1726 | 0 | if (logging) |
1727 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1728 | 0 | "Set PNG chunk-malloc-max to %lu bytes", |
1729 | 0 | chunk_malloc_max); |
1730 | 0 | } |
1731 | 0 | else |
1732 | 0 | { |
1733 | 0 | if (logging) |
1734 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1735 | 0 | "Failed to parse chunk-malloc-max value \"%s\"", |
1736 | 0 | chunk_malloc_max_str); |
1737 | 0 | } |
1738 | 0 | } |
1739 | 111k | } |
1740 | 111k | # endif |
1741 | 111k | #endif /* PNG_SET_USER_LIMITS_SUPPORTED */ |
1742 | | |
1743 | 111k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1744 | 111k | " PNG width limit: %lu, height limit: %lu", |
1745 | 111k | (unsigned long) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)), |
1746 | 111k | (unsigned long) Min(0x7fffffffL, GetMagickResourceLimit(HeightResource))); |
1747 | 111k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1748 | 111k | " PNG pixels limit: %lu", |
1749 | 111k | (unsigned long) GetMagickResourceLimit(PixelsResource)); |
1750 | | |
1751 | | /* |
1752 | | Prepare PNG for reading. |
1753 | | */ |
1754 | 111k | mng_info->image_found++; |
1755 | 111k | png_set_sig_bytes(ping,8); |
1756 | 111k | if (LocaleCompare(image_info->magick,"MNG") == 0) |
1757 | 117k | { |
1758 | 117k | #if defined(PNG_MNG_FEATURES_SUPPORTED) |
1759 | 117k | (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); |
1760 | 117k | png_set_read_fn(ping,image,png_get_data); |
1761 | | #else |
1762 | | # if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) |
1763 | | png_permit_empty_plte(ping,MagickTrue); |
1764 | | png_set_read_fn(ping,image,png_get_data); |
1765 | | # else |
1766 | | mng_info->image=image; |
1767 | | mng_info->bytes_in_read_buffer=0; |
1768 | | mng_info->found_empty_plte=MagickFalse; |
1769 | | mng_info->have_saved_bkgd_index=MagickFalse; |
1770 | | png_set_read_fn(ping,mng_info,mng_get_data); |
1771 | | # endif |
1772 | | #endif |
1773 | 117k | } |
1774 | 18.4E | else |
1775 | 18.4E | png_set_read_fn(ping,image,png_get_data); |
1776 | | |
1777 | 111k | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) |
1778 | | /* Ignore unknown chunks */ |
1779 | | # if PNG_LIBPNG_VER < 10700 /* Avoid a libpng16 warning */ |
1780 | | png_set_keep_unknown_chunks(ping, 2, NULL, 0); |
1781 | | # else |
1782 | 111k | png_set_keep_unknown_chunks(ping, 1, NULL, 0); |
1783 | 111k | # endif |
1784 | | /* Ignore unused chunks and all unknown chunks except for caNv */ |
1785 | 111k | png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_caNv, 1); |
1786 | 111k | png_set_keep_unknown_chunks(ping, 1, unused_chunks, |
1787 | 111k | (int)sizeof(unused_chunks)/5); |
1788 | | /* Callback for other unknown chunks */ |
1789 | 111k | png_set_read_user_chunk_fn(ping, image, read_user_chunk_callback); |
1790 | 111k | #endif |
1791 | | |
1792 | 111k | #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED |
1793 | | /* Disable new libpng-1.5.10 feature while reading */ |
1794 | 111k | png_set_check_for_invalid_index (ping, 0); |
1795 | 111k | #endif |
1796 | | |
1797 | | #if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \ |
1798 | | && (PNG_LIBPNG_VER >= 10200) |
1799 | | /* Disable thread-unsafe features of pnggccrd */ |
1800 | | if (png_access_version_number() >= 10200) |
1801 | | { |
1802 | | png_uint_32 mmx_disable_mask=0; |
1803 | | png_uint_32 asm_flags; |
1804 | | |
1805 | | mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ |
1806 | | | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ |
1807 | | | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ |
1808 | | | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); |
1809 | | asm_flags=png_get_asm_flags(ping); |
1810 | | png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask); |
1811 | | } |
1812 | | #endif |
1813 | | |
1814 | 111k | png_read_info(ping,ping_info); |
1815 | | |
1816 | 111k | (void) png_get_IHDR(ping,ping_info, |
1817 | 111k | &ping_width, |
1818 | 111k | &ping_height, |
1819 | 111k | &ping_bit_depth, |
1820 | 111k | &ping_colortype, |
1821 | 111k | &ping_interlace_method, |
1822 | 111k | &ping_compression_method, |
1823 | | |
1824 | 111k | &ping_filter_method); |
1825 | | |
1826 | | #if (defined(__clang_analyzer__) || defined(__COVERITY__)) |
1827 | | /* |
1828 | | png_get_IHDR() should already have thrown an exception but |
1829 | | Coverity and Clang Analyzer can not see that since it is library |
1830 | | code. |
1831 | | */ |
1832 | | if (ping_bit_depth != 1 && |
1833 | | ping_bit_depth != 2 && |
1834 | | ping_bit_depth != 4 && |
1835 | | ping_bit_depth != 8 && |
1836 | | ping_bit_depth != 16) |
1837 | | { |
1838 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1839 | | " libpng-%.1024s error: %.1024s", |
1840 | | PNG_LIBPNG_VER_STRING, "Bit depth is not valid"); |
1841 | | longjmp(png_jmpbuf(ping),1); |
1842 | | } |
1843 | | #endif /* #if (defined(__clang_analyzer__) || defined(__COVERITY__)) */ |
1844 | | |
1845 | | #if (QuantumDepth == 8) |
1846 | | if (ping_bit_depth > 8) |
1847 | | { |
1848 | | # if defined(PNG_READ_STRIP_16_TO_8_SUPPORTED) || \ |
1849 | | defined(PNG_READ_16_TO_8_SUPPORTED) |
1850 | | png_set_strip_16(ping); |
1851 | | # else |
1852 | | # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED |
1853 | | png_set_scale_16(ping); |
1854 | | # endif |
1855 | | # endif |
1856 | | ping_bit_depth=8; |
1857 | | image->depth=8; |
1858 | | } |
1859 | | #else /* QuantumDepth > 8 */ |
1860 | 111k | if (ping_bit_depth > 8) |
1861 | 28.5k | image->depth=16; |
1862 | 82.5k | else |
1863 | 82.5k | image->depth=8; |
1864 | 111k | #endif |
1865 | | |
1866 | 111k | ping_file_depth = (unsigned int) ping_bit_depth; |
1867 | | |
1868 | | /* Save bit-depth and color-type in case we later want to write a PNG00 */ |
1869 | 111k | { |
1870 | 111k | char |
1871 | 111k | msg[MaxTextExtent]; |
1872 | | |
1873 | 111k | (void) MagickFormatString(msg,sizeof(msg),"%d",(int) ping_colortype); |
1874 | 111k | (void) SetImageAttribute(image,"png:IHDR.color-type-orig",msg); |
1875 | | |
1876 | 111k | (void) MagickFormatString(msg,sizeof(msg),"%d",(int) ping_bit_depth); |
1877 | 111k | (void) SetImageAttribute(image,"png:IHDR.bit-depth-orig",msg); |
1878 | 111k | } |
1879 | | |
1880 | 111k | (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans, |
1881 | 111k | &ping_trans_color); |
1882 | | |
1883 | 111k | (void) png_get_bKGD(ping, ping_info, &ping_background); |
1884 | | |
1885 | 111k | if (logging) |
1886 | 0 | { |
1887 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1888 | 0 | " PNG width: %lu, height: %lu", |
1889 | 0 | (unsigned long)ping_width, |
1890 | 0 | (unsigned long)ping_height); |
1891 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1892 | 0 | " PNG color_type: %d, bit_depth: %d", |
1893 | 0 | ping_colortype, ping_bit_depth); |
1894 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1895 | 0 | " PNG compression_method: %d", |
1896 | 0 | ping_compression_method); |
1897 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1898 | 0 | " PNG interlace_method: %d, filter_method: %d", |
1899 | 0 | ping_interlace_method, |
1900 | 0 | ping_filter_method); |
1901 | 0 | } |
1902 | | |
1903 | | /* Too big? */ |
1904 | 111k | if (ping_width > |
1905 | 111k | (magick_uint64_t) GetMagickResourceLimit(PixelsResource)/ping_height) |
1906 | 0 | { |
1907 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1908 | 0 | "Number of pixels exceeds resource limit"); |
1909 | 0 | png_error(ping, "Number of pixels exceeds resource limit"); |
1910 | 0 | } |
1911 | | |
1912 | 111k | if (ping_bit_depth < 8) |
1913 | 36.8k | { |
1914 | 36.8k | png_set_packing(ping); |
1915 | 36.8k | ping_bit_depth=8; |
1916 | 36.8k | image->depth=8; |
1917 | 36.8k | } |
1918 | | |
1919 | 111k | #if defined(PNG_READ_iCCP_SUPPORTED) |
1920 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_iCCP)) |
1921 | 250 | { |
1922 | 250 | int |
1923 | 250 | compression; |
1924 | | |
1925 | | #if (PNG_LIBPNG_VER < 10500) |
1926 | | png_charp |
1927 | | info; |
1928 | | #else |
1929 | 250 | png_bytep |
1930 | 250 | info; |
1931 | 250 | #endif |
1932 | | |
1933 | 250 | png_charp |
1934 | 250 | name; |
1935 | | |
1936 | 250 | png_uint_32 |
1937 | 250 | profile_length; |
1938 | | |
1939 | 250 | (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info, |
1940 | 250 | &profile_length); |
1941 | 250 | if (profile_length) |
1942 | 250 | { |
1943 | 250 | if (logging) |
1944 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1945 | 0 | " Reading PNG iCCP chunk."); |
1946 | | /* libpng will destroy name and info */ |
1947 | 250 | if (SetImageProfile(image,"ICM",(const unsigned char *) info, |
1948 | 250 | (size_t) profile_length) == MagickFail) |
1949 | 0 | { |
1950 | 0 | MagickError3(ResourceLimitError,MemoryAllocationFailed, |
1951 | 0 | UnableToAllocateICCProfile); |
1952 | 0 | } |
1953 | 250 | } |
1954 | 250 | } |
1955 | 111k | #endif /* #if defined(PNG_READ_iCCP_SUPPORTED) */ |
1956 | 111k | #if defined(PNG_READ_sRGB_SUPPORTED) |
1957 | 111k | { |
1958 | 111k | int |
1959 | 111k | intent; |
1960 | | |
1961 | 111k | if (!png_get_sRGB(ping,ping_info,&intent)) |
1962 | 151k | { |
1963 | 151k | if (mng_info->have_global_srgb) |
1964 | 4.22k | { |
1965 | 4.22k | png_set_sRGB(ping,ping_info,(mng_info->global_srgb_intent+1)); |
1966 | 4.22k | } |
1967 | 151k | } |
1968 | 111k | if (png_get_sRGB(ping,ping_info,&intent)) |
1969 | 5.45k | { |
1970 | 5.45k | image->rendering_intent=(RenderingIntent) (intent+1); |
1971 | 5.45k | if (logging) |
1972 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1973 | 0 | " Reading PNG sRGB chunk:" |
1974 | 0 | " rendering_intent: %d", |
1975 | 0 | intent+1); |
1976 | 5.45k | } |
1977 | 111k | } |
1978 | 111k | #endif /* if defined(PNG_READ_sRGB_SUPPORTED) */ |
1979 | 111k | { |
1980 | 111k | double |
1981 | 111k | file_gamma; |
1982 | | |
1983 | 111k | if (!png_get_gAMA(ping,ping_info,&file_gamma)) |
1984 | 151k | { |
1985 | 151k | if (mng_info->have_global_gama) |
1986 | 805 | png_set_gAMA(ping,ping_info,mng_info->global_gamma); |
1987 | 151k | } |
1988 | 111k | if (png_get_gAMA(ping,ping_info,&file_gamma)) |
1989 | 2.07k | { |
1990 | 2.07k | image->gamma=(float) file_gamma; |
1991 | 2.07k | if (logging) |
1992 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1993 | 0 | " Reading PNG gAMA chunk: gamma: %f", |
1994 | 0 | file_gamma); |
1995 | 2.07k | } |
1996 | 111k | } |
1997 | 111k | if (!png_get_valid(ping, ping_info, PNG_INFO_cHRM)) |
1998 | 152k | { |
1999 | 152k | if (mng_info->have_global_chrm) |
2000 | 5.15k | (void) png_set_cHRM(ping,ping_info, |
2001 | 5.15k | mng_info->global_chrm.white_point.x, |
2002 | 5.15k | mng_info->global_chrm.white_point.y, |
2003 | 5.15k | mng_info->global_chrm.red_primary.x, |
2004 | 5.15k | mng_info->global_chrm.red_primary.y, |
2005 | 5.15k | mng_info->global_chrm.green_primary.x, |
2006 | 5.15k | mng_info->global_chrm.green_primary.y, |
2007 | 5.15k | mng_info->global_chrm.blue_primary.x, |
2008 | 5.15k | mng_info->global_chrm.blue_primary.y); |
2009 | 152k | } |
2010 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_cHRM)) |
2011 | 5.23k | { |
2012 | 5.23k | (void) png_get_cHRM(ping,ping_info, |
2013 | 5.23k | &image->chromaticity.white_point.x, |
2014 | 5.23k | &image->chromaticity.white_point.y, |
2015 | 5.23k | &image->chromaticity.red_primary.x, |
2016 | 5.23k | &image->chromaticity.red_primary.y, |
2017 | 5.23k | &image->chromaticity.green_primary.x, |
2018 | 5.23k | &image->chromaticity.green_primary.y, |
2019 | 5.23k | &image->chromaticity.blue_primary.x, |
2020 | 5.23k | &image->chromaticity.blue_primary.y); |
2021 | 5.23k | if (logging) |
2022 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2023 | 0 | " Reading PNG cHRM chunk."); |
2024 | 5.23k | } |
2025 | 111k | if (image->rendering_intent) |
2026 | 5.45k | { |
2027 | 5.45k | image->gamma=0.45455f; |
2028 | 5.45k | image->chromaticity.red_primary.x=0.6400f; |
2029 | 5.45k | image->chromaticity.red_primary.y=0.3300f; |
2030 | 5.45k | image->chromaticity.green_primary.x=0.3000f; |
2031 | 5.45k | image->chromaticity.green_primary.y=0.6000f; |
2032 | 5.45k | image->chromaticity.blue_primary.x=0.1500f; |
2033 | 5.45k | image->chromaticity.blue_primary.y=0.0600f; |
2034 | 5.45k | image->chromaticity.white_point.x=0.3127f; |
2035 | 5.45k | image->chromaticity.white_point.y=0.3290f; |
2036 | 5.45k | } |
2037 | 111k | #if defined(PNG_oFFs_SUPPORTED) |
2038 | 136k | if (mng_info->mng_type == 0 && (png_get_valid(ping, ping_info, |
2039 | 136k | PNG_INFO_oFFs))) |
2040 | 1.06k | { |
2041 | 1.06k | image->page.x=png_get_x_offset_pixels(ping, ping_info); |
2042 | 1.06k | image->page.y=png_get_y_offset_pixels(ping, ping_info); |
2043 | 1.06k | if (logging) |
2044 | 0 | if (image->page.x || image->page.y) |
2045 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2046 | 0 | " Reading PNG oFFs chunk: x: %ld, y: %ld.", |
2047 | 0 | image->page.x, |
2048 | 0 | image->page.y); |
2049 | 1.06k | } |
2050 | 111k | #endif |
2051 | 111k | #if defined(PNG_pHYs_SUPPORTED) |
2052 | 111k | if (!png_get_valid(ping, ping_info, PNG_INFO_pHYs)) |
2053 | 148k | { |
2054 | 148k | if (mng_info->have_global_phys) |
2055 | 4.88k | { |
2056 | 4.88k | png_set_pHYs(ping,ping_info, |
2057 | 4.88k | mng_info->global_x_pixels_per_unit, |
2058 | 4.88k | mng_info->global_y_pixels_per_unit, |
2059 | 4.88k | mng_info->global_phys_unit_type); |
2060 | 4.88k | } |
2061 | 148k | } |
2062 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_pHYs)) |
2063 | 9.11k | { |
2064 | 9.11k | int |
2065 | 9.11k | unit_type; |
2066 | | |
2067 | 9.11k | png_uint_32 |
2068 | 9.11k | x_resolution, |
2069 | 9.11k | y_resolution; |
2070 | | |
2071 | | /* |
2072 | | Set image resolution. |
2073 | | */ |
2074 | 9.11k | (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution, |
2075 | 9.11k | &unit_type); |
2076 | 9.11k | image->x_resolution=(float) x_resolution; |
2077 | 9.11k | image->y_resolution=(float) y_resolution; |
2078 | 9.11k | if (unit_type == PNG_RESOLUTION_METER) |
2079 | 556 | { |
2080 | 556 | image->units=PixelsPerCentimeterResolution; |
2081 | 556 | image->x_resolution=(double) x_resolution/100.0; |
2082 | 556 | image->y_resolution=(double) y_resolution/100.0; |
2083 | 556 | } |
2084 | 9.11k | if (logging) |
2085 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2086 | 0 | " Reading PNG pHYs chunk:" |
2087 | 0 | " xres: %lu, yres: %lu, units: %d.", |
2088 | 0 | (unsigned long)x_resolution, |
2089 | 0 | (unsigned long)y_resolution, |
2090 | 0 | unit_type); |
2091 | 9.11k | } |
2092 | 111k | #endif |
2093 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_PLTE)) |
2094 | 11.2k | { |
2095 | 11.2k | int |
2096 | 11.2k | number_colors; |
2097 | | |
2098 | 11.2k | png_colorp |
2099 | 11.2k | palette; |
2100 | | |
2101 | 11.2k | (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); |
2102 | 11.2k | if (number_colors == 0 && ping_colortype == |
2103 | 1.45k | PNG_COLOR_TYPE_PALETTE) |
2104 | 1.20k | { |
2105 | 1.20k | if (mng_info->global_plte_length) |
2106 | 1.20k | { |
2107 | 1.20k | png_set_PLTE(ping,ping_info,mng_info->global_plte, |
2108 | 1.20k | (int) mng_info->global_plte_length); |
2109 | 1.20k | if (!(png_get_valid(ping, ping_info, PNG_INFO_tRNS))) |
2110 | 1.20k | if (mng_info->global_trns_length) |
2111 | 621 | { |
2112 | 621 | if (mng_info->global_trns_length > |
2113 | 621 | mng_info->global_plte_length) |
2114 | 2 | png_error(ping, "global tRNS has more entries" |
2115 | 621 | " than global PLTE"); |
2116 | 619 | png_set_tRNS(ping,ping_info,mng_info->global_trns, |
2117 | 619 | (int) mng_info->global_trns_length,NULL); |
2118 | 619 | } |
2119 | 1.20k | #if defined(PNG_READ_bKGD_SUPPORTED) |
2120 | 1.20k | if ( |
2121 | | #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
2122 | | mng_info->have_saved_bkgd_index || |
2123 | | #endif |
2124 | 1.20k | png_get_valid(ping, ping_info, PNG_INFO_bKGD)) |
2125 | 45 | { |
2126 | 45 | png_color_16 |
2127 | 45 | background; |
2128 | | |
2129 | 45 | background.index=0; |
2130 | | #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
2131 | | if (mng_info->have_saved_bkgd_index) |
2132 | | background.index=mng_info->saved_bkgd_index; |
2133 | | #endif |
2134 | 45 | if (png_get_valid(ping, ping_info, PNG_INFO_bKGD)) |
2135 | 45 | background.index=ping_background->index; |
2136 | 45 | background.red=(png_uint_16) |
2137 | 45 | mng_info->global_plte[background.index].red; |
2138 | 45 | background.green=(png_uint_16) |
2139 | 45 | mng_info->global_plte[background.index].green; |
2140 | 45 | background.blue=(png_uint_16) |
2141 | 45 | mng_info->global_plte[background.index].blue; |
2142 | 45 | png_set_bKGD(ping,ping_info,&background); |
2143 | 45 | } |
2144 | 1.20k | #endif |
2145 | 1.20k | } |
2146 | 3 | else |
2147 | 3 | png_error (ping, "No global PLTE in file"); |
2148 | 1.20k | } |
2149 | 11.2k | } |
2150 | | |
2151 | 111k | #if defined(PNG_READ_bKGD_SUPPORTED) |
2152 | 111k | if (mng_info->have_global_bkgd && |
2153 | 719 | !(png_get_valid(ping,ping_info, PNG_INFO_bKGD))) |
2154 | 425 | image->background_color=mng_info->mng_global_bkgd; |
2155 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_bKGD)) |
2156 | 5.58k | { |
2157 | | /* |
2158 | | Set image background color. |
2159 | | */ |
2160 | | |
2161 | 5.58k | if (logging) |
2162 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2163 | 0 | " Reading PNG bKGD chunk."); |
2164 | | |
2165 | 5.58k | if (ping_bit_depth == QuantumDepth) |
2166 | 456 | { |
2167 | 456 | image->background_color.red = ping_background->red; |
2168 | 456 | image->background_color.green= ping_background->green; |
2169 | 456 | image->background_color.blue = ping_background->blue; |
2170 | 456 | } |
2171 | 5.12k | else /* Scale background components to 16-bit */ |
2172 | 5.12k | { |
2173 | 5.12k | unsigned int |
2174 | 5.12k | bkgd_scale; |
2175 | | |
2176 | 5.12k | if (logging != MagickFalse) |
2177 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2178 | 0 | " raw ping_background=(%d,%d,%d).",ping_background->red, |
2179 | 0 | ping_background->green,ping_background->blue); |
2180 | | |
2181 | 5.12k | bkgd_scale = 1; |
2182 | 5.12k | if (ping_file_depth == 1) |
2183 | 4.34k | bkgd_scale = 255; |
2184 | 787 | else if (ping_file_depth == 2) |
2185 | 45 | bkgd_scale = 85; |
2186 | 742 | else if (ping_file_depth == 4) |
2187 | 61 | bkgd_scale = 17; |
2188 | 5.12k | if (ping_file_depth <= 8) |
2189 | 5.12k | bkgd_scale *= 257; |
2190 | | |
2191 | 5.12k | ping_background->red *= bkgd_scale; |
2192 | 5.12k | ping_background->green *= bkgd_scale; |
2193 | 5.12k | ping_background->blue *= bkgd_scale; |
2194 | | |
2195 | 5.12k | if (logging != MagickFalse) |
2196 | 0 | { |
2197 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2198 | 0 | " bkgd_scale=%d.",bkgd_scale); |
2199 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2200 | 0 | " ping_background=(%d,%d,%d).",ping_background->red, |
2201 | 0 | ping_background->green,ping_background->blue); |
2202 | 0 | } |
2203 | | |
2204 | 5.12k | image->background_color.red= |
2205 | 5.12k | ScaleShortToQuantum(ping_background->red); |
2206 | 5.12k | image->background_color.green= |
2207 | 5.12k | ScaleShortToQuantum(ping_background->green); |
2208 | 5.12k | image->background_color.blue= |
2209 | 5.12k | ScaleShortToQuantum(ping_background->blue); |
2210 | 5.12k | image->background_color.opacity=OpaqueOpacity; |
2211 | | |
2212 | 5.12k | if (logging != MagickFalse) |
2213 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2214 | 0 | " image->background_color=(%d,%d,%d).", |
2215 | 0 | image->background_color.red, |
2216 | 0 | image->background_color.green,image->background_color.blue); |
2217 | 5.12k | } |
2218 | 5.58k | } |
2219 | 111k | #endif |
2220 | | |
2221 | 111k | if (png_get_valid(ping, ping_info, PNG_INFO_tRNS) && |
2222 | 27.5k | (ping_trans_color != (png_color_16p) NULL) && |
2223 | 27.5k | (((unsigned int) ping_file_depth) <= MaxColormapSize)) |
2224 | 27.5k | { |
2225 | 27.5k | unsigned int |
2226 | 27.5k | bit_mask; |
2227 | | |
2228 | 27.5k | if (logging != MagickFalse) |
2229 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2230 | 0 | " Reading PNG tRNS chunk."); |
2231 | | |
2232 | 27.5k | bit_mask = MaxValueGivenBits(ping_file_depth); |
2233 | | |
2234 | | /* |
2235 | | Image has a transparent background. |
2236 | | */ |
2237 | | |
2238 | 27.5k | transparent_color.red= |
2239 | 27.5k | (unsigned long)(ping_trans_color->red & bit_mask); |
2240 | 27.5k | transparent_color.green= |
2241 | 27.5k | (unsigned long) (ping_trans_color->green & bit_mask); |
2242 | 27.5k | transparent_color.blue= |
2243 | 27.5k | (unsigned long) (ping_trans_color->blue & bit_mask); |
2244 | 27.5k | transparent_color.opacity= |
2245 | 27.5k | (unsigned long) (ping_trans_color->gray & bit_mask); |
2246 | | |
2247 | 27.5k | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
2248 | 3.32k | { |
2249 | | #if (QuantumDepth == 8) |
2250 | | if (ping_file_depth < QuantumDepth) |
2251 | | #endif |
2252 | 3.32k | transparent_color.opacity=(unsigned long) ( |
2253 | 3.32k | ping_trans_color->gray * |
2254 | 3.32k | (65535L/MaxValueGivenBits(ping_file_depth))); /* Coverity 381876 Division or modulo by zero (DIVIDE_BY_ZERO) */ |
2255 | | |
2256 | | #if (QuantumDepth == 8) |
2257 | | else |
2258 | | transparent_color.opacity=(unsigned long) ( |
2259 | | (ping_trans_color->gray * 65535UL)/ |
2260 | | MaxValueGivenBits(ping_file_depth)); |
2261 | | #endif |
2262 | 3.32k | if (logging != MagickFalse) |
2263 | 0 | { |
2264 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2265 | 0 | " Raw tRNS graylevel is %d.",ping_trans_color->gray); |
2266 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2267 | 0 | " scaled graylevel is %d.", |
2268 | 0 | (int) transparent_color.opacity); |
2269 | 0 | } |
2270 | 3.32k | transparent_color.red=transparent_color.opacity; |
2271 | 3.32k | transparent_color.green=transparent_color.opacity; |
2272 | 3.32k | transparent_color.blue=transparent_color.opacity; |
2273 | 3.32k | } |
2274 | 27.5k | } |
2275 | 111k | #if defined(PNG_READ_sBIT_SUPPORTED) |
2276 | 111k | if (!png_get_valid(ping, ping_info, PNG_INFO_sBIT)) |
2277 | 152k | if (mng_info->have_global_sbit) |
2278 | 648 | png_set_sBIT(ping,ping_info,&mng_info->global_sbit); |
2279 | 111k | #endif |
2280 | 111k | num_passes=png_set_interlace_handling(ping); |
2281 | | |
2282 | 111k | png_read_update_info(ping,ping_info); |
2283 | | |
2284 | 111k | ping_rowbytes=(size_t) png_get_rowbytes(ping,ping_info); |
2285 | | |
2286 | | /* |
2287 | | Initialize image structure. |
2288 | | */ |
2289 | 111k | mng_info->image_box.left=0; |
2290 | 111k | mng_info->image_box.right=(long) ping_width; |
2291 | 111k | mng_info->image_box.top=0; |
2292 | 111k | mng_info->image_box.bottom=(long) ping_height; |
2293 | 111k | if (mng_info->mng_type == 0) |
2294 | 136k | { |
2295 | 136k | mng_info->mng_width=ping_width; |
2296 | 136k | mng_info->mng_height=ping_height; |
2297 | 136k | mng_info->frame=mng_info->image_box; |
2298 | 136k | mng_info->clip=mng_info->image_box; |
2299 | 136k | } |
2300 | 18.4E | else |
2301 | 18.4E | { |
2302 | 18.4E | image->page.y=mng_info->y_off[mng_info->object_id]; |
2303 | 18.4E | } |
2304 | 111k | image->compression=ZipCompression; |
2305 | 111k | image->columns=ping_width; |
2306 | 111k | image->rows=ping_height; |
2307 | 111k | if (((unsigned int) ping_file_depth <= MaxColormapSize) && |
2308 | 152k | ((ping_colortype == PNG_COLOR_TYPE_PALETTE) || |
2309 | 141k | (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) || |
2310 | 128k | (ping_colortype == PNG_COLOR_TYPE_GRAY))) |
2311 | 62.8k | { |
2312 | 62.8k | image->storage_class=PseudoClass; |
2313 | 62.8k | image->colors=1U << ping_file_depth; /* Coverity (#1-3 of 3): Bad bit shift operation (BAD_SHIFT) */ |
2314 | | #if (QuantumDepth == 8) |
2315 | | if (image->colors > 256) |
2316 | | image->colors=256; |
2317 | | #else |
2318 | 62.8k | if (image->colors > 65536L) |
2319 | 0 | image->colors=65536L; |
2320 | 62.8k | #endif |
2321 | 62.8k | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
2322 | 11.0k | { |
2323 | 11.0k | int |
2324 | 11.0k | number_colors; |
2325 | | |
2326 | 11.0k | png_colorp |
2327 | 11.0k | palette; |
2328 | | |
2329 | 11.0k | (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); |
2330 | 11.0k | image->colors=number_colors; /* FIXME: bug 596 */ |
2331 | 11.0k | if (logging) |
2332 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2333 | 0 | " Reading PNG PLTE chunk:" |
2334 | 0 | " number_colors: %d.",number_colors); |
2335 | 11.0k | } |
2336 | 62.8k | } |
2337 | | |
2338 | 111k | if (image->storage_class == PseudoClass) |
2339 | 62.8k | { |
2340 | | /* |
2341 | | Initialize image colormap. |
2342 | | */ |
2343 | 62.8k | if (!AllocateImageColormap(image,image->colors)) |
2344 | 0 | png_error(ping, "Could not allocate image colormap"); |
2345 | 62.8k | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
2346 | 11.0k | { |
2347 | 11.0k | int |
2348 | 11.0k | number_colors; |
2349 | | |
2350 | 11.0k | png_colorp |
2351 | 11.0k | palette; |
2352 | | |
2353 | 11.0k | (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); |
2354 | 223k | for (i=0; i < (long) image->colors; i++) |
2355 | 212k | { |
2356 | 212k | image->colormap[i].red=ScaleCharToQuantum(palette[i].red); |
2357 | 212k | image->colormap[i].green=ScaleCharToQuantum(palette[i].green); |
2358 | 212k | image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue); |
2359 | 212k | } |
2360 | 11.0k | } |
2361 | 51.8k | else |
2362 | 51.8k | { |
2363 | 51.8k | unsigned long |
2364 | 51.8k | scale; |
2365 | | |
2366 | 51.8k | scale=(MaxRGB/MaxValueGivenBits(ping_file_depth)); |
2367 | 51.8k | if (scale < 1) |
2368 | 0 | scale=1; |
2369 | 192M | for (i=0; i < (long) image->colors; i++) |
2370 | 192M | { |
2371 | 192M | image->colormap[i].red=(Quantum) (i*scale); |
2372 | 192M | image->colormap[i].green=(Quantum) (i*scale); |
2373 | 192M | image->colormap[i].blue=(Quantum) (i*scale); |
2374 | 192M | } |
2375 | 51.8k | } |
2376 | 62.8k | } |
2377 | 111k | if (image->delay != 0) |
2378 | 146 | mng_info->scenes_found++; |
2379 | 111k | if (image_info->ping && ((mng_info->mng_type == 0) || |
2380 | 0 | ((image_info->subrange != 0) && |
2381 | 0 | mng_info->scenes_found > (long) (image_info->subimage+ |
2382 | 0 | image_info->subrange)))) |
2383 | 0 | { |
2384 | 0 | image->matte=((ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) || |
2385 | 0 | (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) || |
2386 | 0 | (png_get_valid(ping, ping_info, PNG_INFO_tRNS))); |
2387 | | |
2388 | | /* This happens later in non-ping decodes */ |
2389 | 0 | if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) |
2390 | 0 | image->storage_class=DirectClass; |
2391 | |
|
2392 | 0 | if (logging) |
2393 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2394 | 0 | " Skipping PNG image data for scene %ld", |
2395 | 0 | mng_info->scenes_found-1); |
2396 | 0 | png_destroy_read_struct(&ping,&ping_info,&end_info); |
2397 | 0 | MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline); |
2398 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels); |
2399 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
2400 | | UnlockSemaphoreInfo(png_semaphore); |
2401 | | #endif |
2402 | 0 | if (logging) |
2403 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2404 | 0 | " exit ReadOnePNGImage()."); |
2405 | 0 | return (image); |
2406 | 0 | } |
2407 | | |
2408 | | /* |
2409 | | Read image scanlines. |
2410 | | */ |
2411 | 111k | if (logging) |
2412 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2413 | 0 | " Reading PNG IDAT chunk(s)"); |
2414 | 111k | if (num_passes > 1) |
2415 | 68.1k | { |
2416 | 68.1k | if (ping_rowbytes < (size_t) GetMagickResourceLimit(MemoryResource)/image->rows) |
2417 | 68.1k | mng_info->png_pixels=MagickAllocateResourceLimitedArray(unsigned char *, |
2418 | 68.1k | ping_rowbytes,image->rows); |
2419 | 0 | else |
2420 | 0 | png_error(ping, "png_pixels array exceeds MemoryResource"); |
2421 | 68.1k | } |
2422 | 42.9k | else |
2423 | 42.9k | { |
2424 | 42.9k | if (ping_rowbytes < (size_t) GetMagickResourceLimit(MemoryResource)) |
2425 | 84.2k | mng_info->png_pixels=MagickAllocateResourceLimitedMemory(unsigned char *, ping_rowbytes); |
2426 | 18.4E | else |
2427 | 18.4E | png_error(ping, "png_rowbytes array exceeds MemoryResource"); |
2428 | 42.9k | } |
2429 | 152k | if (mng_info->png_pixels == (unsigned char *) NULL) |
2430 | 0 | { |
2431 | 0 | png_error(ping, "Could not allocate png_pixels array"); |
2432 | 0 | } |
2433 | | |
2434 | 152k | if (logging) |
2435 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2436 | 0 | " Converting PNG pixels to pixel packets"); |
2437 | | /* |
2438 | | Convert PNG pixels to pixel packets. |
2439 | | */ |
2440 | 152k | if (image->storage_class == DirectClass) |
2441 | 405k | for (pass=0; pass < num_passes; pass++) |
2442 | 316k | { |
2443 | | /* |
2444 | | Convert image to DirectClass pixel packets. |
2445 | | */ |
2446 | | #if (QuantumDepth == 8) |
2447 | | int |
2448 | | depth; |
2449 | | |
2450 | | depth=(long) ping_bit_depth; |
2451 | | #endif |
2452 | 316k | image->matte=((ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) || |
2453 | 132k | (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) || |
2454 | 132k | (png_get_valid(ping, ping_info, PNG_INFO_tRNS))); |
2455 | | |
2456 | 1.58M | for (y=0; y < (long) image->rows; y++) |
2457 | 1.31M | { |
2458 | 1.31M | if (num_passes > 1) |
2459 | 1.10M | row_offset=ping_rowbytes*y; |
2460 | | |
2461 | 204k | else |
2462 | 204k | row_offset=0; |
2463 | | |
2464 | 1.31M | png_read_row(ping,mng_info->png_pixels+row_offset,NULL); |
2465 | | |
2466 | 1.31M | if (!SetImagePixels(image,0,y,image->columns,1)) |
2467 | 44.0k | break; |
2468 | | |
2469 | 1.26M | if (pass < num_passes-1) |
2470 | 999k | continue; |
2471 | | |
2472 | | #if (QuantumDepth == 8) |
2473 | | if (depth == 16) |
2474 | | { |
2475 | | register Quantum |
2476 | | *p, |
2477 | | *r; |
2478 | | |
2479 | | r=mng_info->png_pixels+row_offset; |
2480 | | p=r; |
2481 | | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
2482 | | { |
2483 | | for (x=(long) image->columns; x > 0; x--) |
2484 | | { |
2485 | | *r++=*p++; |
2486 | | p++; |
2487 | | if ((png_get_valid(ping, ping_info, PNG_INFO_tRNS)) && |
2488 | | ((unsigned long) (((magick_uint32_t) *(p-2) << 8)| |
2489 | | (magick_uint32_t) *(p-1)) |
2490 | | == transparent_color.opacity)) |
2491 | | { |
2492 | | /* Cheap transparency */ |
2493 | | *r++=TransparentOpacity; |
2494 | | } |
2495 | | else |
2496 | | *r++=OpaqueOpacity; |
2497 | | } |
2498 | | } |
2499 | | else if (ping_colortype == PNG_COLOR_TYPE_RGB) |
2500 | | { |
2501 | | if (png_get_valid(ping, ping_info, PNG_INFO_tRNS)) |
2502 | | for (x=(long) image->columns; x > 0; x--) |
2503 | | { |
2504 | | *r++=*p++; |
2505 | | p++; |
2506 | | *r++=*p++; |
2507 | | p++; |
2508 | | *r++=*p++; |
2509 | | p++; |
2510 | | if (((unsigned long) (((magick_uint32_t) *(p-6) << 8)|*(p-5)) == |
2511 | | transparent_color.red) && |
2512 | | ((unsigned long) (((magick_uint32_t) *(p-4) << 8)|*(p-3)) == |
2513 | | transparent_color.green) && |
2514 | | ((unsigned long) (((magick_uint32_t) *(p-2) << 8)|*(p-1)) == |
2515 | | transparent_color.blue)) |
2516 | | { |
2517 | | /* Cheap transparency */ |
2518 | | *r++=TransparentOpacity; |
2519 | | } |
2520 | | else |
2521 | | *r++=OpaqueOpacity; |
2522 | | } |
2523 | | else |
2524 | | for (x=(long) image->columns; x > 0; x--) |
2525 | | { |
2526 | | *r++=*p++; |
2527 | | p++; |
2528 | | *r++=*p++; |
2529 | | p++; |
2530 | | *r++=*p++; |
2531 | | p++; |
2532 | | *r++=OpaqueOpacity; |
2533 | | } |
2534 | | } |
2535 | | else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) |
2536 | | for (x=(long) (4*image->columns); x > 0; x--) |
2537 | | { |
2538 | | *r++=*p++; |
2539 | | p++; |
2540 | | } |
2541 | | else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) |
2542 | | for (x=(long) (2*image->columns); x > 0; x--) |
2543 | | { |
2544 | | *r++=*p++; |
2545 | | p++; |
2546 | | } |
2547 | | } |
2548 | | if (depth == 8 && ping_colortype == PNG_COLOR_TYPE_GRAY) |
2549 | | (void) ImportImagePixelArea(image,(QuantumType) GrayQuantum, |
2550 | | image->depth,mng_info->png_pixels+ |
2551 | | row_offset,0,0); |
2552 | | else if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
2553 | | { |
2554 | | image->depth=8; |
2555 | | (void) ImportImagePixelArea(image, |
2556 | | (QuantumType) GrayQuantum, |
2557 | | image->depth,mng_info->png_pixels+ |
2558 | | row_offset,0,0); |
2559 | | image->depth=depth; |
2560 | | } |
2561 | | else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) |
2562 | | { |
2563 | | image->depth=8; |
2564 | | (void) ImportImagePixelArea(image, |
2565 | | (QuantumType) GrayAlphaQuantum, |
2566 | | image->depth,mng_info->png_pixels+ |
2567 | | row_offset,0,0); |
2568 | | image->depth=depth; |
2569 | | } |
2570 | | else if (depth == 8 && ping_colortype == PNG_COLOR_TYPE_RGB) |
2571 | | (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum, |
2572 | | image->depth,mng_info->png_pixels+ |
2573 | | row_offset,0,0); |
2574 | | else if (ping_colortype == PNG_COLOR_TYPE_RGB) |
2575 | | { |
2576 | | image->depth=8; |
2577 | | (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum, |
2578 | | image->depth,mng_info->png_pixels+ |
2579 | | row_offset,0,0); |
2580 | | image->depth=depth; |
2581 | | } |
2582 | | else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) |
2583 | | { |
2584 | | image->depth=8; |
2585 | | (void) ImportImagePixelArea(image,(QuantumType) RGBAQuantum, |
2586 | | image->depth,mng_info->png_pixels+ |
2587 | | row_offset,0,0); |
2588 | | image->depth=depth; |
2589 | | } |
2590 | | else if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
2591 | | (void) ImportImagePixelArea(image,(QuantumType) IndexQuantum, |
2592 | | ping_bit_depth,mng_info->png_pixels+ |
2593 | | row_offset,0,0); |
2594 | | /* FIXME, sample size ??? */ |
2595 | | #else /* (QuantumDepth != 8) */ |
2596 | | |
2597 | 268k | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
2598 | 0 | (void) ImportImagePixelArea(image,(QuantumType) GrayQuantum, |
2599 | 0 | image->depth,mng_info->png_pixels+ |
2600 | 0 | row_offset,0,0); |
2601 | 268k | else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) |
2602 | 0 | (void) ImportImagePixelArea(image,(QuantumType) GrayAlphaQuantum, |
2603 | 0 | image->depth,mng_info->png_pixels+ |
2604 | 0 | row_offset,0,0); |
2605 | 268k | else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) |
2606 | 68.8k | (void) ImportImagePixelArea(image,(QuantumType) RGBAQuantum, |
2607 | 68.8k | image->depth,mng_info->png_pixels+ |
2608 | 68.8k | row_offset,0,0); |
2609 | 199k | else if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
2610 | 0 | (void) ImportImagePixelArea(image,(QuantumType) IndexQuantum, |
2611 | 0 | ping_bit_depth,mng_info->png_pixels+ |
2612 | 0 | row_offset,0,0); |
2613 | | /* FIXME, sample size ??? */ |
2614 | 199k | else |
2615 | 199k | (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum, |
2616 | 199k | image->depth,mng_info->png_pixels+ |
2617 | 199k | row_offset,0,0); |
2618 | 268k | #endif |
2619 | 268k | if (!SyncImagePixels(image)) |
2620 | 0 | break; |
2621 | 268k | } |
2622 | | |
2623 | 316k | if (image->previous == (Image *) NULL) |
2624 | 97.8k | if (QuantumTick(pass, num_passes)) |
2625 | 97.8k | if (!MagickMonitorFormatted(pass,num_passes,exception, |
2626 | 97.8k | LoadImageText,image->filename, |
2627 | 97.8k | image->columns,image->rows)) |
2628 | 0 | break; |
2629 | 316k | } |
2630 | | |
2631 | 62.8k | else /* image->storage_class != DirectClass */ |
2632 | 62.8k | { |
2633 | 62.8k | image->matte=ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA; |
2634 | 62.8k | mng_info->quantum_scanline= |
2635 | 62.8k | MagickAllocateResourceLimitedMemory(Quantum *, |
2636 | 62.8k | (image->matte ? 2 : 1) * |
2637 | 62.8k | (size_t) image->columns*sizeof(Quantum)); |
2638 | 62.8k | if (mng_info->quantum_scanline == (Quantum *) NULL) |
2639 | 0 | png_error(ping, "Could not allocate quantum_scanline"); |
2640 | 62.8k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2641 | 62.8k | " Allocated quantum_scanline"); |
2642 | | |
2643 | 172k | for (pass=0; pass < num_passes; pass++) |
2644 | 137k | { |
2645 | 137k | register Quantum |
2646 | 137k | *r; |
2647 | | |
2648 | | /* |
2649 | | Convert grayscale image to PseudoClass pixel packets. |
2650 | | */ |
2651 | 3.09M | for (y=0; y < (long) image->rows; y++) |
2652 | 2.98M | { |
2653 | 2.98M | register unsigned char |
2654 | 2.98M | *p; |
2655 | | |
2656 | 2.98M | if (num_passes > 1) |
2657 | 2.58M | row_offset=ping_rowbytes*y; |
2658 | | |
2659 | 403k | else |
2660 | 403k | row_offset=0; |
2661 | | |
2662 | 2.98M | png_read_row(ping,mng_info->png_pixels+row_offset,NULL); |
2663 | 2.98M | q=SetImagePixels(image,0,y,image->columns,1); |
2664 | 2.98M | if (q == (PixelPacket *) NULL) |
2665 | 6.74k | break; |
2666 | | |
2667 | 2.97M | if (pass < num_passes-1) |
2668 | 2.33M | continue; |
2669 | | |
2670 | 638k | indexes=AccessMutableIndexes(image); |
2671 | 638k | p=mng_info->png_pixels+row_offset; |
2672 | 638k | r=mng_info->quantum_scanline; |
2673 | 638k | switch (ping_bit_depth) |
2674 | 638k | { |
2675 | 543k | case 8: |
2676 | 543k | { |
2677 | 543k | if (ping_colortype == 4) |
2678 | 1.17M | for (x=(long) image->columns; x > 0; x--) |
2679 | 1.15M | { |
2680 | 1.15M | *r++=*p++; |
2681 | | /* In image.h, OpaqueOpacity is 0 |
2682 | | * TransparentOpacity is MaxRGB |
2683 | | * In a PNG datastream, Opaque is MaxRGB |
2684 | | * and Transparent is 0. |
2685 | | */ |
2686 | 1.15M | q->opacity=ScaleCharToQuantum(255-(*p++)); |
2687 | 1.15M | q++; |
2688 | 1.15M | } |
2689 | 522k | else |
2690 | 95.0M | for (x=(long) image->columns; x > 0; x--) |
2691 | 94.4M | *r++=*p++; |
2692 | 543k | break; |
2693 | 0 | } |
2694 | 73.4k | case 16: |
2695 | 73.4k | { |
2696 | 6.81M | for (x=(long) image->columns; x > 0; x--) |
2697 | 6.73M | { |
2698 | 6.73M | #if (QuantumDepth == 16) |
2699 | 6.73M | if (image->colors > 256) |
2700 | 6.73M | *r=(((magick_uint32_t) *p++) << 8); |
2701 | 0 | else |
2702 | 0 | *r=0; |
2703 | 6.73M | *r|=(*p++); |
2704 | 6.73M | r++; |
2705 | 6.73M | if (ping_colortype == 4) |
2706 | 2.34M | { |
2707 | 2.34M | q->opacity=(((magick_uint32_t) *p++) << 8); |
2708 | 2.34M | q->opacity|=((magick_uint32_t) *p++); |
2709 | 2.34M | q->opacity=(Quantum) (MaxRGB-q->opacity); |
2710 | 2.34M | q++; |
2711 | 2.34M | } |
2712 | | #else |
2713 | | #if (QuantumDepth == 32) |
2714 | | if (image->colors > 256) |
2715 | | *r=(((magick_uint32_t) *p++) << 8); |
2716 | | else |
2717 | | *r=0; |
2718 | | *r|=(*p++); |
2719 | | r++; |
2720 | | if (ping_colortype == 4) |
2721 | | { |
2722 | | q->opacity=(((magick_uint32_t) *p++) << 8); |
2723 | | q->opacity|=((magick_uint32_t) *p++); |
2724 | | q->opacity*=65537U; |
2725 | | q->opacity=(Quantum) (MaxRGB-q->opacity); |
2726 | | q++; |
2727 | | } |
2728 | | #else /* QuantumDepth == 8 */ |
2729 | | *r++=(*p++); |
2730 | | p++; /* strip low byte */ |
2731 | | if (ping_colortype == 4) |
2732 | | { |
2733 | | q->opacity=(Quantum) (MaxRGB-(*p++)); |
2734 | | p++; |
2735 | | q++; |
2736 | | } |
2737 | | #endif |
2738 | | #endif |
2739 | 6.73M | } |
2740 | 73.4k | break; |
2741 | 0 | } |
2742 | 0 | default: |
2743 | 0 | break; |
2744 | 638k | } |
2745 | | /* |
2746 | | Transfer image scanline. |
2747 | | */ |
2748 | 617k | r=mng_info->quantum_scanline; |
2749 | | |
2750 | 103M | for (x=0; x < (long) image->columns; x++) |
2751 | 102M | indexes[x]=(*r++); |
2752 | | |
2753 | 617k | if (!SyncImagePixels(image)) |
2754 | 0 | break; |
2755 | 617k | } |
2756 | | |
2757 | | /* Quit 'passes' loop if we encountered an error */ |
2758 | 116k | if (y < (long) image->rows) |
2759 | 6.74k | break; |
2760 | | |
2761 | 109k | if (image->previous == (Image *) NULL) |
2762 | 60.2k | if (QuantumTick(pass, num_passes)) |
2763 | 60.2k | if (!MagickMonitorFormatted(pass,num_passes,exception,LoadImageText, |
2764 | 60.2k | image->filename, |
2765 | 60.2k | image->columns,image->rows)) |
2766 | 0 | break; |
2767 | 109k | } |
2768 | | |
2769 | 41.4k | MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline); |
2770 | 41.4k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2771 | 41.4k | " Free'ed quantum_scanline after last pass"); |
2772 | 41.4k | } |
2773 | | |
2774 | 130k | if (image->storage_class == PseudoClass) |
2775 | 41.4k | (void) SyncImage(image); |
2776 | 130k | png_read_end(ping,ping_info); |
2777 | | |
2778 | 130k | if (image_info->subrange != 0 && mng_info->scenes_found-1 < |
2779 | 111k | (long) image_info->subimage && image->delay != 0.) |
2780 | 0 | { |
2781 | 0 | png_destroy_read_struct(&ping,&ping_info,&end_info); |
2782 | 0 | MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline); |
2783 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels); |
2784 | 0 | if (ReallocateImageColormap(image,2) == MagickFail) |
2785 | 0 | { |
2786 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
2787 | 0 | image); |
2788 | 0 | } |
2789 | 0 | (void) SetImage(image,TransparentOpacity); |
2790 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
2791 | | UnlockSemaphoreInfo(png_semaphore); |
2792 | | #endif |
2793 | 0 | if (logging) |
2794 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2795 | 0 | " exit ReadOnePNGImage()."); |
2796 | 0 | return (image); |
2797 | 0 | } |
2798 | 130k | if (png_get_valid(ping, ping_info, PNG_INFO_tRNS)) |
2799 | 27.0k | { |
2800 | 27.0k | ClassType |
2801 | 27.0k | storage_class; |
2802 | | |
2803 | | /* |
2804 | | Image has a transparent background. |
2805 | | */ |
2806 | 27.0k | storage_class=image->storage_class; |
2807 | 27.0k | image->matte=MagickTrue; |
2808 | 174k | for (y=0; y < (long) image->rows; y++) |
2809 | 154k | { |
2810 | 154k | q=SetImagePixels(image,0,y,image->columns,1); |
2811 | 154k | if (q == (PixelPacket *) NULL) |
2812 | 6.38k | break; |
2813 | 147k | indexes=AccessMutableIndexes(image); |
2814 | | |
2815 | 147k | if (storage_class == PseudoClass) |
2816 | 127k | { |
2817 | 127k | IndexPacket |
2818 | 127k | index; |
2819 | | |
2820 | 127k | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
2821 | 37.1M | for (x=0; x < (long) image->columns; x++) |
2822 | 37.0M | { |
2823 | 37.0M | index=indexes[x]; |
2824 | 37.0M | if ((index < (unsigned int) ping_num_trans) && |
2825 | 35.4M | (ping_trans_alpha != (png_bytep) NULL)) |
2826 | 35.4M | q->opacity= |
2827 | 35.4M | ScaleCharToQuantum(255-ping_trans_alpha[index]); |
2828 | 1.66M | else |
2829 | 1.66M | q->opacity=OpaqueOpacity; |
2830 | 37.0M | q++; |
2831 | 37.0M | } |
2832 | 11.7k | else if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
2833 | 84.0k | for (x=0; x < (long) image->columns; x++) |
2834 | 72.2k | { |
2835 | 72.2k | index=indexes[x]; |
2836 | 72.2k | q->red=image->colormap[index].red; |
2837 | 72.2k | q->green=image->colormap[index].green; |
2838 | 72.2k | q->blue=image->colormap[index].blue; |
2839 | 72.2k | if ((unsigned long) ScaleQuantumToShort(q->red) == |
2840 | 72.2k | transparent_color.opacity) |
2841 | 5.83k | q->opacity=TransparentOpacity; |
2842 | 66.4k | else |
2843 | 66.4k | q->opacity=OpaqueOpacity; |
2844 | 72.2k | q++; |
2845 | 72.2k | } |
2846 | 127k | } |
2847 | 20.2k | else |
2848 | 226k | for (x=(long) image->columns; x > 0; x--) |
2849 | 206k | { |
2850 | 206k | if ((unsigned long) ScaleQuantumToShort(q->red) == |
2851 | 206k | transparent_color.red && |
2852 | 27.1k | (unsigned long) ScaleQuantumToShort(q->green) == |
2853 | 27.1k | transparent_color.green && |
2854 | 18.5k | (unsigned long) ScaleQuantumToShort(q->blue) == |
2855 | 18.5k | transparent_color.blue) |
2856 | 10.2k | q->opacity=TransparentOpacity; |
2857 | 195k | else |
2858 | 195k | q->opacity=OpaqueOpacity; |
2859 | 206k | q++; |
2860 | 206k | } |
2861 | 147k | if (!SyncImagePixels(image)) |
2862 | 0 | break; |
2863 | 147k | } |
2864 | 27.0k | image->storage_class=DirectClass; |
2865 | 27.0k | } |
2866 | | #if (QuantumDepth == 8) |
2867 | | if (image->depth > 8) |
2868 | | image->depth=8; |
2869 | | #endif |
2870 | 130k | if (png_get_text(ping,ping_info,&text,&num_text) != 0) |
2871 | 27.7k | { |
2872 | 27.7k | if (logging) |
2873 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2874 | 0 | " Text chunks: %u", num_text); |
2875 | 160k | for (i=0; i < (long) num_text; i++) |
2876 | 148k | { |
2877 | | /* Check for a profile */ |
2878 | | |
2879 | 148k | if (logging) |
2880 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2881 | 0 | " Reading PNG text chunk[%ld] key=\"%.16s\"," |
2882 | 0 | " length=%" MAGICK_SSIZE_T_F "u",i,text[i].key, |
2883 | 0 | (MAGICK_SSIZE_T) text[i].text_length); |
2884 | 148k | if (strlen(text[i].key) > 16 && |
2885 | 98.1k | !memcmp(text[i].key, "Raw profile type ",17)) |
2886 | 31.0k | { |
2887 | 31.0k | if (text[i].text_length == 0) |
2888 | 1.22k | { |
2889 | 1.22k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2890 | 1.22k | " Skipping empty raw profile..."); |
2891 | 1.22k | } |
2892 | 29.7k | else |
2893 | 29.7k | { |
2894 | 29.7k | if (png_read_raw_profile(image,image_info,text,i,exception) == |
2895 | 29.7k | MagickFail) |
2896 | 16.2k | break; |
2897 | 29.7k | } |
2898 | 31.0k | } |
2899 | 117k | else |
2900 | 117k | { |
2901 | 117k | char |
2902 | 117k | *value; |
2903 | | |
2904 | 117k | length=(unsigned long) text[i].text_length; |
2905 | 117k | value=MagickAllocateMemory(char *,length+1); |
2906 | 117k | if (value == (char *) NULL) |
2907 | 0 | { |
2908 | 0 | png_warning(ping, "Could not allocate memory for text chunk"); |
2909 | 0 | break; |
2910 | 0 | } |
2911 | 117k | *value='\0'; |
2912 | 117k | (void) strlcat(value,text[i].text,length+1); |
2913 | 117k | (void) SetImageAttribute(image,text[i].key,value); |
2914 | 117k | if (logging) |
2915 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2916 | 0 | " Keyword: %s",text[i].key); |
2917 | 117k | MagickFreeMemory(value); |
2918 | 117k | } |
2919 | 148k | } |
2920 | 27.7k | } |
2921 | | #ifdef MNG_OBJECT_BUFFERS |
2922 | | /* |
2923 | | Store the object if necessary. |
2924 | | */ |
2925 | | if (object_id && object_id < MNG_MAX_OBJECTS && !mng_info->frozen[object_id]) |
2926 | | { |
2927 | | if (mng_info->ob[object_id] == (MngBuffer *) NULL) |
2928 | | { |
2929 | | /* |
2930 | | create a new object buffer. |
2931 | | */ |
2932 | | mng_info->ob[object_id]=MagickAllocateMemory(MngBuffer *, |
2933 | | sizeof(MngBuffer)); |
2934 | | if (mng_info->ob[object_id] != (MngBuffer *) NULL) |
2935 | | { |
2936 | | mng_info->ob[object_id]->image=(Image *) NULL; |
2937 | | mng_info->ob[object_id]->reference_count=1; |
2938 | | } |
2939 | | } |
2940 | | if ((mng_info->ob[object_id] == (MngBuffer *) NULL) || |
2941 | | mng_info->ob[object_id]->frozen) |
2942 | | { |
2943 | | if (mng_info->ob[object_id] == (MngBuffer *) NULL) |
2944 | | png_error(ping, "Could not allocate MNG object"); |
2945 | | if (mng_info->ob[object_id]->frozen) |
2946 | | png_error(ping, "Could not overwrite MNG frozen object buffer"); |
2947 | | } |
2948 | | else |
2949 | | { |
2950 | | png_uint_32 |
2951 | | width, |
2952 | | height; |
2953 | | |
2954 | | int |
2955 | | bit_depth, |
2956 | | color_type, |
2957 | | interlace_method, |
2958 | | compression_method, |
2959 | | filter_method; |
2960 | | |
2961 | | if (mng_info->ob[object_id]->image != (Image *) NULL) |
2962 | | { |
2963 | | DestroyImage(mng_info->ob[object_id]->image); |
2964 | | mng_info->ob[object_id]->image=(Image *) NULL; |
2965 | | } |
2966 | | mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue, |
2967 | | &image->exception); |
2968 | | if (mng_info->ob[object_id]->image != (Image *) NULL) |
2969 | | mng_info->ob[object_id]->image->file=(FILE *) NULL; |
2970 | | else |
2971 | | png_error(ping, "Cloning image for object buffer failed"); |
2972 | | png_get_IHDR(ping,ping_info,&width,&height,&bit_depth,&color_type, |
2973 | | &interlace_method,&compression_method,&filter_method); |
2974 | | if (width > 250000L || height > 250000L) |
2975 | | png_error(ping,"PNG Image dimensions are too large."); |
2976 | | mng_info->ob[object_id]->width=width; |
2977 | | mng_info->ob[object_id]->height=height; |
2978 | | mng_info->ob[object_id]->color_type=color_type; |
2979 | | mng_info->ob[object_id]->sample_depth=bit_depth; |
2980 | | mng_info->ob[object_id]->interlace_method=interlace_method; |
2981 | | mng_info->ob[object_id]->compression_method=compression_method; |
2982 | | mng_info->ob[object_id]->filter_method=filter_method; |
2983 | | if (png_get_valid(ping, ping_info, PNG_INFO_PLTE)) |
2984 | | { |
2985 | | int |
2986 | | number_colors; |
2987 | | |
2988 | | png_colorp |
2989 | | plte; |
2990 | | |
2991 | | /* |
2992 | | Copy the PLTE to the object buffer. |
2993 | | */ |
2994 | | png_get_PLTE(ping,ping_info,&plte,&number_colors); |
2995 | | mng_info->ob[object_id]->plte_length=number_colors; |
2996 | | for (i=0; i < number_colors; i++) |
2997 | | { |
2998 | | mng_info->ob[object_id]->plte[i]=plte[i]; |
2999 | | } |
3000 | | } |
3001 | | else |
3002 | | mng_info->ob[object_id]->plte_length=0; |
3003 | | } |
3004 | | } |
3005 | | #endif |
3006 | | /* |
3007 | | Free memory. |
3008 | | */ |
3009 | 130k | png_destroy_read_struct(&ping,&ping_info,&end_info); |
3010 | 130k | MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline); |
3011 | 130k | MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels); |
3012 | | |
3013 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
3014 | | UnlockSemaphoreInfo(png_semaphore); |
3015 | | #endif |
3016 | | |
3017 | | /* |
3018 | | Retrieve image orientation from EXIF (if present) and store in |
3019 | | image. |
3020 | | */ |
3021 | 130k | { |
3022 | 130k | const ImageAttribute |
3023 | 130k | *attribute; |
3024 | | |
3025 | 130k | attribute = GetImageAttribute(image,"EXIF:Orientation"); |
3026 | 130k | if ((attribute != (const ImageAttribute *) NULL) && |
3027 | 2.62k | (attribute->value != (char *) NULL)) |
3028 | 2.62k | { |
3029 | 2.62k | int |
3030 | 2.62k | orientation; |
3031 | | |
3032 | 2.62k | orientation = MagickAtoI(attribute->value); |
3033 | 2.62k | if ((orientation > UndefinedOrientation) && |
3034 | 446 | (orientation <= LeftBottomOrientation)) |
3035 | 27 | image->orientation=(OrientationType) orientation; |
3036 | 2.62k | } |
3037 | 130k | } |
3038 | | |
3039 | 130k | if (logging) |
3040 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3041 | 0 | " exit ReadOnePNGImage()"); |
3042 | 130k | return (image); |
3043 | | |
3044 | | /* End of setjmp-controlled block } */ |
3045 | | |
3046 | | /* end of reading one PNG image */ |
3047 | 130k | } |
3048 | | |
3049 | | static Image *ReadPNGImage(const ImageInfo *image_info, |
3050 | | ExceptionInfo *exception) |
3051 | 223k | { |
3052 | 223k | Image |
3053 | 223k | *image; |
3054 | | |
3055 | 223k | MngInfo |
3056 | 223k | *mng_info; |
3057 | | |
3058 | 223k | char |
3059 | 223k | magic_number[MaxTextExtent]; |
3060 | | |
3061 | 223k | int |
3062 | 223k | have_mng_structure, |
3063 | 223k | logging; |
3064 | | |
3065 | 223k | unsigned int |
3066 | 223k | status; |
3067 | | |
3068 | | /* |
3069 | | Open image file. |
3070 | | */ |
3071 | 223k | assert(image_info != (const ImageInfo *) NULL); |
3072 | 223k | assert(image_info->signature == MagickSignature); |
3073 | 223k | assert(exception != (ExceptionInfo *) NULL); |
3074 | 223k | assert(exception->signature == MagickSignature); |
3075 | 223k | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()"); |
3076 | 223k | image=AllocateImage(image_info); |
3077 | 223k | mng_info=(MngInfo *) NULL; |
3078 | 223k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
3079 | 223k | if (status == MagickFalse) |
3080 | 223k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
3081 | | /* |
3082 | | Verify PNG signature. |
3083 | | */ |
3084 | 223k | if ((ReadBlob(image,8,magic_number) != 8) || |
3085 | 223k | (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)) |
3086 | 1.49k | { |
3087 | 1.49k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
3088 | 0 | } |
3089 | | |
3090 | | /* |
3091 | | Verify that file size large enough to contain a PNG datastream |
3092 | | if using a seekable blob |
3093 | | */ |
3094 | 221k | if (BlobIsSeekable(image) && GetBlobSize(image) < 61) |
3095 | 6.98k | { |
3096 | 6.98k | ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image); |
3097 | 0 | } |
3098 | | |
3099 | | /* |
3100 | | Allocate a MngInfo structure. |
3101 | | */ |
3102 | 214k | have_mng_structure=MagickFalse; |
3103 | 214k | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
3104 | 214k | if (mng_info == (MngInfo *) NULL) |
3105 | 0 | { |
3106 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
3107 | 0 | } |
3108 | | /* |
3109 | | Initialize members of the MngInfo structure. |
3110 | | */ |
3111 | 214k | (void) memset(mng_info,0,sizeof(MngInfo)); |
3112 | 214k | mng_info->image=image; |
3113 | 214k | have_mng_structure=MagickTrue; |
3114 | | |
3115 | 214k | image=ReadOnePNGImage(mng_info,image_info,exception); |
3116 | 214k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
3117 | 214k | if (image == (Image *) NULL) |
3118 | 197k | { |
3119 | 197k | if (logging) |
3120 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3121 | 0 | "exit ReadPNGImage() with error"); |
3122 | 197k | return((Image *) NULL); |
3123 | 197k | } |
3124 | 17.6k | status &= CloseBlob(image); |
3125 | 17.6k | if (image->columns == 0 || image->rows == 0) |
3126 | 0 | { |
3127 | 0 | if (image->exception.severity > exception->severity) |
3128 | 0 | CopyException(exception,&image->exception); |
3129 | 0 | DestroyImageList(image); |
3130 | 0 | image=(Image *) NULL; |
3131 | 0 | if (logging) |
3132 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3133 | 0 | "exit ReadPNGImage() with error."); |
3134 | 0 | return((Image *) NULL); |
3135 | 0 | } |
3136 | | #if 0 |
3137 | | /* |
3138 | | Post-processing to convert the image type in the reader based on a |
3139 | | specified magick prefix string is now disabled. This can (and |
3140 | | should) be done after the image has been returned. |
3141 | | */ |
3142 | | if (LocaleCompare(image_info->magick,"PNG8") == 0) |
3143 | | { |
3144 | | (void) SetImageType(image,PaletteType); |
3145 | | if (image->matte) |
3146 | | { |
3147 | | /* To do: Reduce to binary transparency */ |
3148 | | } |
3149 | | } |
3150 | | if (LocaleCompare(image_info->magick,"PNG24") == 0) |
3151 | | { |
3152 | | (void) SetImageType(image,TrueColorType); |
3153 | | image->matte=MagickFalse; |
3154 | | } |
3155 | | if (LocaleCompare(image_info->magick,"PNG32") == 0) |
3156 | | (void) SetImageType(image,TrueColorMatteType); |
3157 | | #endif |
3158 | 17.6k | if (logging) |
3159 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()"); |
3160 | 17.6k | return (image); |
3161 | 17.6k | } |
3162 | | |
3163 | | |
3164 | | |
3165 | | #if defined(JNG_SUPPORTED) |
3166 | | |
3167 | | static void |
3168 | | DestroyJNG(unsigned char *chunk,Image **color_image, |
3169 | | ImageInfo **color_image_info, |
3170 | | Image **alpha_image,ImageInfo **alpha_image_info) |
3171 | 73.3k | { |
3172 | 73.3k | MagickFreeMemory(chunk); |
3173 | 73.3k | if (*color_image_info) |
3174 | 27.2k | { |
3175 | 27.2k | DestroyImageInfo(*color_image_info); |
3176 | 27.2k | *color_image_info = (ImageInfo *)NULL; |
3177 | 27.2k | } |
3178 | 73.3k | if (*alpha_image_info) |
3179 | 8.24k | { |
3180 | 8.24k | DestroyImageInfo(*alpha_image_info); |
3181 | 8.24k | *alpha_image_info = (ImageInfo *)NULL; |
3182 | 8.24k | } |
3183 | 73.3k | if (*color_image) |
3184 | 27.2k | { |
3185 | 27.2k | DestroyImageList(*color_image); |
3186 | 27.2k | *color_image = (Image *)NULL; |
3187 | 27.2k | } |
3188 | 73.3k | if (*alpha_image) |
3189 | 8.24k | { |
3190 | 8.24k | (void) LiberateTemporaryFile((*alpha_image)->filename); |
3191 | 8.24k | DestroyImageList(*alpha_image); |
3192 | 8.24k | *alpha_image = (Image *)NULL; |
3193 | 8.24k | } |
3194 | 73.3k | } |
3195 | | /* |
3196 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3197 | | % % |
3198 | | % % |
3199 | | % % |
3200 | | % R e a d O n e J N G I m a g e % |
3201 | | % % |
3202 | | % % |
3203 | | % % |
3204 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3205 | | % |
3206 | | % Method ReadOneJNGImage reads a JPEG Network Graphics (JNG) image file |
3207 | | % (minus the 8-byte signature) and returns it. It allocates the memory |
3208 | | % necessary for the new Image structure and returns a pointer to the new |
3209 | | % image. |
3210 | | % |
3211 | | % JNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu. |
3212 | | % |
3213 | | % The format of the ReadOneJNGImage method is: |
3214 | | % |
3215 | | % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info, |
3216 | | % ExceptionInfo *exception) |
3217 | | % |
3218 | | % A description of each parameter follows: |
3219 | | % |
3220 | | % o image: Method ReadOneJNGImage returns a pointer to the image after |
3221 | | % reading. A null image is returned if there is a memory shortage or |
3222 | | % if the image cannot be read. |
3223 | | % |
3224 | | % o mng_info: Specifies a pointer to a MngInfo structure. |
3225 | | % |
3226 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
3227 | | % |
3228 | | % o exception: return any errors or warnings in this structure. |
3229 | | % |
3230 | | */ |
3231 | | static Image *ReadOneJNGImage(MngInfo *mng_info, |
3232 | | const ImageInfo *image_info, |
3233 | | ExceptionInfo *exception) |
3234 | 70.8k | { |
3235 | 70.8k | Image |
3236 | 70.8k | *alpha_image, |
3237 | 70.8k | *color_image, |
3238 | 70.8k | *image, |
3239 | 70.8k | *jng_image; |
3240 | | |
3241 | 70.8k | ImageInfo |
3242 | 70.8k | *alpha_image_info, |
3243 | 70.8k | *color_image_info; |
3244 | | |
3245 | 70.8k | long |
3246 | 70.8k | y; |
3247 | | |
3248 | 70.8k | magick_int64_t |
3249 | 70.8k | height_resource, |
3250 | 70.8k | width_resource; |
3251 | | |
3252 | 70.8k | unsigned long |
3253 | 70.8k | jng_height, |
3254 | 70.8k | jng_width; |
3255 | | |
3256 | 70.8k | png_byte |
3257 | 70.8k | jng_color_type, |
3258 | 70.8k | jng_image_sample_depth, |
3259 | 70.8k | jng_image_compression_method, |
3260 | 70.8k | jng_image_interlace_method, |
3261 | 70.8k | jng_alpha_sample_depth, |
3262 | 70.8k | jng_alpha_compression_method, |
3263 | 70.8k | jng_alpha_filter_method, |
3264 | 70.8k | jng_alpha_interlace_method; |
3265 | | |
3266 | 70.8k | register const PixelPacket |
3267 | 70.8k | *s; |
3268 | | |
3269 | 70.8k | register long |
3270 | 70.8k | x; |
3271 | | |
3272 | 70.8k | register PixelPacket |
3273 | 70.8k | *q; |
3274 | | |
3275 | 70.8k | register unsigned char |
3276 | 70.8k | *p; |
3277 | | |
3278 | 70.8k | unsigned int |
3279 | 70.8k | logging, |
3280 | 70.8k | read_JSEP, |
3281 | 70.8k | reading_idat, |
3282 | 70.8k | status; |
3283 | | |
3284 | 70.8k | size_t |
3285 | 70.8k | length; |
3286 | | |
3287 | 70.8k | magick_off_t |
3288 | 70.8k | blob_size; |
3289 | | |
3290 | 70.8k | jng_alpha_compression_method=0; |
3291 | 70.8k | jng_alpha_sample_depth=8; |
3292 | 70.8k | jng_color_type=0; |
3293 | 70.8k | jng_height=0; |
3294 | 70.8k | jng_width=0; |
3295 | 70.8k | alpha_image=(Image *) NULL; |
3296 | 70.8k | color_image=(Image *) NULL; |
3297 | 70.8k | alpha_image_info=(ImageInfo *) NULL; |
3298 | 70.8k | color_image_info=(ImageInfo *) NULL; |
3299 | | |
3300 | 70.8k | logging=LogMagickEvent(CoderEvent,GetMagickModule(), |
3301 | 70.8k | " enter ReadOneJNGImage()"); |
3302 | | |
3303 | 70.8k | image=mng_info->image; |
3304 | 70.8k | blob_size=GetBlobSize(image); |
3305 | 70.8k | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
3306 | 0 | { |
3307 | | /* |
3308 | | Allocate next image structure. |
3309 | | */ |
3310 | 0 | if (logging) |
3311 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3312 | 0 | " AllocateNextImage()"); |
3313 | 0 | AllocateNextImage(image_info,image); |
3314 | 0 | if (image->next == (Image *) NULL) |
3315 | 0 | return((Image *) NULL); |
3316 | 0 | image=SyncNextImageInList(image); |
3317 | 0 | } |
3318 | 70.8k | mng_info->image=image; |
3319 | | |
3320 | | /* |
3321 | | Signature bytes have already been read. |
3322 | | */ |
3323 | | |
3324 | 70.8k | read_JSEP=MagickFalse; |
3325 | 70.8k | reading_idat=MagickFalse; |
3326 | | |
3327 | 70.8k | width_resource = GetMagickResourceLimit(WidthResource); |
3328 | 70.8k | height_resource = GetMagickResourceLimit(HeightResource); |
3329 | | |
3330 | 70.8k | for (;;) |
3331 | 1.65M | { |
3332 | 1.65M | char |
3333 | 1.65M | type[MaxTextExtent]; |
3334 | | |
3335 | 1.65M | unsigned char |
3336 | 1.65M | *chunk = (unsigned char *) NULL; |
3337 | | |
3338 | 1.65M | unsigned int |
3339 | 1.65M | count; |
3340 | | |
3341 | | /* |
3342 | | Read a new JNG chunk. |
3343 | | */ |
3344 | | |
3345 | 1.65M | if (QuantumTick(TellBlob(image),2*blob_size)) |
3346 | 97.6k | if (!MagickMonitorFormatted(TellBlob(image),2*blob_size, |
3347 | 97.6k | exception,LoadImagesText,image->filename)) |
3348 | 0 | break; |
3349 | | |
3350 | 1.65M | type[0]='\0'; |
3351 | 1.65M | (void) strlcat(type,"errr",sizeof(type)); |
3352 | 1.65M | length=(size_t) ReadBlobMSBLong(image); |
3353 | 1.65M | count=(unsigned int) ReadBlob(image,4,type); |
3354 | 1.65M | if (count != 4) |
3355 | 9.20k | { |
3356 | 9.20k | DestroyJNG(NULL,&color_image,&color_image_info, |
3357 | 9.20k | &alpha_image,&alpha_image_info); |
3358 | 9.20k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3359 | 9.20k | "chunk count is zero"); |
3360 | 9.20k | ThrowException(exception,CorruptImageError, |
3361 | 9.20k | UnexpectedEndOfFile,image->filename); |
3362 | 9.20k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3363 | 9.20k | return ((Image*)NULL); |
3364 | 9.20k | } |
3365 | 1.65M | if (logging) |
3366 | 0 | { |
3367 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3368 | 0 | " Reading JNG chunk type %c%c%c%c, " |
3369 | 0 | "length: %" MAGICK_SIZE_T_F "u", |
3370 | 0 | type[0],type[1],type[2],type[3], |
3371 | 0 | (MAGICK_SIZE_T) length); |
3372 | |
|
3373 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3374 | 0 | " count=%u",count); |
3375 | 0 | } |
3376 | | |
3377 | 1.65M | if (length > PNG_MAX_UINT) |
3378 | 4.33k | { |
3379 | 4.33k | DestroyJNG(NULL,&color_image,&color_image_info, |
3380 | 4.33k | &alpha_image,&alpha_image_info); |
3381 | 4.33k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3382 | 4.33k | "chunk length (%" MAGICK_SIZE_T_F "u) > PNG_MAX_UINT", |
3383 | 4.33k | (MAGICK_SIZE_T) length); |
3384 | 4.33k | ThrowException(exception,CorruptImageError, |
3385 | 4.33k | ImproperImageHeader,image->filename); |
3386 | 4.33k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3387 | 4.33k | return ((Image*)NULL); |
3388 | 4.33k | } |
3389 | 1.64M | if (length > (size_t) blob_size) |
3390 | 29.2k | { |
3391 | 29.2k | DestroyJNG(NULL,&color_image,&color_image_info, |
3392 | 29.2k | &alpha_image,&alpha_image_info); |
3393 | 29.2k | if (image->logging) |
3394 | 29.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3395 | 29.2k | "chunk length (%" MAGICK_SIZE_T_F "u)" |
3396 | 29.2k | " is greater than input size" |
3397 | 29.2k | " (%" MAGICK_OFF_F "d)", |
3398 | 29.2k | (MAGICK_SIZE_T) length, |
3399 | 29.2k | blob_size); |
3400 | 29.2k | ThrowException(exception,CorruptImageError, |
3401 | 29.2k | ImproperImageHeader,image->filename); |
3402 | 29.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3403 | 29.2k | return ((Image*)NULL); |
3404 | 29.2k | } |
3405 | | |
3406 | 1.61M | p=NULL; |
3407 | 1.61M | if (length) |
3408 | 296k | { |
3409 | 296k | chunk=MagickAllocateMemory(unsigned char *,length); |
3410 | 296k | if (chunk == (unsigned char *) NULL) |
3411 | 0 | { |
3412 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3413 | 0 | &alpha_image,&alpha_image_info); |
3414 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3415 | 0 | " Could not allocate chunk memory"); |
3416 | 0 | ThrowException(exception,ResourceLimitError, |
3417 | 0 | MemoryAllocationFailed,image->filename); |
3418 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3419 | 0 | return ((Image*)NULL); |
3420 | 0 | } |
3421 | 296k | if (ReadBlob(image,length,chunk) != length) |
3422 | 7.63k | { |
3423 | 7.63k | DestroyJNG(chunk,&color_image,&color_image_info, |
3424 | 7.63k | &alpha_image,&alpha_image_info); |
3425 | 7.63k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3426 | 7.63k | " chunk reading was incomplete"); |
3427 | 7.63k | ThrowException(exception,CorruptImageError, |
3428 | 7.63k | InsufficientImageDataInFile,image->filename); |
3429 | 7.63k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3430 | 7.63k | return ((Image*)NULL); |
3431 | 7.63k | } |
3432 | 288k | p=chunk; |
3433 | 288k | } |
3434 | 1.60M | (void) ReadBlobMSBLong(image); /* read crc word */ |
3435 | | |
3436 | 1.60M | if (!memcmp(type,mng_JHDR,4)) |
3437 | 77.9k | { |
3438 | 77.9k | if (length == 16) |
3439 | 62.7k | { |
3440 | 62.7k | jng_width=(unsigned long) mng_get_long(p); |
3441 | 62.7k | jng_height=(unsigned long) mng_get_long(&p[4]); |
3442 | 62.7k | jng_color_type=p[8]; |
3443 | 62.7k | jng_image_sample_depth=p[9]; |
3444 | 62.7k | jng_image_compression_method=p[10]; |
3445 | 62.7k | jng_image_interlace_method=p[11]; |
3446 | 62.7k | jng_alpha_sample_depth=p[12]; |
3447 | 62.7k | jng_alpha_compression_method=p[13]; |
3448 | 62.7k | jng_alpha_filter_method=p[14]; |
3449 | 62.7k | jng_alpha_interlace_method=p[15]; |
3450 | 62.7k | if (logging) |
3451 | 0 | { |
3452 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3453 | 0 | " jng_width: %16lu", |
3454 | 0 | jng_width); |
3455 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3456 | 0 | " jng_height: %16lu", |
3457 | 0 | jng_height); |
3458 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3459 | 0 | " jng_color_type: %16d", |
3460 | 0 | jng_color_type); |
3461 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3462 | 0 | " jng_image_sample_depth: %3d", |
3463 | 0 | jng_image_sample_depth); |
3464 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3465 | 0 | " jng_image_compression_method:%3d", |
3466 | 0 | jng_image_compression_method); |
3467 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3468 | 0 | " jng_image_interlace_method: %3d", |
3469 | 0 | jng_image_interlace_method); |
3470 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3471 | 0 | " jng_alpha_sample_depth: %3d", |
3472 | 0 | jng_alpha_sample_depth); |
3473 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3474 | 0 | " jng_alpha_compression_method:%3d", |
3475 | 0 | jng_alpha_compression_method); |
3476 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3477 | 0 | " jng_alpha_filter_method: %3d", |
3478 | 0 | jng_alpha_filter_method); |
3479 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3480 | 0 | " jng_alpha_interlace_method: %3d", |
3481 | 0 | jng_alpha_interlace_method); |
3482 | 0 | } |
3483 | 62.7k | } |
3484 | | |
3485 | 77.9k | MagickFreeMemory(chunk); |
3486 | | |
3487 | 77.9k | if (jng_width > 65535 || jng_height > 65535 || |
3488 | 74.4k | (long) jng_width > GetMagickResourceLimit(WidthResource) || |
3489 | 73.2k | (long) jng_height > GetMagickResourceLimit(HeightResource)) |
3490 | 6.25k | { |
3491 | 6.25k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3492 | 6.25k | " JNG width or height too large: (%lu x %lu)", |
3493 | 6.25k | jng_width, jng_height); |
3494 | 6.25k | ThrowException(exception,CorruptImageError, |
3495 | 6.25k | ImproperImageHeader,image->filename); |
3496 | 6.25k | DestroyJNG(chunk,&color_image,&color_image_info, |
3497 | 6.25k | &alpha_image,&alpha_image_info); |
3498 | 6.25k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3499 | 6.25k | return ((Image *)NULL); |
3500 | 6.25k | } |
3501 | | |
3502 | | /* Rationalize dimensions with blob size if it is available */ |
3503 | 71.7k | if ((blob_size == 0) || |
3504 | 71.7k | ((((double) jng_width*jng_height)/blob_size) > 512.0)) |
3505 | 0 | { |
3506 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3507 | 0 | " Unreasonable dimensions: " |
3508 | 0 | "geometry = %lux%lu, " |
3509 | 0 | "blob size = %" MAGICK_OFF_F "d", |
3510 | 0 | jng_width, jng_height, blob_size); |
3511 | |
|
3512 | 0 | ThrowException(exception,CorruptImageError, |
3513 | 0 | InsufficientImageDataInFile,image->filename); |
3514 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3515 | 0 | &alpha_image,&alpha_image_info); |
3516 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3517 | 0 | return ((Image *)NULL); |
3518 | 0 | } |
3519 | | |
3520 | | /* Temporarily set width and height resources to match JHDR */ |
3521 | 71.7k | SetMagickResourceLimit(WidthResource,jng_width); |
3522 | 71.7k | SetMagickResourceLimit(HeightResource,jng_height); |
3523 | | |
3524 | 71.7k | continue; |
3525 | 71.7k | } |
3526 | | |
3527 | 1.53M | if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) && |
3528 | 247k | ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) || |
3529 | 215k | (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0))) |
3530 | 40.8k | { |
3531 | | /* |
3532 | | o create color_image |
3533 | | o open color_blob, attached to color_image |
3534 | | o if (color type has alpha) |
3535 | | open alpha_blob, attached to alpha_image |
3536 | | */ |
3537 | | |
3538 | 40.8k | color_image_info=MagickAllocateMemory(ImageInfo *,sizeof(ImageInfo)); |
3539 | 40.8k | if (color_image_info == (ImageInfo *) NULL) |
3540 | 0 | { |
3541 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3542 | 0 | &alpha_image,&alpha_image_info); |
3543 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3544 | 0 | " could not allocate color_image_info"); |
3545 | 0 | ThrowException(exception,ResourceLimitError, |
3546 | 0 | MemoryAllocationFailed,image->filename); |
3547 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3548 | 0 | return ((Image *)NULL); |
3549 | 0 | } |
3550 | 40.8k | GetImageInfo(color_image_info); |
3551 | 40.8k | color_image=AllocateImage(color_image_info); |
3552 | 40.8k | if (color_image == (Image *) NULL) |
3553 | 0 | { |
3554 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3555 | 0 | &alpha_image,&alpha_image_info); |
3556 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3557 | 0 | " could not allocate color_image"); |
3558 | 0 | ThrowException(exception,ResourceLimitError, |
3559 | 0 | MemoryAllocationFailed,image->filename); |
3560 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3561 | 0 | return ((Image *)NULL); |
3562 | 0 | } |
3563 | 40.8k | if (logging) |
3564 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3565 | 0 | " Creating color_blob."); |
3566 | 40.8k | (void) AcquireTemporaryFileName(color_image->filename); |
3567 | 40.8k | status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode, |
3568 | 40.8k | exception); |
3569 | 40.8k | if (status == MagickFalse) |
3570 | 0 | { |
3571 | 0 | CopyException(exception,&color_image->exception); |
3572 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3573 | 0 | &alpha_image,&alpha_image_info); |
3574 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3575 | 0 | " could not open color_image blob"); |
3576 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3577 | 0 | return ((Image *)NULL); |
3578 | 0 | } |
3579 | | |
3580 | 40.8k | if (!image_info->ping && jng_color_type >= 12) |
3581 | 8.40k | { |
3582 | 8.40k | if ((jng_alpha_compression_method != 0) && |
3583 | 476 | (jng_alpha_compression_method != 8)) |
3584 | 160 | { |
3585 | 160 | if (logging) |
3586 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3587 | 0 | "Unsupported Alpha_compression_method: %u" |
3588 | 0 | " (returning NULL)", |
3589 | 0 | jng_alpha_compression_method); |
3590 | 160 | DestroyJNG(chunk,&color_image,&color_image_info, |
3591 | 160 | &alpha_image,&alpha_image_info); |
3592 | 160 | ThrowException(exception,CorruptImageError,ImproperImageHeader, |
3593 | 160 | image->filename); |
3594 | 160 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3595 | 160 | return ((Image *)NULL); |
3596 | 160 | } |
3597 | | |
3598 | 8.24k | alpha_image_info=MagickAllocateMemory(ImageInfo *, |
3599 | 8.24k | sizeof(ImageInfo)); |
3600 | 8.24k | if (alpha_image_info == (ImageInfo *) NULL) |
3601 | 0 | { |
3602 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3603 | 0 | &alpha_image,&alpha_image_info); |
3604 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3605 | 0 | " could not allocate alpha_image_info (returning NULL)"); |
3606 | 0 | ThrowException(exception,ResourceLimitError, |
3607 | 0 | MemoryAllocationFailed,image->filename); |
3608 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3609 | 0 | return ((Image *)NULL); |
3610 | 0 | } |
3611 | 8.24k | GetImageInfo(alpha_image_info); |
3612 | 8.24k | alpha_image=AllocateImage(alpha_image_info); |
3613 | 8.24k | if (alpha_image == (Image *) NULL) |
3614 | 0 | { |
3615 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3616 | 0 | &alpha_image,&alpha_image_info); |
3617 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3618 | 0 | " could not allocate alpha_image (returning NULL)"); |
3619 | 0 | ThrowException(exception,ResourceLimitError, |
3620 | 0 | MemoryAllocationFailed,image->filename); |
3621 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3622 | 0 | return ((Image *)NULL); |
3623 | 0 | } |
3624 | 8.24k | if (logging) |
3625 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3626 | 0 | " Creating alpha_blob."); |
3627 | 8.24k | (void) AcquireTemporaryFileName(alpha_image->filename); /* Freed by DestroyJNG() */ |
3628 | 8.24k | status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode, |
3629 | 8.24k | exception); |
3630 | 8.24k | if (status == MagickFalse) |
3631 | 0 | { |
3632 | 0 | DestroyJNG(chunk,&color_image,&color_image_info, |
3633 | 0 | &alpha_image,&alpha_image_info); |
3634 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3635 | 0 | " could not open alpha_image blob (returning NULL)"); |
3636 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3637 | 0 | return ((Image *)NULL); |
3638 | 0 | } |
3639 | 8.24k | if (jng_alpha_compression_method == 0) |
3640 | 7.93k | { |
3641 | 7.93k | unsigned char |
3642 | 7.93k | data[18]; |
3643 | | |
3644 | 7.93k | if (logging) |
3645 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3646 | 0 | " Writing IHDR chunk" |
3647 | 0 | " to alpha_blob."); |
3648 | 7.93k | (void) WriteBlob(alpha_image,8,"\211PNG\r\n\032\n"); |
3649 | 7.93k | (void) WriteBlobMSBULong(alpha_image,13L); |
3650 | 7.93k | PNGType(data,mng_IHDR); |
3651 | 7.93k | LogPNGChunk(logging,mng_IHDR,13L); |
3652 | 7.93k | PNGLong(data+4,jng_width); |
3653 | 7.93k | PNGLong(data+8,jng_height); |
3654 | 7.93k | data[12]=jng_alpha_sample_depth; |
3655 | 7.93k | data[13]=0; /* color_type gray */ |
3656 | 7.93k | data[14]=0; /* compression method 0 */ |
3657 | 7.93k | data[15]=0; /* filter_method 0 */ |
3658 | 7.93k | data[16]=0; /* interlace_method 0 */ |
3659 | 7.93k | (void) WriteBlob(alpha_image,17,data); |
3660 | 7.93k | (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17)); |
3661 | 7.93k | } |
3662 | 8.24k | } |
3663 | 40.6k | reading_idat=MagickTrue; |
3664 | 40.6k | } |
3665 | | |
3666 | 1.53M | if (!memcmp(type,mng_JDAT,4)) |
3667 | 18.8k | { |
3668 | | /* |
3669 | | Copy chunk to color_image->blob |
3670 | | */ |
3671 | | |
3672 | | |
3673 | 18.8k | if (length && color_image != (Image *)NULL) |
3674 | 16.2k | { |
3675 | 16.2k | if (logging) |
3676 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3677 | 0 | " Copying %" MAGICK_SIZE_T_F "u" |
3678 | 0 | " bytes of JDAT chunk data" |
3679 | 0 | " to color_blob.", |
3680 | 0 | (MAGICK_SIZE_T) length); |
3681 | 16.2k | (void) WriteBlob(color_image,length,(char *) chunk); |
3682 | 16.2k | } |
3683 | 2.62k | else |
3684 | 2.62k | { |
3685 | 2.62k | if (logging) |
3686 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3687 | 0 | " Skipping copy of %" MAGICK_SIZE_T_F "u" |
3688 | 0 | " bytes of JDAT chunk data" |
3689 | 0 | " to color_blob (color_image=%p).", |
3690 | 0 | (MAGICK_SIZE_T) length, color_image); |
3691 | 2.62k | } |
3692 | 18.8k | MagickFreeMemory(chunk); |
3693 | 18.8k | continue; |
3694 | 18.8k | } |
3695 | | |
3696 | 1.51M | if (!memcmp(type,mng_IDAT,4)) |
3697 | 52.4k | { |
3698 | 52.4k | png_byte |
3699 | 52.4k | data[5]; |
3700 | | |
3701 | | /* |
3702 | | Copy IDAT header and chunk data to alpha_image->blob |
3703 | | */ |
3704 | | |
3705 | 52.4k | if (alpha_image != NULL && image_info->ping == MagickFalse) |
3706 | 45.2k | { |
3707 | 45.2k | if (logging) |
3708 | 0 | { |
3709 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3710 | 0 | " Copying IDAT chunk data" |
3711 | 0 | " to alpha_blob."); |
3712 | 0 | } |
3713 | 45.2k | if (length == 0) |
3714 | 424 | { |
3715 | 424 | if (logging) |
3716 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3717 | 0 | " IDAT chunk has length 0"); |
3718 | 424 | MagickFreeMemory(chunk); |
3719 | 424 | continue; |
3720 | 424 | } |
3721 | 44.7k | (void) WriteBlobMSBULong(alpha_image,(unsigned long) length); |
3722 | 44.7k | PNGType(data,mng_IDAT); |
3723 | 44.7k | LogPNGChunk(logging,mng_IDAT,length); |
3724 | 44.7k | (void) WriteBlob(alpha_image,4,(char *) data); |
3725 | 44.7k | (void) WriteBlob(alpha_image,length,(char *) chunk); |
3726 | 44.7k | (void) WriteBlobMSBULong(alpha_image, |
3727 | 44.7k | crc32(crc32(0,data,4),chunk,(uInt) length)); |
3728 | 44.7k | } |
3729 | 51.9k | MagickFreeMemory(chunk); |
3730 | 51.9k | continue; |
3731 | 52.4k | } |
3732 | | |
3733 | 1.45M | if (!memcmp(type,mng_JDAA,4) || !memcmp(type,mng_JdAA,4)) |
3734 | 103k | { |
3735 | | /* |
3736 | | Copy chunk data to alpha_image->blob |
3737 | | */ |
3738 | | |
3739 | 103k | if (alpha_image != NULL && image_info->ping == MagickFalse && length != 0) |
3740 | 87.2k | { |
3741 | 87.2k | if (logging) |
3742 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3743 | 0 | " Copying JDAA chunk data" |
3744 | 0 | " to alpha_blob."); |
3745 | | |
3746 | 87.2k | (void) WriteBlob(alpha_image,length,(char *) chunk); |
3747 | 87.2k | } |
3748 | 103k | MagickFreeMemory(chunk); |
3749 | 103k | continue; |
3750 | 103k | } |
3751 | | |
3752 | 1.35M | if (!memcmp(type,mng_JSEP,4)) |
3753 | 2.35k | { |
3754 | 2.35k | read_JSEP=MagickTrue; |
3755 | 2.35k | MagickFreeMemory(chunk); |
3756 | 2.35k | continue; |
3757 | 2.35k | } |
3758 | | |
3759 | 1.35M | if (!memcmp(type,mng_bKGD,4)) |
3760 | 2.29k | { |
3761 | 2.29k | if (length == 2) |
3762 | 734 | { |
3763 | 734 | image->background_color.red=ScaleCharToQuantum(p[1]); |
3764 | 734 | image->background_color.green=image->background_color.red; |
3765 | 734 | image->background_color.blue=image->background_color.red; |
3766 | 734 | } |
3767 | 2.29k | if (length == 6) |
3768 | 1.01k | { |
3769 | 1.01k | image->background_color.red=ScaleCharToQuantum(p[1]); |
3770 | 1.01k | image->background_color.green=ScaleCharToQuantum(p[3]); |
3771 | 1.01k | image->background_color.blue=ScaleCharToQuantum(p[5]); |
3772 | 1.01k | } |
3773 | 2.29k | MagickFreeMemory(chunk); |
3774 | 2.29k | continue; |
3775 | 2.29k | } |
3776 | | |
3777 | 1.35M | if (!memcmp(type,mng_gAMA,4)) |
3778 | 2.36k | { |
3779 | 2.36k | if (length == 4) |
3780 | 643 | image->gamma=((float) mng_get_long(p))*0.00001; |
3781 | 2.36k | MagickFreeMemory(chunk); |
3782 | 2.36k | continue; |
3783 | 2.36k | } |
3784 | | |
3785 | 1.34M | if (!memcmp(type,mng_cHRM,4)) |
3786 | 3.34k | { |
3787 | 3.34k | if (length == 32) |
3788 | 906 | { |
3789 | 906 | image->chromaticity.white_point.x=0.00001*mng_get_long(p); |
3790 | 906 | image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]); |
3791 | 906 | image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]); |
3792 | 906 | image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]); |
3793 | 906 | image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]); |
3794 | 906 | image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]); |
3795 | 906 | image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]); |
3796 | 906 | image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]); |
3797 | 906 | } |
3798 | 3.34k | MagickFreeMemory(chunk); |
3799 | 3.34k | continue; |
3800 | 3.34k | } |
3801 | | |
3802 | 1.34M | if (!memcmp(type,mng_sRGB,4)) |
3803 | 1.91k | { |
3804 | 1.91k | if (length == 1) |
3805 | 955 | { |
3806 | 955 | image->rendering_intent=(RenderingIntent) (p[0]+1); |
3807 | 955 | image->gamma=0.45455f; |
3808 | 955 | image->chromaticity.red_primary.x=0.6400f; |
3809 | 955 | image->chromaticity.red_primary.y=0.3300f; |
3810 | 955 | image->chromaticity.green_primary.x=0.3000f; |
3811 | 955 | image->chromaticity.green_primary.y=0.6000f; |
3812 | 955 | image->chromaticity.blue_primary.x=0.1500f; |
3813 | 955 | image->chromaticity.blue_primary.y=0.0600f; |
3814 | 955 | image->chromaticity.white_point.x=0.3127f; |
3815 | 955 | image->chromaticity.white_point.y=0.3290f; |
3816 | 955 | } |
3817 | 1.91k | MagickFreeMemory(chunk); |
3818 | 1.91k | continue; |
3819 | 1.91k | } |
3820 | | |
3821 | 1.34M | if (!memcmp(type,mng_oFFs,4)) |
3822 | 4.05k | { |
3823 | 4.05k | if (length > 8) |
3824 | 2.23k | { |
3825 | 2.23k | image->page.x=mng_get_long(p); |
3826 | 2.23k | image->page.y=mng_get_long(&p[4]); |
3827 | 2.23k | if ((int) p[8] != 0) |
3828 | 614 | { |
3829 | 614 | image->page.x/=10000; |
3830 | 614 | image->page.y/=10000; |
3831 | 614 | } |
3832 | 2.23k | } |
3833 | 4.05k | MagickFreeMemory(chunk); |
3834 | 4.05k | continue; |
3835 | 4.05k | } |
3836 | | |
3837 | 1.33M | if (!memcmp(type,mng_pHYs,4)) |
3838 | 3.94k | { |
3839 | 3.94k | if (length > 8) |
3840 | 1.05k | { |
3841 | 1.05k | image->x_resolution=(double) mng_get_long(p); |
3842 | 1.05k | image->y_resolution=(double) mng_get_long(&p[4]); |
3843 | 1.05k | if ((int) p[8] == PNG_RESOLUTION_METER) |
3844 | 340 | { |
3845 | 340 | image->units=PixelsPerCentimeterResolution; |
3846 | 340 | image->x_resolution=image->x_resolution/100.0f; |
3847 | 340 | image->y_resolution=image->y_resolution/100.0f; |
3848 | 340 | } |
3849 | 1.05k | } |
3850 | 3.94k | MagickFreeMemory(chunk); |
3851 | 3.94k | continue; |
3852 | 3.94k | } |
3853 | | |
3854 | | #if 0 |
3855 | | if (!memcmp(type,mng_iCCP,4)) |
3856 | | { |
3857 | | /* To do. */ |
3858 | | MagickFreeMemory(chunk); |
3859 | | continue; |
3860 | | } |
3861 | | #endif |
3862 | | |
3863 | 1.33M | MagickFreeMemory(chunk); |
3864 | | |
3865 | 1.33M | if (memcmp(type,mng_IEND,4)) |
3866 | 1.32M | continue; |
3867 | 14.0k | break; |
3868 | 1.33M | } |
3869 | | |
3870 | | |
3871 | | /* IEND found or loop ended */ |
3872 | | |
3873 | | /* |
3874 | | Finish up reading image data: |
3875 | | |
3876 | | o read main image from color_blob. |
3877 | | |
3878 | | o close color_blob. |
3879 | | |
3880 | | o if (color_type has alpha) |
3881 | | if alpha_encoding is PNG |
3882 | | read secondary image from alpha_blob via ReadPNG |
3883 | | if alpha_encoding is JPEG |
3884 | | read secondary image from alpha_blob via ReadJPEG |
3885 | | |
3886 | | o close alpha_blob. |
3887 | | |
3888 | | o copy intensity of secondary image into |
3889 | | opacity samples of main image. |
3890 | | |
3891 | | o destroy the secondary image. |
3892 | | */ |
3893 | | |
3894 | 14.0k | if (color_image_info == (ImageInfo *) NULL || color_image == (Image *) NULL) |
3895 | 399 | { |
3896 | | |
3897 | 399 | if (logging) |
3898 | 0 | { |
3899 | 0 | if (color_image_info == (ImageInfo *) NULL) |
3900 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3901 | 0 | "Color image info is NULL!"); |
3902 | 0 | if (color_image == (Image *) NULL) |
3903 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3904 | 0 | "Color image is NULL!"); |
3905 | 0 | } |
3906 | 399 | if (color_image == (Image *) NULL) |
3907 | 399 | { |
3908 | 399 | ThrowException(exception,CorruptImageError, |
3909 | 399 | ImageFileDoesNotContainAnyImageData,image->filename); |
3910 | 399 | } |
3911 | 399 | DestroyImageList(color_image); |
3912 | 399 | color_image=(Image *) NULL; |
3913 | 399 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3914 | 399 | return (Image *) NULL; |
3915 | 399 | } |
3916 | | |
3917 | 13.6k | else |
3918 | 13.6k | { |
3919 | 13.6k | status &= CloseBlob(color_image); |
3920 | 13.6k | if (logging) |
3921 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3922 | 0 | " Reading jng_image from color_blob."); |
3923 | | |
3924 | 13.6k | MagickFormatString(color_image_info->filename,sizeof(color_image_info->filename),"JPEG:%.1024s",color_image->filename); |
3925 | | |
3926 | 13.6k | color_image_info->ping=MagickFalse; /* To do: avoid this */ |
3927 | 13.6k | color_image_info->subimage=0; |
3928 | 13.6k | color_image_info->subrange=1; |
3929 | | |
3930 | 13.6k | jng_image=ReadImage(color_image_info,exception); |
3931 | 13.6k | (void) LiberateTemporaryFile(color_image->filename); |
3932 | 13.6k | DestroyImage(color_image); |
3933 | 13.6k | color_image = (Image *)NULL; |
3934 | 13.6k | DestroyImageInfo(color_image_info); |
3935 | 13.6k | color_image_info = (ImageInfo *)NULL; |
3936 | | |
3937 | 13.6k | if (jng_image == (Image *) NULL) |
3938 | 9.52k | { |
3939 | | /* |
3940 | | Don't throw exception here since ReadImage() will already |
3941 | | have thrown it. |
3942 | | */ |
3943 | 9.52k | DestroyJNG(/*chunk*/ NULL,&color_image,&color_image_info, |
3944 | 9.52k | &alpha_image,&alpha_image_info); |
3945 | 9.52k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3946 | 9.52k | return (Image *) NULL; |
3947 | 9.52k | } |
3948 | | |
3949 | 4.09k | if (logging) |
3950 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3951 | 0 | "jng_height=%lu, jng_width=%lu", |
3952 | 0 | jng_height, jng_width); |
3953 | 4.09k | image->rows=jng_height; |
3954 | 4.09k | image->columns=jng_width; |
3955 | 4.09k | length=MagickArraySize(image->columns,sizeof(PixelPacket)); |
3956 | 4.09k | if (jng_height == 0 || jng_width == 0 || length == 0) |
3957 | 1.17k | { |
3958 | 1.17k | if (logging) |
3959 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3960 | 0 | " jng_width=%lu jng_height=%lu", |
3961 | 0 | (unsigned long)jng_width,(unsigned long)jng_height); |
3962 | 1.17k | DestroyJNG(NULL,&color_image,&color_image_info, |
3963 | 1.17k | &alpha_image,&alpha_image_info); |
3964 | 1.17k | DestroyImageList(jng_image); |
3965 | 1.17k | ThrowException(exception,CorruptImageError, |
3966 | 1.17k | ImproperImageHeader,image->filename); |
3967 | 1.17k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3968 | 1.17k | return ((Image *)NULL); |
3969 | 1.17k | } |
3970 | 2.91k | if ((image->columns != jng_image->columns) || |
3971 | 2.91k | (image->rows != jng_image->rows)) |
3972 | 0 | { |
3973 | 0 | if (logging) |
3974 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3975 | 0 | "image dimensions %lux%lu do not" |
3976 | 0 | " match JPEG dimensions %lux%lu", |
3977 | 0 | image->columns,image->rows, |
3978 | 0 | jng_image->columns,jng_image->rows); |
3979 | 0 | DestroyJNG(NULL,&color_image,&color_image_info, |
3980 | 0 | &alpha_image,&alpha_image_info); |
3981 | 0 | DestroyImage(jng_image); |
3982 | 0 | ThrowException(exception,CorruptImageError, |
3983 | 0 | ImproperImageHeader,image->filename); |
3984 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
3985 | 0 | return ((Image *)NULL); |
3986 | 0 | } |
3987 | 2.91k | if (logging) |
3988 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3989 | 0 | "copying jng_image pixels to main image"); |
3990 | 5.82k | for (y=0; y < (long) image->rows; y++) |
3991 | 2.91k | { |
3992 | 2.91k | s=AcquireImagePixels(jng_image,0,y,image->columns,1, |
3993 | 2.91k | exception); |
3994 | 2.91k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
3995 | 2.91k | if ((s == (const PixelPacket *) NULL) || |
3996 | 2.91k | (q == (PixelPacket *) NULL)) |
3997 | 0 | break; |
3998 | 2.91k | (void) memcpy(q,s,length); |
3999 | 2.91k | if (!SyncImagePixels(image)) |
4000 | 0 | break; |
4001 | 2.91k | } |
4002 | 2.91k | DestroyImage(jng_image); |
4003 | 2.91k | jng_image = (Image *)NULL; |
4004 | 2.91k | if ((unsigned long) y != image->rows) |
4005 | 0 | { |
4006 | 0 | if (logging) |
4007 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4008 | 0 | "Failed to transfer JPEG scanlines"); |
4009 | 0 | DestroyJNG(NULL,&color_image,&color_image_info, |
4010 | 0 | &alpha_image,&alpha_image_info); |
4011 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); |
4012 | 0 | return ((Image *)NULL); |
4013 | 0 | } |
4014 | 2.91k | if (alpha_image != (Image *)NULL && !image_info->ping) |
4015 | 2.90k | { |
4016 | 2.90k | if (jng_color_type >= 12) |
4017 | 2.90k | { |
4018 | | /* |
4019 | | Alpha is stored in PNG or JPEG format: |
4020 | | Alpha_compression_method: |
4021 | | 1 byte. |
4022 | | 0: PNG grayscale IDAT format. |
4023 | | 8: JNG 8-bit grayscale JDAA format |
4024 | | */ |
4025 | 2.90k | const char *jng_alpha_magick= |
4026 | 2.90k | (jng_alpha_compression_method == 0 ? "PNG" : |
4027 | 2.90k | (jng_alpha_compression_method == 8 ? "JPEG" : |
4028 | 11 | "UNKNOWN")); |
4029 | 2.90k | if (jng_alpha_compression_method == 0) |
4030 | 2.89k | { |
4031 | 2.89k | png_byte |
4032 | 2.89k | data[5]; |
4033 | 2.89k | (void) WriteBlobMSBULong(alpha_image,0x00000000L); |
4034 | 2.89k | PNGType(data,mng_IEND); |
4035 | 2.89k | LogPNGChunk(logging,mng_IEND,0L); |
4036 | 2.89k | (void) WriteBlob(alpha_image,4,(char *) data); |
4037 | 2.89k | (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4)); |
4038 | 2.89k | } |
4039 | 2.90k | status &= CloseBlob(alpha_image); |
4040 | 2.90k | if (logging) |
4041 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4042 | 0 | " Reading opacity from %s alpha_blob.", |
4043 | 0 | jng_alpha_magick); |
4044 | 2.90k | MagickFormatString(alpha_image_info->filename,sizeof(alpha_image_info->filename), |
4045 | 2.90k | "%s:%.1024s", jng_alpha_magick, alpha_image->filename); |
4046 | 2.90k | alpha_image_info->subimage=0; |
4047 | 2.90k | alpha_image_info->subrange=1; |
4048 | | |
4049 | 2.90k | jng_image=ReadImage(alpha_image_info,exception); |
4050 | | |
4051 | 2.90k | if (jng_image == (Image *)NULL) |
4052 | 2.18k | { |
4053 | 2.18k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4054 | 2.18k | " jng_image is NULL."); |
4055 | 2.18k | DestroyJNG(NULL,&color_image,&color_image_info, |
4056 | 2.18k | &alpha_image,&alpha_image_info); |
4057 | 2.18k | } |
4058 | 721 | else |
4059 | 721 | { |
4060 | | |
4061 | 721 | if (logging) |
4062 | 0 | { |
4063 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4064 | 0 | " Read jng_image (%s)",image->magick); |
4065 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4066 | 0 | " jng_image->width=%lu, jng_image->height=%lu", |
4067 | 0 | (unsigned long)jng_width,(unsigned long)jng_height); |
4068 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4069 | 0 | " image->rows=%lu, image->columns=%lu", |
4070 | 0 | (unsigned long)image->rows, |
4071 | 0 | (unsigned long)image->columns); |
4072 | 0 | } |
4073 | | |
4074 | 1.44k | for (y=0; y < (long) image->rows; y++) |
4075 | 721 | { |
4076 | 721 | s=AcquireImagePixels(jng_image,0,y,image->columns,1, |
4077 | 721 | &image->exception); |
4078 | 721 | if (s == (PixelPacket *) NULL) |
4079 | 0 | break; |
4080 | 721 | if (image->matte) |
4081 | 0 | { |
4082 | 0 | q=SetImagePixels(image,0,y,image->columns,1); |
4083 | 0 | if (q == (PixelPacket *) NULL) |
4084 | 0 | break; |
4085 | 0 | for (x=(long) image->columns; x > 0; x--,q++,s++) |
4086 | 0 | q->opacity=(Quantum) MaxRGB-s->red; |
4087 | 0 | } |
4088 | 721 | else |
4089 | 721 | { |
4090 | 721 | q=SetImagePixels(image,0,y,image->columns,1); |
4091 | 721 | if (q == (PixelPacket *) NULL) |
4092 | 0 | break; |
4093 | 1.44k | for (x=(long) image->columns; x > 0; x--,q++,s++) |
4094 | 721 | { |
4095 | 721 | q->opacity=(Quantum) MaxRGB-s->red; |
4096 | 721 | if (q->opacity != OpaqueOpacity) |
4097 | 639 | image->matte=MagickTrue; |
4098 | 721 | } |
4099 | 721 | } |
4100 | 721 | if (!SyncImagePixels(image)) |
4101 | 0 | break; |
4102 | 721 | } |
4103 | 721 | DestroyJNG(NULL,&color_image,&color_image_info, |
4104 | 721 | &alpha_image,&alpha_image_info); |
4105 | 721 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4106 | 721 | " Destroy the JNG image"); |
4107 | 721 | DestroyImageList(jng_image); |
4108 | 721 | jng_image = (Image *)NULL; |
4109 | 721 | } |
4110 | 2.90k | } |
4111 | 2.90k | } |
4112 | | |
4113 | | /* |
4114 | | Read the JNG image. |
4115 | | */ |
4116 | 2.91k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4117 | 2.91k | " Read the JNG image"); |
4118 | 2.91k | image->page.width=jng_width; |
4119 | 2.91k | image->page.height=jng_height; |
4120 | 2.91k | image->page.x=mng_info->x_off[mng_info->object_id]; |
4121 | 2.91k | image->page.y=mng_info->y_off[mng_info->object_id]; |
4122 | 2.91k | mng_info->image_found++; |
4123 | 2.91k | if (QuantumTick(2*GetBlobSize(image),2*GetBlobSize(image))) |
4124 | 795 | (void) MagickMonitorFormatted(2*GetBlobSize(image),2*GetBlobSize(image), |
4125 | 795 | exception,LoadImagesText,image->filename); |
4126 | 2.91k | } |
4127 | | |
4128 | | /* Clean up in case we didn't earlier */ |
4129 | | |
4130 | 2.91k | DestroyJNG(NULL,&color_image,&color_image_info, |
4131 | 2.91k | &alpha_image,&alpha_image_info); |
4132 | | |
4133 | 2.91k | if (logging) |
4134 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4135 | 0 | " exit ReadOneJNGImage()"); |
4136 | | |
4137 | 2.91k | SetMagickResourceLimit(WidthResource,width_resource); |
4138 | 2.91k | SetMagickResourceLimit(HeightResource,height_resource); |
4139 | | |
4140 | 2.91k | StopTimer(&image->timer); |
4141 | | |
4142 | 2.91k | return (image); |
4143 | 14.0k | } |
4144 | | |
4145 | | /* |
4146 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4147 | | % % |
4148 | | % % |
4149 | | % % |
4150 | | % R e a d J N G I m a g e % |
4151 | | % % |
4152 | | % % |
4153 | | % % |
4154 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4155 | | % |
4156 | | % Method ReadJNGImage reads a JPEG Network Graphics (JNG) image file |
4157 | | % (including the 8-byte signature) and returns it. It allocates the memory |
4158 | | % necessary for the new Image structure and returns a pointer to the new |
4159 | | % image. |
4160 | | % |
4161 | | % JNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu. |
4162 | | % |
4163 | | % The format of the ReadJNGImage method is: |
4164 | | % |
4165 | | % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo |
4166 | | % *exception) |
4167 | | % |
4168 | | % A description of each parameter follows: |
4169 | | % |
4170 | | % o image: Method ReadJNGImage returns a pointer to the image after |
4171 | | % reading. A null image is returned if there is a memory shortage or |
4172 | | % if the image cannot be read. |
4173 | | % |
4174 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
4175 | | % |
4176 | | % o exception: return any errors or warnings in this structure. |
4177 | | % |
4178 | | */ |
4179 | | |
4180 | | static Image *ReadJNGImage(const ImageInfo *image_info, |
4181 | | ExceptionInfo *exception) |
4182 | 44.7k | { |
4183 | 44.7k | Image |
4184 | 44.7k | *image; |
4185 | | |
4186 | 44.7k | MngInfo |
4187 | 44.7k | *mng_info; |
4188 | | |
4189 | 44.7k | char |
4190 | 44.7k | magic_number[MaxTextExtent]; |
4191 | | |
4192 | 44.7k | int |
4193 | 44.7k | have_mng_structure, |
4194 | 44.7k | logging; |
4195 | | |
4196 | 44.7k | unsigned int |
4197 | 44.7k | status; |
4198 | | |
4199 | | /* |
4200 | | Open image file. |
4201 | | */ |
4202 | 44.7k | assert(image_info != (const ImageInfo *) NULL); |
4203 | 44.7k | assert(image_info->signature == MagickSignature); |
4204 | 44.7k | assert(exception != (ExceptionInfo *) NULL); |
4205 | 44.7k | assert(exception->signature == MagickSignature); |
4206 | 44.7k | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()"); |
4207 | 44.7k | image=AllocateImage(image_info); |
4208 | 44.7k | mng_info=(MngInfo *) NULL; |
4209 | 44.7k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
4210 | 44.7k | if (status == MagickFalse) |
4211 | 0 | { |
4212 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Unable to open file"); |
4213 | 0 | ThrowException(exception,FileOpenError,UnableToOpenFile,image->filename); |
4214 | 0 | DestroyImageList(image); |
4215 | 0 | image=(Image *) NULL; |
4216 | 0 | return ((Image *)NULL); |
4217 | 0 | } |
4218 | 44.7k | if (LocaleCompare(image_info->magick,"JNG") != 0) |
4219 | 0 | { |
4220 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header"); |
4221 | 0 | ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename); |
4222 | 0 | DestroyImageList(image); |
4223 | 0 | image=(Image *) NULL; |
4224 | 0 | return((Image *)NULL); |
4225 | 0 | } |
4226 | | /* |
4227 | | Verify JNG signature. |
4228 | | */ |
4229 | 44.7k | if ((ReadBlob(image,8,magic_number) != 8) || |
4230 | 44.7k | (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)) |
4231 | 76 | { |
4232 | 76 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header"); |
4233 | 76 | ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename); |
4234 | 76 | DestroyImageList(image); |
4235 | 76 | image=(Image *) NULL; |
4236 | 76 | return((Image *)NULL); |
4237 | 76 | } |
4238 | | |
4239 | 44.6k | if (BlobIsSeekable(image) && GetBlobSize(image) < 147) |
4240 | 624 | { |
4241 | 624 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4242 | 624 | "Insufficient Image Data"); |
4243 | 624 | ThrowException(exception,CorruptImageError,InsufficientImageDataInFile,image->filename); |
4244 | 624 | DestroyImageList(image); |
4245 | 624 | image=(Image *) NULL; |
4246 | 624 | return((Image *)NULL); |
4247 | 624 | } |
4248 | | |
4249 | | /* |
4250 | | Allocate a MngInfo structure. |
4251 | | */ |
4252 | 44.0k | have_mng_structure=MagickFalse; |
4253 | 44.0k | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
4254 | 44.0k | if (mng_info == (MngInfo *) NULL) |
4255 | 0 | { |
4256 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4257 | 0 | "Memory Allocation Failed"); |
4258 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename); |
4259 | 0 | DestroyImageList(image); |
4260 | 0 | image=(Image *) NULL; |
4261 | 0 | return((Image *)NULL); |
4262 | 0 | } |
4263 | | /* |
4264 | | Initialize members of the MngInfo structure. |
4265 | | */ |
4266 | 44.0k | (void) memset(mng_info,0,sizeof(MngInfo)); |
4267 | 44.0k | have_mng_structure=MagickTrue; |
4268 | | |
4269 | 44.0k | mng_info->image=image; |
4270 | 44.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOneJNGImage()"); |
4271 | 44.0k | image=ReadOneJNGImage(mng_info,image_info,exception); |
4272 | 44.0k | if (image == (Image *) NULL || image->columns == 0 || image->rows == 0) |
4273 | 41.1k | { |
4274 | 41.1k | if (logging) |
4275 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4276 | 0 | "exit ReadJNGImage() with error"); |
4277 | 41.1k | if (image != (Image *) NULL) |
4278 | 0 | { |
4279 | 0 | DestroyImageList(image); |
4280 | 0 | image=(Image *) NULL; |
4281 | 0 | } |
4282 | 41.1k | if (mng_info->image != (Image *) NULL) |
4283 | 41.1k | { |
4284 | 41.1k | DestroyImageList(mng_info->image); |
4285 | 41.1k | mng_info->image=(Image *) NULL; |
4286 | 41.1k | } |
4287 | 41.1k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4288 | 41.1k | return((Image *)NULL); |
4289 | 41.1k | } |
4290 | | |
4291 | 2.91k | status &= CloseBlob(image); |
4292 | 2.91k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4293 | | |
4294 | 2.91k | if (logging) |
4295 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()"); |
4296 | 2.91k | return (image); |
4297 | 44.0k | } |
4298 | | #endif |
4299 | | |
4300 | | static Image *ReadMNGImage(const ImageInfo *image_info, |
4301 | | ExceptionInfo *exception) |
4302 | 259k | { |
4303 | 259k | char |
4304 | 259k | page_geometry[MaxTextExtent]; |
4305 | | |
4306 | 259k | Image |
4307 | 259k | *image; |
4308 | | |
4309 | 259k | int |
4310 | 259k | have_mng_structure; |
4311 | | |
4312 | 259k | volatile int |
4313 | 259k | first_mng_object, |
4314 | 259k | logging, |
4315 | 259k | object_id, |
4316 | 259k | term_chunk_found, |
4317 | 259k | skip_to_iend; |
4318 | | |
4319 | 259k | volatile long |
4320 | 259k | image_count=0; |
4321 | | |
4322 | 259k | MngInfo |
4323 | 259k | *mng_info; |
4324 | | |
4325 | 259k | MngBox |
4326 | 259k | default_fb, |
4327 | 259k | fb, |
4328 | 259k | previous_fb; |
4329 | | |
4330 | 259k | #ifdef MNG_INSERT_LAYERS |
4331 | 259k | PixelPacket |
4332 | 259k | mng_background_color; |
4333 | 259k | #endif |
4334 | | |
4335 | 259k | register long |
4336 | 259k | i; |
4337 | | |
4338 | 259k | size_t |
4339 | 259k | count; |
4340 | | |
4341 | 259k | short |
4342 | 259k | loop_level |
4343 | | #if defined(PNG_DEBUG_LOOPS_ACTIVE) |
4344 | | ,loops_active = 0 |
4345 | | #endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */ |
4346 | 259k | ; |
4347 | | |
4348 | 259k | volatile short |
4349 | 259k | skipping_loop; |
4350 | | |
4351 | 259k | unsigned int |
4352 | 259k | #ifdef MNG_INSERT_LAYERS |
4353 | 259k | mandatory_back=0, |
4354 | 259k | #endif |
4355 | 259k | status; |
4356 | | |
4357 | 259k | volatile unsigned int |
4358 | | #ifdef MNG_OBJECT_BUFFERS |
4359 | | mng_background_object=0, |
4360 | | #endif |
4361 | 259k | mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */ |
4362 | | |
4363 | 259k | unsigned long |
4364 | 259k | default_frame_timeout, |
4365 | 259k | frame_timeout, |
4366 | 259k | #ifdef MNG_INSERT_LAYERS |
4367 | 259k | image_height, |
4368 | 259k | image_width, |
4369 | 259k | #endif |
4370 | 259k | length; |
4371 | | |
4372 | 259k | volatile unsigned long |
4373 | 259k | default_frame_delay, |
4374 | 259k | final_delay, |
4375 | 259k | final_image_delay, |
4376 | 259k | frame_delay, |
4377 | 259k | #ifdef MNG_INSERT_LAYERS |
4378 | 259k | insert_layers, |
4379 | 259k | #endif |
4380 | 259k | mng_iterations=1, |
4381 | 259k | simplicity=0, |
4382 | 259k | subframe_height=0, |
4383 | 259k | subframe_width=0; |
4384 | | |
4385 | 259k | magick_off_t |
4386 | 259k | blob_size; |
4387 | | |
4388 | 259k | previous_fb.top=0; |
4389 | 259k | previous_fb.bottom=0; |
4390 | 259k | previous_fb.left=0; |
4391 | 259k | previous_fb.right=0; |
4392 | 259k | default_fb.top=0; |
4393 | 259k | default_fb.bottom=0; |
4394 | 259k | default_fb.left=0; |
4395 | 259k | default_fb.right=0; |
4396 | | |
4397 | | /* |
4398 | | Open image file. |
4399 | | */ |
4400 | 259k | assert(image_info != (const ImageInfo *) NULL); |
4401 | 259k | assert(image_info->signature == MagickSignature); |
4402 | 259k | assert(exception != (ExceptionInfo *) NULL); |
4403 | 259k | assert(exception->signature == MagickSignature); |
4404 | 259k | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()"); |
4405 | 259k | image=AllocateImage(image_info); |
4406 | 259k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ALLOCATED %p", image); |
4407 | 259k | mng_info=(MngInfo *) NULL; |
4408 | 259k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
4409 | 259k | if (status == MagickFalse) |
4410 | 259k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
4411 | 259k | blob_size=GetBlobSize(image); |
4412 | 259k | first_mng_object=MagickFalse; |
4413 | 259k | skipping_loop=(-1); |
4414 | 259k | have_mng_structure=MagickFalse; |
4415 | | /* |
4416 | | Allocate a MngInfo structure. |
4417 | | */ |
4418 | 259k | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
4419 | 259k | if (mng_info == (MngInfo *) NULL) |
4420 | 259k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
4421 | | /* |
4422 | | Initialize members of the MngInfo structure. |
4423 | | */ |
4424 | 259k | (void) memset(mng_info,0,sizeof(MngInfo)); |
4425 | 259k | mng_info->image=image; |
4426 | 259k | have_mng_structure=MagickTrue; |
4427 | | |
4428 | 259k | if (LocaleCompare(image_info->magick,"MNG") == 0) |
4429 | 259k | { |
4430 | 259k | char |
4431 | 259k | magic_number[MaxTextExtent]; |
4432 | | |
4433 | | /* |
4434 | | Verify MNG signature. |
4435 | | */ |
4436 | 259k | if ((ReadBlob(image,8,magic_number) != 8) || |
4437 | 259k | (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)) |
4438 | 71 | { |
4439 | 71 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4440 | 71 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
4441 | 0 | } |
4442 | | /* |
4443 | | Initialize some nonzero members of the MngInfo structure. |
4444 | | */ |
4445 | 66.6M | for (i=0; i < MNG_MAX_OBJECTS; i++) |
4446 | 66.4M | { |
4447 | 66.4M | mng_info->object_clip[i].right=PNG_MAX_UINT; |
4448 | 66.4M | mng_info->object_clip[i].bottom=PNG_MAX_UINT; |
4449 | 66.4M | } |
4450 | 259k | mng_info->exists[0]=MagickTrue; |
4451 | 259k | } |
4452 | 259k | first_mng_object=MagickTrue; |
4453 | 259k | mng_type=0; |
4454 | 259k | #ifdef MNG_INSERT_LAYERS |
4455 | 259k | insert_layers=MagickFalse; /* should be False if converting or mogrifying */ |
4456 | 259k | #endif |
4457 | 259k | default_frame_delay=0; |
4458 | 259k | default_frame_timeout=0; |
4459 | 259k | frame_delay=0; |
4460 | 259k | final_delay=1; |
4461 | 259k | mng_info->ticks_per_second=100; |
4462 | 259k | object_id=0; |
4463 | 259k | skip_to_iend=MagickFalse; |
4464 | 259k | term_chunk_found=MagickFalse; |
4465 | 259k | mng_info->framing_mode=1; |
4466 | 259k | #ifdef MNG_INSERT_LAYERS |
4467 | 259k | mandatory_back=MagickFalse; |
4468 | 259k | #endif |
4469 | 259k | #ifdef MNG_INSERT_LAYERS |
4470 | 259k | mng_background_color=image->background_color; |
4471 | 259k | #endif |
4472 | 259k | do |
4473 | 1.58M | { |
4474 | 1.58M | char |
4475 | 1.58M | type[MaxTextExtent]; |
4476 | | |
4477 | 1.58M | if (LocaleCompare(image_info->magick,"MNG") == 0) |
4478 | 1.58M | { |
4479 | 1.58M | register unsigned char |
4480 | 1.58M | *p = 0; |
4481 | | |
4482 | 1.58M | unsigned char |
4483 | 1.58M | *chunk = (unsigned char *) NULL; |
4484 | | |
4485 | | /* |
4486 | | Read a new chunk. |
4487 | | */ |
4488 | 1.58M | type[0]='\0'; |
4489 | 1.58M | (void) strlcat(type,"errr",sizeof(type)); |
4490 | 1.58M | length=(size_t) ReadBlobMSBLong(image); |
4491 | 1.58M | count=ReadBlob(image,4,type); |
4492 | 1.58M | if (count != 4) |
4493 | 44.4k | { |
4494 | 44.4k | if (logging) |
4495 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4496 | 0 | " Reading MNG chunk, count: " |
4497 | 0 | "%" MAGICK_SIZE_T_F "u", |
4498 | 0 | (MAGICK_SIZE_T) count); |
4499 | 44.4k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4500 | 44.4k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4501 | 0 | } |
4502 | | |
4503 | 1.53M | if (logging) |
4504 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4505 | 0 | " Reading MNG chunk type %c%c%c%c," |
4506 | 0 | " length: %lu", |
4507 | 0 | type[0],type[1],type[2],type[3],length); |
4508 | | |
4509 | 1.53M | if (length > PNG_MAX_UINT) |
4510 | 24.6k | { |
4511 | 24.6k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4512 | 24.6k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4513 | 0 | } |
4514 | 1.51M | if (length > (size_t) blob_size) |
4515 | 85.5k | { |
4516 | 85.5k | if (image->logging) |
4517 | 85.5k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4518 | 85.5k | "chunk length (%" MAGICK_SIZE_T_F "u)" |
4519 | 85.5k | " is greater than input size" |
4520 | 85.5k | " (%" MAGICK_OFF_F "d)", |
4521 | 85.5k | (MAGICK_SIZE_T) length, |
4522 | 85.5k | blob_size); |
4523 | 85.5k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4524 | 85.5k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4525 | 0 | } |
4526 | 1.42M | if (length) |
4527 | 574k | { |
4528 | 574k | chunk=MagickAllocateMemory(unsigned char *,length); |
4529 | 574k | if (chunk == (unsigned char *) NULL) |
4530 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
4531 | 574k | image); |
4532 | 574k | if (ReadBlob(image,length,chunk) != length) |
4533 | 15.7k | { |
4534 | 15.7k | MagickFreeMemory(chunk); |
4535 | 15.7k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4536 | 15.7k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4537 | 0 | } |
4538 | 558k | p=chunk; |
4539 | 558k | } |
4540 | 1.41M | (void) ReadBlobMSBLong(image); /* read crc word */ |
4541 | | |
4542 | | #if !defined(JNG_SUPPORTED) |
4543 | | if (!memcmp(type,mng_JHDR,4)) |
4544 | | { |
4545 | | skip_to_iend=MagickTrue; |
4546 | | if (!mng_info->jhdr_warning) |
4547 | | (void) ThrowException(exception,CoderError, |
4548 | | JNGCompressionNotSupported, |
4549 | | image->filename); |
4550 | | mng_info->jhdr_warning++; |
4551 | | } |
4552 | | #endif |
4553 | 1.41M | if (!memcmp(type,mng_DHDR,4)) |
4554 | 2.91k | { |
4555 | 2.91k | skip_to_iend=MagickTrue; |
4556 | 2.91k | if (!mng_info->dhdr_warning) |
4557 | 1.60k | (void) ThrowException(exception,CoderError, |
4558 | 2.91k | DeltaPNGNotSupported,image->filename); |
4559 | 2.91k | mng_info->dhdr_warning++; |
4560 | 2.91k | } |
4561 | 1.41M | if (!memcmp(type,mng_MEND,4)) |
4562 | 7.21k | { |
4563 | 7.21k | MagickFreeMemory(chunk); |
4564 | 7.21k | break; |
4565 | 7.21k | } |
4566 | 1.40M | if (skip_to_iend) |
4567 | 12.1k | { |
4568 | 12.1k | if (!memcmp(type,mng_IEND,4)) |
4569 | 1.29k | skip_to_iend=MagickFalse; |
4570 | 12.1k | MagickFreeMemory(chunk); |
4571 | 12.1k | if (logging) |
4572 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4573 | 0 | " Skip to IEND."); |
4574 | 12.1k | continue; |
4575 | 12.1k | } |
4576 | 1.39M | if (!memcmp(type,mng_MHDR,4)) |
4577 | 31.9k | { |
4578 | 31.9k | if (length < 16) |
4579 | 8.14k | { |
4580 | 8.14k | MagickFreeMemory(chunk); |
4581 | 8.14k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4582 | 8.14k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4583 | 0 | } |
4584 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
4585 | | /* To quiet a Coverity complaint */ |
4586 | | LockSemaphoreInfo(png_semaphore); |
4587 | | #endif |
4588 | 23.7k | mng_info->mng_width=(unsigned long) mng_get_long(p); |
4589 | 23.7k | mng_info->mng_height=(unsigned long) mng_get_long(&p[4]); |
4590 | 23.7k | if (logging) |
4591 | 0 | { |
4592 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4593 | 0 | " MNG width: %lu", |
4594 | 0 | mng_info->mng_width); |
4595 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4596 | 0 | " MNG height: %lu", |
4597 | 0 | mng_info->mng_height); |
4598 | 0 | } |
4599 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
4600 | | UnlockSemaphoreInfo(png_semaphore); |
4601 | | #endif |
4602 | 23.7k | if ((mng_info->mng_width == 0) || |
4603 | 12.9k | (mng_info->mng_height == 0)) |
4604 | 13.7k | { |
4605 | 13.7k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4606 | 13.7k | " MNG width or height is zero: width %lu, height %lu", |
4607 | 13.7k | mng_info->mng_width,mng_info->mng_height); |
4608 | 13.7k | MagickFreeMemory(chunk); |
4609 | 13.7k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4610 | 13.7k | ThrowReaderException(CorruptImageError,ImproperImageHeader, |
4611 | 13.7k | image); |
4612 | 0 | } |
4613 | 10.0k | if ((long) mng_info->mng_width > |
4614 | 10.0k | GetMagickResourceLimit(WidthResource) || |
4615 | 7.06k | (long) mng_info->mng_height > |
4616 | 7.06k | GetMagickResourceLimit(HeightResource)) |
4617 | 3.57k | { |
4618 | 3.57k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4619 | 3.57k | " MNG width or height too large: width %lu, height %lu", |
4620 | 3.57k | mng_info->mng_width,mng_info->mng_height); |
4621 | 3.57k | MagickFreeMemory(chunk); |
4622 | 3.57k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4623 | 3.57k | ThrowReaderException(CorruptImageError,ImproperImageHeader, |
4624 | 3.57k | image); |
4625 | 0 | } |
4626 | | |
4627 | 6.49k | p+=8; |
4628 | 6.49k | mng_info->ticks_per_second=mng_get_long(p); |
4629 | 6.49k | if (mng_info->ticks_per_second == 0) |
4630 | 3.50k | default_frame_delay=0; |
4631 | 2.98k | else |
4632 | 2.98k | default_frame_delay=100/mng_info->ticks_per_second; |
4633 | 6.49k | frame_delay=default_frame_delay; |
4634 | 6.49k | simplicity=0; |
4635 | 6.49k | if (length >= 28) |
4636 | 330 | { |
4637 | 330 | p+=16; |
4638 | 330 | simplicity=mng_get_long(p); |
4639 | 330 | } |
4640 | 6.49k | if (logging) |
4641 | 0 | { |
4642 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4643 | 0 | " MNG simplicity: %lx",simplicity); |
4644 | 0 | } |
4645 | 6.49k | mng_type=1; /* Full MNG */ |
4646 | 6.49k | if ((simplicity != 0) && ((simplicity | 11) == 11)) |
4647 | 94 | mng_type=2; /* LC */ |
4648 | 6.49k | if ((simplicity != 0) && ((simplicity | 9) == 9)) |
4649 | 62 | mng_type=3; /* VLC */ |
4650 | 6.49k | #ifdef MNG_INSERT_LAYERS |
4651 | 6.49k | if (mng_type != 3 && !image_info->ping) |
4652 | 6.43k | insert_layers=MagickTrue; |
4653 | 6.49k | #endif |
4654 | 6.49k | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
4655 | 253 | { |
4656 | 253 | StopTimer(&image->timer); |
4657 | | /* |
4658 | | Allocate next image structure. |
4659 | | */ |
4660 | 253 | AllocateNextImage(image_info,image); |
4661 | 253 | if (image->next == (Image *) NULL) |
4662 | 0 | { |
4663 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
4664 | 0 | return((Image *) NULL); |
4665 | 0 | } |
4666 | 253 | image=SyncNextImageInList(image); |
4667 | 253 | mng_info->image=image; |
4668 | 253 | } |
4669 | | |
4670 | 6.49k | if ((mng_info->mng_width > 65535L) || |
4671 | 6.49k | (mng_info->mng_height > 65535L)) |
4672 | 0 | { |
4673 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4674 | 0 | " MNG width or height is too large: %lu, %lu", |
4675 | 0 | mng_info->mng_width,mng_info->mng_height); |
4676 | 0 | MagickFreeMemory(chunk); |
4677 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4678 | 0 | ThrowReaderException(CorruptImageError, |
4679 | 0 | ImproperImageHeader,image); |
4680 | 0 | } |
4681 | | |
4682 | 6.49k | MagickFormatString(page_geometry,sizeof(page_geometry),"%lux%lu+0+0", |
4683 | 6.49k | mng_info->mng_width,mng_info->mng_height); |
4684 | 6.49k | mng_info->frame.left=0; |
4685 | 6.49k | mng_info->frame.right=(long) mng_info->mng_width; |
4686 | 6.49k | mng_info->frame.top=0; |
4687 | 6.49k | mng_info->frame.bottom=(long) mng_info->mng_height; |
4688 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
4689 | | /* To quiet a Coverity complaint */ |
4690 | | LockSemaphoreInfo(png_semaphore); |
4691 | | #endif |
4692 | 6.49k | mng_info->clip=default_fb=previous_fb=mng_info->frame; |
4693 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
4694 | | UnlockSemaphoreInfo(png_semaphore); |
4695 | | #endif |
4696 | 1.66M | for (i=0; i < MNG_MAX_OBJECTS; i++) |
4697 | 1.66M | mng_info->object_clip[i]=mng_info->frame; |
4698 | 6.49k | MagickFreeMemory(chunk); |
4699 | 6.49k | continue; |
4700 | 6.49k | } |
4701 | | |
4702 | 1.36M | if (!memcmp(type,mng_TERM,4)) |
4703 | 13.5k | { |
4704 | 13.5k | int |
4705 | 13.5k | repeat=0; |
4706 | | |
4707 | 13.5k | if (length) |
4708 | 9.85k | repeat=p[0]; |
4709 | 13.5k | if (repeat == 3 && length > 9) |
4710 | 1.01k | { |
4711 | 1.01k | final_delay=(png_uint_32) mng_get_long(&p[2]); |
4712 | 1.01k | mng_iterations=(png_uint_32) mng_get_long(&p[6]); |
4713 | 1.01k | if (mng_iterations == PNG_MAX_UINT) |
4714 | 142 | mng_iterations=0; |
4715 | 1.01k | image->iterations=mng_iterations; |
4716 | 1.01k | term_chunk_found=MagickTrue; |
4717 | 1.01k | } |
4718 | 13.5k | if (logging) |
4719 | 0 | { |
4720 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4721 | 0 | " repeat=%d",repeat); |
4722 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4723 | 0 | " final_delay=%ld",final_delay); |
4724 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4725 | 0 | " image->iterations=%ld", |
4726 | 0 | image->iterations); |
4727 | 0 | } |
4728 | 13.5k | MagickFreeMemory(chunk); |
4729 | 13.5k | continue; |
4730 | 13.5k | } |
4731 | 1.34M | if (!memcmp(type,mng_DEFI,4)) |
4732 | 57.8k | { |
4733 | 57.8k | if (mng_type == 3) |
4734 | 136 | { |
4735 | 136 | if (logging) |
4736 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4737 | 0 | "DEFI chunk found in MNG-VLC" |
4738 | 0 | " datastream"); |
4739 | 136 | MagickFreeMemory(chunk); |
4740 | 136 | continue; |
4741 | 136 | } |
4742 | 57.7k | if (length < 2) |
4743 | 2.79k | { |
4744 | 2.79k | if (logging) |
4745 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4746 | 0 | " DEFI chunk must be at least" |
4747 | 0 | " 2 bytes long"); |
4748 | 2.79k | MagickFreeMemory(chunk); |
4749 | 2.79k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4750 | 2.79k | ThrowReaderException(CorruptImageError,CorruptImage,image); |
4751 | 0 | } |
4752 | 54.9k | object_id=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1]; |
4753 | 54.9k | if (mng_type == 2 && object_id != 0) |
4754 | 181 | (void) ThrowException2(exception,CoderError, |
4755 | 54.9k | "Nonzero object_id in MNG-LC" |
4756 | 54.9k | " datastream", |
4757 | 54.9k | (char *) NULL); |
4758 | 54.9k | if (object_id >= MNG_MAX_OBJECTS) |
4759 | 49.7k | { |
4760 | | /* |
4761 | | Instead of issuing a warning we should allocate a larger |
4762 | | MngInfo structure and continue. |
4763 | | */ |
4764 | 49.7k | if (logging) |
4765 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4766 | 0 | "object id (%u) too large", object_id); |
4767 | 49.7k | object_id=MNG_MAX_OBJECTS-1; |
4768 | 49.7k | } |
4769 | 54.9k | if (mng_info->exists[object_id]) |
4770 | 5.88k | if (mng_info->frozen[object_id]) |
4771 | 1.22k | { |
4772 | 1.22k | if (logging) |
4773 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4774 | 0 | "DEFI cannot redefine a frozen" |
4775 | 0 | " MNG object"); |
4776 | 1.22k | MagickFreeMemory(chunk); |
4777 | 1.22k | continue; |
4778 | 1.22k | } |
4779 | 53.6k | mng_info->exists[object_id]=MagickTrue; |
4780 | 53.6k | if (length > 2) |
4781 | 51.8k | mng_info->invisible[object_id]=p[2]; |
4782 | | /* |
4783 | | Extract object offset info. |
4784 | | */ |
4785 | 53.6k | if (length > 11) |
4786 | 50.7k | { |
4787 | 50.7k | mng_info->x_off[object_id]= mng_get_long(&p[4]); |
4788 | 50.7k | mng_info->y_off[object_id]= mng_get_long(&p[8]); |
4789 | 50.7k | if (logging) |
4790 | 0 | { |
4791 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4792 | 0 | " x_off[%d]: %lu",object_id, |
4793 | 0 | mng_info->x_off[object_id]); |
4794 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4795 | 0 | " y_off[%d]: %lu",object_id, |
4796 | 0 | mng_info->y_off[object_id]); |
4797 | 0 | } |
4798 | 50.7k | } |
4799 | | /* |
4800 | | Extract object clipping info. |
4801 | | */ |
4802 | 53.6k | if (length > 27) |
4803 | 50.1k | mng_info->object_clip[object_id] |
4804 | 50.1k | =mng_read_box( mng_info->frame,0,&p[12]); |
4805 | 53.6k | MagickFreeMemory(chunk); |
4806 | 53.6k | continue; |
4807 | 54.9k | } |
4808 | 1.28M | if (!memcmp(type,mng_bKGD,4)) |
4809 | 1.96k | { |
4810 | 1.96k | mng_info->have_global_bkgd=MagickFalse; |
4811 | 1.96k | if (length > 5) |
4812 | 526 | { |
4813 | 526 | mng_info->mng_global_bkgd.red |
4814 | 526 | =ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) | |
4815 | 526 | (magick_uint32_t) p[1])); |
4816 | 526 | mng_info->mng_global_bkgd.green |
4817 | 526 | =ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) | |
4818 | 526 | (magick_uint32_t) p[3])); |
4819 | 526 | mng_info->mng_global_bkgd.blue |
4820 | 526 | =ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) | |
4821 | 526 | (magick_uint32_t) p[5])); |
4822 | 526 | mng_info->have_global_bkgd=MagickTrue; |
4823 | 526 | } |
4824 | 1.96k | MagickFreeMemory(chunk); |
4825 | 1.96k | continue; |
4826 | 1.96k | } |
4827 | 1.28M | if (!memcmp(type,mng_BACK,4)) |
4828 | 10.1k | { |
4829 | 10.1k | #ifdef MNG_INSERT_LAYERS |
4830 | 10.1k | if (length > 6) |
4831 | 8.54k | mandatory_back=p[6]; |
4832 | 1.64k | else |
4833 | 1.64k | mandatory_back=0; |
4834 | 10.1k | if (mandatory_back && length > 5) |
4835 | 4.84k | { |
4836 | 4.84k | mng_background_color.red= |
4837 | 4.84k | ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) | |
4838 | 4.84k | (magick_uint32_t) p[1])); |
4839 | 4.84k | mng_background_color.green= |
4840 | 4.84k | ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) | |
4841 | 4.84k | (magick_uint32_t) p[3])); |
4842 | 4.84k | mng_background_color.blue= |
4843 | 4.84k | ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) | |
4844 | 4.84k | (magick_uint32_t) p[5])); |
4845 | 4.84k | mng_background_color.opacity=OpaqueOpacity; |
4846 | 4.84k | } |
4847 | | #ifdef MNG_OBJECT_BUFFERS |
4848 | | if (length > 8) |
4849 | | mng_background_object=((magick_uint32_t) p[7] << 8) | |
4850 | | (magick_uint32_t) p[8]; |
4851 | | #endif |
4852 | 10.1k | #endif |
4853 | 10.1k | MagickFreeMemory(chunk); |
4854 | 10.1k | continue; |
4855 | 10.1k | } |
4856 | 1.27M | if (!memcmp(type,mng_PLTE,4)) |
4857 | 3.39k | { |
4858 | | /* |
4859 | | Read global PLTE. |
4860 | | */ |
4861 | 3.39k | if (length && (length < 769)) |
4862 | 3.00k | { |
4863 | 3.00k | if (mng_info->global_plte == (png_colorp) NULL) |
4864 | 604 | mng_info->global_plte= |
4865 | 604 | MagickAllocateMemory(png_colorp,256*sizeof(png_color)); |
4866 | 3.00k | if (mng_info->global_plte == (png_colorp) NULL) |
4867 | 0 | { |
4868 | 0 | mng_info->global_plte_length=0; |
4869 | 0 | MagickFreeMemory(chunk); |
4870 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
4871 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
4872 | 0 | image); |
4873 | 0 | } |
4874 | 30.4k | for (i=0; i < (long) (length/3); i++) |
4875 | 27.4k | { |
4876 | 27.4k | mng_info->global_plte[i].red=p[3*i]; |
4877 | 27.4k | mng_info->global_plte[i].green=p[3*i+1]; |
4878 | 27.4k | mng_info->global_plte[i].blue=p[3*i+2]; |
4879 | 27.4k | } |
4880 | 3.00k | mng_info->global_plte_length=length/3; |
4881 | 3.00k | } |
4882 | | #ifdef MNG_LOOSE |
4883 | | for ( ; i < 256; i++) |
4884 | | { |
4885 | | mng_info->global_plte[i].red=i; |
4886 | | mng_info->global_plte[i].green=i; |
4887 | | mng_info->global_plte[i].blue=i; |
4888 | | } |
4889 | | if (length) |
4890 | | mng_info->global_plte_length=256; |
4891 | | #endif |
4892 | 395 | else |
4893 | 395 | mng_info->global_plte_length=0; |
4894 | 3.39k | MagickFreeMemory(chunk); |
4895 | 3.39k | continue; |
4896 | 3.39k | } |
4897 | 1.27M | if (!memcmp(type,mng_tRNS,4)) |
4898 | 12.3k | { |
4899 | | /* read global tRNS */ |
4900 | | |
4901 | 12.3k | if (length < 257) |
4902 | 77.1k | for (i=0; i < (long) length; i++) |
4903 | 64.8k | mng_info->global_trns[i]=p[i]; |
4904 | | |
4905 | | #ifdef MNG_LOOSE |
4906 | | for ( ; i < 256; i++) |
4907 | | mng_info->global_trns[i]=255; |
4908 | | #endif |
4909 | 12.3k | mng_info->global_trns_length=length; |
4910 | 12.3k | MagickFreeMemory(chunk); |
4911 | 12.3k | continue; |
4912 | 12.3k | } |
4913 | 1.26M | if (!memcmp(type,mng_gAMA,4)) |
4914 | 1.45k | { |
4915 | 1.45k | if (length == 4) |
4916 | 678 | { |
4917 | 678 | long |
4918 | 678 | igamma; |
4919 | | |
4920 | 678 | igamma=mng_get_long(p); |
4921 | 678 | mng_info->global_gamma=((float) igamma*0.00001f); |
4922 | 678 | mng_info->have_global_gama=MagickTrue; |
4923 | 678 | } |
4924 | 777 | else |
4925 | 777 | mng_info->have_global_gama=MagickFalse; |
4926 | 1.45k | MagickFreeMemory(chunk); |
4927 | 1.45k | continue; |
4928 | 1.45k | } |
4929 | | |
4930 | 1.26M | if (!memcmp(type,mng_cHRM,4)) |
4931 | 5.86k | { |
4932 | | /* |
4933 | | Read global cHRM |
4934 | | */ |
4935 | 5.86k | if (length == 32) |
4936 | 4.18k | { |
4937 | 4.18k | mng_info->global_chrm.white_point.x=0.00001* |
4938 | 4.18k | mng_get_long(p); |
4939 | 4.18k | mng_info->global_chrm.white_point.y=0.00001* |
4940 | 4.18k | mng_get_long(&p[4]); |
4941 | 4.18k | mng_info->global_chrm.red_primary.x=0.00001* |
4942 | 4.18k | mng_get_long(&p[8]); |
4943 | 4.18k | mng_info->global_chrm.red_primary.y=0.00001* |
4944 | 4.18k | mng_get_long(&p[12]); |
4945 | 4.18k | mng_info->global_chrm.green_primary.x=0.00001* |
4946 | 4.18k | mng_get_long(&p[16]); |
4947 | 4.18k | mng_info->global_chrm.green_primary.y=0.00001* |
4948 | 4.18k | mng_get_long(&p[20]); |
4949 | 4.18k | mng_info->global_chrm.blue_primary.x=0.00001* |
4950 | 4.18k | mng_get_long(&p[24]); |
4951 | 4.18k | mng_info->global_chrm.blue_primary.y=0.00001* |
4952 | 4.18k | mng_get_long(&p[28]); |
4953 | 4.18k | mng_info->have_global_chrm=MagickTrue; |
4954 | 4.18k | } |
4955 | 1.67k | else |
4956 | 1.67k | mng_info->have_global_chrm=MagickFalse; |
4957 | 5.86k | MagickFreeMemory(chunk); |
4958 | 5.86k | continue; |
4959 | 5.86k | } |
4960 | 1.25M | if (!memcmp(type,mng_sRGB,4)) |
4961 | 1.12k | { |
4962 | | /* |
4963 | | Read global sRGB. |
4964 | | */ |
4965 | 1.12k | if (length) |
4966 | 636 | { |
4967 | 636 | mng_info->global_srgb_intent=(RenderingIntent) (p[0]+1); |
4968 | 636 | mng_info->have_global_srgb=MagickTrue; |
4969 | 636 | } |
4970 | 484 | else |
4971 | 484 | mng_info->have_global_srgb=MagickFalse; |
4972 | 1.12k | MagickFreeMemory(chunk); |
4973 | 1.12k | continue; |
4974 | 1.12k | } |
4975 | 1.25M | if (!memcmp(type,mng_iCCP,4)) |
4976 | 3.83k | { |
4977 | | /* To do. */ |
4978 | | |
4979 | | /* |
4980 | | Read global iCCP. |
4981 | | */ |
4982 | 3.83k | MagickFreeMemory(chunk); |
4983 | 3.83k | continue; |
4984 | 3.83k | } |
4985 | 1.24M | if (!memcmp(type,mng_FRAM,4)) |
4986 | 112k | { |
4987 | 112k | if (mng_type == 3) |
4988 | 523 | (void) ThrowException2(exception,CoderError, |
4989 | 112k | "FRAM chunk found in MNG-VLC" |
4990 | 112k | " datastream", |
4991 | 112k | (char *) NULL); |
4992 | 112k | if ((mng_info->framing_mode == 2) || |
4993 | 112k | (mng_info->framing_mode == 4)) |
4994 | 32.8k | image->delay=frame_delay; |
4995 | 112k | frame_delay=default_frame_delay; |
4996 | 112k | frame_timeout=default_frame_timeout; |
4997 | 112k | fb=default_fb; |
4998 | 112k | if (length) |
4999 | 108k | if (p[0]) |
5000 | 73.2k | mng_info->framing_mode=p[0]; |
5001 | 112k | if (logging) |
5002 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5003 | 0 | " Framing_mode=%d", |
5004 | 0 | mng_info->framing_mode); |
5005 | 112k | if (length > 6) |
5006 | 107k | { |
5007 | | /* |
5008 | | Note the delay and frame clipping boundaries. |
5009 | | */ |
5010 | 107k | p++; /* framing mode */ |
5011 | 340k | while (((p-chunk) < (long) length) && *p) |
5012 | 232k | p++; /* frame name */ |
5013 | 107k | p++; /* frame name terminator */ |
5014 | 107k | if ((p-chunk) < (long) (length-4)) |
5015 | 70.4k | { |
5016 | 70.4k | int |
5017 | 70.4k | change_delay, |
5018 | 70.4k | change_timeout, |
5019 | 70.4k | change_clipping; |
5020 | | |
5021 | 70.4k | change_delay=(*p++); |
5022 | 70.4k | change_timeout=(*p++); |
5023 | 70.4k | change_clipping=(*p++); |
5024 | 70.4k | p++; /* change_sync */ |
5025 | 70.4k | if (change_delay && ((p-chunk) < (ssize_t) (length-4))) |
5026 | 4.84k | { |
5027 | 4.84k | if (mng_info->ticks_per_second == 0) |
5028 | 119 | frame_delay=0; |
5029 | 4.72k | else |
5030 | 4.72k | frame_delay=(100*(mng_get_long(p))/ |
5031 | 4.72k | mng_info->ticks_per_second); |
5032 | 4.84k | if (change_delay == 2) |
5033 | 268 | default_frame_delay=frame_delay; |
5034 | 4.84k | p+=4; |
5035 | 4.84k | if (logging) |
5036 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5037 | 0 | " Framing_delay=%ld", |
5038 | 0 | frame_delay); |
5039 | 4.84k | } |
5040 | 70.4k | if (change_timeout && (p-chunk) < (ssize_t) (length-4)) |
5041 | 5.22k | { |
5042 | 5.22k | if (mng_info->ticks_per_second == 0) |
5043 | 95 | frame_timeout=0; |
5044 | 5.13k | else |
5045 | 5.13k | frame_timeout= |
5046 | 5.13k | (100*(mng_get_long(p))/mng_info->ticks_per_second); |
5047 | 5.22k | if (change_timeout == 2) |
5048 | 2 | default_frame_timeout=frame_timeout; |
5049 | 5.22k | p+=4; |
5050 | 5.22k | if (logging) |
5051 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5052 | 0 | " Framing_timeout=%ld", |
5053 | 0 | frame_timeout); |
5054 | 5.22k | } |
5055 | 70.4k | if (change_clipping && (p-chunk) < (ssize_t) (length-16)) |
5056 | 53.3k | { |
5057 | 53.3k | fb=mng_read_box(previous_fb,p[0],&p[1]); |
5058 | 53.3k | p+=16; |
5059 | 53.3k | previous_fb=fb; |
5060 | 53.3k | if (logging) |
5061 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5062 | 0 | " Frame_clipping:" |
5063 | 0 | " L=%ld R=%ld T=%ld B=%ld", |
5064 | 0 | fb.left, fb.right,fb.top, |
5065 | 0 | fb.bottom); |
5066 | 53.3k | if (change_clipping == 2) |
5067 | 48.1k | default_fb=fb; |
5068 | 53.3k | } |
5069 | 70.4k | } |
5070 | 107k | } |
5071 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
5072 | | /* To quiet a Coverity complaint */ |
5073 | | LockSemaphoreInfo(png_semaphore); |
5074 | | #endif |
5075 | 112k | mng_info->clip=fb; |
5076 | 112k | mng_info->clip=mng_minimum_box(fb,mng_info->frame); |
5077 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
5078 | | UnlockSemaphoreInfo(png_semaphore); |
5079 | | #endif |
5080 | 112k | subframe_width=(mng_info->clip.right-mng_info->clip.left); |
5081 | 112k | subframe_height=(mng_info->clip.bottom-mng_info->clip.top); |
5082 | | /* |
5083 | | Insert a background layer behind the frame |
5084 | | if framing_mode is 4. |
5085 | | */ |
5086 | 112k | #ifdef MNG_INSERT_LAYERS |
5087 | 112k | if (logging) |
5088 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5089 | 0 | " subframe_width=%lu," |
5090 | 0 | " subframe_height=%lu", |
5091 | 0 | subframe_width, subframe_height); |
5092 | 112k | if (insert_layers && (mng_info->framing_mode == 4) && |
5093 | 32.6k | (subframe_width) && (subframe_height)) |
5094 | 32.2k | { |
5095 | | /* |
5096 | | Allocate next image structure. |
5097 | | */ |
5098 | 32.2k | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
5099 | 31.1k | { |
5100 | 31.1k | StopTimer(&image->timer); |
5101 | 31.1k | AllocateNextImage(image_info,image); |
5102 | 31.1k | if (image->next == (Image *) NULL) |
5103 | 0 | { |
5104 | 0 | DestroyImageList(image); |
5105 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5106 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5107 | 0 | return((Image *) NULL); |
5108 | 0 | } |
5109 | 31.1k | image=SyncNextImageInList(image); |
5110 | 31.1k | } |
5111 | 32.2k | mng_info->image=image; |
5112 | 32.2k | if (term_chunk_found) |
5113 | 116 | { |
5114 | 116 | image->start_loop=MagickTrue; |
5115 | 116 | image->iterations=mng_iterations; |
5116 | 116 | term_chunk_found=MagickFalse; |
5117 | 116 | } |
5118 | 32.0k | else |
5119 | 32.0k | image->start_loop=MagickFalse; |
5120 | 32.2k | image->columns=subframe_width; |
5121 | 32.2k | image->rows=subframe_height; |
5122 | 32.2k | image->page.width=subframe_width; |
5123 | 32.2k | image->page.height=subframe_height; |
5124 | 32.2k | image->page.x=mng_info->clip.left; |
5125 | 32.2k | image->page.y=mng_info->clip.top; |
5126 | 32.2k | image->background_color=mng_background_color; |
5127 | 32.2k | image->matte=MagickFalse; |
5128 | 32.2k | image->delay=0; |
5129 | 32.2k | if (SetImage(image,OpaqueOpacity) != MagickPass) |
5130 | 236 | { |
5131 | 236 | if (logging) |
5132 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5133 | 0 | " Failed to insert background layer," |
5134 | 0 | " L=%ld, R=%ld, T=%ld, B=%ld", |
5135 | 0 | mng_info->clip.left, |
5136 | 0 | mng_info->clip.right, |
5137 | 0 | mng_info->clip.top, |
5138 | 0 | mng_info->clip.bottom); |
5139 | 236 | CopyException(exception,&image->exception); |
5140 | 236 | MagickFreeMemory(chunk); |
5141 | 236 | DestroyImageList(image); |
5142 | 236 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5143 | 236 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5144 | 236 | return((Image *) NULL); |
5145 | 236 | } |
5146 | 31.9k | if (logging) |
5147 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5148 | 0 | " Inserted background layer," |
5149 | 0 | " L=%ld, R=%ld, T=%ld, B=%ld", |
5150 | 0 | mng_info->clip.left, |
5151 | 0 | mng_info->clip.right, |
5152 | 0 | mng_info->clip.top, |
5153 | 0 | mng_info->clip.bottom); |
5154 | 31.9k | } |
5155 | 112k | #endif |
5156 | 112k | MagickFreeMemory(chunk); |
5157 | 112k | continue; |
5158 | 112k | } |
5159 | 1.13M | if (!memcmp(type,mng_CLIP,4)) |
5160 | 5.72k | { |
5161 | 5.72k | unsigned int |
5162 | 5.72k | first_object, |
5163 | 5.72k | last_object; |
5164 | | |
5165 | | /* |
5166 | | Read CLIP. |
5167 | | */ |
5168 | 5.72k | if (length > 3) |
5169 | 2.59k | { |
5170 | 2.59k | first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1]; |
5171 | 2.59k | last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3]; |
5172 | 2.59k | p+=4; |
5173 | | |
5174 | 14.6M | for (i=(int) first_object; i <= (int) last_object; i++) |
5175 | 14.6M | { |
5176 | 14.6M | if (i >= MNG_MAX_OBJECTS) |
5177 | 14.4M | continue; |
5178 | 263k | if (mng_info->exists[i] && !mng_info->frozen[i]) |
5179 | 2.69k | { |
5180 | 2.69k | MngBox |
5181 | 2.69k | box; |
5182 | | |
5183 | 2.69k | box=mng_info->object_clip[i]; |
5184 | 2.69k | if ((p-chunk) < (ssize_t) (length-17)) |
5185 | 1.52k | mng_info->object_clip[i]= |
5186 | 1.52k | mng_read_box(box,p[0],&p[1]); |
5187 | 2.69k | } |
5188 | 263k | } |
5189 | 2.59k | } |
5190 | 5.72k | MagickFreeMemory(chunk); |
5191 | 5.72k | continue; |
5192 | 5.72k | } |
5193 | 1.13M | if (!memcmp(type,mng_SAVE,4)) |
5194 | 27.7k | { |
5195 | 7.09M | for (i=1; i < MNG_MAX_OBJECTS; i++) |
5196 | 7.06M | if (mng_info->exists[i]) |
5197 | 26.4k | { |
5198 | 26.4k | mng_info->frozen[i]=MagickTrue; |
5199 | | #ifdef MNG_OBJECT_BUFFERS |
5200 | | if (mng_info->ob[i] != (MngBuffer *) NULL) |
5201 | | mng_info->ob[i]->frozen=MagickTrue; |
5202 | | #endif |
5203 | 26.4k | } |
5204 | 27.7k | MagickFreeMemory(chunk); |
5205 | 27.7k | continue; |
5206 | 27.7k | } |
5207 | | |
5208 | 1.10M | if (!memcmp(type,mng_DISC,4) || !memcmp(type,mng_SEEK,4)) |
5209 | 15.1k | { |
5210 | | /* |
5211 | | Read DISC or SEEK. |
5212 | | */ |
5213 | 15.1k | if ((length == 0) || (length % 2) || !memcmp(type,mng_SEEK,4)) |
5214 | 9.99k | { |
5215 | 2.55M | for (i=1; i < MNG_MAX_OBJECTS; i++) |
5216 | 2.54M | MngInfoDiscardObject(mng_info,i); |
5217 | 9.99k | } |
5218 | 5.14k | else |
5219 | 5.14k | { |
5220 | 5.14k | register long |
5221 | 5.14k | j; |
5222 | | |
5223 | 179k | for (j=0; j < (long) length; j+=2) |
5224 | 173k | { |
5225 | 173k | i=(magick_uint32_t) p[j] << 8 | (magick_uint32_t) p[j+1]; |
5226 | 173k | MngInfoDiscardObject(mng_info,i); |
5227 | 173k | } |
5228 | 5.14k | } |
5229 | 15.1k | MagickFreeMemory(chunk); |
5230 | 15.1k | continue; |
5231 | 15.1k | } |
5232 | 1.08M | if (!memcmp(type,mng_MOVE,4)) |
5233 | 4.83k | { |
5234 | 4.83k | unsigned long |
5235 | 4.83k | first_object, |
5236 | 4.83k | last_object; |
5237 | | |
5238 | | /* |
5239 | | read MOVE |
5240 | | */ |
5241 | | |
5242 | 4.83k | if (length > 3) |
5243 | 3.86k | { |
5244 | 3.86k | first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1]; |
5245 | 3.86k | last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3]; |
5246 | 3.86k | p+=4; |
5247 | | |
5248 | 28.4M | for (i=(long) first_object; i <= (long) last_object; i++) |
5249 | 28.4M | { |
5250 | 28.4M | if (i >= MNG_MAX_OBJECTS) |
5251 | 28.2M | continue; |
5252 | 218k | if (mng_info->exists[i] && !mng_info->frozen[i] && |
5253 | 1.97k | (p-chunk) < (ssize_t) (length-8)) |
5254 | 787 | { |
5255 | 787 | MngPair |
5256 | 787 | new_pair; |
5257 | | |
5258 | 787 | MngPair |
5259 | 787 | old_pair; |
5260 | | |
5261 | 787 | old_pair.a=mng_info->x_off[i]; |
5262 | 787 | old_pair.b=mng_info->y_off[i]; |
5263 | 787 | new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]); |
5264 | 787 | mng_info->x_off[i]=new_pair.a; |
5265 | 787 | mng_info->y_off[i]=new_pair.b; |
5266 | 787 | } |
5267 | 218k | } |
5268 | 3.86k | } |
5269 | 4.83k | MagickFreeMemory(chunk); |
5270 | 4.83k | continue; |
5271 | 4.83k | } |
5272 | | |
5273 | 1.08M | if (!memcmp(type,mng_LOOP,4)) |
5274 | 4.01k | { |
5275 | 4.01k | long loop_iters=1; |
5276 | | |
5277 | 4.01k | if (logging) |
5278 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5279 | 0 | "Handling LOOP chunk"); |
5280 | 4.01k | if (length >= 5) /* To do: check spec, if empty LOOP is allowed */ |
5281 | 2.86k | { |
5282 | 2.86k | loop_level=chunk[0]; /* 1 byte */ |
5283 | | #if defined(PNG_DEBUG_LOOPS_ACTIVE) |
5284 | | loops_active++; |
5285 | | #endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */ |
5286 | 2.86k | mng_info->loop_active[loop_level]=1; /* mark loop active */ |
5287 | | /* |
5288 | | Record starting point. |
5289 | | */ |
5290 | 2.86k | loop_iters=mng_get_long(&chunk[1]); /* 4 bytes */ |
5291 | 2.86k | if (logging) |
5292 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5293 | 0 | "Loop iterations requested: %ld", loop_iters); |
5294 | 2.86k | if (loop_iters <= 0) |
5295 | 1.37k | skipping_loop=loop_level; |
5296 | 1.48k | else |
5297 | 1.48k | { |
5298 | 1.48k | long |
5299 | 1.48k | loop_iters_max = 512; |
5300 | | |
5301 | 1.48k | const char |
5302 | 1.48k | *definition_value; |
5303 | | |
5304 | 1.48k | if (image_info->subrange != 0) |
5305 | 1.48k | { |
5306 | | /* |
5307 | | FIXME: This is a quick hack to adjust the |
5308 | | maximum loop iterations based on the |
5309 | | subrange specification. A proper solution |
5310 | | would be to handle scene/subimage/subrange |
5311 | | for MNG as it should have been in the |
5312 | | first place. |
5313 | | */ |
5314 | 1.48k | if (logging) |
5315 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5316 | 0 | "Adjusting loop ierations based on subrange:" |
5317 | 0 | " scene: %lu: subimage: %lu, subrange: %lu", |
5318 | 0 | image->scene, image_info->subimage, |
5319 | 0 | image_info->subrange); |
5320 | 1.48k | loop_iters=Min(image_info->subrange,(unsigned long) loop_iters); |
5321 | 1.48k | } |
5322 | 1.48k | if ((definition_value=AccessDefinition(image_info,"mng","maximum-loops"))) |
5323 | 0 | loop_iters_max=atol(definition_value); |
5324 | 1.48k | if (loop_iters > loop_iters_max) |
5325 | 0 | loop_iters=loop_iters_max; |
5326 | | |
5327 | | /* |
5328 | | The LOOP chunk allows an iteration count in the range 0..2^31-1 |
5329 | | */ |
5330 | 1.48k | if (loop_iters >= 2147483647L) |
5331 | 0 | loop_iters=2147483647L; |
5332 | 1.48k | else if (loop_iters < 0) |
5333 | 0 | loop_iters=1; |
5334 | | |
5335 | 1.48k | if (logging) |
5336 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5337 | 0 | "Loop iterations allowed: %ld", loop_iters); |
5338 | | |
5339 | 1.48k | mng_info->loop_jump[loop_level]=TellBlob(image); |
5340 | 1.48k | mng_info->loop_count[loop_level]=loop_iters; |
5341 | 1.48k | } |
5342 | 2.86k | mng_info->loop_iteration[loop_level]=0; |
5343 | 2.86k | } |
5344 | 1.15k | else |
5345 | 1.15k | { |
5346 | 1.15k | if (logging) |
5347 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5348 | 0 | "Ignoring short LOOP chunk (%lu bytes)", length); |
5349 | 1.15k | } |
5350 | 4.01k | MagickFreeMemory(chunk); |
5351 | 4.01k | continue; |
5352 | 4.01k | } |
5353 | 1.07M | if (!memcmp(type,mng_ENDL,4)) |
5354 | 5.80k | { |
5355 | 5.80k | if (length < 1) |
5356 | 934 | { |
5357 | 934 | if (logging) |
5358 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5359 | 0 | "Ignoring empty ENDL chunk"); |
5360 | 934 | MagickFreeMemory(chunk); |
5361 | 934 | continue; |
5362 | 934 | } |
5363 | 4.86k | loop_level=chunk[0]; |
5364 | | #if defined(PNG_DEBUG_LOOPS_ACTIVE) |
5365 | | if (logging) |
5366 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5367 | | "ENDL: loop_level = %d," |
5368 | | " loop_active[%d]=%d," |
5369 | | " mng_info->loop_count[%d]=%ld," |
5370 | | " loop_iteration[%d]=%ld", |
5371 | | (int) loop_level, |
5372 | | (int) loop_level, (int) mng_info->loop_active[loop_level], |
5373 | | (int) loop_level, mng_info->loop_count[loop_level], |
5374 | | (int) loop_level, mng_info->loop_iteration[loop_level]); |
5375 | | #endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */ |
5376 | 4.86k | if (skipping_loop > 0) |
5377 | 1.59k | { |
5378 | 1.59k | if (skipping_loop == loop_level) |
5379 | 836 | { |
5380 | | /* |
5381 | | Found end of zero-iteration loop. |
5382 | | */ |
5383 | 836 | skipping_loop=(-1); |
5384 | | #if defined(PNG_DEBUG_LOOPS_ACTIVE) |
5385 | | loops_active--; |
5386 | | #endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */ |
5387 | 836 | mng_info->loop_active[loop_level]=0; |
5388 | 836 | } |
5389 | 1.59k | } |
5390 | 3.27k | else |
5391 | 3.27k | { |
5392 | 3.27k | if (mng_info->loop_active[loop_level] == 1) |
5393 | 783 | { |
5394 | 783 | mng_info->loop_count[loop_level]--; |
5395 | 783 | mng_info->loop_iteration[loop_level]++; |
5396 | 783 | if (mng_info->loop_count[loop_level] > 0) |
5397 | 0 | (void) SeekBlob(image,mng_info->loop_jump[loop_level], |
5398 | 0 | SEEK_SET); |
5399 | 783 | else |
5400 | 783 | { |
5401 | 783 | short |
5402 | 783 | last_level; |
5403 | | |
5404 | | /* |
5405 | | Finished loop. |
5406 | | */ |
5407 | | #if defined(PNG_DEBUG_LOOPS_ACTIVE) |
5408 | | loops_active--; |
5409 | | #endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */ |
5410 | 783 | mng_info->loop_active[loop_level]=0; |
5411 | 783 | last_level=(-1); |
5412 | 15.0k | for (i=0; i < loop_level; i++) |
5413 | 14.2k | if (mng_info->loop_active[i] == 1) |
5414 | 254 | last_level=(short) i; |
5415 | 783 | loop_level=last_level; |
5416 | 783 | } |
5417 | 783 | } |
5418 | 3.27k | } |
5419 | 4.86k | MagickFreeMemory(chunk); |
5420 | 4.86k | continue; |
5421 | 5.80k | } |
5422 | 1.07M | if (!memcmp(type,mng_CLON,4)) |
5423 | 2.37k | { |
5424 | 2.37k | if (!mng_info->clon_warning) |
5425 | 1.00k | (void) ThrowException2(exception,CoderError, |
5426 | 2.37k | "CLON is not implemented yet", |
5427 | 2.37k | image->filename); |
5428 | 2.37k | mng_info->clon_warning++; |
5429 | 2.37k | } |
5430 | 1.07M | if (!memcmp(type,mng_MAGN,4)) |
5431 | 50.8k | { |
5432 | 50.8k | png_uint_16 |
5433 | 50.8k | magn_first, |
5434 | 50.8k | magn_last, |
5435 | 50.8k | magn_mb, |
5436 | 50.8k | magn_ml, |
5437 | 50.8k | magn_mr, |
5438 | 50.8k | magn_mt, |
5439 | 50.8k | magn_mx, |
5440 | 50.8k | magn_my, |
5441 | 50.8k | magn_methx, |
5442 | 50.8k | magn_methy; |
5443 | | |
5444 | 50.8k | if (length > 1) |
5445 | 45.4k | magn_first=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1]; |
5446 | 5.36k | else |
5447 | 5.36k | magn_first=0; |
5448 | 50.8k | if (length > 3) |
5449 | 45.4k | magn_last=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3]; |
5450 | 5.43k | else |
5451 | 5.43k | magn_last=magn_first; |
5452 | 50.8k | #ifndef MNG_OBJECT_BUFFERS |
5453 | 50.8k | if (magn_first || magn_last) |
5454 | 43.5k | if (!mng_info->magn_warning) |
5455 | 35.6k | { |
5456 | 35.6k | (void) ThrowException2(exception,CoderError, |
5457 | 35.6k | "MAGN is not implemented yet" |
5458 | 35.6k | " for nonzero objects", |
5459 | 35.6k | image->filename); |
5460 | 35.6k | mng_info->magn_warning++; |
5461 | 35.6k | } |
5462 | 50.8k | #endif |
5463 | 50.8k | if (length > 4) |
5464 | 45.2k | magn_methx=p[4]; |
5465 | 5.58k | else |
5466 | 5.58k | magn_methx=0; |
5467 | | |
5468 | 50.8k | if (length > 6) |
5469 | 44.7k | magn_mx=((magick_uint32_t) p[5] << 8) | (magick_uint32_t) p[6]; |
5470 | 6.05k | else |
5471 | 6.05k | magn_mx=1; |
5472 | 50.8k | if (magn_mx == 0) |
5473 | 9.91k | magn_mx=1; |
5474 | | |
5475 | 50.8k | if (length > 8) |
5476 | 41.9k | magn_my=((magick_uint32_t) p[7] << 8) | (magick_uint32_t) p[8]; |
5477 | 8.93k | else |
5478 | 8.93k | magn_my=magn_mx; |
5479 | 50.8k | if (magn_my == 0) |
5480 | 32.2k | magn_my=1; |
5481 | | |
5482 | 50.8k | if (length > 10) |
5483 | 10.3k | magn_ml=((magick_uint32_t) p[9] << 8) | (magick_uint32_t) p[10]; |
5484 | 40.4k | else |
5485 | 40.4k | magn_ml=magn_mx; |
5486 | 50.8k | if (magn_ml == 0) |
5487 | 5.45k | magn_ml=1; |
5488 | | |
5489 | 50.8k | if (length > 12) |
5490 | 10.3k | magn_mr=((magick_uint32_t) p[11] << 8) | (magick_uint32_t) p[12]; |
5491 | 40.4k | else |
5492 | 40.4k | magn_mr=magn_mx; |
5493 | 50.8k | if (magn_mr == 0) |
5494 | 4.50k | magn_mr=1; |
5495 | | |
5496 | 50.8k | if (length > 14) |
5497 | 9.15k | magn_mt=((magick_uint32_t) p[13] << 8) | (magick_uint32_t) p[14]; |
5498 | 41.6k | else |
5499 | 41.6k | magn_mt=magn_my; |
5500 | 50.8k | if (magn_mt == 0) |
5501 | 7.75k | magn_mt=1; |
5502 | | |
5503 | 50.8k | if (length > 16) |
5504 | 9.13k | magn_mb=((magick_uint32_t) p[15] << 8) | (magick_uint32_t) p[16]; |
5505 | 41.7k | else |
5506 | 41.7k | magn_mb=magn_my; |
5507 | 50.8k | if (magn_mb == 0) |
5508 | 4.87k | magn_mb=1; |
5509 | | |
5510 | 50.8k | if (length > 17) |
5511 | 2.65k | magn_methy=p[17]; |
5512 | 48.1k | else |
5513 | 48.1k | magn_methy=magn_methx; |
5514 | | |
5515 | 50.8k | if (logging) |
5516 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5517 | 0 | "MAGN chunk (%lu bytes): " |
5518 | 0 | "First_magnified_object_id=%u, Last_magnified_object_id=%u, " |
5519 | 0 | "MB=%u, ML=%u, MR=%u, MT=%u, MX=%u, MY=%u, " |
5520 | 0 | "X_method=%u, Y_method=%u", |
5521 | 0 | length, |
5522 | 0 | (unsigned) magn_first, (unsigned) magn_last, |
5523 | 0 | (unsigned) magn_mb, |
5524 | 0 | (unsigned) magn_ml, (unsigned) magn_mr, |
5525 | 0 | (unsigned) magn_mt, |
5526 | 0 | (unsigned) magn_mx, (unsigned) magn_my, |
5527 | 0 | (unsigned) magn_methx, (unsigned) magn_methy); |
5528 | | |
5529 | | |
5530 | 50.8k | if (magn_methx > 5 || magn_methy > 5) |
5531 | 8.46k | if (!mng_info->magn_warning) |
5532 | 119 | { |
5533 | 119 | (void) ThrowException2(exception,CoderError, |
5534 | 119 | "Unknown MAGN method in" |
5535 | 119 | " MNG datastream", |
5536 | 119 | image->filename); |
5537 | 119 | mng_info->magn_warning++; |
5538 | 119 | } |
5539 | | #ifdef MNG_OBJECT_BUFFERS |
5540 | | /* Magnify existing objects in the range magn_first |
5541 | | to magn_last */ |
5542 | | #endif |
5543 | 50.8k | if (magn_first == 0 || magn_last == 0) |
5544 | 47.7k | { |
5545 | | /* Save the magnification factors for object 0 */ |
5546 | 47.7k | if (logging) |
5547 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5548 | 0 | "MAGN chunk factors saved for object 0"); |
5549 | 47.7k | mng_info->magn_mb=magn_mb; |
5550 | 47.7k | mng_info->magn_ml=magn_ml; |
5551 | 47.7k | mng_info->magn_mr=magn_mr; |
5552 | 47.7k | mng_info->magn_mt=magn_mt; |
5553 | 47.7k | mng_info->magn_mx=magn_mx; |
5554 | 47.7k | mng_info->magn_my=magn_my; |
5555 | 47.7k | mng_info->magn_methx=magn_methx; |
5556 | 47.7k | mng_info->magn_methy=magn_methy; |
5557 | 47.7k | } |
5558 | 50.8k | } |
5559 | 1.07M | if (!memcmp(type,mng_PAST,4)) |
5560 | 3.52k | { |
5561 | 3.52k | if (!mng_info->past_warning) |
5562 | 2.36k | (void) ThrowException2(exception,CoderError, |
5563 | 3.52k | "PAST is not implemented yet", |
5564 | 3.52k | image->filename); |
5565 | 3.52k | mng_info->past_warning++; |
5566 | 3.52k | } |
5567 | 1.07M | if (!memcmp(type,mng_SHOW,4)) |
5568 | 40.2k | { |
5569 | 40.2k | if (!mng_info->show_warning) |
5570 | 34.9k | (void) ThrowException2(exception,CoderError, |
5571 | 40.2k | "SHOW is not implemented yet", |
5572 | 40.2k | image->filename); |
5573 | 40.2k | mng_info->show_warning++; |
5574 | 40.2k | } |
5575 | 1.07M | if (!memcmp(type,mng_sBIT,4)) |
5576 | 3.68k | { |
5577 | 3.68k | if (length < 4) |
5578 | 836 | mng_info->have_global_sbit=MagickFalse; |
5579 | 2.85k | else |
5580 | 2.85k | { |
5581 | 2.85k | mng_info->global_sbit.gray=p[0]; |
5582 | 2.85k | mng_info->global_sbit.red=p[0]; |
5583 | 2.85k | mng_info->global_sbit.green=p[1]; |
5584 | 2.85k | mng_info->global_sbit.blue=p[2]; |
5585 | 2.85k | mng_info->global_sbit.alpha=p[3]; |
5586 | 2.85k | mng_info->have_global_sbit=MagickTrue; |
5587 | 2.85k | } |
5588 | 3.68k | } |
5589 | 1.07M | if (!memcmp(type,mng_pHYs,4)) |
5590 | 2.61k | { |
5591 | 2.61k | if (length > 8) |
5592 | 1.27k | { |
5593 | 1.27k | mng_info->global_x_pixels_per_unit=mng_get_long(p); |
5594 | 1.27k | mng_info->global_y_pixels_per_unit=mng_get_long(&p[4]); |
5595 | 1.27k | mng_info->global_phys_unit_type=p[8]; |
5596 | 1.27k | mng_info->have_global_phys=MagickTrue; |
5597 | 1.27k | } |
5598 | 1.34k | else |
5599 | 1.34k | mng_info->have_global_phys=MagickFalse; |
5600 | 2.61k | } |
5601 | 1.07M | if (!memcmp(type,mng_pHYg,4)) |
5602 | 2.47k | { |
5603 | 2.47k | if (!mng_info->phyg_warning) |
5604 | 1.43k | (void) ThrowException2(exception,CoderError, |
5605 | 2.47k | "pHYg is not implemented.", |
5606 | 2.47k | image->filename); |
5607 | 2.47k | mng_info->phyg_warning++; |
5608 | 2.47k | } |
5609 | 1.07M | if (!memcmp(type,mng_BASI,4)) |
5610 | 1.82k | { |
5611 | 1.82k | skip_to_iend=MagickTrue; |
5612 | 1.82k | if (!mng_info->basi_warning) |
5613 | 1.13k | (void) ThrowException2(exception,CoderError, |
5614 | 1.82k | "BASI is not implemented yet", |
5615 | 1.82k | image->filename); |
5616 | 1.82k | mng_info->basi_warning++; |
5617 | | #ifdef MNG_BASI_SUPPORTED |
5618 | | basi_width=(unsigned long) mng_get_long(p); |
5619 | | ((magick_uint32_t) p[1] << 16) | |
5620 | | ((magick_uint32_t) p[2] << 8) | |
5621 | | (magick_uint32_t) p[3]); |
5622 | | basi_height=(unsigned long) mng_get_long(&p[4]); |
5623 | | basi_color_type=p[8]; |
5624 | | basi_compression_method=p[9]; |
5625 | | basi_filter_type=p[10]; |
5626 | | basi_interlace_method=p[11]; |
5627 | | if (length > 11) |
5628 | | basi_red=((magick_uint32_t) p[12] << 8) & (magick_uint32_t) p[13]; |
5629 | | else |
5630 | | basi_red=0; |
5631 | | if (length > 13) |
5632 | | basi_green=((magick_uint32_t) p[14] << 8) & (magick_uint32_t) p[15]; |
5633 | | else |
5634 | | basi_green=0; |
5635 | | if (length > 15) |
5636 | | basi_blue=((magick_uint32_t) p[16] << 8) & (magick_uint32_t) p[17]; |
5637 | | else |
5638 | | basi_blue=0; |
5639 | | if (length > 17) |
5640 | | basi_alpha=((magick_uint32_t) p[18] << 8) & (magick_uint32_t) p[19]; |
5641 | | else |
5642 | | { |
5643 | | if (basi_sample_depth == 16) |
5644 | | basi_alpha=65535L; |
5645 | | else |
5646 | | basi_alpha=255; |
5647 | | } |
5648 | | if (length > 19) |
5649 | | basi_viewable=p[20]; |
5650 | | else |
5651 | | basi_viewable=0; |
5652 | | #endif |
5653 | 1.82k | MagickFreeMemory(chunk); |
5654 | 1.82k | continue; |
5655 | 1.82k | } |
5656 | 1.07M | if (memcmp(type,mng_IHDR,4) |
5657 | 953k | #if defined(JNG_SUPPORTED) |
5658 | 953k | && memcmp(type,mng_JHDR,4) |
5659 | 1.07M | #endif |
5660 | 1.07M | ) |
5661 | 924k | { |
5662 | | /* Not an IHDR or JHDR chunk */ |
5663 | 924k | MagickFreeMemory(chunk); |
5664 | 924k | continue; |
5665 | 924k | } |
5666 | | /* Process IHDR */ |
5667 | 147k | if (logging) |
5668 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5669 | 0 | " Processing %c%c%c%c chunk", |
5670 | 0 | type[0],type[1],type[2],type[3]); |
5671 | 147k | mng_info->exists[object_id]=MagickTrue; |
5672 | 147k | mng_info->viewable[object_id]=MagickTrue; |
5673 | 147k | if (mng_info->invisible[object_id]) |
5674 | 925 | { |
5675 | 925 | if (logging) |
5676 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5677 | 0 | " Skipping invisible object"); |
5678 | 925 | skip_to_iend=MagickTrue; |
5679 | 925 | MagickFreeMemory(chunk); |
5680 | 925 | continue; |
5681 | 925 | } |
5682 | 146k | #ifdef MNG_INSERT_LAYERS |
5683 | 146k | if (length < 8) |
5684 | 1.80k | { |
5685 | 1.80k | MagickFreeMemory(chunk); |
5686 | 1.80k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5687 | 1.80k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
5688 | 0 | } |
5689 | 144k | image_width=mng_get_long(p); |
5690 | 144k | image_height=mng_get_long(&p[4]); |
5691 | 144k | #endif |
5692 | 144k | MagickFreeMemory(chunk); |
5693 | | |
5694 | | /* |
5695 | | Insert a transparent background layer behind the entire animation |
5696 | | if it is not full screen. |
5697 | | */ |
5698 | 144k | #ifdef MNG_INSERT_LAYERS |
5699 | 144k | if (insert_layers && mng_type && first_mng_object) |
5700 | 1.02k | { |
5701 | 1.02k | if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) || |
5702 | 756 | (image_width < mng_info->mng_width) || |
5703 | 748 | (mng_info->clip.right < (long) mng_info->mng_width) || |
5704 | 746 | (image_height < mng_info->mng_height) || |
5705 | 733 | (mng_info->clip.bottom < (long) mng_info->mng_height)) |
5706 | 296 | { |
5707 | 296 | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
5708 | 15 | { |
5709 | 15 | StopTimer(&image->timer); |
5710 | | /* |
5711 | | Allocate next image structure. |
5712 | | */ |
5713 | 15 | AllocateNextImage(image_info,image); |
5714 | 15 | if (image->next == (Image *) NULL) |
5715 | 0 | { |
5716 | 0 | DestroyImageList(image); |
5717 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5718 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5719 | 0 | return((Image *) NULL); |
5720 | 0 | } |
5721 | 15 | image=SyncNextImageInList(image); |
5722 | 15 | } |
5723 | 296 | mng_info->image=image; |
5724 | 296 | if (term_chunk_found) |
5725 | 3 | { |
5726 | 3 | image->start_loop=MagickTrue; |
5727 | 3 | image->iterations=mng_iterations; |
5728 | 3 | term_chunk_found=MagickFalse; |
5729 | 3 | } |
5730 | 293 | else |
5731 | 293 | image->start_loop=MagickFalse; |
5732 | | /* |
5733 | | Make a background rectangle. |
5734 | | */ |
5735 | 296 | image->delay=0; |
5736 | 296 | image->columns=mng_info->mng_width; |
5737 | 296 | image->rows=mng_info->mng_height; |
5738 | 296 | image->page.width=mng_info->mng_width; |
5739 | 296 | image->page.height=mng_info->mng_height; |
5740 | 296 | image->page.x=0; |
5741 | 296 | image->page.y=0; |
5742 | 296 | image->background_color=mng_background_color; |
5743 | 296 | (void) SetImage(image,TransparentOpacity); |
5744 | 296 | if (logging) |
5745 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5746 | 0 | " Inserted transparent background" |
5747 | 0 | " layer, W=%lud, H=%lud", |
5748 | 0 | mng_info->mng_width, |
5749 | 0 | mng_info->mng_height); |
5750 | 296 | } |
5751 | 1.02k | } |
5752 | | /* |
5753 | | Insert a background layer behind the upcoming image if |
5754 | | framing_mode is 3, and we haven't already inserted one. |
5755 | | */ |
5756 | 144k | if (insert_layers && (mng_info->framing_mode == 3) && |
5757 | 2.53k | (subframe_width) && (subframe_height) && (simplicity == 0 || |
5758 | 391 | (simplicity & 0x08))) |
5759 | 1.63k | { |
5760 | 1.63k | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
5761 | 551 | { |
5762 | 551 | StopTimer(&image->timer); |
5763 | | /* |
5764 | | Allocate next image structure. |
5765 | | */ |
5766 | 551 | AllocateNextImage(image_info,image); |
5767 | 551 | if (image->next == (Image *) NULL) |
5768 | 0 | { |
5769 | 0 | DestroyImageList(image); |
5770 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5771 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5772 | 0 | return((Image *) NULL); |
5773 | 0 | } |
5774 | 551 | image=SyncNextImageInList(image); |
5775 | 551 | } |
5776 | 1.63k | mng_info->image=image; |
5777 | 1.63k | if (term_chunk_found) |
5778 | 11 | { |
5779 | 11 | image->start_loop=MagickTrue; |
5780 | 11 | image->iterations=mng_iterations; |
5781 | 11 | term_chunk_found=MagickFalse; |
5782 | 11 | } |
5783 | 1.62k | else |
5784 | 1.62k | image->start_loop=MagickFalse; |
5785 | 1.63k | image->delay=0; |
5786 | 1.63k | image->columns=subframe_width; |
5787 | 1.63k | image->rows=subframe_height; |
5788 | 1.63k | image->page.width=subframe_width; |
5789 | 1.63k | image->page.height=subframe_height; |
5790 | 1.63k | image->page.x=mng_info->clip.left; |
5791 | 1.63k | image->page.y=mng_info->clip.top; |
5792 | 1.63k | image->background_color=mng_background_color; |
5793 | 1.63k | image->matte=MagickFalse; |
5794 | 1.63k | if (SetImage(image,OpaqueOpacity) == MagickFail) |
5795 | 134 | { |
5796 | 134 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," SetImage() returned MagickFail!"); |
5797 | 134 | DestroyImageList(image); |
5798 | 134 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5799 | 134 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5800 | 134 | return((Image *) NULL); |
5801 | 134 | } |
5802 | 1.49k | if (logging) |
5803 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5804 | 0 | " Inserted background layer," |
5805 | 0 | " L=%ld, R=%ld, T=%ld, B=%ld", |
5806 | 0 | mng_info->clip.left, |
5807 | 0 | mng_info->clip.right, |
5808 | 0 | mng_info->clip.top, |
5809 | 0 | mng_info->clip.bottom); |
5810 | 1.49k | } |
5811 | 144k | #endif /* MNG_INSERT_LAYERS */ |
5812 | 144k | first_mng_object=MagickFalse; |
5813 | 144k | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
5814 | 71.1k | { |
5815 | 71.1k | StopTimer(&image->timer); |
5816 | | /* |
5817 | | Allocate next image structure. |
5818 | | */ |
5819 | 71.1k | AllocateNextImage(image_info,image); |
5820 | 71.1k | if (image->next == (Image *) NULL) |
5821 | 0 | { |
5822 | 0 | DestroyImageList(image); |
5823 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5824 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5825 | 0 | return((Image *) NULL); |
5826 | 0 | } |
5827 | 71.1k | image=SyncNextImageInList(image); |
5828 | 71.1k | } |
5829 | 144k | mng_info->image=image; |
5830 | 144k | if (QuantumTick(TellBlob(image),GetBlobSize(image))) |
5831 | 48.6k | if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image), |
5832 | 48.6k | exception,LoadImagesText, |
5833 | 48.6k | image->filename)) |
5834 | 0 | break; |
5835 | 144k | if (term_chunk_found) |
5836 | 124 | { |
5837 | 124 | image->start_loop=MagickTrue; |
5838 | 124 | term_chunk_found=MagickFalse; |
5839 | 124 | } |
5840 | 144k | else |
5841 | 144k | image->start_loop=MagickFalse; |
5842 | 144k | if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3) |
5843 | 135k | { |
5844 | 135k | image->delay=frame_delay; |
5845 | 135k | frame_delay=default_frame_delay; |
5846 | 135k | } |
5847 | 8.87k | else |
5848 | 8.87k | image->delay=0; |
5849 | 144k | image->page.width=mng_info->mng_width; |
5850 | 144k | image->page.height=mng_info->mng_height; |
5851 | 144k | image->page.x=mng_info->x_off[object_id]; |
5852 | 144k | image->page.y=mng_info->y_off[object_id]; |
5853 | 144k | image->iterations=mng_iterations; |
5854 | | /* |
5855 | | Seek back to the beginning of the IHDR or JHDR chunk's |
5856 | | length field. |
5857 | | */ |
5858 | 144k | if (logging) |
5859 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5860 | 0 | " Seeking back to beginning of" |
5861 | 0 | " %c%c%c%c chunk", |
5862 | 0 | type[0],type[1], |
5863 | 0 | type[2],type[3]); |
5864 | 144k | (void) SeekBlob(image,-((long) length+12),SEEK_CUR); |
5865 | 144k | } |
5866 | | |
5867 | 144k | mng_info->image=image; |
5868 | 144k | mng_info->mng_type=mng_type; |
5869 | 144k | mng_info->object_id=object_id; |
5870 | | |
5871 | 144k | if (!memcmp(type,mng_IHDR,4)) |
5872 | 117k | { |
5873 | 117k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOnePNGImage()"); |
5874 | | /* If NULL is returned, then mng_info->image was already freed by ReadOnePNGImage! */ |
5875 | 117k | image=ReadOnePNGImage(mng_info,image_info,exception); |
5876 | 117k | } |
5877 | 26.8k | #if defined(JNG_SUPPORTED) |
5878 | 26.8k | else |
5879 | 26.8k | { |
5880 | 26.8k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOneJNGImage()"); |
5881 | | /* ReadOneJNGImage() does not free mng_info->image as ReadOnePNGImage() does! */ |
5882 | 26.8k | image=ReadOneJNGImage(mng_info,image_info,exception); |
5883 | 26.8k | } |
5884 | 144k | #endif |
5885 | | |
5886 | 144k | if (image == (Image *) NULL) |
5887 | 51.3k | { |
5888 | 51.3k | if (mng_info->image != (Image *) NULL) |
5889 | 26.8k | { |
5890 | 26.8k | status &= CloseBlob(mng_info->image); |
5891 | 26.8k | DestroyImageList(mng_info->image); |
5892 | 26.8k | mng_info->image=(Image *) NULL; |
5893 | 26.8k | } |
5894 | 51.3k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5895 | 51.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5896 | 51.3k | return((Image *) NULL); |
5897 | 51.3k | } |
5898 | 93.4k | if (image->columns == 0 || image->rows == 0) |
5899 | 0 | { |
5900 | 0 | status &= CloseBlob(image); |
5901 | 0 | DestroyImageList(image); |
5902 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
5903 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
5904 | 0 | return((Image *) NULL); |
5905 | 0 | } |
5906 | | |
5907 | 93.4k | mng_info->image=image; |
5908 | | |
5909 | 93.4k | if (mng_type) |
5910 | 15.6k | { |
5911 | 15.6k | MngBox |
5912 | 15.6k | crop_box; |
5913 | | |
5914 | | /* |
5915 | | If magnifying and a supported method is requested then |
5916 | | magnify the image. |
5917 | | |
5918 | | http://www.libpng.org/pub/mng/spec/mng-1.0-20010209-pdg.html#mng-MAGN |
5919 | | |
5920 | | Extracted summary of magnification options: |
5921 | | |
5922 | | X_method: 1 byte |
5923 | | 0 or omitted: No magnification |
5924 | | 1: Pixel replication of color and alpha samples. |
5925 | | 2: Magnified intervals with linear interpolation of |
5926 | | color and alpha samples. |
5927 | | 3: Magnified intervals with replication of color and |
5928 | | alpha samples from the closest pixel. |
5929 | | 4: Magnified intervals with linear interpolation of |
5930 | | color samples and replication of alpha samples from |
5931 | | the closest pixel. |
5932 | | 5: Magnified intervals with linear interpolation of |
5933 | | alpha samples and replication of color samples from |
5934 | | the closest pixel. |
5935 | | MX: 2 bytes. X magnification factor, range 1-65535. If |
5936 | | omitted, MX=1. Ignored if X_method is 0 and assumed to |
5937 | | be 1. |
5938 | | MY: 2 bytes. Y magnification factor. If omitted, MY=MX. |
5939 | | ML: 2 bytes. Left X magnification factor. If omitted, ML=MX. |
5940 | | MR: 2 bytes. Right X magnification factor. If omitted, MR=MX. |
5941 | | MT: 2 bytes. Top Y magnification factor. If omitted, MT=MY. |
5942 | | Ignored if Y_method is 0 and assumed to be 1. |
5943 | | MB: 2 bytes. Bottom Y magnification factor. If omitted, |
5944 | | MB=MY. |
5945 | | Y_method: 1 byte. If omitted, Y_method is the same as X_method. |
5946 | | |
5947 | | |
5948 | | */ |
5949 | 15.6k | if (((mng_info->magn_methx > 0) && (mng_info->magn_methx <= 5)) && |
5950 | 2.93k | ((mng_info->magn_methy > 0) && (mng_info->magn_methy <= 5))) |
5951 | 2.13k | { |
5952 | 2.13k | png_uint_32 |
5953 | 2.13k | magnified_height, |
5954 | 2.13k | magnified_width; |
5955 | | |
5956 | 2.13k | if (logging) |
5957 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5958 | 0 | " Processing MNG MAGN chunk: MB=%u, ML=%u," |
5959 | 0 | " MR=%u, MT=%u, MX=%u, MY=%u," |
5960 | 0 | " X_method=%u, Y_method=%u", |
5961 | 0 | mng_info->magn_mb,mng_info->magn_ml, |
5962 | 0 | mng_info->magn_mr,mng_info->magn_mt, |
5963 | 0 | mng_info->magn_mx,mng_info->magn_my, |
5964 | 0 | mng_info->magn_methx, |
5965 | 0 | mng_info->magn_methy); |
5966 | | |
5967 | | /* |
5968 | | If the image width is 1, then X magnification is done |
5969 | | by simple pixel replication. |
5970 | | */ |
5971 | 2.13k | if (image->columns == 1) |
5972 | 2.13k | { |
5973 | 2.13k | if (logging) |
5974 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5975 | 0 | " MNG MAGN X_method reduced from %u to 1 due to columns = 1", |
5976 | 0 | mng_info->magn_methx); |
5977 | 2.13k | mng_info->magn_methx = 1; |
5978 | 2.13k | } |
5979 | | |
5980 | | /* |
5981 | | If the image height is 1, then Y magnification is done |
5982 | | by simple pixel replication. |
5983 | | */ |
5984 | 2.13k | if (image->rows == 1) |
5985 | 2.13k | { |
5986 | 2.13k | if (logging) |
5987 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5988 | 0 | " MNG MAGN Y_method reduced from %u to 1 due to rows = 1", |
5989 | 0 | mng_info->magn_methy); |
5990 | 2.13k | mng_info->magn_methy = 1; |
5991 | 2.13k | } |
5992 | | |
5993 | 2.13k | if (mng_info->magn_methx == 1) |
5994 | 2.13k | { |
5995 | 2.13k | magnified_width=mng_info->magn_ml; |
5996 | 2.13k | if (image->columns > 1) |
5997 | 0 | magnified_width += mng_info->magn_mr; |
5998 | 2.13k | if (image->columns > 2) |
5999 | 0 | magnified_width += (image->columns-2)*(mng_info->magn_mx); |
6000 | 2.13k | } |
6001 | 0 | else |
6002 | 0 | { |
6003 | 0 | magnified_width=image->columns; |
6004 | 0 | if (image->columns > 1) |
6005 | 0 | magnified_width += mng_info->magn_ml-1; |
6006 | 0 | if (image->columns > 2) |
6007 | 0 | magnified_width += mng_info->magn_mr-1; |
6008 | 0 | if (image->columns > 3) |
6009 | 0 | magnified_width += (image->columns-3)* |
6010 | 0 | (mng_info->magn_mx-1); |
6011 | 0 | } |
6012 | 2.13k | if (mng_info->magn_methy == 1) |
6013 | 2.13k | { |
6014 | 2.13k | magnified_height=mng_info->magn_mt; |
6015 | 2.13k | if (image->rows > 1) |
6016 | 0 | magnified_height += mng_info->magn_mb; |
6017 | 2.13k | if (image->rows > 2) |
6018 | 0 | magnified_height += (image->rows-2)*(mng_info->magn_my); |
6019 | 2.13k | } |
6020 | 0 | else |
6021 | 0 | { |
6022 | 0 | magnified_height=image->rows; |
6023 | 0 | if (image->rows > 1) |
6024 | 0 | magnified_height += mng_info->magn_mt-1; |
6025 | 0 | if (image->rows > 2) |
6026 | 0 | magnified_height += mng_info->magn_mb-1; |
6027 | 0 | if (image->rows > 3) |
6028 | 0 | magnified_height += (image->rows-3)*(mng_info->magn_my-1); |
6029 | 0 | } |
6030 | 2.13k | if (magnified_height > image->rows || |
6031 | 1.03k | magnified_width > image->columns) |
6032 | 1.77k | { |
6033 | 1.77k | Image |
6034 | 1.77k | *large_image; |
6035 | | |
6036 | 1.77k | long |
6037 | 1.77k | m, |
6038 | 1.77k | y, |
6039 | 1.77k | yy; |
6040 | | |
6041 | 1.77k | register long |
6042 | 1.77k | x; |
6043 | | |
6044 | 1.77k | register PixelPacket |
6045 | 1.77k | *n, |
6046 | 1.77k | *p, |
6047 | 1.77k | *q; |
6048 | | |
6049 | 1.77k | PixelPacket |
6050 | 1.77k | *next, |
6051 | 1.77k | *prev; |
6052 | | |
6053 | 1.77k | size_t |
6054 | 1.77k | row_length; |
6055 | | |
6056 | 1.77k | png_uint_16 |
6057 | 1.77k | magn_methx, |
6058 | 1.77k | magn_methy; |
6059 | | |
6060 | | /* |
6061 | | Allocate next image structure. |
6062 | | */ |
6063 | 1.77k | if (logging) |
6064 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6065 | 0 | " Allocate magnified image (%lux%lu ==> %ux%u)", |
6066 | 0 | image->columns, image->rows, |
6067 | 0 | (unsigned) magnified_width, |
6068 | 0 | (unsigned) magnified_height); |
6069 | 1.77k | AllocateNextImage(image_info,image); |
6070 | 1.77k | if (image->next == (Image *) NULL) |
6071 | 0 | { |
6072 | 0 | DestroyImageList(image); |
6073 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6074 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
6075 | 0 | return((Image *) NULL); |
6076 | 0 | } |
6077 | | |
6078 | 1.77k | large_image=SyncNextImageInList(image); |
6079 | | |
6080 | 1.77k | large_image->columns=magnified_width; |
6081 | 1.77k | large_image->rows=magnified_height; |
6082 | | |
6083 | 1.77k | magn_methx=mng_info->magn_methx; |
6084 | 1.77k | magn_methy=mng_info->magn_methy; |
6085 | | |
6086 | | #if (QuantumDepth == 32) |
6087 | | #define QM unsigned short |
6088 | | if (magn_methx != 1 || magn_methy != 1) |
6089 | | { |
6090 | | /* |
6091 | | Scale pixels to unsigned shorts to prevent |
6092 | | overflow of intermediate values of interpolations |
6093 | | */ |
6094 | | for (y=0; y < (long) image->rows; y++) |
6095 | | { |
6096 | | q=GetImagePixels(image,0,y,image->columns,1); |
6097 | | if(q == (PixelPacket *) NULL) |
6098 | | break; |
6099 | | for (x=(long) image->columns; x > 0; x--) |
6100 | | { |
6101 | | q->red=ScaleQuantumToShort(q->red); |
6102 | | q->green=ScaleQuantumToShort(q->green); |
6103 | | q->blue=ScaleQuantumToShort(q->blue); |
6104 | | q->opacity=ScaleQuantumToShort(q->opacity); |
6105 | | q++; |
6106 | | } |
6107 | | if (!SyncImagePixels(image)) |
6108 | | break; |
6109 | | } |
6110 | | } |
6111 | | #else |
6112 | 1.77k | #define QM Quantum |
6113 | 1.77k | #endif |
6114 | | |
6115 | 1.77k | if (image->matte) |
6116 | 889 | (void) SetImage(large_image,TransparentOpacity); |
6117 | 887 | else |
6118 | 887 | { |
6119 | 887 | large_image->background_color.opacity=OpaqueOpacity; |
6120 | 887 | (void) SetImage(large_image,OpaqueOpacity); |
6121 | 887 | if (magn_methx == 4) |
6122 | 0 | magn_methx=2; |
6123 | 887 | if (magn_methx == 5) |
6124 | 0 | magn_methx=3; |
6125 | 887 | if (magn_methy == 4) |
6126 | 0 | magn_methy=2; |
6127 | 887 | if (magn_methy == 5) |
6128 | 0 | magn_methy=3; |
6129 | 887 | } |
6130 | | |
6131 | | /* magnify the rows into the right side of the large image */ |
6132 | | |
6133 | 1.77k | if (logging) |
6134 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6135 | 0 | " Magnify the rows to %lu", |
6136 | 0 | large_image->rows); |
6137 | 1.77k | m=mng_info->magn_mt; |
6138 | 1.77k | yy=0; |
6139 | 1.77k | row_length=MagickArraySize(image->columns,sizeof(PixelPacket)); |
6140 | 1.77k | next=MagickAllocateMemory(PixelPacket *,row_length); |
6141 | 1.77k | prev=MagickAllocateMemory(PixelPacket *,row_length); |
6142 | 1.77k | if ((prev == (PixelPacket *) NULL) || |
6143 | 1.77k | (next == (PixelPacket *) NULL)) |
6144 | 0 | { |
6145 | 0 | MagickFreeMemory(next); |
6146 | 0 | MagickFreeMemory(prev); |
6147 | 0 | DestroyImageList(image); |
6148 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6149 | 0 | ThrowReaderException(ResourceLimitError, |
6150 | 0 | MemoryAllocationFailed,image) |
6151 | 0 | } |
6152 | 1.77k | n=GetImagePixels(image,0,0,image->columns,1); |
6153 | 1.77k | if(n == (PixelPacket *) NULL) |
6154 | 6 | { |
6155 | 6 | MagickFreeMemory(next); |
6156 | 6 | MagickFreeMemory(prev); |
6157 | 6 | DestroyImageList(image); |
6158 | 6 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6159 | 6 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6160 | 6 | " return NULL from ReadMNGImage()"); |
6161 | 6 | return ((Image *) NULL); |
6162 | 6 | } |
6163 | 1.77k | (void) memcpy(next,n,row_length); |
6164 | 3.54k | for (y=0; y < (long) image->rows; y++) |
6165 | 1.77k | { |
6166 | 1.77k | if (y == 0) |
6167 | 1.77k | m=mng_info->magn_mt; |
6168 | 0 | else if (magn_methy > 1 && y == (long) image->rows-2) |
6169 | 0 | m=mng_info->magn_mb; |
6170 | 0 | else if (magn_methy <= 1 && y == (long) image->rows-1) |
6171 | 0 | m=mng_info->magn_mb; |
6172 | 0 | else if (magn_methy > 1 && y == (long) image->rows-1) |
6173 | 0 | m=1; |
6174 | 0 | else |
6175 | 0 | m=mng_info->magn_my; |
6176 | 1.77k | n=prev; |
6177 | 1.77k | prev=next; |
6178 | 1.77k | next=n; |
6179 | 1.77k | if (y < (long) image->rows-1) |
6180 | 0 | { |
6181 | 0 | n=GetImagePixels(image,0,y+1,image->columns,1); |
6182 | 0 | if(n == (PixelPacket *) NULL) |
6183 | 0 | break; |
6184 | 0 | (void) memcpy(next,n,row_length); |
6185 | 0 | } |
6186 | 1.77k | for (i=0; i < m; i++, yy++) |
6187 | 1.77k | { |
6188 | 1.77k | assert(yy < (long) large_image->rows); |
6189 | 1.77k | p=prev; |
6190 | 1.77k | n=next; |
6191 | 1.77k | q=SetImagePixelsEx(large_image,0,yy, |
6192 | 1.77k | large_image->columns,1,exception); |
6193 | 1.77k | if (q == (const PixelPacket *) NULL) |
6194 | 1.77k | break; |
6195 | 0 | q+=(large_image->columns-image->columns); |
6196 | 0 | for (x=(long) image->columns; x > 0; x--) |
6197 | 0 | { |
6198 | | /* TO DO: get color as function of indexes[x] */ |
6199 | | /* |
6200 | | if (image->storage_class == PseudoClass) |
6201 | | { |
6202 | | } |
6203 | | */ |
6204 | |
|
6205 | 0 | if (magn_methy <= 1) |
6206 | 0 | { |
6207 | 0 | *q=(*p); /* replicate previous */ |
6208 | 0 | } |
6209 | 0 | else if (magn_methy == 2 || magn_methy == 4) |
6210 | 0 | { |
6211 | 0 | if (i == 0) |
6212 | 0 | *q=(*p); |
6213 | 0 | else |
6214 | 0 | { |
6215 | | /* Interpolate */ |
6216 | 0 | (*q).red=(QM) (((long) (2*i*((*n).red |
6217 | 0 | -(*p).red)+m))/ |
6218 | 0 | ((long) (m*2))+(*p).red); |
6219 | 0 | (*q).green=(QM) (((long) (2*i*((*n).green |
6220 | 0 | -(*p).green)+m))/ |
6221 | 0 | ((long) (m*2))+(*p).green); |
6222 | 0 | (*q).blue=(QM) (((long) (2*i*((*n).blue |
6223 | 0 | -(*p).blue)+m))/ |
6224 | 0 | ((long) (m*2))+(*p).blue); |
6225 | 0 | if (image->matte) |
6226 | 0 | (*q).opacity=(QM) (((long) |
6227 | 0 | (2*i*((*n).opacity- |
6228 | 0 | (*p).opacity)+m)) |
6229 | 0 | /((long) (m*2))+ |
6230 | 0 | (*p).opacity); |
6231 | 0 | } |
6232 | 0 | if (magn_methy == 4) |
6233 | 0 | { |
6234 | | /* Replicate nearest */ |
6235 | 0 | if (i <= ((m+1) << 1)) |
6236 | 0 | (*q).opacity=(*p).opacity+0; |
6237 | 0 | else |
6238 | 0 | (*q).opacity=(*n).opacity+0; |
6239 | 0 | } |
6240 | 0 | } |
6241 | 0 | else /* if (magn_methy == 3 || |
6242 | | magn_methy == 5) */ |
6243 | 0 | { |
6244 | | /* Replicate nearest */ |
6245 | 0 | if (i <= ((m+1) << 1)) |
6246 | 0 | *q=(*p); |
6247 | 0 | else |
6248 | 0 | *q=(*n); |
6249 | 0 | if (magn_methy == 5) |
6250 | 0 | { |
6251 | 0 | if (i == 0) |
6252 | 0 | { |
6253 | | /* Copy */ |
6254 | 0 | (*q).opacity=(*p).opacity; |
6255 | 0 | } |
6256 | 0 | else |
6257 | 0 | { |
6258 | | /* Interpolate */ |
6259 | 0 | (*q).opacity=(QM) ( |
6260 | 0 | ((long) (2*i*((*n).opacity |
6261 | 0 | -(*p).opacity)+m))/ |
6262 | 0 | ((long) (m*2))+ |
6263 | 0 | (*p).opacity); |
6264 | 0 | } |
6265 | 0 | } |
6266 | 0 | } |
6267 | 0 | n++; |
6268 | 0 | q++; |
6269 | 0 | p++; |
6270 | 0 | } /* x */ |
6271 | 0 | if (!SyncImagePixels(large_image)) |
6272 | 0 | break; |
6273 | 0 | } /* i */ |
6274 | 1.77k | } /* y */ |
6275 | 1.77k | MagickFreeMemory(prev); |
6276 | 1.77k | MagickFreeMemory(next); |
6277 | | |
6278 | 1.77k | row_length=image->columns; |
6279 | | |
6280 | 1.77k | if (logging) |
6281 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6282 | 0 | " Delete original image"); |
6283 | | |
6284 | 1.77k | DeleteImageFromList(&image); |
6285 | | |
6286 | 1.77k | image=large_image; |
6287 | | |
6288 | 1.77k | mng_info->image=image; |
6289 | | |
6290 | | /* magnify the columns */ |
6291 | 1.77k | if (logging) |
6292 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6293 | 0 | " Magnify the columns to %lu", |
6294 | 0 | image->columns); |
6295 | | |
6296 | 1.77k | for (y=0; y < (long) image->rows; y++) |
6297 | 1.77k | { |
6298 | 1.77k | q=GetImagePixels(image,0,y,image->columns,1); |
6299 | 1.77k | if(q == (PixelPacket * ) NULL) |
6300 | 1.77k | break; |
6301 | 0 | p=q+(image->columns-row_length); |
6302 | 0 | n=p+1; |
6303 | 0 | for (x=(long) (image->columns-row_length); |
6304 | 0 | x < (long) image->columns; x++) |
6305 | 0 | { |
6306 | 0 | if (x == (long) (image->columns-row_length)) |
6307 | 0 | m=mng_info->magn_ml; |
6308 | 0 | else if (magn_methx > 1 && |
6309 | 0 | x == (long) image->columns-2) |
6310 | 0 | m=mng_info->magn_mr; |
6311 | 0 | else if (magn_methx <= 1 && |
6312 | 0 | x == (long) image->columns-1) |
6313 | 0 | m=mng_info->magn_mr; |
6314 | 0 | else if (magn_methx > 1 && |
6315 | 0 | x == (long) image->columns-1) |
6316 | 0 | m=1; |
6317 | 0 | else |
6318 | 0 | m=mng_info->magn_mx; |
6319 | 0 | for (i=0; i < m; i++) |
6320 | 0 | { |
6321 | 0 | if (magn_methx <= 1) |
6322 | 0 | { |
6323 | | /* replicate previous */ |
6324 | 0 | *q=(*p); |
6325 | 0 | } |
6326 | 0 | else if (magn_methx == 2 || magn_methx == 4) |
6327 | 0 | { |
6328 | 0 | if (i == 0) |
6329 | 0 | *q=(*p); |
6330 | 0 | else |
6331 | 0 | { |
6332 | | /* Interpolate */ |
6333 | 0 | (*q).red=(QM) ((2*i*((*n).red- |
6334 | 0 | (*p).red)+m) |
6335 | 0 | /((long) (m*2))+ |
6336 | 0 | (*p).red); |
6337 | 0 | (*q).green=(QM) ((2*i*((*n).green- |
6338 | 0 | (*p).green) |
6339 | 0 | +m)/((long) (m*2))+ |
6340 | 0 | (*p).green); |
6341 | 0 | (*q).blue=(QM) ((2*i*((*n).blue- |
6342 | 0 | (*p).blue)+m) |
6343 | 0 | /((long) (m*2))+ |
6344 | 0 | (*p).blue); |
6345 | 0 | if (image->matte) |
6346 | 0 | (*q).opacity=(QM) ((2*i*((*n).opacity |
6347 | 0 | -(*p).opacity)+m)/ |
6348 | 0 | ((long) (m*2)) |
6349 | 0 | +(*p).opacity); |
6350 | 0 | } |
6351 | 0 | if (magn_methx == 4) |
6352 | 0 | { |
6353 | | /* Replicate nearest */ |
6354 | 0 | if (i <= ((m+1) << 1)) |
6355 | 0 | (*q).opacity=(*p).opacity+0; |
6356 | 0 | else |
6357 | 0 | (*q).opacity=(*n).opacity+0; |
6358 | 0 | } |
6359 | 0 | } |
6360 | 0 | else /* if (magn_methx == 3 || |
6361 | | magn_methx == 5) */ |
6362 | 0 | { |
6363 | | /* Replicate nearest */ |
6364 | 0 | if (i <= ((m+1) << 1)) |
6365 | 0 | *q=(*p); |
6366 | 0 | else |
6367 | 0 | *q=(*n); |
6368 | 0 | if (magn_methx == 5) |
6369 | 0 | { |
6370 | 0 | if (i == 0) |
6371 | 0 | { |
6372 | | /* Copy */ |
6373 | 0 | (*q).opacity=(*p).opacity; |
6374 | 0 | } |
6375 | 0 | else |
6376 | 0 | { |
6377 | | /* Interpolate */ |
6378 | 0 | (*q).opacity=(QM) ((2*i*((*n).opacity |
6379 | 0 | -(*p).opacity)+m)/ |
6380 | 0 | ((long) (m*2)) |
6381 | 0 | +(*p).opacity); |
6382 | 0 | } |
6383 | 0 | } |
6384 | 0 | } |
6385 | 0 | q++; |
6386 | 0 | } |
6387 | 0 | n++; |
6388 | 0 | p++; |
6389 | 0 | } |
6390 | 0 | if (!SyncImagePixels(image)) |
6391 | 0 | break; |
6392 | 0 | } |
6393 | | #if (QuantumDepth == 32) |
6394 | | if (magn_methx != 1 || magn_methy != 1) |
6395 | | { |
6396 | | /* |
6397 | | Rescale pixels to Quantum |
6398 | | */ |
6399 | | for (y=0; y < (long) image->rows; y++) |
6400 | | { |
6401 | | q=GetImagePixels(image,0,y,image->columns,1); |
6402 | | if(q == (PixelPacket *) NULL) |
6403 | | break; |
6404 | | for (x=(long) image->columns; x > 0; x--) |
6405 | | { |
6406 | | q->red=ScaleShortToQuantum(q->red); |
6407 | | q->green=ScaleShortToQuantum(q->green); |
6408 | | q->blue=ScaleShortToQuantum(q->blue); |
6409 | | q->opacity=ScaleShortToQuantum(q->opacity); |
6410 | | q++; |
6411 | | } |
6412 | | if (!SyncImagePixels(image)) |
6413 | | break; |
6414 | | } |
6415 | | } |
6416 | | #endif |
6417 | 1.77k | if (logging) |
6418 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6419 | 0 | " Finished MAGN processing"); |
6420 | 1.77k | } |
6421 | 2.13k | } |
6422 | | |
6423 | | /* |
6424 | | Crop_box is with respect to the upper left corner of the MNG. |
6425 | | */ |
6426 | 15.6k | crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id]; |
6427 | 15.6k | crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id]; |
6428 | 15.6k | crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id]; |
6429 | 15.6k | crop_box.bottom=mng_info->image_box.bottom+ |
6430 | 15.6k | mng_info->y_off[object_id]; |
6431 | 15.6k | crop_box=mng_minimum_box(crop_box,mng_info->clip); |
6432 | 15.6k | crop_box=mng_minimum_box(crop_box,mng_info->frame); |
6433 | 15.6k | crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]); |
6434 | 15.6k | if ((crop_box.left != (mng_info->image_box.left |
6435 | 15.6k | +mng_info->x_off[object_id])) || |
6436 | 14.5k | (crop_box.right != (mng_info->image_box.right |
6437 | 14.5k | +mng_info->x_off[object_id])) || |
6438 | 13.7k | (crop_box.top != (mng_info->image_box.top |
6439 | 13.7k | +mng_info->y_off[object_id])) || |
6440 | 6.39k | (crop_box.bottom != (mng_info->image_box.bottom |
6441 | 6.39k | +mng_info->y_off[object_id]))) |
6442 | 9.49k | { |
6443 | 9.49k | if (logging) |
6444 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6445 | 0 | " Crop the PNG image"); |
6446 | 9.49k | if ((crop_box.left < crop_box.right) && |
6447 | 7.59k | (crop_box.top < crop_box.bottom)) |
6448 | 0 | { |
6449 | 0 | Image |
6450 | 0 | *p; |
6451 | |
|
6452 | 0 | RectangleInfo |
6453 | 0 | crop_info; |
6454 | | |
6455 | | /* |
6456 | | Crop_info is with respect to the upper left corner of |
6457 | | the image. |
6458 | | */ |
6459 | 0 | crop_info.x=(crop_box.left-mng_info->x_off[object_id]); |
6460 | 0 | crop_info.y=(crop_box.top-mng_info->y_off[object_id]); |
6461 | 0 | crop_info.width=(crop_box.right-crop_box.left); |
6462 | 0 | crop_info.height=(crop_box.bottom-crop_box.top); |
6463 | 0 | image->page.width=image->columns; |
6464 | 0 | image->page.height=image->rows; |
6465 | 0 | image->page.x=0; |
6466 | 0 | image->page.y=0; |
6467 | 0 | p=CropImage(image,&crop_info,exception); |
6468 | 0 | if (p != (Image *) NULL) |
6469 | 0 | { |
6470 | 0 | image->columns=p->columns; |
6471 | 0 | image->rows=p->rows; |
6472 | 0 | DestroyImage(p); |
6473 | 0 | image->page.width=image->columns; |
6474 | 0 | image->page.height=image->rows; |
6475 | 0 | image->page.x=crop_box.left; |
6476 | 0 | image->page.y=crop_box.top; |
6477 | 0 | } |
6478 | 0 | } |
6479 | 9.49k | else |
6480 | 9.49k | { |
6481 | | /* |
6482 | | No pixels in crop area. The MNG spec still requires |
6483 | | a layer, though, so make a single transparent pixel in |
6484 | | the top left corner. |
6485 | | */ |
6486 | 9.49k | image->columns=1; |
6487 | 9.49k | image->rows=1; |
6488 | 9.49k | if (ReallocateImageColormap(image,2) == MagickFail) |
6489 | 0 | { |
6490 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
6491 | 0 | image); |
6492 | 0 | } |
6493 | 9.49k | (void) SetImage(image,TransparentOpacity); |
6494 | 9.49k | image->page.width=1; |
6495 | 9.49k | image->page.height=1; |
6496 | 9.49k | image->page.x=0; |
6497 | 9.49k | image->page.y=0; |
6498 | 9.49k | } |
6499 | 9.49k | } |
6500 | | #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED |
6501 | | image=mng_info->image; |
6502 | | #endif |
6503 | 15.6k | } |
6504 | | |
6505 | | /* |
6506 | | Transfer most significant exception to exception argument |
6507 | | FIXME: should status be used to terminate processing? |
6508 | | */ |
6509 | 93.4k | GetImageException(image,exception); |
6510 | 93.4k | if (image_info->subrange != 0) |
6511 | 93.4k | { |
6512 | 93.4k | if (mng_info->scenes_found > (long) (image_info->subimage+ |
6513 | 93.4k | image_info->subrange)) |
6514 | 15 | break; |
6515 | 93.4k | } |
6516 | 93.4k | if (logging) |
6517 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6518 | 0 | " Finished reading image datastream."); |
6519 | 1.32M | } while (LocaleCompare(image_info->magick,"MNG") == 0); |
6520 | 7.22k | status &= CloseBlob(image); |
6521 | 7.22k | if (logging) |
6522 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6523 | 0 | " Finished reading all image datastreams."); |
6524 | 7.22k | #ifdef MNG_INSERT_LAYERS |
6525 | 7.22k | if (insert_layers && !mng_info->image_found && (mng_info->mng_width) && |
6526 | 684 | (mng_info->mng_height)) |
6527 | 684 | { |
6528 | | /* |
6529 | | Insert a background layer if nothing else was found. |
6530 | | */ |
6531 | 684 | if (logging) |
6532 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6533 | 0 | " No images found. Inserting a" |
6534 | 0 | " background layer."); |
6535 | 684 | if (AccessMutablePixels(image) != (PixelPacket *) NULL) |
6536 | 506 | { |
6537 | 506 | StopTimer(&image->timer); |
6538 | | /* |
6539 | | Allocate next image structure. |
6540 | | */ |
6541 | 506 | AllocateNextImage(image_info,image); |
6542 | 506 | if (image->next == (Image *) NULL) |
6543 | 0 | { |
6544 | 0 | DestroyImageList(image); |
6545 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6546 | 0 | if (logging) |
6547 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6548 | 0 | " Allocation failed, returning NULL."); |
6549 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
6550 | 0 | return((Image *) NULL); |
6551 | 0 | } |
6552 | 506 | image=SyncNextImageInList(image); |
6553 | 506 | } |
6554 | 684 | image->columns=mng_info->mng_width; |
6555 | 684 | image->rows=mng_info->mng_height; |
6556 | 684 | image->page.width=mng_info->mng_width; |
6557 | 684 | image->page.height=mng_info->mng_height; |
6558 | 684 | image->page.x=0; |
6559 | 684 | image->page.y=0; |
6560 | 684 | image->background_color=mng_background_color; |
6561 | 684 | image->matte=MagickFalse; |
6562 | 684 | if (!image_info->ping) |
6563 | 684 | (void) SetImage(image,OpaqueOpacity); |
6564 | 684 | mng_info->image_found++; |
6565 | 684 | } |
6566 | 7.22k | #endif |
6567 | 7.22k | image->iterations=mng_iterations; |
6568 | 7.22k | if (mng_iterations == 1) |
6569 | 7.06k | image->start_loop=MagickTrue; |
6570 | 34.4k | while (image->previous != (Image *) NULL) |
6571 | 27.2k | { |
6572 | 27.2k | image_count++; |
6573 | | #if 0 |
6574 | | /* This code triggers and fails to release memory in oss-fuzz 8710 */ |
6575 | | if (image_count > 10*mng_info->image_found) |
6576 | | { |
6577 | | if (logging) |
6578 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6579 | | " No beginning"); |
6580 | | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6581 | | (void) ThrowException2(exception,(ExceptionType) CoderError, |
6582 | | "Linked list is corrupted," |
6583 | | " beginning of list not found", |
6584 | | image_info->filename); |
6585 | | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
6586 | | return((Image *) NULL); |
6587 | | } |
6588 | | #endif |
6589 | 27.2k | image=image->previous; |
6590 | 27.2k | if (image->next == (Image *) NULL) |
6591 | 0 | { |
6592 | 0 | if (logging) |
6593 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6594 | 0 | " Corrupt list"); |
6595 | 0 | (void) ThrowException2(exception,(ExceptionType) CoderError, |
6596 | 0 | "Linked list is corrupted;" |
6597 | 0 | " next_image is NULL", |
6598 | 0 | image_info->filename); |
6599 | 0 | } |
6600 | 27.2k | } |
6601 | 7.22k | if (mng_info->ticks_per_second && mng_info->image_found > 1 && image->next == |
6602 | 166 | (Image *) NULL) |
6603 | 4 | { |
6604 | 4 | if (logging) |
6605 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6606 | 0 | " First image null"); |
6607 | 4 | (void) ThrowException2(exception,(ExceptionType) CoderError, |
6608 | 4 | "image->next for first image is NULL but" |
6609 | 4 | " shouldn't be.", |
6610 | 4 | image_info->filename); |
6611 | 4 | } |
6612 | 7.22k | if (!mng_info->image_found) |
6613 | 6.32k | { |
6614 | 6.32k | if (logging) |
6615 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6616 | 0 | " No visible images found."); |
6617 | 6.32k | (void) ThrowException2(exception,(ExceptionType) CoderError, |
6618 | 6.32k | "No visible images in file",image_info->filename); |
6619 | 6.32k | if (image != (Image *) NULL) |
6620 | 6.32k | DestroyImageList(image); |
6621 | 6.32k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6622 | 6.32k | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
6623 | 6.32k | return((Image *) NULL); |
6624 | 6.32k | } |
6625 | | |
6626 | 897 | if (mng_info->ticks_per_second) |
6627 | 872 | final_delay=100*final_delay/mng_info->ticks_per_second; |
6628 | 25 | else |
6629 | 25 | image->start_loop=MagickTrue; |
6630 | | /* Find final nonzero image delay */ |
6631 | 897 | final_image_delay=0; |
6632 | 28.1k | while (image->next != (Image *) NULL) |
6633 | 27.2k | { |
6634 | 27.2k | if (image->delay) |
6635 | 22.4k | final_image_delay=image->delay; |
6636 | 27.2k | image=image->next; |
6637 | 27.2k | } |
6638 | 897 | if (final_delay < final_image_delay) |
6639 | 89 | final_delay=final_image_delay; |
6640 | 897 | image->delay=final_delay; |
6641 | 897 | if (logging) |
6642 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6643 | 0 | " image->delay=%lu, final_delay=%lu", |
6644 | 0 | image->delay,final_delay); |
6645 | 897 | if (logging) |
6646 | 0 | { |
6647 | 0 | int |
6648 | 0 | scene; |
6649 | |
|
6650 | 0 | scene=0; |
6651 | 0 | while (image->previous != (Image *) NULL) |
6652 | 0 | image=image->previous; |
6653 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6654 | 0 | " Before coalesce:"); |
6655 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6656 | 0 | " scene 0 delay=%lu",image->delay); |
6657 | 0 | while (image->next != (Image *) NULL) |
6658 | 0 | { |
6659 | 0 | image=image->next; |
6660 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6661 | 0 | " scene %d delay=%lu",++scene,image->delay); |
6662 | 0 | } |
6663 | 0 | } |
6664 | | |
6665 | 28.1k | while (image->previous != (Image *) NULL) |
6666 | 27.2k | image=image->previous; |
6667 | 897 | #ifdef MNG_COALESCE_LAYERS |
6668 | 897 | if (insert_layers && image->next) |
6669 | 676 | { |
6670 | 676 | Image |
6671 | 676 | *next_image, |
6672 | 676 | *next; |
6673 | | |
6674 | 676 | unsigned long |
6675 | 676 | scene; |
6676 | | |
6677 | 676 | if (logging) |
6678 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6679 | 0 | " Coalesce Images"); |
6680 | 676 | scene=image->scene; |
6681 | 676 | next_image=CoalesceImages(image,exception); |
6682 | 676 | DestroyImageList(image); |
6683 | 676 | if (next_image == (Image *) NULL) |
6684 | 0 | { |
6685 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6686 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); |
6687 | 0 | return((Image *) NULL); |
6688 | 0 | } |
6689 | 676 | image=next_image; |
6690 | 27.7k | for (next=image; next != (Image *) NULL; next=next_image) |
6691 | 27.7k | { |
6692 | 27.7k | next->page.width=mng_info->mng_width; |
6693 | 27.7k | next->page.height=mng_info->mng_height; |
6694 | 27.7k | next->page.x=0; |
6695 | 27.7k | next->page.y=0; |
6696 | 27.7k | next->scene=scene++; |
6697 | 27.7k | next_image=next->next; |
6698 | 27.7k | if (next_image == (Image *) NULL) |
6699 | 676 | break; |
6700 | 27.1k | if (next->delay == 0) |
6701 | 4.60k | { |
6702 | 4.60k | scene--; |
6703 | 4.60k | next_image->previous=next->previous; |
6704 | 4.60k | if (next->previous == (Image *) NULL) |
6705 | 3.15k | image=next_image; |
6706 | 1.45k | else |
6707 | 1.45k | next->previous->next=next_image; |
6708 | 4.60k | DestroyImage(next); |
6709 | 4.60k | } |
6710 | 27.1k | } |
6711 | 676 | } |
6712 | 897 | #endif |
6713 | | |
6714 | 23.5k | while (image->next != (Image *) NULL) |
6715 | 22.6k | image=image->next; |
6716 | 897 | image->dispose=BackgroundDispose; |
6717 | | |
6718 | 897 | if (logging) |
6719 | 0 | { |
6720 | 0 | int |
6721 | 0 | scene; |
6722 | |
|
6723 | 0 | scene=0; |
6724 | 0 | while (image->previous != (Image *) NULL) |
6725 | 0 | image=image->previous; |
6726 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6727 | 0 | " After coalesce:"); |
6728 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6729 | 0 | " scene 0 delay=%lu dispose=%d", |
6730 | 0 | image->delay,(int) image->dispose); |
6731 | 0 | while (image->next != (Image *) NULL) |
6732 | 0 | { |
6733 | 0 | image=image->next; |
6734 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6735 | 0 | " scene %d delay=%lu dispose=%d",++scene, |
6736 | 0 | image->delay,(int) image->dispose); |
6737 | 0 | } |
6738 | 0 | } |
6739 | 23.5k | while (image->previous != (Image *) NULL) |
6740 | 22.6k | image=image->previous; |
6741 | 897 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
6742 | 897 | have_mng_structure=MagickFalse; |
6743 | 897 | if (logging) |
6744 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()"); |
6745 | 897 | return(image); |
6746 | 897 | } |
6747 | | #else /* PNG_LIBPNG_VER > 10011 */ |
6748 | | static Image *ReadPNGImage(const ImageInfo *image_info, |
6749 | | ExceptionInfo *exception) |
6750 | | { |
6751 | | printf("Your PNG library is too old: You have libpng-%s\n", |
6752 | | PNG_LIBPNG_VER_STRING); |
6753 | | (void) ThrowException2(exception,CoderError,"PNG library is too old", |
6754 | | image_info->filename); |
6755 | | return (Image *) NULL; |
6756 | | } |
6757 | | static Image *ReadMNGImage(const ImageInfo *image_info, |
6758 | | ExceptionInfo *exception) |
6759 | | { |
6760 | | return (ReadPNGImage(image_info,exception)); |
6761 | | } |
6762 | | #endif /* PNG_LIBPNG_VER > 10011 */ |
6763 | | #endif |
6764 | | |
6765 | | /* |
6766 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
6767 | | % % |
6768 | | % % |
6769 | | % % |
6770 | | % R e g i s t e r P N G I m a g e % |
6771 | | % % |
6772 | | % % |
6773 | | % % |
6774 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
6775 | | % |
6776 | | % Method RegisterPNGImage adds attributes for the PNG image format to |
6777 | | % the list of supported formats. The attributes include the image format |
6778 | | % tag, a method to read and/or write the format, whether the format |
6779 | | % supports the saving of more than one frame to the same file or blob, |
6780 | | % whether the format supports native in-memory I/O, and a brief |
6781 | | % description of the format. |
6782 | | % |
6783 | | % The format of the RegisterPNGImage method is: |
6784 | | % |
6785 | | % RegisterPNGImage(void) |
6786 | | % |
6787 | | */ |
6788 | | ModuleExport void RegisterPNGImage(void) |
6789 | 17 | { |
6790 | 17 | static char |
6791 | 17 | version[32]; |
6792 | | |
6793 | 17 | MagickInfo |
6794 | 17 | *entry; |
6795 | | |
6796 | 17 | static const char |
6797 | 17 | PNGNote[]= |
6798 | 17 | { |
6799 | 17 | "See http://www.libpng.org/ for information on PNG.." |
6800 | 17 | }; |
6801 | | |
6802 | 17 | static const char |
6803 | 17 | JNGNote[]= |
6804 | 17 | { |
6805 | 17 | "See http://www.libpng.org/pub/mng/ for information on JNG." |
6806 | 17 | }; |
6807 | | |
6808 | 17 | static const char |
6809 | 17 | MNGNote[]= |
6810 | 17 | { |
6811 | 17 | "See http://www.libpng.org/pub/mng/ for information on MNG." |
6812 | 17 | }; |
6813 | | |
6814 | 17 | *version='\0'; |
6815 | 17 | #if defined(PNG_LIBPNG_VER_STRING) |
6816 | 17 | (void) strlcat(version,"libpng ",sizeof(version)); |
6817 | 17 | (void) strlcat(version,PNG_LIBPNG_VER_STRING,sizeof(version)); |
6818 | 17 | #if (PNG_LIBPNG_VER > 10005) |
6819 | 17 | if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0) |
6820 | 0 | { |
6821 | 0 | (void) strlcat(version,",",sizeof(version)); |
6822 | 0 | (void) strlcat(version,png_get_libpng_ver(NULL),sizeof(version)); |
6823 | 0 | } |
6824 | 17 | #endif |
6825 | 17 | #endif |
6826 | | |
6827 | 17 | #if defined(ZLIB_VERSION) |
6828 | 17 | if (*version != '\0') |
6829 | 17 | (void) strlcat(version,", ",sizeof(version)); |
6830 | 17 | (void) strlcat(version,"zlib ",sizeof(version)); |
6831 | 17 | (void) strlcat(version,ZLIB_VERSION,sizeof(version)); |
6832 | 17 | if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0) |
6833 | 0 | { |
6834 | 0 | (void) strlcat(version,",",sizeof(version)); |
6835 | 0 | (void) strlcat(version,zlib_version,sizeof(version)); |
6836 | 0 | } |
6837 | 17 | #endif |
6838 | | |
6839 | 17 | entry=SetMagickInfo("MNG"); |
6840 | 17 | entry->seekable_stream=MagickTrue; /* To do: eliminate this. */ |
6841 | 17 | entry->thread_support=MagickTrue; |
6842 | 17 | #if defined(HasPNG) |
6843 | 17 | entry->decoder=(DecoderHandler) ReadMNGImage; |
6844 | 17 | entry->encoder=(EncoderHandler) WriteMNGImage; |
6845 | 17 | #endif |
6846 | 17 | entry->magick=(MagickHandler) IsMNG; |
6847 | 17 | entry->description="Multiple-image Network Graphics"; |
6848 | 17 | if (*version != '\0') |
6849 | 17 | entry->version=version; |
6850 | 17 | entry->module="PNG"; |
6851 | 17 | entry->coder_class=StableCoderClass; |
6852 | 17 | entry->note=MNGNote; |
6853 | 17 | (void) RegisterMagickInfo(entry); |
6854 | | |
6855 | 17 | entry=SetMagickInfo("PNG"); |
6856 | 17 | #if defined(HasPNG) |
6857 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6858 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6859 | 17 | #endif |
6860 | 17 | entry->magick=(MagickHandler) IsPNG; |
6861 | 17 | entry->adjoin=MagickFalse; |
6862 | 17 | entry->thread_support=MagickTrue; |
6863 | 17 | entry->description="Portable Network Graphics"; |
6864 | 17 | if (*version != '\0') |
6865 | 17 | entry->version=version; |
6866 | 17 | entry->note=PNGNote; |
6867 | 17 | entry->module="PNG"; |
6868 | 17 | entry->coder_class=PrimaryCoderClass; |
6869 | 17 | (void) RegisterMagickInfo(entry); |
6870 | | |
6871 | 17 | entry=SetMagickInfo("PNG8"); |
6872 | 17 | #if defined(HasPNG) |
6873 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6874 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6875 | 17 | #endif |
6876 | 17 | entry->magick=(MagickHandler) IsPNG; |
6877 | 17 | entry->adjoin=MagickFalse; |
6878 | 17 | entry->thread_support=MagickTrue; |
6879 | 17 | entry->description="8-bit indexed PNG, binary transparency only"; |
6880 | 17 | if (*version != '\0') |
6881 | 17 | entry->version=version; |
6882 | 17 | entry->module="PNG"; |
6883 | 17 | entry->coder_class=PrimaryCoderClass; |
6884 | 17 | (void) RegisterMagickInfo(entry); |
6885 | | |
6886 | 17 | entry=SetMagickInfo("PNG24"); |
6887 | 17 | #if defined(HasPNG) |
6888 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6889 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6890 | 17 | #endif |
6891 | 17 | entry->magick=(MagickHandler) IsPNG; |
6892 | 17 | entry->adjoin=MagickFalse; |
6893 | 17 | entry->thread_support=MagickTrue; |
6894 | 17 | entry->description="24-bit RGB PNG, opaque only"; |
6895 | 17 | if (*version != '\0') |
6896 | 17 | entry->version=version; |
6897 | 17 | entry->module="PNG"; |
6898 | 17 | entry->coder_class=PrimaryCoderClass; |
6899 | 17 | (void) RegisterMagickInfo(entry); |
6900 | | |
6901 | 17 | entry=SetMagickInfo("PNG32"); |
6902 | 17 | #if defined(HasPNG) |
6903 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6904 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6905 | 17 | #endif |
6906 | 17 | entry->magick=(MagickHandler) IsPNG; |
6907 | 17 | entry->adjoin=MagickFalse; |
6908 | 17 | entry->thread_support=MagickTrue; |
6909 | 17 | entry->description="32-bit RGBA PNG, semitransparency OK"; |
6910 | 17 | if (*version != '\0') |
6911 | 17 | entry->version=version; |
6912 | 17 | entry->module="PNG"; |
6913 | 17 | entry->coder_class=PrimaryCoderClass; |
6914 | 17 | (void) RegisterMagickInfo(entry); |
6915 | | |
6916 | 17 | entry=SetMagickInfo("PNG48"); |
6917 | | |
6918 | 17 | #if defined(HasPNG) |
6919 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6920 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6921 | 17 | #endif |
6922 | | |
6923 | 17 | entry->magick=(MagickHandler) IsPNG; |
6924 | 17 | entry->adjoin=MagickFalse; |
6925 | 17 | entry->thread_support=MagickTrue; |
6926 | 17 | entry->description="opaque or binary transparent 48-bit RGB"; |
6927 | 17 | if (*version != '\0') |
6928 | 17 | entry->version=version; |
6929 | 17 | entry->module="PNG"; |
6930 | 17 | entry->coder_class=PrimaryCoderClass; |
6931 | 17 | (void) RegisterMagickInfo(entry); |
6932 | | |
6933 | 17 | entry=SetMagickInfo("PNG64"); |
6934 | | |
6935 | 17 | #if defined(HasPNG) |
6936 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6937 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6938 | 17 | #endif |
6939 | | |
6940 | 17 | entry->magick=(MagickHandler) IsPNG; |
6941 | 17 | entry->adjoin=MagickFalse; |
6942 | 17 | entry->thread_support=MagickTrue; |
6943 | 17 | entry->description="opaque or transparent 64-bit RGBA"; |
6944 | 17 | if (*version != '\0') |
6945 | 17 | entry->version=version; |
6946 | 17 | entry->module="PNG"; |
6947 | 17 | entry->coder_class=PrimaryCoderClass; |
6948 | 17 | (void) RegisterMagickInfo(entry); |
6949 | | |
6950 | 17 | entry=SetMagickInfo("PNG00"); |
6951 | | |
6952 | 17 | #if defined(HasPNG) |
6953 | 17 | entry->decoder=(DecoderHandler) ReadPNGImage; |
6954 | 17 | entry->encoder=(EncoderHandler) WritePNGImage; |
6955 | 17 | #endif |
6956 | | |
6957 | 17 | entry->magick=(MagickHandler) IsPNG; |
6958 | 17 | entry->adjoin=MagickFalse; |
6959 | 17 | entry->thread_support=MagickTrue; |
6960 | 17 | entry->description="PNG that inherits type and depth from original"; |
6961 | 17 | if (*version != '\0') |
6962 | 17 | entry->version=version; |
6963 | 17 | entry->module="PNG"; |
6964 | 17 | entry->coder_class=PrimaryCoderClass; |
6965 | 17 | (void) RegisterMagickInfo(entry); |
6966 | | |
6967 | 17 | entry=SetMagickInfo("JNG"); |
6968 | 17 | #if defined(JNG_SUPPORTED) |
6969 | 17 | #if defined(HasPNG) |
6970 | 17 | entry->decoder=(DecoderHandler) ReadJNGImage; |
6971 | 17 | entry->encoder=(EncoderHandler) WriteJNGImage; |
6972 | 17 | #endif |
6973 | 17 | #endif |
6974 | 17 | entry->magick=(MagickHandler) IsJNG; |
6975 | 17 | entry->seekable_stream=MagickTrue; /* To do: eliminate this. */ |
6976 | 17 | entry->adjoin=MagickFalse; |
6977 | 17 | entry->thread_support=MagickTrue; |
6978 | 17 | entry->description="JPEG Network Graphics"; |
6979 | 17 | entry->note=JNGNote; |
6980 | 17 | if (*version != '\0') |
6981 | 17 | entry->version=version; |
6982 | 17 | entry->module="PNG"; |
6983 | 17 | entry->coder_class=StableCoderClass; |
6984 | 17 | (void) RegisterMagickInfo(entry); |
6985 | | |
6986 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
6987 | | png_semaphore=AllocateSemaphoreInfo(); |
6988 | | #endif |
6989 | 17 | } |
6990 | | |
6991 | | /* |
6992 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
6993 | | % % |
6994 | | % % |
6995 | | % % |
6996 | | % U n r e g i s t e r P N G I m a g e % |
6997 | | % % |
6998 | | % % |
6999 | | % % |
7000 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
7001 | | % |
7002 | | % Method UnregisterPNGImage removes format registrations made by the |
7003 | | % PNG module from the list of supported formats. |
7004 | | % |
7005 | | % The format of the UnregisterPNGImage method is: |
7006 | | % |
7007 | | % UnregisterPNGImage(void) |
7008 | | % |
7009 | | */ |
7010 | | ModuleExport void UnregisterPNGImage(void) |
7011 | 0 | { |
7012 | 0 | (void) UnregisterMagickInfo("MNG"); |
7013 | 0 | (void) UnregisterMagickInfo("PNG"); |
7014 | 0 | (void) UnregisterMagickInfo("PNG8"); |
7015 | 0 | (void) UnregisterMagickInfo("PNG24"); |
7016 | 0 | (void) UnregisterMagickInfo("PNG32"); |
7017 | 0 | (void) UnregisterMagickInfo("PNG48"); |
7018 | 0 | (void) UnregisterMagickInfo("PNG64"); |
7019 | 0 | (void) UnregisterMagickInfo("PNG00"); |
7020 | 0 | (void) UnregisterMagickInfo("JNG"); |
7021 | |
|
7022 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
7023 | | DestroySemaphoreInfo(&png_semaphore); |
7024 | | #endif |
7025 | 0 | } |
7026 | | |
7027 | | #if defined(HasPNG) |
7028 | | #if PNG_LIBPNG_VER > 10011 |
7029 | | /* |
7030 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
7031 | | % % |
7032 | | % % |
7033 | | % % |
7034 | | % W r i t e M N G I m a g e % |
7035 | | % % |
7036 | | % % |
7037 | | % % |
7038 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
7039 | | % |
7040 | | % Method WriteMNGImage writes an image in the Portable Network Graphics |
7041 | | % Group's "Multiple-image Network Graphics" encoded image format. |
7042 | | % |
7043 | | % MNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu |
7044 | | % |
7045 | | % The format of the WriteMNGImage method is: |
7046 | | % |
7047 | | % unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image) |
7048 | | % |
7049 | | % A description of each parameter follows. |
7050 | | % |
7051 | | % o status: Method WriteMNGImage return True if the image is written. |
7052 | | % MagickFalse is returned is there is a memory shortage or if the |
7053 | | % image file fails to write. |
7054 | | % |
7055 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
7056 | | % |
7057 | | % o image: A pointer to an Image structure. |
7058 | | % |
7059 | | % |
7060 | | % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also |
7061 | | % "To do" under ReadPNGImage): |
7062 | | % |
7063 | | % Fix problem with palette sorting (when PNG_SORT_PALETTE is enabled, |
7064 | | % some GIF animations don't convert properly) |
7065 | | % |
7066 | | % Preserve all unknown and not-yet-handled known chunks found in input |
7067 | | % PNG file and copy them into output PNG files according to the PNG |
7068 | | % copying rules. |
7069 | | % |
7070 | | % Write the iCCP chunk at MNG level when (image->color_profile.length > 0) |
7071 | | % |
7072 | | % Improve selection of color type (use indexed-colour or indexed-colour |
7073 | | % with tRNS when 256 or fewer unique RGBA values are present). |
7074 | | % |
7075 | | % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3) |
7076 | | % This will be complicated if we limit ourselves to generating MNG-LC |
7077 | | % files. For now we ignore disposal method 3 and simply overlay the next |
7078 | | % image on it. |
7079 | | % |
7080 | | % Check for identical PLTE's or PLTE/tRNS combinations and use a |
7081 | | % global MNG PLTE or PLTE/tRNS combination when appropriate. |
7082 | | % [mostly done 15 June 1999 but still need to take care of tRNS] |
7083 | | % |
7084 | | % Check for identical sRGB and replace with a global sRGB (and remove |
7085 | | % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and |
7086 | | % replace with global gAMA/cHRM (or with sRGB if appropriate; replace |
7087 | | % local gAMA/cHRM with local sRGB if appropriate). |
7088 | | % |
7089 | | % Check for identical sBIT chunks and write global ones. |
7090 | | % |
7091 | | % Provide option to skip writing the signature tEXt chunks. |
7092 | | % |
7093 | | % Use signatures to detect identical objects and reuse the first |
7094 | | % instance of such objects instead of writing duplicate objects. |
7095 | | % |
7096 | | % Use a smaller-than-32k value of compression window size when |
7097 | | % appropriate. |
7098 | | % |
7099 | | % Encode JNG datastreams. Mostly done as of 5.5.2; need to write |
7100 | | % ancillary text chunks and save profiles. |
7101 | | % |
7102 | | % Provide an option to force LC files (to ensure exact framing rate) |
7103 | | % instead of VLC. |
7104 | | % |
7105 | | % Provide an option to force VLC files instead of LC, even when offsets |
7106 | | % are present. This will involve expanding the embedded images with a |
7107 | | % transparent region at the top and/or left. |
7108 | | */ |
7109 | | |
7110 | | |
7111 | | static MagickPassFail |
7112 | | png_write_raw_profile(const ImageInfo *image_info,png_struct *ping, |
7113 | | png_info *ping_info, const char *profile_type, |
7114 | | const char *profile_description, |
7115 | | const unsigned char *profile_data, |
7116 | | size_t length,ExceptionInfo *exception) |
7117 | 1.78k | { |
7118 | 1.78k | png_textp |
7119 | 1.78k | text = (png_textp) NULL; |
7120 | | |
7121 | 1.78k | register long |
7122 | 1.78k | i; |
7123 | | |
7124 | 1.78k | const unsigned char |
7125 | 1.78k | *sp; |
7126 | | |
7127 | 1.78k | png_charp |
7128 | 1.78k | dp; |
7129 | | |
7130 | 1.78k | size_t |
7131 | 1.78k | allocated_length, |
7132 | 1.78k | description_length; |
7133 | | |
7134 | 1.78k | unsigned int |
7135 | 1.78k | status = MagickPass; |
7136 | | |
7137 | 1.78k | static const unsigned char |
7138 | 1.78k | hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; |
7139 | | |
7140 | 1.78k | if (image_info->verbose) |
7141 | 0 | { |
7142 | 0 | (void) printf("writing raw profile: type=%.1024s, length=%zu\n", |
7143 | 0 | profile_type, length); |
7144 | 0 | } |
7145 | 1.78k | if (length >= (PNG_UINT_31_MAX / 2)) |
7146 | 0 | { |
7147 | 0 | ThrowException(exception,ResourceLimitError,UnableToAddOrRemoveProfile,image_info->filename); |
7148 | 0 | status=MagickFail; |
7149 | 0 | return status; |
7150 | 0 | } |
7151 | 1.78k | description_length=strlen((const char *) profile_description); |
7152 | 1.78k | allocated_length=(length*2 + (length >> 5) + 20 + description_length); |
7153 | 1.78k | if (((png_uint_32)allocated_length) < length) |
7154 | 0 | { |
7155 | 0 | ThrowException(exception,CoderError,ArithmeticOverflow,image_info->filename); |
7156 | 0 | status=MagickFail; |
7157 | 0 | return status; |
7158 | 0 | } |
7159 | | #if PNG_LIBPNG_VER >= 14000 |
7160 | | text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text)); |
7161 | | #else |
7162 | 1.78k | text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); |
7163 | 1.78k | #endif |
7164 | 1.78k | if (text == (png_textp) NULL) |
7165 | 0 | { |
7166 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image_info->filename); |
7167 | 0 | status=MagickFail; |
7168 | 0 | return status; |
7169 | 0 | } |
7170 | 1.78k | (void) memset(&text[0],0,sizeof(png_text)); |
7171 | | |
7172 | | #if PNG_LIBPNG_VER >= 14000 |
7173 | | text[0].text=(png_charp) png_malloc(ping,(png_alloc_size_t) allocated_length); |
7174 | | text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80); |
7175 | | #else |
7176 | 1.78k | text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length); |
7177 | 1.78k | text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80); |
7178 | 1.78k | #endif |
7179 | 1.78k | if ((text[0].text == (png_charp) NULL) || (text[0].key == (png_charp) NULL)) |
7180 | 0 | { |
7181 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image_info->filename); |
7182 | 0 | status=MagickFail; |
7183 | 0 | goto png_write_raw_profile_cleanup; |
7184 | 0 | } |
7185 | 1.78k | text[0].key[0]='\0'; |
7186 | 1.78k | (void) strlcat(text[0].key, "Raw profile type ", 80); |
7187 | 1.78k | (void) strncat(text[0].key, (const char *) profile_type, 61); |
7188 | 1.78k | sp=profile_data; |
7189 | 1.78k | dp=text[0].text; |
7190 | 1.78k | *dp++='\n'; |
7191 | 1.78k | (void) strlcpy(dp,(const char *) profile_description,(allocated_length-(dp-text[0].text))); |
7192 | 1.78k | dp+=strlen(dp); |
7193 | 1.78k | *dp++='\n'; |
7194 | 1.78k | (void) snprintf(dp,(allocated_length-(dp-text[0].text)),"%8zu ",length); |
7195 | 1.78k | dp+=strlen(dp); |
7196 | 57.0k | for (i=0; i < (long) length; i++) |
7197 | 55.2k | { |
7198 | 55.2k | if (i%36 == 0) |
7199 | 3.12k | *dp++='\n'; |
7200 | 55.2k | *(dp++)=hex[((*sp >> 4) & 0x0f)]; |
7201 | 55.2k | *(dp++)=hex[((*sp++ ) & 0x0f)]; |
7202 | 55.2k | } |
7203 | 1.78k | *dp++='\n'; |
7204 | 1.78k | *dp='\0'; |
7205 | 1.78k | text[0].text_length=dp-text[0].text; |
7206 | 1.78k | if (text[0].text_length > allocated_length) |
7207 | 0 | { |
7208 | 0 | ThrowException(exception,CoderError,ArithmeticOverflow,image_info->filename); |
7209 | 0 | status=MagickFail; |
7210 | 0 | goto png_write_raw_profile_cleanup; |
7211 | 0 | } |
7212 | 1.78k | text[0].compression=image_info->compression == NoCompression || |
7213 | 1.78k | (image_info->compression == UndefinedCompression && |
7214 | 1.78k | text[0].text_length < 128) ? -1 : 0; |
7215 | 1.78k | png_set_text(ping,ping_info,text,1); /* returns void */ |
7216 | 1.78k | png_write_raw_profile_cleanup: |
7217 | 1.78k | png_free(ping,text[0].text); |
7218 | 1.78k | png_free(ping,text[0].key); |
7219 | 1.78k | png_free(ping,text); |
7220 | 1.78k | return status; |
7221 | 1.78k | } |
7222 | | |
7223 | | static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, |
7224 | | const ImageInfo *image_info,Image *imagep) |
7225 | 29.6k | { |
7226 | 29.6k | const char |
7227 | 29.6k | *gm_vers, |
7228 | 29.6k | *libpng_runv, |
7229 | 29.6k | *libpng_vers, |
7230 | 29.6k | *zlib_runv, |
7231 | 29.6k | *zlib_vers; |
7232 | | |
7233 | 29.6k | #ifdef HasLCMS |
7234 | 29.6k | char |
7235 | 29.6k | lcms_vers[32]; |
7236 | 29.6k | #endif |
7237 | | |
7238 | 29.6k | char |
7239 | 29.6k | filename[MaxTextExtent]; |
7240 | | |
7241 | 29.6k | Image |
7242 | 29.6k | * volatile imagev = imagep, /* Use only 'imagev' before setjmp() */ |
7243 | 29.6k | *image; /* Use only 'image' after setjmp() */ |
7244 | | |
7245 | | /* Write one PNG image */ |
7246 | 29.6k | const ImageAttribute |
7247 | 29.6k | *attribute; |
7248 | | |
7249 | 29.6k | char |
7250 | 29.6k | s[2]; |
7251 | | |
7252 | 29.6k | int |
7253 | 29.6k | num_passes, |
7254 | 29.6k | pass, |
7255 | 29.6k | ping_bit_depth = 0, |
7256 | 29.6k | ping_colortype = 0, |
7257 | 29.6k | ping_interlace_method = 0, |
7258 | 29.6k | ping_compression_method = 0; |
7259 | | |
7260 | 29.6k | volatile int |
7261 | 29.6k | ping_filter_method = 0, |
7262 | 29.6k | ping_num_trans = 0, |
7263 | 29.6k | ping_valid_trns = 0; |
7264 | | |
7265 | 29.6k | volatile png_bytep |
7266 | 29.6k | ping_trans_alpha = NULL; |
7267 | | |
7268 | 29.6k | png_colorp |
7269 | 29.6k | palette; |
7270 | | |
7271 | 29.6k | png_color_16 |
7272 | 29.6k | ping_background, |
7273 | 29.6k | ping_trans_color; |
7274 | | |
7275 | 29.6k | png_info |
7276 | 29.6k | *ping_info; |
7277 | | |
7278 | 29.6k | png_struct |
7279 | 29.6k | *ping; |
7280 | | |
7281 | 29.6k | png_uint_32 |
7282 | 29.6k | ping_width, |
7283 | 29.6k | ping_height; |
7284 | | |
7285 | 29.6k | long |
7286 | 29.6k | y; |
7287 | | |
7288 | 29.6k | register const IndexPacket |
7289 | 29.6k | *indexes; |
7290 | | |
7291 | 29.6k | register unsigned long |
7292 | 29.6k | i; |
7293 | | |
7294 | 29.6k | register long |
7295 | 29.6k | x; |
7296 | | |
7297 | 29.6k | unsigned char |
7298 | 29.6k | *png_pixels; |
7299 | | |
7300 | 29.6k | unsigned int |
7301 | 29.6k | image_colors, |
7302 | 29.6k | image_depth, |
7303 | 29.6k | image_matte, |
7304 | 29.6k | logging, |
7305 | 29.6k | matte; |
7306 | | |
7307 | 29.6k | unsigned long |
7308 | 29.6k | quantum_size, /* depth for ExportImage */ |
7309 | 29.6k | rowbytes, |
7310 | 29.6k | save_image_depth; |
7311 | | |
7312 | 29.6k | ImageCharacteristics |
7313 | 29.6k | characteristics; |
7314 | | |
7315 | 29.6k | logging=LogMagickEvent(CoderEvent,GetMagickModule(), |
7316 | 29.6k | " enter WriteOnePNGImage()"); |
7317 | | |
7318 | 29.6k | assert(mng_info->png_pixels == (unsigned char *) NULL); |
7319 | | |
7320 | 29.6k | if (imagev == (Image *) NULL) |
7321 | 0 | return(MagickFalse); |
7322 | | |
7323 | 29.6k | (void) MagickStrlCpy(filename, imagev->filename, sizeof(filename)); |
7324 | | |
7325 | | /* Define these outside of the following "if logging()" block so they will |
7326 | | * show in debuggers. |
7327 | | */ |
7328 | 29.6k | gm_vers=MagickLibVersionText; |
7329 | 29.6k | #ifdef HasLCMS |
7330 | 29.6k | (void) snprintf(lcms_vers,sizeof(lcms_vers),"%.4d",LCMS_VERSION); |
7331 | 29.6k | #endif |
7332 | 29.6k | libpng_runv=png_get_libpng_ver(NULL); |
7333 | 29.6k | libpng_vers=PNG_LIBPNG_VER_STRING; |
7334 | 29.6k | zlib_runv=zlib_version; |
7335 | 29.6k | zlib_vers=ZLIB_VERSION; |
7336 | | |
7337 | 29.6k | if (logging != MagickFalse) |
7338 | 0 | { |
7339 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7340 | 0 | " GM version = %.31s", gm_vers); |
7341 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7342 | 0 | " Libpng version = %.31s", libpng_vers); |
7343 | 0 | if (LocaleCompare(libpng_vers,libpng_runv) != 0) |
7344 | 0 | { |
7345 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7346 | 0 | " running with %.31s", libpng_runv); |
7347 | 0 | } |
7348 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7349 | 0 | " Zlib version = %.31s", zlib_vers); |
7350 | 0 | if (LocaleCompare(zlib_vers,zlib_runv) != 0) |
7351 | 0 | { |
7352 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7353 | 0 | " running with %.31s", zlib_runv); |
7354 | 0 | } |
7355 | 0 | #ifdef HasLCMS |
7356 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7357 | 0 | " LCMS version = %.31s", lcms_vers); |
7358 | 0 | #endif |
7359 | 0 | } |
7360 | | /* Initialize some stuff */ |
7361 | 29.6k | ping_background.red = 0; |
7362 | 29.6k | ping_background.green = 0; |
7363 | 29.6k | ping_background.blue = 0; |
7364 | 29.6k | ping_background.gray = 0; |
7365 | 29.6k | ping_background.index = 0; |
7366 | | |
7367 | 29.6k | ping_trans_color.red=0; |
7368 | 29.6k | ping_trans_color.green=0; |
7369 | 29.6k | ping_trans_color.blue=0; |
7370 | 29.6k | ping_trans_color.gray=0; |
7371 | | |
7372 | | /* |
7373 | | Allocate the PNG structures |
7374 | | */ |
7375 | 29.6k | #ifdef PNG_USER_MEM_SUPPORTED |
7376 | 29.6k | ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,imagev, |
7377 | 29.6k | PNGErrorHandler,PNGWarningHandler, |
7378 | 29.6k | (void *) NULL, |
7379 | 29.6k | (png_malloc_ptr) png_IM_malloc, |
7380 | 29.6k | (png_free_ptr) png_IM_free); |
7381 | | #else |
7382 | | ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,imagev, |
7383 | | PNGErrorHandler,PNGWarningHandler); |
7384 | | #endif |
7385 | 29.6k | if (ping == (png_struct *) NULL) |
7386 | 29.6k | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,imagev); |
7387 | 29.6k | ping_info=png_create_info_struct(ping); |
7388 | 29.6k | if (ping_info == (png_info *) NULL) |
7389 | 0 | { |
7390 | 0 | png_destroy_write_struct(&ping,(png_info **) NULL); |
7391 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,imagev); |
7392 | 0 | } |
7393 | 29.6k | png_set_write_fn(ping,imagev,png_put_data,png_flush_data); |
7394 | 29.6k | png_pixels=(unsigned char *) NULL; |
7395 | | |
7396 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
7397 | | LockSemaphoreInfo(png_semaphore); |
7398 | | #endif |
7399 | | |
7400 | 29.6k | if (setjmp(png_jmpbuf(ping))) |
7401 | 80 | { |
7402 | | /* |
7403 | | PNG write failed. |
7404 | | */ |
7405 | 80 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7406 | 80 | "Setjmp return from longjmp!"); |
7407 | 80 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7408 | 80 | "PNG write has failed!"); |
7409 | 80 | png_destroy_write_struct(&ping,&ping_info); |
7410 | 80 | MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels); |
7411 | | |
7412 | | /* |
7413 | | Handle write failure by removing the output file. |
7414 | | */ |
7415 | 80 | if (unlink(filename) != -1) |
7416 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7417 | 0 | "Removed broken output file \"%s\"",filename); |
7418 | | |
7419 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
7420 | | UnlockSemaphoreInfo(png_semaphore); |
7421 | | #endif |
7422 | 80 | return(MagickFail); |
7423 | 80 | } |
7424 | | |
7425 | | /* { For navigation to end of setjmp-controlled block */ |
7426 | | |
7427 | 29.5k | #ifdef PNG_BENIGN_ERRORS_SUPPORTED |
7428 | | /* Allow benign errors */ |
7429 | 29.5k | png_set_benign_errors(ping, 1); |
7430 | 29.5k | #endif |
7431 | | |
7432 | 29.5k | image=imagev; /* Use 'image' after this point for optimization */ |
7433 | | |
7434 | | /* |
7435 | | Make sure that image is in an RGB type space. |
7436 | | */ |
7437 | 29.5k | if (!TransformColorspace(image,RGBColorspace)) |
7438 | 0 | { |
7439 | 0 | CloseBlob(image); |
7440 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
7441 | | UnlockSemaphoreInfo(png_semaphore); |
7442 | | #endif |
7443 | 0 | return MagickFail; |
7444 | 0 | } |
7445 | | |
7446 | | /* |
7447 | | Analyze image to be written. |
7448 | | */ |
7449 | 29.5k | if (!GetImageCharacteristics(image,&characteristics, |
7450 | 29.5k | (OptimizeType == image_info->type), |
7451 | 29.5k | &image->exception)) |
7452 | 0 | { |
7453 | 0 | CloseBlob(image); |
7454 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
7455 | | UnlockSemaphoreInfo(png_semaphore); |
7456 | | #endif |
7457 | 0 | return MagickFail; |
7458 | 0 | } |
7459 | | |
7460 | 29.5k | if (logging) |
7461 | 0 | { |
7462 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7463 | 0 | " Image Characteristics:\n" |
7464 | 0 | " CMYK: %u\n" |
7465 | 0 | " Grayscale: %u\n" |
7466 | 0 | " Monochrome: %u\n" |
7467 | 0 | " Opaque: %u\n" |
7468 | 0 | " Palette: %u", |
7469 | 0 | characteristics.cmyk, |
7470 | 0 | characteristics.grayscale , |
7471 | 0 | characteristics.monochrome, |
7472 | 0 | characteristics.opaque, |
7473 | 0 | characteristics.palette); |
7474 | 0 | } |
7475 | | |
7476 | 29.5k | if (image->storage_class == PseudoClass) |
7477 | 28.2k | image_colors=image->colors; |
7478 | 1.36k | else |
7479 | 1.36k | image_colors=0; |
7480 | | |
7481 | 29.5k | image_depth=image->depth; |
7482 | 29.5k | image_matte=image->matte; |
7483 | | |
7484 | 29.5k | if (image->storage_class == PseudoClass && |
7485 | 28.2k | image_colors <= 256) |
7486 | 28.1k | { |
7487 | 28.1k | mng_info->IsPalette=MagickTrue; |
7488 | 28.1k | image_depth=8; |
7489 | 28.1k | } |
7490 | | |
7491 | 29.5k | if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32) |
7492 | 5.25k | image_depth=8; |
7493 | | |
7494 | 24.3k | else if (mng_info->write_png48 || mng_info->write_png64) |
7495 | 3.32k | image_depth=16; |
7496 | | |
7497 | 21.0k | else if (image_depth < 8) |
7498 | 0 | image_depth=8; |
7499 | | |
7500 | 21.0k | else if (image_depth > 8) |
7501 | 82 | image_depth=16; |
7502 | | |
7503 | | /* |
7504 | | Prepare PNG for writing. |
7505 | | */ |
7506 | | |
7507 | 29.5k | #if defined(PNG_MNG_FEATURES_SUPPORTED) |
7508 | 29.5k | if (mng_info->write_mng) |
7509 | 17.6k | { |
7510 | 17.6k | # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED |
7511 | | /* Disable new libpng-1.5.10 feature when writing a MNG */ |
7512 | 17.6k | png_set_check_for_invalid_index (ping, 0); |
7513 | 17.6k | # endif |
7514 | 17.6k | (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); |
7515 | 17.6k | } |
7516 | | #else |
7517 | | # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
7518 | | if (mng_info->write_mng) |
7519 | | png_permit_empty_plte(ping,MagickTrue); |
7520 | | # endif |
7521 | | #endif |
7522 | 29.5k | x=0; |
7523 | 29.5k | ping_width=image->columns; |
7524 | 29.5k | ping_height=image->rows; |
7525 | 29.5k | if (logging) |
7526 | 0 | { |
7527 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7528 | 0 | " width=%lu", |
7529 | 0 | (unsigned long)ping_width); |
7530 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7531 | 0 | " height=%lu", |
7532 | 0 | (unsigned long)ping_height); |
7533 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7534 | 0 | " image->depth=%u",image_depth); |
7535 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7536 | 0 | " image_colors=%u",image_colors); |
7537 | 0 | } |
7538 | | |
7539 | | |
7540 | 29.5k | quantum_size=(image_depth > 8) ? 16:8; |
7541 | | |
7542 | 29.5k | save_image_depth=image_depth; |
7543 | 29.5k | ping_bit_depth=(png_byte) save_image_depth; |
7544 | 29.5k | if (logging) |
7545 | 0 | { |
7546 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7547 | 0 | " ping_bit_depth=%u", |
7548 | 0 | ping_bit_depth); |
7549 | 0 | } |
7550 | | /* |
7551 | | Select the color type. |
7552 | | */ |
7553 | 29.5k | matte=image_matte; |
7554 | 29.5k | if (mng_info->write_png8) |
7555 | 1.85k | { |
7556 | 1.85k | QuantizeInfo |
7557 | 1.85k | quantize_info; |
7558 | | |
7559 | 1.85k | unsigned long |
7560 | 1.85k | number_colors; |
7561 | | |
7562 | 1.85k | if (logging) |
7563 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7564 | 0 | " Entering PNG8 block"); |
7565 | | |
7566 | 1.85k | ping_colortype=PNG_COLOR_TYPE_PALETTE; |
7567 | 1.85k | ping_bit_depth=8; |
7568 | | |
7569 | 1.85k | number_colors=image_colors; |
7570 | 1.85k | if ((number_colors == 0) || (number_colors > 256)) |
7571 | 494 | { |
7572 | 494 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7573 | 494 | " Quantizing image..."); |
7574 | 494 | GetQuantizeInfo(&quantize_info); |
7575 | 494 | quantize_info.dither=image_info->dither; |
7576 | 494 | quantize_info.number_colors=256; |
7577 | 494 | (void) QuantizeImage(&quantize_info,image); |
7578 | 494 | number_colors=image->colors; |
7579 | 494 | if (logging) |
7580 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7581 | 0 | " Colors quantized to %lu colors", |
7582 | 0 | number_colors); |
7583 | 494 | image_colors=image->colors; |
7584 | 494 | } |
7585 | | |
7586 | 1.85k | if (!characteristics.opaque) /* Previously image->matte or image_matte */ |
7587 | 328 | { |
7588 | | /* |
7589 | | Analyze the image pixels to see if just one color index |
7590 | | is transparent, and if it matches the background |
7591 | | color. |
7592 | | */ |
7593 | 328 | unsigned int num_transparent = 0; |
7594 | 328 | unsigned int background_index = 0; |
7595 | 328 | MagickBool background_index_transparent = MagickFalse; |
7596 | | |
7597 | | /* |
7598 | | Refresh index for background color |
7599 | | */ |
7600 | 3.19k | for (i=0; i < Max(Max(1,number_colors)-1,1); i++) |
7601 | 3.05k | { |
7602 | 3.05k | if (RGBColorMatchExact(ping_background,image->colormap[i])) |
7603 | 186 | { |
7604 | 186 | background_index=i; |
7605 | 186 | ping_background.index=(png_uint_16) background_index; |
7606 | 186 | if (logging) |
7607 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7608 | 0 | " background index %u (%u, %u, %u)", |
7609 | 0 | ping_background.index, |
7610 | 0 | image->colormap[ping_background.index].red, |
7611 | 0 | image->colormap[ping_background.index].green, |
7612 | 0 | image->colormap[ping_background.index].blue); |
7613 | 186 | break; |
7614 | 186 | } |
7615 | 3.05k | } |
7616 | | |
7617 | | /* |
7618 | | Determine which colormap indexes are non-opaque. |
7619 | | */ |
7620 | 18.0k | for (i=0; i < image->colors; i++) |
7621 | 17.6k | { |
7622 | 17.6k | image->colormap[i].opacity=OpaqueOpacity; |
7623 | 17.6k | } |
7624 | 23.3k | for (y=0; y < (long) image->rows; y++) |
7625 | 23.0k | { |
7626 | 23.0k | register const PixelPacket |
7627 | 23.0k | *p; |
7628 | | |
7629 | 23.0k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
7630 | 23.0k | if (p == (const PixelPacket *) NULL) |
7631 | 0 | break; |
7632 | 23.0k | indexes=AccessImmutableIndexes(image); |
7633 | 7.60M | for (x=0; x < (long) image->columns; x++) |
7634 | 7.58M | { |
7635 | 7.58M | if (p->opacity != OpaqueOpacity) |
7636 | 7.05M | { |
7637 | 7.05M | IndexPacket |
7638 | 7.05M | index; |
7639 | | |
7640 | 7.05M | index=indexes[x]; |
7641 | 7.05M | image->colormap[index].opacity = p->opacity; |
7642 | 7.05M | } |
7643 | 7.58M | p++; |
7644 | 7.58M | } |
7645 | 23.0k | } |
7646 | | /* |
7647 | | Is background color index fully transparent? |
7648 | | */ |
7649 | 18.0k | for (i=0; i < image->colors; i++) |
7650 | 17.6k | { |
7651 | 17.6k | if (image->colormap[i].opacity != OpaqueOpacity) |
7652 | 7.91k | { |
7653 | 7.91k | if ((i == background_index) && |
7654 | 185 | (image->colormap[i].opacity == TransparentOpacity)) |
7655 | 116 | background_index_transparent = MagickTrue; |
7656 | 7.91k | num_transparent++; |
7657 | 7.91k | } |
7658 | 17.6k | } |
7659 | 328 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7660 | 328 | " quantized image has %u transparent colors," |
7661 | 328 | " background color index " |
7662 | 328 | "%u (%u, %u, %u)" |
7663 | 328 | " %s fully transparent", |
7664 | 328 | num_transparent, |
7665 | 328 | background_index, |
7666 | 328 | image->colormap[background_index].red, |
7667 | 328 | image->colormap[background_index].green, |
7668 | 328 | image->colormap[background_index].blue, |
7669 | 328 | background_index_transparent ? "is" : "is not"); |
7670 | | |
7671 | | /* |
7672 | | If we have more than one transparent color, and the |
7673 | | background color is fully transparent, then remove |
7674 | | transparency for non-background pixels so there will now |
7675 | | be only one transparent (the background) color. |
7676 | | */ |
7677 | 328 | if ((num_transparent > 1) && (background_index_transparent)) |
7678 | 101 | { |
7679 | 101 | if (logging) |
7680 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7681 | 0 | " Fixing non-background pixels which are not opaque..."); |
7682 | 5.34k | for (y=0; y < (long) image->rows; y++) |
7683 | 5.24k | { |
7684 | 5.24k | register PixelPacket |
7685 | 5.24k | *p; |
7686 | | |
7687 | 5.24k | p=GetImagePixelsEx(image,0,y,image->columns,1,&image->exception); |
7688 | 5.24k | if (p == (const PixelPacket *) NULL) |
7689 | 0 | break; |
7690 | | /* indexes=AccessImmutableIndexes(image); */ |
7691 | 5.24k | indexes=AccessMutableIndexes(image); |
7692 | 1.54M | for (x=0; x < (long) image->columns; x++) |
7693 | 1.53M | { |
7694 | | /* |
7695 | | Replace non-opaque pixels which are very close |
7696 | | to the transparent background color with the |
7697 | | transparent background color. |
7698 | | */ |
7699 | 1.53M | if ((indexes[x] != background_index) && (p->opacity != OpaqueOpacity)) |
7700 | 852k | { |
7701 | 852k | double distance = DistanceVector(&image->colormap[background_index],p); |
7702 | 852k | if (distance < 0.3) |
7703 | 181k | { |
7704 | 181k | *p=image->colormap[background_index]; |
7705 | 181k | p->opacity=TransparentOpacity; |
7706 | 181k | } |
7707 | 671k | else |
7708 | 671k | { |
7709 | 671k | p->opacity=OpaqueOpacity; |
7710 | 671k | } |
7711 | 852k | } |
7712 | 1.53M | p++; |
7713 | 1.53M | } |
7714 | 5.24k | SyncImagePixelsEx(image,&image->exception); |
7715 | 5.24k | } |
7716 | | |
7717 | | /* Re-quantize */ |
7718 | 101 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7719 | 101 | " Quantizing image..."); |
7720 | 101 | image->storage_class=DirectClass; |
7721 | 101 | GetQuantizeInfo(&quantize_info); |
7722 | 101 | quantize_info.dither=image_info->dither; |
7723 | 101 | quantize_info.number_colors=256; |
7724 | 101 | (void) QuantizeImage(&quantize_info,image); |
7725 | 101 | number_colors=image->colors; |
7726 | 101 | if (logging) |
7727 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7728 | 0 | " colors quantized to %lu colors", |
7729 | 0 | number_colors); |
7730 | 101 | image_colors=image->colors; |
7731 | | |
7732 | | /* |
7733 | | Refresh index for background color |
7734 | | */ |
7735 | 1.47k | for (i=0; i < Max(Max(1,number_colors)-1,1); i++) |
7736 | 1.41k | { |
7737 | 1.41k | if (RGBColorMatchExact(ping_background,image->colormap[i])) |
7738 | 50 | { |
7739 | 50 | background_index=i; |
7740 | 50 | ping_background.index=(png_uint_16) background_index; |
7741 | 50 | if (logging) |
7742 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7743 | 0 | " background index %u (%u, %u, %u)", |
7744 | 0 | ping_background.index, |
7745 | 0 | image->colormap[ping_background.index].red, |
7746 | 0 | image->colormap[ping_background.index].green, |
7747 | 0 | image->colormap[ping_background.index].blue); |
7748 | 50 | break; |
7749 | 50 | } |
7750 | 1.41k | } |
7751 | 101 | } |
7752 | 328 | } /* End of if (!characteristics.opaque) */ |
7753 | | |
7754 | | /* |
7755 | | Set image palette. |
7756 | | */ |
7757 | 1.85k | ping_colortype=PNG_COLOR_TYPE_PALETTE; |
7758 | | |
7759 | 1.85k | if (logging) |
7760 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7761 | 0 | " Setting up PLTE chunk with %d colors", |
7762 | 0 | (int) number_colors); |
7763 | 1.85k | palette=MagickAllocateMemory(png_color *, |
7764 | 1.85k | number_colors*sizeof(png_color)); |
7765 | 1.85k | if (palette == (png_color *) NULL) |
7766 | 0 | { |
7767 | 0 | png_error(ping, "Could not allocate palette"); |
7768 | 0 | } |
7769 | 1.85k | else |
7770 | 1.85k | { |
7771 | 93.8k | for (i=0; i < number_colors; i++) |
7772 | 92.0k | { |
7773 | 92.0k | palette[i].red=ScaleQuantumToChar(image->colormap[i].red); |
7774 | 92.0k | palette[i].green=ScaleQuantumToChar(image->colormap[i].green); |
7775 | 92.0k | palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); |
7776 | 92.0k | if (logging) |
7777 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7778 | | #if QuantumDepth == 8 |
7779 | | " %3ld (%3d,%3d,%3d)", |
7780 | | #else |
7781 | 0 | " %5ld (%5d,%5d,%5d)", |
7782 | 0 | #endif |
7783 | 0 | i,palette[i].red,palette[i].green, |
7784 | 0 | palette[i].blue); |
7785 | | |
7786 | 92.0k | } |
7787 | 1.85k | if (logging) |
7788 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7789 | 0 | " Setting up PLTE chunk with %d colors", |
7790 | 0 | (int) number_colors); |
7791 | 1.85k | png_set_PLTE(ping,ping_info,palette,(int) number_colors); |
7792 | 1.85k | MagickFreeMemory(palette); |
7793 | 1.85k | } |
7794 | 1.85k | if (!characteristics.opaque) /* Previously image->matte or image_matte */ |
7795 | 328 | { |
7796 | | /* |
7797 | | Determine which (and how many) colormap indexes are non-opaque. |
7798 | | */ |
7799 | 328 | unsigned int |
7800 | 328 | transparent_index = 0; |
7801 | | |
7802 | 328 | assert(number_colors <= 256); |
7803 | | |
7804 | 328 | ping_num_trans=0; |
7805 | 17.3k | for (i=0; i < image->colors; i++) |
7806 | 17.0k | { |
7807 | 17.0k | image->colormap[i].opacity=OpaqueOpacity; |
7808 | 17.0k | } |
7809 | 23.3k | for (y=0; y < (long) image->rows; y++) |
7810 | 23.0k | { |
7811 | 23.0k | register const PixelPacket |
7812 | 23.0k | *p; |
7813 | | |
7814 | 23.0k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
7815 | 23.0k | if (p == (const PixelPacket *) NULL) |
7816 | 0 | break; |
7817 | 23.0k | indexes=AccessImmutableIndexes(image); |
7818 | 7.60M | for (x=0; x < (long) image->columns; x++) |
7819 | 7.58M | { |
7820 | 7.58M | if (p->opacity != OpaqueOpacity) |
7821 | 6.38M | { |
7822 | 6.38M | IndexPacket |
7823 | 6.38M | index; |
7824 | | |
7825 | 6.38M | index=indexes[x]; |
7826 | 6.38M | image->colormap[index].opacity = p->opacity; |
7827 | 6.38M | } |
7828 | 7.58M | p++; |
7829 | 7.58M | } |
7830 | 23.0k | } |
7831 | 17.3k | for (i=0; i < image->colors; i++) |
7832 | 17.0k | { |
7833 | 17.0k | if (image->colormap[i].opacity != OpaqueOpacity) |
7834 | 6.41k | { |
7835 | 6.41k | transparent_index=i; |
7836 | 6.41k | ++ping_num_trans; |
7837 | 6.41k | } |
7838 | 17.0k | } |
7839 | 328 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7840 | 328 | " image has %u transparent color%s", |
7841 | 328 | ping_num_trans, (ping_num_trans > 1) ? "s" : ""); |
7842 | 328 | if (ping_num_trans > 1) |
7843 | 125 | { |
7844 | 125 | png_warning(ping, |
7845 | 125 | "PNG8 only supports 1 transparent color, disabling transparency..."); |
7846 | 125 | image->matte=MagickFalse; |
7847 | 125 | ping_num_trans=0; |
7848 | 125 | } |
7849 | | |
7850 | 328 | if (ping_num_trans != 0) |
7851 | 190 | { |
7852 | 190 | unsigned int |
7853 | 190 | mask = 0x00ff; /* For ping_bit_depth == 8 */ |
7854 | | |
7855 | 190 | const PixelPacket * |
7856 | 190 | p = &image->colormap[transparent_index]; |
7857 | | |
7858 | 190 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7859 | 190 | " %u transparent colors, enable tRNS", |
7860 | 190 | ping_num_trans); |
7861 | | |
7862 | 190 | ping_trans_color.red=ScaleQuantumToShort(p->red)&mask; |
7863 | 190 | ping_trans_color.green=ScaleQuantumToShort(p->green) |
7864 | 190 | &mask; |
7865 | 190 | ping_trans_color.blue=ScaleQuantumToShort(p->blue) |
7866 | 190 | &mask; |
7867 | 190 | ping_trans_color.gray= |
7868 | 190 | (png_uint_16) ScaleQuantumToShort(PixelIntensity(p))&mask; |
7869 | 190 | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
7870 | 190 | ping_trans_color.index = (png_byte) ping_background.index; |
7871 | 0 | else |
7872 | 0 | ping_trans_color.index=(unsigned char) |
7873 | 0 | (ScaleQuantumToChar(MaxRGB-p->opacity)); |
7874 | 190 | ping_valid_trns=1; |
7875 | 190 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7876 | 190 | "Single transparent color (%d,%d,%d index=%d)", |
7877 | 190 | ping_trans_color.red,ping_trans_color.green, |
7878 | 190 | ping_trans_color.blue,ping_trans_color.index); |
7879 | | |
7880 | | /* |
7881 | | FIXME: To optimize file size, we want just one entry |
7882 | | in tRNS, and this requires that the transparent color |
7883 | | should be at the first index in the palette. Libpng |
7884 | | appears to optimize the chunk size by trimming |
7885 | | trailing opaque entries. |
7886 | | */ |
7887 | 190 | ping_trans_alpha= |
7888 | 190 | MagickAllocateMemory(unsigned char *, number_colors); |
7889 | 190 | if (ping_trans_alpha == (unsigned char *) NULL) |
7890 | 0 | png_error(ping, "Could not allocate trans_alpha"); |
7891 | | |
7892 | 6.18k | for (i=0; i < number_colors; i++) |
7893 | 5.99k | ping_trans_alpha[i]=255; |
7894 | 190 | ping_trans_alpha[ping_trans_color.index]=0; |
7895 | 190 | } |
7896 | 328 | } |
7897 | | |
7898 | | /* |
7899 | | Identify which colormap entry is the background color. |
7900 | | */ |
7901 | 34.1k | for (i=0; i < Max(Max(1,number_colors)-1,1); i++) |
7902 | 33.7k | { |
7903 | 33.7k | if (RGBColorMatchExact(ping_background,image->colormap[i])) |
7904 | 1.46k | { |
7905 | | /* background_index=i; */ |
7906 | 1.46k | ping_background.index=(png_uint_16) i; |
7907 | 1.46k | if (logging) |
7908 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7909 | 0 | " background index %u (%u, %u, %u)", |
7910 | 0 | ping_background.index, |
7911 | 0 | image->colormap[ping_background.index].red, |
7912 | 0 | image->colormap[ping_background.index].green, |
7913 | 0 | image->colormap[ping_background.index].blue); |
7914 | 1.46k | break; |
7915 | 1.46k | } |
7916 | 33.7k | } |
7917 | | |
7918 | 1.85k | if (logging) |
7919 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7920 | 0 | " Leaving PNG8 block"); |
7921 | 1.85k | } |
7922 | 27.7k | else if (mng_info->write_png24 || mng_info->write_png48) |
7923 | 3.41k | { |
7924 | 3.41k | image_matte=MagickFalse; |
7925 | 3.41k | ping_colortype=PNG_COLOR_TYPE_RGB; |
7926 | 3.41k | } |
7927 | 24.3k | else if (mng_info->write_png32 || mng_info->write_png64) |
7928 | 3.30k | { |
7929 | 3.30k | image_matte=MagickTrue; |
7930 | 3.30k | ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA; |
7931 | 3.30k | } |
7932 | 21.0k | else |
7933 | 21.0k | { |
7934 | 21.0k | if (ping_bit_depth < 8) |
7935 | 0 | ping_bit_depth=8; |
7936 | | |
7937 | 21.0k | ping_colortype=PNG_COLOR_TYPE_RGB; |
7938 | 21.0k | if (characteristics.monochrome) |
7939 | 4.26k | { |
7940 | 4.26k | if (characteristics.opaque) |
7941 | 4.26k | { |
7942 | 4.26k | ping_colortype=PNG_COLOR_TYPE_GRAY; |
7943 | 4.26k | ping_bit_depth=1; |
7944 | 4.26k | } |
7945 | 0 | else |
7946 | 0 | { |
7947 | 0 | ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA; |
7948 | 0 | } |
7949 | 4.26k | } |
7950 | 16.7k | else if (characteristics.grayscale) |
7951 | 1.49k | { |
7952 | 1.49k | if (characteristics.opaque) |
7953 | 1.46k | ping_colortype=PNG_COLOR_TYPE_GRAY; |
7954 | 27 | else |
7955 | 27 | ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA; |
7956 | 1.49k | } |
7957 | 15.2k | else if (characteristics.palette && image_colors <= 256) |
7958 | 14.7k | { |
7959 | 14.7k | ping_colortype=PNG_COLOR_TYPE_PALETTE; |
7960 | 14.7k | ping_bit_depth=8; |
7961 | 14.7k | mng_info->IsPalette=MagickTrue; |
7962 | 14.7k | } |
7963 | 521 | else |
7964 | 521 | { |
7965 | 521 | if (characteristics.opaque) |
7966 | 70 | ping_colortype=PNG_COLOR_TYPE_RGB; |
7967 | 451 | else |
7968 | 451 | ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA; |
7969 | 521 | } |
7970 | 21.0k | if (image_info->type == BilevelType) |
7971 | 0 | { |
7972 | 0 | if (characteristics.monochrome) |
7973 | 0 | { |
7974 | 0 | if (!image_matte) |
7975 | 0 | ping_bit_depth=1; |
7976 | 0 | } |
7977 | 0 | } |
7978 | 21.0k | if (image_info->type == GrayscaleType) |
7979 | 0 | ping_colortype=PNG_COLOR_TYPE_GRAY; |
7980 | 21.0k | if (image_info->type == GrayscaleMatteType) |
7981 | 0 | ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA; |
7982 | | |
7983 | 21.0k | if (logging) |
7984 | 0 | { |
7985 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7986 | 0 | " Tentative PNG color type: %s (%d)", |
7987 | 0 | PngColorTypeToString(ping_colortype), |
7988 | 0 | ping_colortype); |
7989 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7990 | 0 | " image_info->type: %d",image_info->type); |
7991 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7992 | 0 | " image->depth: %u",image_depth); |
7993 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7994 | 0 | " ping_bit_depth: %d", |
7995 | 0 | ping_bit_depth); |
7996 | 0 | } |
7997 | | |
7998 | 21.0k | if (matte && mng_info->IsPalette) |
7999 | 21 | { |
8000 | 21 | register const PixelPacket |
8001 | 21 | *p=NULL; |
8002 | | |
8003 | 21 | if (characteristics.opaque) |
8004 | 0 | { |
8005 | | /* |
8006 | | No transparent pixels are present. Change 4 or 6 to 0 or 2, |
8007 | | and unset the ping_valid_trns flag. |
8008 | | */ |
8009 | 0 | image_matte=MagickFalse; |
8010 | 0 | ping_colortype&=0x03; |
8011 | 0 | ping_valid_trns=0; |
8012 | 0 | } |
8013 | 21 | else |
8014 | 21 | { |
8015 | 21 | unsigned int |
8016 | 21 | mask; |
8017 | | |
8018 | 21 | MagickBool |
8019 | 21 | opaque = MagickTrue; |
8020 | | |
8021 | 21 | mask=0xffff; |
8022 | 21 | if (ping_bit_depth == 8) |
8023 | 21 | mask=0x00ff; |
8024 | 21 | if (ping_bit_depth == 4) |
8025 | 0 | mask=0x000f; |
8026 | 21 | if (ping_bit_depth == 2) |
8027 | 0 | mask=0x0003; |
8028 | 21 | if (ping_bit_depth == 1) |
8029 | 0 | mask=0x0001; |
8030 | | |
8031 | | /* |
8032 | | Find a transparent color. |
8033 | | */ |
8034 | 86 | for (y=0; y < (long) image->rows; y++) |
8035 | 85 | { |
8036 | 85 | p=AcquireImagePixels(image,0,y,image->columns,1, |
8037 | 85 | &image->exception); |
8038 | 85 | if (p == (const PixelPacket *) NULL) |
8039 | 0 | break; |
8040 | 8.27k | for (x=(long) image->columns; x > 0; x--) |
8041 | 8.21k | { |
8042 | 8.21k | if (p->opacity != OpaqueOpacity) |
8043 | 20 | { |
8044 | 20 | opaque=MagickFalse; |
8045 | 20 | break; |
8046 | 20 | } |
8047 | 8.19k | p++; |
8048 | 8.19k | } |
8049 | 85 | if (!opaque) |
8050 | 20 | break; |
8051 | 85 | } |
8052 | 21 | if ((!opaque) && (p != (const PixelPacket *) NULL)) |
8053 | 20 | { |
8054 | 20 | ping_trans_color.red=ScaleQuantumToShort(p->red)&mask; |
8055 | 20 | ping_trans_color.green=ScaleQuantumToShort(p->green) |
8056 | 20 | &mask; |
8057 | 20 | ping_trans_color.blue=ScaleQuantumToShort(p->blue) |
8058 | 20 | &mask; |
8059 | 20 | ping_trans_color.gray= |
8060 | 20 | (png_uint_16) ScaleQuantumToShort(PixelIntensity(p))&mask; |
8061 | 20 | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
8062 | 0 | ping_trans_color.index = (png_byte) ping_background.index; |
8063 | 20 | else |
8064 | 20 | ping_trans_color.index=(unsigned char) |
8065 | 20 | (ScaleQuantumToChar(MaxRGB-p->opacity)); |
8066 | 20 | ping_valid_trns=1; |
8067 | 20 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8068 | 20 | " Found transparent color: (%d,%d,%d)", |
8069 | 20 | ping_trans_color.red, ping_trans_color.green, |
8070 | 20 | ping_trans_color.blue); |
8071 | 20 | } |
8072 | 21 | } |
8073 | 21 | if (ping_valid_trns != 0) |
8074 | 20 | { |
8075 | | /* |
8076 | | Determine if there is one and only one transparent color |
8077 | | and if so if it is fully transparent. |
8078 | | */ |
8079 | 20 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8080 | 20 | " Determine if there is exactly one transparent color"); |
8081 | 72 | for (y=0; y < (long) image->rows; y++) |
8082 | 63 | { |
8083 | 63 | p=AcquireImagePixels(image,0,y,image->columns,1, |
8084 | 63 | &image->exception); |
8085 | 63 | x=0; |
8086 | 63 | if (p == (const PixelPacket *) NULL) |
8087 | 0 | break; |
8088 | 208 | for (x=(long) image->columns; x > 0; x--) |
8089 | 156 | { |
8090 | 156 | if (p->opacity != OpaqueOpacity) |
8091 | 155 | { |
8092 | 155 | if (!RGBColorMatchExact(ping_trans_color,*p)) |
8093 | 7 | { |
8094 | 7 | break; /* Can't use RGB + tRNS for multiple |
8095 | | transparent colors. */ |
8096 | 7 | } |
8097 | 148 | if (p->opacity != TransparentOpacity) |
8098 | 4 | { |
8099 | 4 | break; /* Can't use RGB + tRNS for |
8100 | | semitransparency. */ |
8101 | 4 | } |
8102 | 148 | } |
8103 | 1 | else |
8104 | 1 | { |
8105 | 1 | if (RGBColorMatchExact(ping_trans_color,*p)) |
8106 | 0 | break; /* Can't use RGB + tRNS when another pixel |
8107 | | having the same RGB samples is |
8108 | | transparent. */ |
8109 | 1 | } |
8110 | 145 | p++; |
8111 | 145 | } |
8112 | 63 | if (x != 0) |
8113 | 11 | break; |
8114 | 63 | } |
8115 | 20 | if (x != 0) |
8116 | 11 | { |
8117 | 11 | ping_valid_trns = 0; |
8118 | 11 | } |
8119 | 9 | else if (logging) |
8120 | 0 | { |
8121 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8122 | 0 | "Single transparent color (%d,%d,%d index=%d)", |
8123 | 0 | ping_trans_color.red,ping_trans_color.green, |
8124 | 0 | ping_trans_color.blue,ping_trans_color.index); |
8125 | 0 | } |
8126 | 20 | } |
8127 | 21 | if (ping_valid_trns != 0) |
8128 | 9 | { |
8129 | 9 | ping_colortype &= 0x03; /* changes 4 or 6 to 0 or 2 */ |
8130 | 9 | if (image_depth == 8) |
8131 | 9 | { |
8132 | 9 | ping_trans_color.red&=0xff; |
8133 | 9 | ping_trans_color.green&=0xff; |
8134 | 9 | ping_trans_color.blue&=0xff; |
8135 | 9 | ping_trans_color.gray&=0xff; |
8136 | 9 | } |
8137 | 9 | } |
8138 | 21 | } |
8139 | 21.0k | matte=image_matte; |
8140 | 21.0k | if (ping_valid_trns != 0) |
8141 | 9 | image_matte=MagickFalse; |
8142 | 21.0k | if (mng_info->IsPalette && |
8143 | 20.4k | characteristics.grayscale && (!image_matte || image_depth >= 8)) |
8144 | 5.72k | { |
8145 | 5.72k | if (image_matte) |
8146 | 12 | ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA; |
8147 | 5.71k | else |
8148 | 5.71k | { |
8149 | 5.71k | ping_colortype=PNG_COLOR_TYPE_GRAY; |
8150 | 5.71k | if (save_image_depth == 16 && image_depth == 8) |
8151 | 0 | ping_trans_color.gray*=0x0101; |
8152 | 5.71k | } |
8153 | 5.72k | if (image_depth > QuantumDepth) |
8154 | 0 | image_depth=QuantumDepth; |
8155 | 5.72k | if (image_colors == 0 || image_colors-1 > MaxRGB) |
8156 | 0 | image_colors=1U << image_depth; |
8157 | 5.72k | if (image_depth > 8) |
8158 | 0 | ping_bit_depth=16; |
8159 | 5.72k | else |
8160 | 5.72k | { |
8161 | 5.72k | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
8162 | 0 | { |
8163 | 0 | ping_bit_depth=1; |
8164 | 0 | while ((int) (1U << ping_bit_depth) < |
8165 | 0 | (long) image_colors) |
8166 | 0 | ping_bit_depth <<= 1; |
8167 | 0 | } |
8168 | 5.72k | } |
8169 | 5.72k | } |
8170 | 15.2k | else |
8171 | 15.2k | if (mng_info->IsPalette) |
8172 | 14.7k | { |
8173 | 14.7k | if (image_depth <= 8) |
8174 | 14.7k | { |
8175 | 14.7k | unsigned long |
8176 | 14.7k | number_colors; |
8177 | | |
8178 | 14.7k | number_colors=image_colors; |
8179 | | /* |
8180 | | Set image palette. |
8181 | | */ |
8182 | 14.7k | ping_colortype=PNG_COLOR_TYPE_PALETTE; |
8183 | 14.7k | if (mng_info->have_write_global_plte && !matte) |
8184 | 1.95k | { |
8185 | 1.95k | png_set_PLTE(ping,ping_info,NULL,0); |
8186 | 1.95k | if (logging) |
8187 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8188 | 0 | " Setting up empty PLTE chunk"); |
8189 | 1.95k | } |
8190 | 12.7k | else |
8191 | 12.7k | { |
8192 | 12.7k | palette=MagickAllocateArray(png_color *, |
8193 | 12.7k | number_colors, |
8194 | 12.7k | sizeof(png_color)); |
8195 | 12.7k | if (palette == (png_color *) NULL) |
8196 | 0 | png_error(ping, "Could not allocate palette"); |
8197 | 35.8k | for (i=0; i < number_colors; i++) |
8198 | 23.1k | { |
8199 | 23.1k | palette[i].red=ScaleQuantumToChar |
8200 | 23.1k | (image->colormap[i].red); |
8201 | 23.1k | palette[i].green=ScaleQuantumToChar |
8202 | 23.1k | (image->colormap[i].green); |
8203 | 23.1k | palette[i].blue=ScaleQuantumToChar |
8204 | 23.1k | (image->colormap[i].blue); |
8205 | 23.1k | } |
8206 | 12.7k | if (logging) |
8207 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8208 | 0 | " Setting up PLTE chunk with %d colors", |
8209 | 0 | (int) number_colors); |
8210 | 12.7k | png_set_PLTE(ping,ping_info,palette,(int) number_colors); |
8211 | 12.7k | MagickFreeMemory(palette); |
8212 | 12.7k | } |
8213 | 14.7k | ping_bit_depth=1; |
8214 | 15.2k | while ((1U << ping_bit_depth) < number_colors) |
8215 | 558 | ping_bit_depth <<= 1; |
8216 | 14.7k | ping_num_trans=0; |
8217 | 14.7k | if (matte) |
8218 | 0 | { |
8219 | 0 | int |
8220 | 0 | num_alpha=0, |
8221 | 0 | trans_alpha[256]; |
8222 | | |
8223 | | /* |
8224 | | Identify which colormap entry is transparent. |
8225 | | */ |
8226 | 0 | assert(number_colors <= 256); |
8227 | |
|
8228 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8229 | 0 | " Look for transparent colormap entry, number_colors=%d", |
8230 | 0 | (int) number_colors); |
8231 | |
|
8232 | 0 | for (i=0; i < number_colors; i++) |
8233 | 0 | trans_alpha[i]=256; |
8234 | |
|
8235 | 0 | for (y=0; y < (long) image->rows; y++) |
8236 | 0 | { |
8237 | 0 | register const PixelPacket |
8238 | 0 | *p=NULL; |
8239 | |
|
8240 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
8241 | 0 | &image->exception); |
8242 | 0 | if (p == (const PixelPacket *) NULL) |
8243 | 0 | break; |
8244 | 0 | indexes=AccessImmutableIndexes(image); |
8245 | 0 | for (x=0; x < (long) image->columns; x++) |
8246 | 0 | { |
8247 | 0 | if (p->opacity != OpaqueOpacity) |
8248 | 0 | { |
8249 | 0 | IndexPacket |
8250 | 0 | index; |
8251 | |
|
8252 | 0 | index=indexes[x]; |
8253 | 0 | assert((unsigned long) index < number_colors); |
8254 | 0 | if (trans_alpha[index] == 256) |
8255 | 0 | { |
8256 | 0 | (void) LogMagickEvent(CoderEvent, |
8257 | 0 | GetMagickModule(), |
8258 | 0 | " Index=%d is transparent", |
8259 | 0 | (int) index); |
8260 | 0 | trans_alpha[index]=(png_byte) (255- |
8261 | 0 | ScaleQuantumToChar(p->opacity)); |
8262 | 0 | num_alpha++; |
8263 | 0 | } |
8264 | 0 | } |
8265 | 0 | p++; |
8266 | 0 | } |
8267 | 0 | } |
8268 | | |
8269 | 0 | (void) LogMagickEvent(CoderEvent, GetMagickModule(), |
8270 | 0 | " num_alpha = %d",num_alpha); |
8271 | 0 | if (num_alpha == 0) |
8272 | 0 | { |
8273 | 0 | image_matte = MagickFalse; |
8274 | 0 | ping_valid_trns = 0; |
8275 | 0 | } |
8276 | 0 | else if (num_alpha == 1) |
8277 | 0 | { |
8278 | 0 | ping_valid_trns = 1; |
8279 | 0 | } |
8280 | 0 | else |
8281 | 0 | { |
8282 | 0 | ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA; |
8283 | 0 | ping_num_trans=0; |
8284 | 0 | if (ping_bit_depth < 8) |
8285 | 0 | ping_bit_depth=8; |
8286 | 0 | ping_valid_trns = 0; |
8287 | 0 | png_set_invalid(ping, ping_info, PNG_INFO_PLTE); |
8288 | 0 | mng_info->IsPalette=MagickFalse; |
8289 | 0 | image_matte=MagickTrue; |
8290 | 0 | (void) SyncImage(image); |
8291 | 0 | if (logging) |
8292 | 0 | (void) LogMagickEvent(CoderEvent, |
8293 | 0 | GetMagickModule(), |
8294 | 0 | " Cannot write image" |
8295 | 0 | " as indexed PNG," |
8296 | 0 | " writing RGBA."); |
8297 | 0 | } |
8298 | |
|
8299 | 0 | if (ping_valid_trns != 0) |
8300 | 0 | { |
8301 | 0 | for (i=0; i < number_colors; i++) |
8302 | 0 | { |
8303 | 0 | if (trans_alpha[i] == 256) |
8304 | 0 | trans_alpha[i]=255; |
8305 | 0 | if (trans_alpha[i] != 255) |
8306 | 0 | ping_num_trans=(unsigned short) (i+1); |
8307 | 0 | } |
8308 | 0 | (void) LogMagickEvent(CoderEvent, GetMagickModule(), |
8309 | 0 | " ping_num_trans = %d",ping_num_trans); |
8310 | 0 | } |
8311 | 0 | if (ping_num_trans == 0) |
8312 | 0 | ping_valid_trns = 0; |
8313 | 0 | else |
8314 | 0 | ping_valid_trns = 1; |
8315 | 0 | if (ping_valid_trns == 0) |
8316 | 0 | ping_num_trans=0; |
8317 | |
|
8318 | 0 | if (ping_valid_trns != 0) |
8319 | 0 | { |
8320 | 0 | ping_trans_alpha= |
8321 | 0 | MagickAllocateMemory(unsigned char *, number_colors); |
8322 | 0 | if (ping_trans_alpha == (unsigned char *) NULL) |
8323 | 0 | png_error(ping, "Could not allocate trans_alpha"); |
8324 | | |
8325 | 0 | for (i=0; i < number_colors; i++) |
8326 | 0 | { |
8327 | 0 | if (trans_alpha[i] == 256) |
8328 | 0 | ping_trans_alpha[i]=255; |
8329 | 0 | else |
8330 | 0 | ping_trans_alpha[i]=(png_byte) trans_alpha[i]; |
8331 | 0 | (void) LogMagickEvent(CoderEvent, GetMagickModule(), |
8332 | 0 | " Alpha[%d]=%d",(int) i, |
8333 | 0 | (int) trans_alpha[i]); |
8334 | 0 | } |
8335 | 0 | } |
8336 | 0 | } /* if (matte) */ |
8337 | | |
8338 | | /* |
8339 | | Identify which colormap entry is the background color. |
8340 | | */ |
8341 | 33.6k | for (i=0; i < Max(Max(1,number_colors)-1,1); i++) |
8342 | 19.1k | if (RGBColorMatchExact(ping_background, |
8343 | 19.1k | image->colormap[i])) |
8344 | 203 | break; |
8345 | 14.7k | ping_background.index=(png_uint_16) i; |
8346 | 14.7k | if (logging) |
8347 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8348 | 0 | " background index %u (%u, %u, %u)", |
8349 | 0 | ping_background.index, |
8350 | 0 | image->colormap[ping_background.index].red, |
8351 | 0 | image->colormap[ping_background.index].green, |
8352 | 0 | image->colormap[ping_background.index].blue); |
8353 | 14.7k | } |
8354 | 14.7k | } |
8355 | 557 | else |
8356 | 557 | { |
8357 | 557 | if (image_depth < 8) |
8358 | 0 | image_depth=8; |
8359 | 557 | if ((save_image_depth == 16) && (image_depth == 8)) |
8360 | 0 | { |
8361 | 0 | ping_trans_color.red*=0x0101; |
8362 | 0 | ping_trans_color.green*=0x0101; |
8363 | 0 | ping_trans_color.blue*=0x0101; |
8364 | 0 | ping_trans_color.gray*=0x0101; |
8365 | 0 | } |
8366 | 557 | } |
8367 | | |
8368 | | /* |
8369 | | Adjust background and transparency samples in sub-8-bit |
8370 | | grayscale files. |
8371 | | */ |
8372 | 21.0k | if (ping_bit_depth < 8 && ping_colortype == |
8373 | 18.9k | PNG_COLOR_TYPE_GRAY) |
8374 | 4.26k | { |
8375 | 4.26k | png_uint_16 |
8376 | 4.26k | maxval; |
8377 | | |
8378 | 4.26k | maxval=(1U << ping_bit_depth)-1; |
8379 | | |
8380 | 4.26k | ping_trans_color.gray=(png_uint_16)(maxval* |
8381 | 4.26k | ping_trans_color.gray/ |
8382 | 4.26k | MaxRGB); |
8383 | 4.26k | } |
8384 | 21.0k | } |
8385 | | |
8386 | 29.5k | if (logging) |
8387 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8388 | 0 | " PNG color type: %s (%d)", |
8389 | 0 | PngColorTypeToString(ping_colortype), |
8390 | 0 | ping_colortype); |
8391 | | /* |
8392 | | Initialize compression level and filtering. |
8393 | | */ |
8394 | 29.5k | if (logging) |
8395 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8396 | 0 | " Setting up deflate compression"); |
8397 | 29.5k | if (logging) |
8398 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8399 | 0 | " Compression buffer size: 32768"); |
8400 | 29.5k | png_set_compression_buffer_size(ping,32768L); |
8401 | 29.5k | if (logging) |
8402 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8403 | 0 | " Compression mem level: 9"); |
8404 | 29.5k | png_set_compression_mem_level(ping, 9); |
8405 | 29.5k | if (image_info->quality > 9) |
8406 | 29.6k | { |
8407 | 29.6k | int |
8408 | 29.6k | level; |
8409 | | |
8410 | 29.6k | level=(int) Min(image_info->quality/10,9); |
8411 | 29.6k | if (logging) |
8412 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8413 | 0 | " Compression level: %d",level); |
8414 | 29.6k | png_set_compression_level(ping,level); |
8415 | 29.6k | } |
8416 | 18.4E | else |
8417 | 18.4E | { |
8418 | 18.4E | if (logging) |
8419 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8420 | 0 | " Compression strategy: Z_HUFFMAN_ONLY"); |
8421 | 18.4E | png_set_compression_strategy(ping, Z_HUFFMAN_ONLY); |
8422 | 18.4E | png_set_compression_level(ping,2); |
8423 | 18.4E | } |
8424 | 29.5k | if (logging) |
8425 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8426 | 0 | " Setting up filtering"); |
8427 | 29.5k | #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING) |
8428 | | |
8429 | | /* This became available in libpng-1.0.9. Output must be a MNG. */ |
8430 | 29.5k | if (mng_info->write_mng && ((image_info->quality % 10) == 7)) |
8431 | 0 | { |
8432 | 0 | if (logging) |
8433 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8434 | 0 | " Filter_type: PNG_INTRAPIXEL_DIFFERENCING"); |
8435 | 0 | ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING; |
8436 | 0 | } |
8437 | 29.5k | else |
8438 | 29.5k | if (logging) |
8439 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8440 | 0 | " Filter_type: 0"); |
8441 | 29.5k | #endif |
8442 | 29.5k | { |
8443 | 29.5k | int |
8444 | 29.5k | base_filter; |
8445 | | |
8446 | 29.5k | if ((image_info->quality % 10) > 5) |
8447 | 0 | base_filter=PNG_ALL_FILTERS; |
8448 | 29.5k | else |
8449 | 29.5k | if ((image_info->quality % 10) != 5) |
8450 | 0 | base_filter=(int) image_info->quality % 10; |
8451 | 29.5k | else |
8452 | 29.5k | if ((ping_colortype == PNG_COLOR_TYPE_GRAY) || |
8453 | 23.9k | (ping_colortype == PNG_COLOR_TYPE_PALETTE) || |
8454 | 7.34k | (image_info->quality < 50)) |
8455 | 22.3k | base_filter=PNG_NO_FILTERS; |
8456 | 7.26k | else |
8457 | 7.26k | base_filter=PNG_ALL_FILTERS; |
8458 | 29.5k | if (logging) |
8459 | 0 | { |
8460 | 0 | if (base_filter == PNG_ALL_FILTERS) |
8461 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8462 | 0 | " Base filter method: ADAPTIVE"); |
8463 | 0 | else |
8464 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8465 | 0 | " Base filter method: NONE"); |
8466 | 0 | } |
8467 | 29.5k | png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter); |
8468 | 29.5k | } |
8469 | | |
8470 | 29.5k | ping_interlace_method=(image_info->interlace == LineInterlace); |
8471 | | |
8472 | 29.5k | if (mng_info->write_mng) |
8473 | 17.6k | png_set_sig_bytes(ping,8); |
8474 | | |
8475 | 29.5k | if (logging) |
8476 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8477 | 0 | " Writing PNG header chunks"); |
8478 | | |
8479 | 29.5k | png_set_IHDR(ping,ping_info, |
8480 | 29.5k | ping_width, |
8481 | 29.5k | ping_height, |
8482 | 29.5k | ping_bit_depth, |
8483 | 29.5k | ping_colortype, |
8484 | 29.5k | ping_interlace_method, |
8485 | 29.5k | ping_compression_method, |
8486 | 29.5k | ping_filter_method); |
8487 | | |
8488 | 29.5k | if (ping_colortype == 3 && ping_valid_trns != 0) |
8489 | 190 | { |
8490 | 190 | if (logging) |
8491 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8492 | 0 | " Setting up tRNS chunk"); |
8493 | 190 | (void) png_set_tRNS(ping, ping_info, |
8494 | 190 | ping_trans_alpha, |
8495 | 190 | ping_num_trans, |
8496 | 190 | &ping_trans_color); |
8497 | 190 | } |
8498 | | |
8499 | 29.5k | MagickFreeMemory(ping_trans_alpha); |
8500 | | |
8501 | 29.5k | if (image_matte && (!mng_info->adjoin || !mng_info->equal_backgrounds)) |
8502 | 4.18k | { |
8503 | 4.18k | if (logging) |
8504 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8505 | 0 | " Setting up bKGD chunk for %s image", |
8506 | 0 | PngColorTypeToString(ping_colortype)); |
8507 | | |
8508 | 4.18k | if (ping_bit_depth < 8 && ping_colortype == PNG_COLOR_TYPE_GRAY) |
8509 | 0 | { |
8510 | 0 | png_uint_16 |
8511 | 0 | maxval; |
8512 | |
|
8513 | 0 | png_color_16 |
8514 | 0 | background; |
8515 | |
|
8516 | 0 | maxval=(1U << ping_bit_depth)-1; |
8517 | | |
8518 | |
|
8519 | 0 | background.gray=(png_uint_16) |
8520 | 0 | (maxval*(PixelIntensity(&image->background_color))/MaxRGB); |
8521 | 0 | if (logging) |
8522 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8523 | 0 | " bKGD gray %u", background.gray); |
8524 | |
|
8525 | 0 | png_set_bKGD(ping,ping_info,&background); |
8526 | 0 | } |
8527 | | |
8528 | 4.18k | else |
8529 | 4.18k | { |
8530 | 4.18k | png_color_16 |
8531 | 4.18k | background; |
8532 | | |
8533 | 4.18k | if (image_depth < QuantumDepth) |
8534 | 2.44k | { |
8535 | 2.44k | int |
8536 | 2.44k | maxval; |
8537 | | |
8538 | 2.44k | maxval=(1U << image_depth)-1; |
8539 | 2.44k | background.red=(png_uint_16) |
8540 | 2.44k | (maxval*image->background_color.red/MaxRGB); |
8541 | 2.44k | background.green=(png_uint_16) |
8542 | 2.44k | (maxval*image->background_color.green/MaxRGB); |
8543 | 2.44k | background.blue=(png_uint_16) |
8544 | 2.44k | (maxval*image->background_color.blue/MaxRGB); |
8545 | 2.44k | background.gray=(png_uint_16) |
8546 | 2.44k | (maxval*PixelIntensity(&image->background_color)/MaxRGB); |
8547 | 2.44k | if (logging) |
8548 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8549 | 0 | " background (red=%u, green=%u, blue=%u, gray=%u)", |
8550 | 0 | background.red, background.green, background.blue, |
8551 | 0 | background.gray); |
8552 | 2.44k | } |
8553 | 1.73k | else |
8554 | 1.73k | { |
8555 | 1.73k | background.red=image->background_color.red; |
8556 | 1.73k | background.green=image->background_color.green; |
8557 | 1.73k | background.blue=image->background_color.blue; |
8558 | 1.73k | background.gray= |
8559 | 1.73k | (png_uint_16) PixelIntensity(&image->background_color); |
8560 | 1.73k | if (logging) |
8561 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8562 | 0 | " background (red=%u, green=%u, blue=%u, gray=%u)", |
8563 | 0 | background.red, background.green, background.blue, |
8564 | 0 | background.gray); |
8565 | 1.73k | } |
8566 | 4.18k | if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
8567 | 328 | background.index=(png_byte) ping_background.index; |
8568 | 3.85k | else |
8569 | 3.85k | background.index=(png_byte) background.gray; |
8570 | 4.18k | if (logging) |
8571 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8572 | 0 | " bKGD index %u", |
8573 | 0 | background.index); |
8574 | 4.18k | png_set_bKGD(ping,ping_info,&background); |
8575 | 4.18k | } |
8576 | 4.18k | } |
8577 | | |
8578 | 29.5k | #if defined(PNG_pHYs_SUPPORTED) |
8579 | 29.5k | if ((image->x_resolution != 0) && (image->y_resolution != 0) && |
8580 | 75 | (!mng_info->write_mng || !mng_info->equal_physs)) |
8581 | 75 | { |
8582 | 75 | int |
8583 | 75 | unit_type; |
8584 | | |
8585 | 75 | png_uint_32 |
8586 | 75 | x_resolution, |
8587 | 75 | y_resolution; |
8588 | | |
8589 | 75 | if (image->units == PixelsPerInchResolution) |
8590 | 0 | { |
8591 | 0 | unit_type=PNG_RESOLUTION_METER; |
8592 | 0 | x_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->x_resolution+0.5)/2.54); |
8593 | 0 | y_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->y_resolution+0.5)/2.54); |
8594 | 0 | } |
8595 | 75 | else if (image->units == PixelsPerCentimeterResolution) |
8596 | 19 | { |
8597 | 19 | unit_type=PNG_RESOLUTION_METER; |
8598 | 19 | x_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->x_resolution+0.5); |
8599 | 19 | y_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->y_resolution+0.5); |
8600 | 19 | } |
8601 | 56 | else |
8602 | 56 | { |
8603 | 56 | unit_type=PNG_RESOLUTION_UNKNOWN; |
8604 | 56 | x_resolution=(png_uint_32) MagickDoubleToUInt(image->x_resolution); |
8605 | 56 | y_resolution=(png_uint_32) MagickDoubleToUInt(image->y_resolution); |
8606 | 56 | } |
8607 | | |
8608 | 75 | png_set_pHYs(ping,ping_info,x_resolution,y_resolution,unit_type); |
8609 | | |
8610 | 75 | if (logging) |
8611 | 0 | { |
8612 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8613 | 0 | " Setting up pHYs chunk"); |
8614 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8615 | 0 | " x_resolution=%u",(unsigned int) x_resolution); |
8616 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8617 | 0 | " y_resolution=%u",(unsigned int) y_resolution); |
8618 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8619 | 0 | " unit_type=%lu",(unsigned long) unit_type); |
8620 | 0 | } |
8621 | 75 | } |
8622 | 29.5k | #endif |
8623 | | |
8624 | 29.5k | #if defined(PNG_oFFs_SUPPORTED) |
8625 | 29.5k | if (mng_info->write_mng == 0 && (image->page.x || image->page.y)) |
8626 | 1.47k | { |
8627 | 1.47k | if (!((image->page.width != 0 && image->page.width != image->columns) || |
8628 | 1.09k | (image->page.height != 0 && image->page.height != image->rows))) |
8629 | 778 | { |
8630 | 778 | png_set_oFFs(ping,ping_info,(png_int_32) image->page.x, |
8631 | 778 | (png_int_32) image->page.y, 0); |
8632 | 778 | if (logging) |
8633 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8634 | 0 | " Setting up oFFs chunk"); |
8635 | 778 | } |
8636 | | /* else write caNv instead, later */ |
8637 | 1.47k | } |
8638 | 29.5k | #endif |
8639 | | |
8640 | 29.5k | { |
8641 | 29.5k | ImageProfileIterator |
8642 | 29.5k | profile_iterator; |
8643 | | |
8644 | 29.5k | profile_iterator=AllocateImageProfileIterator(image); |
8645 | 29.5k | if (profile_iterator) |
8646 | 3.04k | { |
8647 | 3.04k | const char |
8648 | 3.04k | *profile_name_uc; |
8649 | | |
8650 | 3.04k | const unsigned char |
8651 | 3.04k | *profile_info; |
8652 | | |
8653 | 3.04k | char |
8654 | 3.04k | profile_name[MaxTextExtent]; |
8655 | | |
8656 | 3.04k | size_t |
8657 | 3.04k | profile_length; |
8658 | | |
8659 | 7.35k | while (NextImageProfile(profile_iterator,&profile_name_uc,&profile_info, |
8660 | 7.35k | &profile_length) != MagickFail) |
8661 | 4.30k | { |
8662 | 4.30k | (void) strlcpy(profile_name, profile_name_uc, sizeof(profile_name)); |
8663 | 4.30k | LocaleLower(profile_name); |
8664 | 4.30k | if (LocaleCompare(profile_name,"ICM") == 0) |
8665 | 90 | { |
8666 | 90 | if (profile_length < 132) |
8667 | 32 | { |
8668 | 32 | if (logging) |
8669 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8670 | 0 | " Ignoring %s profile (%u byte%s)" |
8671 | 0 | " because it is too short!", |
8672 | 0 | profile_name, |
8673 | 0 | (unsigned int) profile_length, |
8674 | 0 | profile_length > 1 ? "s" : ""); |
8675 | 32 | } |
8676 | 58 | else |
8677 | 58 | { |
8678 | 58 | #if defined(PNG_WRITE_iCCP_SUPPORTED) |
8679 | 58 | { |
8680 | 58 | if (logging) |
8681 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8682 | 0 | " Setting up iCCP chunk (%u byte%s)", |
8683 | 0 | (unsigned int) profile_length, |
8684 | 0 | profile_length > 1 ? "s" : ""); |
8685 | | |
8686 | 58 | png_set_iCCP(ping,ping_info,(png_charp) "icm", |
8687 | 58 | (int) 0, |
8688 | | #if (PNG_LIBPNG_VER < 10500) |
8689 | | (png_charp) profile_info, |
8690 | | #else |
8691 | 58 | (png_const_bytep) profile_info, |
8692 | 58 | #endif |
8693 | | |
8694 | 58 | (png_uint_32) profile_length); |
8695 | 58 | } |
8696 | | #else |
8697 | | { |
8698 | | if (logging) |
8699 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8700 | | " Setting up text chunk with" |
8701 | | " iCCP Profile"); |
8702 | | (void) png_write_raw_profile(image_info,ping,ping_info, |
8703 | | "icm", |
8704 | | "ICC Profile", |
8705 | | profile_info, |
8706 | | (png_uint_32) profile_length, |
8707 | | &image->exception); |
8708 | | } |
8709 | | #endif |
8710 | 58 | } |
8711 | 90 | } |
8712 | 4.21k | else if (LocaleCompare(profile_name,"IPTC") == 0) |
8713 | 23 | { |
8714 | 23 | if (logging) |
8715 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8716 | 0 | " Setting up text chunk with" |
8717 | 0 | " iPTC Profile"); |
8718 | 23 | (void) png_write_raw_profile(image_info,ping,ping_info, |
8719 | 23 | "iptc", |
8720 | 23 | "IPTC profile", |
8721 | 23 | profile_info, |
8722 | 23 | (png_uint_32) profile_length, |
8723 | 23 | &image->exception); |
8724 | 23 | } |
8725 | 4.19k | else if (LocaleCompare(profile_name,"exif") == 0) |
8726 | | /* Do not write exif; we'll write it later as eXIf */ |
8727 | 2.43k | ; |
8728 | 1.76k | else |
8729 | 1.76k | { |
8730 | 1.76k | if (logging) |
8731 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8732 | 0 | " Setting up text chunk with" |
8733 | 0 | " %s profile", |
8734 | 0 | profile_name); |
8735 | 1.76k | (void) png_write_raw_profile(image_info,ping,ping_info, |
8736 | 1.76k | profile_name, |
8737 | 1.76k | "generic profile", |
8738 | 1.76k | profile_info, |
8739 | 1.76k | (png_uint_32) profile_length, |
8740 | 1.76k | &image->exception); |
8741 | 1.76k | } |
8742 | 4.30k | } |
8743 | | |
8744 | 3.04k | DeallocateImageProfileIterator(profile_iterator); |
8745 | 3.04k | } |
8746 | 29.5k | } |
8747 | | |
8748 | 29.5k | #if defined(PNG_WRITE_sRGB_SUPPORTED) |
8749 | 29.5k | if (!mng_info->have_write_global_srgb && |
8750 | 29.6k | ((image->rendering_intent != UndefinedIntent) || |
8751 | 29.5k | image_info->colorspace == sRGBColorspace)) |
8752 | 68 | { |
8753 | | /* |
8754 | | Note image rendering intent. |
8755 | | */ |
8756 | 68 | if (logging) |
8757 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8758 | 0 | " Setting up sRGB chunk"); |
8759 | 68 | if (image->rendering_intent != UndefinedIntent) |
8760 | 68 | (void) png_set_sRGB(ping,ping_info,(int) (image->rendering_intent-1)); |
8761 | 0 | else |
8762 | 0 | (void) png_set_sRGB(ping,ping_info,PerceptualIntent); |
8763 | 68 | png_set_gAMA(ping,ping_info,0.45455); |
8764 | 68 | } |
8765 | 29.5k | if ((!mng_info->write_mng) || |
8766 | 17.6k | !png_get_valid(ping, ping_info, PNG_INFO_sRGB)) |
8767 | 29.6k | #endif |
8768 | 29.6k | { |
8769 | 29.6k | if (!mng_info->have_write_global_gama && (image->gamma != 0.0)) |
8770 | 487 | { |
8771 | | /* |
8772 | | Note image gamma. |
8773 | | To do: check for cHRM+gAMA == sRGB, and write sRGB instead. |
8774 | | */ |
8775 | 487 | if (logging) |
8776 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8777 | 0 | " Setting up gAMA chunk gamma=%f", image->gamma); |
8778 | 487 | png_set_gAMA(ping,ping_info,image->gamma); |
8779 | 487 | } |
8780 | 29.6k | if (!mng_info->have_write_global_chrm && |
8781 | 29.6k | (image->chromaticity.red_primary.x != 0.0)) |
8782 | 84 | { |
8783 | | /* |
8784 | | Note image chromaticity. |
8785 | | To do: check for cHRM+gAMA == sRGB, and write sRGB instead. |
8786 | | */ |
8787 | 84 | PrimaryInfo |
8788 | 84 | bp, |
8789 | 84 | gp, |
8790 | 84 | rp, |
8791 | 84 | wp; |
8792 | | |
8793 | 84 | wp=image->chromaticity.white_point; |
8794 | 84 | rp=image->chromaticity.red_primary; |
8795 | 84 | gp=image->chromaticity.green_primary; |
8796 | 84 | bp=image->chromaticity.blue_primary; |
8797 | | |
8798 | 84 | if (logging) |
8799 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8800 | 0 | " Setting up cHRM chunk"); |
8801 | 84 | png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y, |
8802 | 84 | bp.x,bp.y); |
8803 | 84 | } |
8804 | 29.6k | } |
8805 | | |
8806 | 29.5k | png_write_info(ping,ping_info); |
8807 | | |
8808 | | /* write orNT if image->orientation is defined and not TopLeft */ |
8809 | 29.5k | if (image->orientation > 1 && image->orientation < 9) |
8810 | 21 | { |
8811 | 21 | unsigned char |
8812 | 21 | chunk[6]; |
8813 | 21 | (void) WriteBlobMSBULong(image,1L); /* data length=1 */ |
8814 | 21 | PNGType(chunk,mng_orNT); |
8815 | 21 | LogPNGChunk(logging,mng_orNT,1L); |
8816 | 21 | chunk[4]=image->orientation; |
8817 | 21 | (void) WriteBlob(image,5,chunk); |
8818 | 21 | (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); |
8819 | 21 | } |
8820 | | |
8821 | | /* write caNv chunk */ |
8822 | 29.6k | if ((image->page.width != 0 && image->page.width != image->columns) || |
8823 | 29.2k | (image->page.height != 0 && image->page.height != image->rows) || |
8824 | 28.9k | image->page.x != 0 || image->page.y != 0) |
8825 | 1.47k | { |
8826 | 1.47k | unsigned char |
8827 | 1.47k | chunk[22]; |
8828 | | |
8829 | 1.47k | (void) WriteBlobMSBULong(image,16L); /* data length=16 */ |
8830 | 1.47k | PNGType(chunk,mng_caNv); |
8831 | 1.47k | LogPNGChunk(logging,mng_caNv,16L); |
8832 | 1.47k | PNGLong(chunk+4,(png_uint_32) image->page.width); |
8833 | 1.47k | PNGLong(chunk+8,(png_uint_32) image->page.height); |
8834 | 1.47k | PNGsLong(chunk+12,(png_int_32) image->page.x); |
8835 | 1.47k | PNGsLong(chunk+16,(png_int_32) image->page.y); |
8836 | 1.47k | (void) WriteBlob(image,20,chunk); |
8837 | 1.47k | (void) WriteBlobMSBULong(image,crc32(0,chunk,20)); |
8838 | 1.47k | } |
8839 | | |
8840 | | #if (PNG_LIBPNG_VER == 10206) |
8841 | | /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */ |
8842 | | #define PNG_HAVE_IDAT 0x04 |
8843 | | ping->mode |= PNG_HAVE_IDAT; |
8844 | | #undef PNG_HAVE_IDAT |
8845 | | #endif |
8846 | | |
8847 | 29.5k | png_set_packing(ping); |
8848 | | /* |
8849 | | Allocate memory. |
8850 | | */ |
8851 | 29.5k | if (logging) |
8852 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8853 | 0 | " mng_info: columns=%lu, image_depth=%u, " |
8854 | 0 | "write_png8=%u, write_png24=%u, write_png32=%u " |
8855 | 0 | "write_png48=%u, write_png64=%u, IsPalette=%u, " |
8856 | 0 | "image_matte=%u", |
8857 | 0 | image->columns, image_depth, mng_info->write_png8, |
8858 | 0 | mng_info->write_png24, mng_info->write_png32, |
8859 | 0 | mng_info->write_png48, mng_info->write_png64, |
8860 | 0 | mng_info->IsPalette, image_matte |
8861 | 0 | ); |
8862 | 29.5k | rowbytes=image->columns; |
8863 | 29.5k | if (image_depth <= 8) |
8864 | 26.2k | { |
8865 | 26.2k | if (mng_info->write_png24) |
8866 | 1.78k | rowbytes*=3; |
8867 | 24.4k | else if (mng_info->write_png32) |
8868 | 1.61k | rowbytes*=4; |
8869 | 22.8k | else if (!mng_info->write_png8 && (mng_info->IsPalette && |
8870 | 20.4k | IsGrayImage(image,&image->exception))) |
8871 | 5.72k | rowbytes*=(image_matte ? 2 : 1); |
8872 | 17.1k | else |
8873 | 17.1k | { |
8874 | 17.1k | if (!mng_info->IsPalette) |
8875 | 1.04k | rowbytes*=(image_matte ? 4 : 3); |
8876 | 17.1k | } |
8877 | 26.2k | } |
8878 | 3.32k | else |
8879 | 3.32k | { |
8880 | 3.32k | if (mng_info->write_png48) |
8881 | 1.62k | rowbytes*=6; |
8882 | | |
8883 | 1.69k | else if (mng_info->write_png64) |
8884 | 1.69k | rowbytes*=8; |
8885 | | |
8886 | 2 | else if (mng_info->IsPalette && |
8887 | 0 | IsGrayImage(image,&image->exception)) |
8888 | 0 | rowbytes*=(image_matte ? 4 : 2); |
8889 | | |
8890 | 2 | else |
8891 | 18.4E | rowbytes*=(image_matte ? 8 : 6); |
8892 | 3.32k | } |
8893 | 29.5k | if (logging) |
8894 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8895 | 0 | " Allocating %lu bytes of memory for pixels", |
8896 | 0 | rowbytes); |
8897 | 29.5k | png_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,rowbytes); |
8898 | 29.5k | if (png_pixels == (unsigned char *) NULL) |
8899 | 0 | png_error(ping, "Could not allocate png_pixels"); |
8900 | 29.5k | mng_info->png_pixels=png_pixels; /* For free in setjmp handler */ |
8901 | | /* |
8902 | | Initialize image scanlines. |
8903 | | */ |
8904 | 29.5k | num_passes=png_set_interlace_handling(ping); |
8905 | 29.5k | if ((!mng_info->write_png8 && !mng_info->write_png24 && |
8906 | 26.0k | !mng_info->write_png32 && !mng_info->write_png48 && |
8907 | 22.7k | !mng_info->write_png64) && (mng_info->IsPalette || |
8908 | 637 | image_info->type == BilevelType) && |
8909 | 20.4k | !image_matte && |
8910 | 20.4k | IsMonochromeImage(image,&image->exception)) |
8911 | 8.53k | for (pass=0; pass < num_passes; pass++) |
8912 | 4.26k | { |
8913 | | /* |
8914 | | Convert PseudoClass image to a PNG monochrome image. |
8915 | | */ |
8916 | 4.26k | if (logging) |
8917 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8918 | 0 | " pass %d, Image Is Monochrome",pass); |
8919 | 9.82k | for (y=0; y < (long) image->rows; y++) |
8920 | 5.55k | { |
8921 | 5.55k | if (!AcquireImagePixels(image,0,y,image->columns,1, |
8922 | 5.55k | &image->exception)) |
8923 | 0 | break; |
8924 | 5.55k | if (mng_info->IsPalette) |
8925 | 5.55k | (void) ExportImagePixelArea(image,(QuantumType) GrayQuantum, |
8926 | 5.55k | quantum_size,png_pixels,0,0); |
8927 | 0 | else |
8928 | 0 | (void) ExportImagePixelArea(image,(QuantumType) RedQuantum, |
8929 | 0 | quantum_size,png_pixels,0,0); |
8930 | 167k | for (i=0; i < image->columns; i++) |
8931 | 161k | *(png_pixels+i)=(*(png_pixels+i) > 128) ? 255 : 0; |
8932 | 5.55k | png_write_row(ping,png_pixels); |
8933 | 5.55k | if (image->previous == (Image *) NULL) |
8934 | 2.79k | if (QuantumTick((magick_uint64_t) y*((magick_uint64_t)pass+1), |
8935 | 2.79k | (magick_uint64_t) image->rows * num_passes)) |
8936 | 2.67k | if (!MagickMonitorFormatted((magick_uint64_t) y*((magick_uint64_t)pass+1), |
8937 | 2.67k | (magick_uint64_t) image->rows* |
8938 | 2.67k | num_passes, |
8939 | 2.67k | &image->exception, |
8940 | 2.67k | SaveImageText, |
8941 | 2.67k | image->filename, |
8942 | 2.67k | image->columns,image->rows)) |
8943 | 0 | break; |
8944 | | |
8945 | 5.55k | } |
8946 | 4.26k | } |
8947 | 25.3k | else |
8948 | 50.7k | for (pass=0; pass < num_passes; pass++) |
8949 | 25.3k | { |
8950 | 25.3k | if ((!mng_info->write_png8 && !mng_info->write_png24 && |
8951 | 21.7k | !mng_info->write_png32 && !mng_info->write_png48 && |
8952 | 18.5k | !mng_info->write_png64) && |
8953 | 16.8k | (!image_matte || (ping_bit_depth >= QuantumDepth)) && |
8954 | 16.3k | mng_info->IsPalette && |
8955 | 16.1k | IsGrayImage(image,&image->exception)) |
8956 | 1.44k | { |
8957 | 1.44k | if (logging) |
8958 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
8959 | 0 | " pass %d, Image Is Gray",pass); |
8960 | 8.65k | for (y=0; y < (long) image->rows; y++) |
8961 | 7.20k | { |
8962 | 7.20k | if (!AcquireImagePixels(image,0,y,image->columns,1, |
8963 | 7.20k | &image->exception)) |
8964 | 0 | break; |
8965 | 7.20k | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
8966 | 7.20k | { |
8967 | 7.20k | if (mng_info->IsPalette) |
8968 | 7.20k | (void) ExportImagePixelArea(image, |
8969 | 7.20k | (QuantumType) GrayQuantum, |
8970 | 7.20k | quantum_size,png_pixels,0,0); |
8971 | 0 | else |
8972 | 0 | (void) ExportImagePixelArea(image, |
8973 | 0 | (QuantumType) RedQuantum, |
8974 | 0 | quantum_size, |
8975 | 0 | png_pixels,0,0); |
8976 | 7.20k | } |
8977 | 0 | else if (ping_colortype == PNG_COLOR_TYPE_PALETTE) |
8978 | 0 | { |
8979 | 0 | (void) ExportImagePixelArea(image,(QuantumType) |
8980 | 0 | IndexQuantum, |
8981 | 0 | quantum_size, |
8982 | 0 | png_pixels,0,0); |
8983 | 0 | } |
8984 | 0 | else /* PNG_COLOR_TYPE_GRAY_ALPHA */ |
8985 | 0 | { |
8986 | 0 | (void) ExportImagePixelArea(image,(QuantumType) |
8987 | 0 | GrayAlphaQuantum, |
8988 | 0 | quantum_size, |
8989 | 0 | png_pixels,0,0); |
8990 | 0 | } |
8991 | 7.20k | png_write_row(ping,png_pixels); |
8992 | 7.20k | if (image->previous == (Image *) NULL) |
8993 | 6.96k | if (QuantumTick((magick_uint64_t) y*((magick_uint64_t) pass+1), |
8994 | 6.96k | (magick_uint64_t) image->rows * num_passes)) |
8995 | 5.61k | if (!MagickMonitorFormatted((magick_uint64_t) y*((magick_uint64_t) pass+1), |
8996 | 5.61k | (magick_uint64_t) image->rows* |
8997 | 5.61k | num_passes, |
8998 | 5.61k | &image->exception,SaveImageText, |
8999 | 5.61k | image->filename, |
9000 | 5.61k | image->columns,image->rows)) |
9001 | 0 | break; |
9002 | 7.20k | } |
9003 | 1.44k | } |
9004 | 23.9k | else |
9005 | 47.8k | for (pass=0; pass < num_passes; pass++) |
9006 | 23.9k | { |
9007 | 23.9k | if ((image_depth > 8) || |
9008 | 20.5k | (mng_info->write_png24 || mng_info->write_png32 || |
9009 | 17.1k | mng_info->write_png48 || mng_info->write_png64 || |
9010 | 17.1k | (!mng_info->write_png8 && !mng_info->IsPalette))) |
9011 | 7.35k | { |
9012 | 7.35k | if (logging) |
9013 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9014 | 0 | " pass %d, Image Is RGB," |
9015 | 0 | " PNG colortype is %s (%d)",pass, |
9016 | 0 | PngColorTypeToString( |
9017 | 0 | ping_colortype), |
9018 | 0 | ping_colortype); |
9019 | 249k | for (y=0; y < (long) image->rows; y++) |
9020 | 242k | { |
9021 | 242k | if (!AcquireImagePixels(image,0,y,image->columns,1, |
9022 | 242k | &image->exception)) |
9023 | 0 | break; |
9024 | 242k | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
9025 | 899 | { |
9026 | 899 | if (image->storage_class == DirectClass) |
9027 | 0 | (void) ExportImagePixelArea(image,(QuantumType) |
9028 | 0 | RedQuantum, |
9029 | 0 | quantum_size, |
9030 | 0 | png_pixels,0,0); |
9031 | 899 | else |
9032 | 899 | (void) ExportImagePixelArea(image,(QuantumType) |
9033 | 899 | GrayQuantum, |
9034 | 899 | quantum_size, |
9035 | 899 | png_pixels,0,0); |
9036 | 899 | } |
9037 | 241k | else if (ping_colortype == |
9038 | 241k | PNG_COLOR_TYPE_GRAY_ALPHA) |
9039 | 70 | (void) ExportImagePixelArea(image,(QuantumType) |
9040 | 70 | GrayAlphaQuantum, |
9041 | 70 | quantum_size, |
9042 | 70 | png_pixels,0,0); |
9043 | 241k | else if (image_matte) |
9044 | 142k | (void) ExportImagePixelArea(image,(QuantumType) |
9045 | 142k | RGBAQuantum, |
9046 | 142k | quantum_size, |
9047 | 142k | png_pixels,0,0); |
9048 | 99.3k | else |
9049 | 99.3k | { |
9050 | 99.3k | (void) ExportImagePixelArea(image,(QuantumType) |
9051 | 99.3k | RGBQuantum, |
9052 | 99.3k | quantum_size, |
9053 | 99.3k | png_pixels,0,0); |
9054 | 99.3k | } |
9055 | 242k | png_write_row(ping,png_pixels); |
9056 | 242k | if (image->previous == (Image *) NULL) |
9057 | 242k | if (QuantumTick((magick_uint64_t) y * ((magick_uint64_t) pass+1), |
9058 | 242k | (magick_uint64_t) image->rows * |
9059 | 242k | num_passes)) |
9060 | 147k | if (!MagickMonitorFormatted((magick_uint64_t) |
9061 | 147k | y*((magick_uint64_t) pass+1), |
9062 | 147k | (magick_uint64_t) |
9063 | 147k | image->rows*num_passes, |
9064 | 147k | &image->exception, |
9065 | 147k | SaveImageText, |
9066 | 147k | image->filename, |
9067 | 147k | image->columns,image->rows)) |
9068 | 0 | break; |
9069 | 242k | } |
9070 | 7.35k | if (logging) |
9071 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9072 | 0 | " pass %d done",pass); |
9073 | 7.35k | } |
9074 | 16.5k | else |
9075 | 16.5k | { |
9076 | 16.5k | if (logging) |
9077 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9078 | 0 | " pass %d, Image Is RGB," |
9079 | 0 | " 16-bit GRAY, or GRAY_ALPHA",pass); |
9080 | 92.6k | for (y=0; y < (long) image->rows; y++) |
9081 | 76.0k | { |
9082 | 76.0k | if (!AcquireImagePixels(image,0,y,image->columns,1, |
9083 | 76.0k | &image->exception)) |
9084 | 0 | break; |
9085 | 76.0k | if (ping_colortype == PNG_COLOR_TYPE_GRAY) |
9086 | 0 | (void) ExportImagePixelArea(image,(QuantumType) |
9087 | 0 | GrayQuantum, |
9088 | 0 | quantum_size, |
9089 | 0 | png_pixels,0,0); |
9090 | 76.0k | else if (ping_colortype == |
9091 | 76.0k | PNG_COLOR_TYPE_GRAY_ALPHA) |
9092 | 1.02k | (void) ExportImagePixelArea(image,(QuantumType) |
9093 | 1.02k | GrayAlphaQuantum, |
9094 | 1.02k | quantum_size, |
9095 | 1.02k | png_pixels,0,0); |
9096 | 75.0k | else |
9097 | 75.0k | (void) ExportImagePixelArea(image,(QuantumType) |
9098 | 75.0k | IndexQuantum, |
9099 | 75.0k | quantum_size, |
9100 | 75.0k | png_pixels,0,0); |
9101 | 76.0k | png_write_row(ping,png_pixels); |
9102 | 76.0k | if (image->previous == (Image *) NULL) |
9103 | 61.9k | if (QuantumTick((magick_uint64_t) y * ((magick_uint64_t) pass+1), |
9104 | 61.9k | (magick_uint64_t) image->rows * |
9105 | 61.9k | num_passes)) |
9106 | 35.1k | if (!MagickMonitorFormatted((magick_uint64_t) |
9107 | 35.1k | y*((magick_uint64_t) pass+1), |
9108 | 35.1k | (magick_uint64_t) |
9109 | 35.1k | image->rows*num_passes, |
9110 | 35.1k | &image->exception, |
9111 | 35.1k | SaveImageText, |
9112 | 35.1k | image->filename, |
9113 | 35.1k | image->columns, |
9114 | 35.1k | image->rows)) |
9115 | 0 | break; |
9116 | 76.0k | } |
9117 | 16.5k | } |
9118 | 23.9k | } |
9119 | 25.3k | } |
9120 | | |
9121 | 29.5k | MagickFreeResourceLimitedMemory(unsigned char *,png_pixels); |
9122 | 29.5k | mng_info->png_pixels = (unsigned char *) NULL; |
9123 | | |
9124 | 29.5k | if (logging) |
9125 | 0 | { |
9126 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9127 | 0 | " Writing PNG image data"); |
9128 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9129 | 0 | " Width: %lu", |
9130 | 0 | (unsigned long)ping_width); |
9131 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9132 | 0 | " Height: %lu", |
9133 | 0 | (unsigned long)ping_height); |
9134 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9135 | 0 | " PNG sample depth: %d",ping_bit_depth); |
9136 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9137 | 0 | " PNG color type: %s (%d)", |
9138 | 0 | PngColorTypeToString(ping_colortype), |
9139 | 0 | ping_colortype); |
9140 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9141 | 0 | " PNG Interlace method: %d", |
9142 | 0 | ping_interlace_method); |
9143 | 0 | } |
9144 | | /* |
9145 | | Generate text chunks. |
9146 | | */ |
9147 | 29.5k | attribute=GetImageAttribute(image,(char *) NULL); |
9148 | 110k | for ( ; attribute != (const ImageAttribute *) NULL; |
9149 | 80.7k | attribute=attribute->next) |
9150 | 80.7k | { |
9151 | 80.7k | png_textp |
9152 | 80.7k | text; |
9153 | | |
9154 | 80.7k | if (*attribute->key == '[') |
9155 | 249 | continue; |
9156 | 80.4k | if (LocaleCompare(attribute->key,"png:IHDR.color-type-orig") == 0 || |
9157 | 68.5k | LocaleCompare(attribute->key,"png:IHDR.bit-depth-orig") == 0) |
9158 | 23.9k | continue; |
9159 | | #if PNG_LIBPNG_VER >= 14000 |
9160 | | text=(png_textp) png_malloc(ping, |
9161 | | (png_alloc_size_t) sizeof(png_text)); |
9162 | | #else |
9163 | 56.5k | text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); |
9164 | 56.5k | #endif |
9165 | 56.5k | text[0].key=attribute->key; |
9166 | 56.5k | text[0].text=attribute->value; |
9167 | 56.5k | text[0].text_length=strlen(attribute->value); |
9168 | 56.5k | text[0].compression=image_info->compression == NoCompression || |
9169 | 56.5k | (image_info->compression == UndefinedCompression && |
9170 | 56.5k | text[0].text_length < 128) ? -1 : 0; |
9171 | 56.5k | if (logging) |
9172 | 0 | { |
9173 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9174 | 0 | " Setting up text chunk"); |
9175 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9176 | 0 | " keyword: %s",text[0].key); |
9177 | 0 | } |
9178 | 56.5k | png_set_text(ping,ping_info,text,1); |
9179 | 56.5k | png_free(ping,text); |
9180 | 56.5k | } |
9181 | | |
9182 | | /* write eXIf profile */ |
9183 | 29.5k | { |
9184 | 29.5k | ImageProfileIterator |
9185 | 29.5k | profile_iterator; |
9186 | | |
9187 | 29.5k | profile_iterator=AllocateImageProfileIterator(image); |
9188 | 29.5k | if (profile_iterator) |
9189 | 3.04k | { |
9190 | 3.04k | const char |
9191 | 3.04k | *profile_name; |
9192 | | |
9193 | 3.04k | const unsigned char |
9194 | 3.04k | *profile_info; |
9195 | | |
9196 | 3.04k | size_t |
9197 | 3.04k | profile_length; |
9198 | | |
9199 | 4.77k | while (NextImageProfile(profile_iterator,&profile_name,&profile_info, |
9200 | 4.77k | &profile_length) != MagickFail) |
9201 | 4.16k | { |
9202 | 4.16k | if (LocaleCompare(profile_name,"exif") == 0) |
9203 | 2.43k | { |
9204 | 2.43k | png_uint_32 |
9205 | 2.43k | length; |
9206 | 2.43k | unsigned char |
9207 | 2.43k | chunk[4]; |
9208 | 2.43k | const unsigned char |
9209 | 2.43k | *data; |
9210 | | |
9211 | 2.43k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9212 | 2.43k | " Have eXIf profile"); |
9213 | | |
9214 | 2.43k | data=profile_info; |
9215 | | |
9216 | 2.43k | length=(png_uint_32) profile_length; |
9217 | | |
9218 | 2.43k | PNGType(chunk,mng_eXIf); |
9219 | | |
9220 | 2.43k | if (length < 7) |
9221 | 54 | break; /* otherwise crashes */ |
9222 | | |
9223 | 2.37k | if (data[0] == 'E' && data[1] == 'x' && data[2] == 'i' && |
9224 | 2.21k | data[3] == 'f' && data[4] == '\0' && data[5] == '\0') |
9225 | 2.16k | { |
9226 | | /* skip the optional Exif identifier code ("Exif\0\0") */ |
9227 | 2.16k | length -= 6; |
9228 | 2.16k | data += 6; |
9229 | 2.16k | } |
9230 | | |
9231 | 2.37k | LogPNGChunk(logging,chunk,length); |
9232 | 2.37k | (void) WriteBlobMSBULong(image,length); |
9233 | 2.37k | (void) WriteBlob(image,4,chunk); |
9234 | 2.37k | (void) WriteBlob(image,length,data); |
9235 | 2.37k | (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4), |
9236 | 2.37k | data, (uInt) length)); |
9237 | 2.37k | break; |
9238 | 2.43k | } |
9239 | 4.16k | } |
9240 | 3.04k | DeallocateImageProfileIterator(profile_iterator); |
9241 | 3.04k | } |
9242 | 29.5k | } |
9243 | | |
9244 | 29.5k | if (logging) |
9245 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9246 | 0 | " Writing PNG end info"); |
9247 | 29.5k | png_write_end(ping,ping_info); |
9248 | 29.5k | if (mng_info->need_fram && (int) image->dispose == BackgroundDispose) |
9249 | 177 | { |
9250 | 177 | if (mng_info->page.x || mng_info->page.y || (ping_width != |
9251 | 177 | mng_info->page.width) || |
9252 | 177 | (ping_height != mng_info->page.height)) |
9253 | 0 | { |
9254 | 0 | unsigned char |
9255 | 0 | chunk[32]; |
9256 | | |
9257 | | /* |
9258 | | Write FRAM 4 with clipping boundaries followed by FRAM 1. |
9259 | | */ |
9260 | 0 | (void) WriteBlobMSBULong(image,27L); /* data length=27 */ |
9261 | 0 | PNGType(chunk,mng_FRAM); |
9262 | 0 | LogPNGChunk(logging,mng_FRAM,27L); |
9263 | 0 | chunk[4]=4; |
9264 | 0 | chunk[5]=0; /* frame name separator (no name) */ |
9265 | 0 | chunk[6]=1; /* flag for changing delay, for next frame only */ |
9266 | 0 | chunk[7]=0; /* flag for changing frame timeout */ |
9267 | 0 | chunk[8]=1; /* flag for changing frame clipping for next frame */ |
9268 | 0 | chunk[9]=0; /* flag for changing frame sync_id */ |
9269 | 0 | PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */ |
9270 | 0 | chunk[14]=0; /* clipping boundaries delta type */ |
9271 | 0 | PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */ |
9272 | 0 | PNGLong(chunk+19,(png_uint_32) (mng_info->page.x + |
9273 | 0 | ping_width)); |
9274 | 0 | PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */ |
9275 | 0 | PNGLong(chunk+27,(png_uint_32) (mng_info->page.y + |
9276 | 0 | ping_height)); |
9277 | 0 | (void) WriteBlob(image,31,(char *) chunk); |
9278 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,31)); |
9279 | 0 | mng_info->old_framing_mode=4; |
9280 | 0 | mng_info->framing_mode=1; |
9281 | 0 | } |
9282 | 177 | else |
9283 | 177 | mng_info->framing_mode=3; |
9284 | 177 | } |
9285 | 29.5k | if (mng_info->write_mng && !mng_info->need_fram && |
9286 | 15.7k | ((int) image->dispose == 3)) |
9287 | 0 | png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC"); |
9288 | 29.5k | image->depth=save_image_depth; |
9289 | | |
9290 | | /* Save depth actually written */ |
9291 | | |
9292 | 29.5k | s[0]=(char) ping_bit_depth; |
9293 | 29.5k | s[1]='\0'; |
9294 | | |
9295 | 29.5k | (void) SetImageAttribute(image,"[png:bit-depth-written]",s); |
9296 | | |
9297 | | /* |
9298 | | Free PNG resources. |
9299 | | */ |
9300 | 29.5k | png_destroy_write_struct(&ping,&ping_info); |
9301 | | |
9302 | | #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE) |
9303 | | UnlockSemaphoreInfo(png_semaphore); |
9304 | | #endif |
9305 | | |
9306 | | |
9307 | 29.5k | if (logging) |
9308 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9309 | 0 | " exit WriteOnePNGImage()"); |
9310 | 29.5k | return (MagickPass); |
9311 | | |
9312 | | /* } end of setjmp-controlled block */ |
9313 | | |
9314 | | /* End write one PNG image */ |
9315 | 29.5k | } |
9316 | | |
9317 | | /* |
9318 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
9319 | | % % |
9320 | | % % |
9321 | | % % |
9322 | | % W r i t e P N G I m a g e % |
9323 | | % % |
9324 | | % % |
9325 | | % % |
9326 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
9327 | | % |
9328 | | % WritePNGImage() writes a Portable Network Graphics (PNG) or |
9329 | | % Multiple-image Network Graphics (MNG) image file. |
9330 | | % |
9331 | | % MNG support written by Glenn Randers-Pehrson, glennrp@image... |
9332 | | % |
9333 | | % The format of the WritePNGImage method is: |
9334 | | % |
9335 | | % MagickPassFail WritePNGImage(const ImageInfo *image_info,Image *image) |
9336 | | % |
9337 | | % A description of each parameter follows: |
9338 | | % |
9339 | | % o image_info: the image info. |
9340 | | % |
9341 | | % o image: The image. |
9342 | | % |
9343 | | % Returns MagickPass on success, MagickFail on failure. |
9344 | | % |
9345 | | % While the datastream written is always in PNG format and normally |
9346 | | % would be given the "png" file extension, this method also writes |
9347 | | % the following pseudo-formats which are subsets of PNG: |
9348 | | % |
9349 | | % o PNG8: An 8-bit indexed PNG datastream is written. |
9350 | | % If transparency is present, the tRNS chunk |
9351 | | % must only have values 0 and 255 (i.e., transparency is binary: |
9352 | | % fully opaque or fully transparent). The pixels contain 8-bit |
9353 | | % indices even if they could be represented with 1, 2, or 4 bits. |
9354 | | % Note: grayscale images will be written as indexed PNG files |
9355 | | % even though the PNG grayscale type might be slightly more |
9356 | | % efficient. |
9357 | | % |
9358 | | % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS |
9359 | | % chunk can be present to convey binary transparency by naming |
9360 | | % one of the colors as transparent. |
9361 | | % |
9362 | | % o PNG32: An 8-bit per sample RGBA PNG is written. Partial |
9363 | | % transparency is permitted, i.e., the alpha sample for |
9364 | | % each pixel can have any value from 0 to 255. The alpha |
9365 | | % channel is present even if the image is fully opaque. |
9366 | | % |
9367 | | % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS |
9368 | | % chunk can be present to convey binary transparency by naming |
9369 | | % one of the colors as transparent. If the image has more |
9370 | | % than one transparent color, has semitransparent pixels, or |
9371 | | % has an opaque pixel with the same RGB components as the |
9372 | | % transparent color, an image is not written. |
9373 | | % |
9374 | | % o PNG64: A 16-bit per sample RGBA PNG is written. Partial |
9375 | | % transparency is permitted, i.e., the alpha sample for |
9376 | | % each pixel can have any value from 0 to 65535. The alpha |
9377 | | % channel is present even if the image is fully opaque. |
9378 | | % |
9379 | | % o PNG00: A PNG that inherits its colortype and bit-depth from the input |
9380 | | % image, if the input was a PNG, is written. If these values |
9381 | | % cannot be found, then "PNG00" falls back to the regular "PNG" |
9382 | | % format. |
9383 | | % |
9384 | | % If the image cannot be written in the requested PNG8|24|32|48|64 |
9385 | | % format without loss, a PNG file will not be written, and MagickFail |
9386 | | % will be returned. Since image encoders should not be responsible for |
9387 | | % the "heavy lifting", the user should make sure that GraphicsMagick has |
9388 | | % already reduced the image depth and number of colors and limit |
9389 | | % transparency to binary transparency prior to attempting to write the |
9390 | | % image in a format that is subject to depth, color, or transparency |
9391 | | % limitations. |
9392 | | % |
9393 | | % TODO: Enforce the previous paragraph. |
9394 | | % |
9395 | | % TODO: Allow all other PNG subformats to be requested via new |
9396 | | % "-define png:bit-depth -define png:color-type" options. |
9397 | | % |
9398 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
9399 | | */ |
9400 | | static MagickPassFail WritePNGImage(const ImageInfo *image_info,Image *image) |
9401 | 11.9k | { |
9402 | 11.9k | MngInfo |
9403 | 11.9k | *mng_info; |
9404 | | |
9405 | 11.9k | int |
9406 | 11.9k | have_mng_structure; |
9407 | | |
9408 | 11.9k | unsigned int |
9409 | 11.9k | logging, |
9410 | 11.9k | status; |
9411 | | |
9412 | | /* |
9413 | | Open image file. |
9414 | | */ |
9415 | 11.9k | assert(image_info != (const ImageInfo *) NULL); |
9416 | 11.9k | assert(image_info->signature == MagickSignature); |
9417 | 11.9k | assert(image != (Image *) NULL); |
9418 | 11.9k | assert(image->signature == MagickSignature); |
9419 | 11.9k | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()"); |
9420 | 11.9k | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
9421 | 11.9k | if (status == MagickFalse) |
9422 | 11.9k | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
9423 | | |
9424 | | /* |
9425 | | Allocate a MngInfo structure. |
9426 | | */ |
9427 | 11.9k | have_mng_structure=MagickFalse; |
9428 | 11.9k | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
9429 | 11.9k | if (mng_info == (MngInfo *) NULL) |
9430 | 11.9k | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
9431 | | /* |
9432 | | Initialize members of the MngInfo structure. |
9433 | | */ |
9434 | 11.9k | (void) memset(mng_info,0,sizeof(MngInfo)); |
9435 | 11.9k | mng_info->image=image; |
9436 | 11.9k | have_mng_structure=MagickTrue; |
9437 | 11.9k | mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; |
9438 | 11.9k | mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; |
9439 | 11.9k | mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; |
9440 | 11.9k | mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0; |
9441 | 11.9k | mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0; |
9442 | | |
9443 | 11.9k | if (LocaleCompare(image_info->magick,"png00") == 0) |
9444 | 1.62k | { |
9445 | 1.62k | const ImageAttribute |
9446 | 1.62k | *attribute; |
9447 | | |
9448 | | /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig */ |
9449 | 1.62k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9450 | 1.62k | " Format=%s",image_info->magick); |
9451 | | |
9452 | 1.62k | attribute=GetImageAttribute(image,"png:IHDR.bit-depth-orig"); |
9453 | | |
9454 | 1.62k | if (attribute != (ImageAttribute *) NULL) |
9455 | 1.62k | { |
9456 | 1.62k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9457 | 1.62k | " png00 inherited bit depth=%s",attribute->value); |
9458 | | |
9459 | 1.62k | if (LocaleCompare(attribute->value,"1") == 0) |
9460 | 651 | mng_info->write_png_depth = 1; |
9461 | | |
9462 | 972 | else if (LocaleCompare(attribute->value,"1") == 0) |
9463 | 0 | mng_info->write_png_depth = 2; |
9464 | | |
9465 | 972 | else if (LocaleCompare(attribute->value,"2") == 0) |
9466 | 279 | mng_info->write_png_depth = 4; |
9467 | | |
9468 | 693 | else if (LocaleCompare(attribute->value,"8") == 0) |
9469 | 465 | mng_info->write_png_depth = 8; |
9470 | | |
9471 | 228 | else if (LocaleCompare(attribute->value,"16") == 0) |
9472 | 38 | mng_info->write_png_depth = 16; |
9473 | 1.62k | } |
9474 | | |
9475 | 1.62k | attribute=GetImageAttribute(image,"png:IHDR.color-type-orig"); |
9476 | | |
9477 | 1.62k | if (attribute != (ImageAttribute *) NULL) |
9478 | 1.62k | { |
9479 | 1.62k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9480 | 1.62k | " png00 inherited color type=%s",attribute->value); |
9481 | | |
9482 | 1.62k | if (LocaleCompare(attribute->value,"0") == 0) |
9483 | 1.07k | mng_info->write_png_colortype = 1; |
9484 | | |
9485 | 549 | else if (LocaleCompare(attribute->value,"2") == 0) |
9486 | 32 | mng_info->write_png_colortype = 3; |
9487 | | |
9488 | 517 | else if (LocaleCompare(attribute->value,"3") == 0) |
9489 | 485 | mng_info->write_png_colortype = 4; |
9490 | | |
9491 | 32 | else if (LocaleCompare(attribute->value,"4") == 0) |
9492 | 10 | mng_info->write_png_colortype = 5; |
9493 | | |
9494 | 22 | else if (LocaleCompare(attribute->value,"6") == 0) |
9495 | 22 | mng_info->write_png_colortype = 7; |
9496 | 1.62k | } |
9497 | 1.62k | } |
9498 | | |
9499 | 11.9k | status=WriteOnePNGImage(mng_info,image_info,image); |
9500 | | |
9501 | 11.9k | status &= CloseBlob(image); |
9502 | | |
9503 | 11.9k | MngInfoFreeStruct(mng_info,&have_mng_structure); |
9504 | 11.9k | if (logging) |
9505 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()"); |
9506 | 11.9k | return (status); |
9507 | 11.9k | } |
9508 | | |
9509 | | #if defined(JNG_SUPPORTED) |
9510 | | |
9511 | | /* Write one JNG image */ |
9512 | | static MagickPassFail WriteOneJNGImage(MngInfo *mng_info, |
9513 | | const ImageInfo *image_info,Image *image) |
9514 | 0 | { |
9515 | 0 | Image |
9516 | 0 | *jpeg_image; |
9517 | |
|
9518 | 0 | ImageInfo |
9519 | 0 | *jpeg_image_info; |
9520 | |
|
9521 | 0 | char |
9522 | 0 | *blob; |
9523 | |
|
9524 | 0 | size_t |
9525 | 0 | length; |
9526 | |
|
9527 | 0 | unsigned char |
9528 | 0 | chunk[80], |
9529 | 0 | *p; |
9530 | |
|
9531 | 0 | unsigned int |
9532 | 0 | jng_alpha_compression_method, |
9533 | 0 | jng_alpha_sample_depth, |
9534 | 0 | jng_color_type, |
9535 | 0 | logging, |
9536 | 0 | status=MagickPass, |
9537 | 0 | transparent; |
9538 | |
|
9539 | 0 | unsigned long |
9540 | 0 | jng_quality; |
9541 | |
|
9542 | 0 | logging=LogMagickEvent(CoderEvent,GetMagickModule(), |
9543 | 0 | " enter WriteOneJNGImage()"); |
9544 | |
|
9545 | 0 | if (image->columns > 65500U) |
9546 | 0 | { |
9547 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9548 | 0 | " JNG dimensions too large" |
9549 | 0 | " (%lu columns exceeds limit of 65500)", |
9550 | 0 | image->columns); |
9551 | 0 | ThrowWriterException(CoderError,UnsupportedNumberOfColumns, |
9552 | 0 | image); |
9553 | 0 | } |
9554 | 0 | if (image->rows > 65500U) |
9555 | 0 | { |
9556 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9557 | 0 | " JNG dimensions too large" |
9558 | 0 | " (%lu rows exceeds limit of 65500)", |
9559 | 0 | image->rows); |
9560 | 0 | ThrowWriterException(CoderError,UnsupportedNumberOfRows, |
9561 | 0 | image); |
9562 | 0 | } |
9563 | | |
9564 | 0 | blob=(char *) NULL; |
9565 | 0 | jpeg_image=(Image *) NULL; |
9566 | 0 | jpeg_image_info=(ImageInfo *) NULL; |
9567 | |
|
9568 | 0 | status=MagickTrue; |
9569 | 0 | transparent=image_info->type==GrayscaleMatteType || |
9570 | 0 | image_info->type==TrueColorMatteType; |
9571 | 0 | jng_color_type=10; |
9572 | 0 | jng_alpha_sample_depth=0; |
9573 | 0 | jng_quality=image_info->quality; |
9574 | 0 | jng_alpha_compression_method=0; |
9575 | |
|
9576 | 0 | if (image->matte) |
9577 | 0 | { |
9578 | | /* if any pixels are transparent */ |
9579 | 0 | transparent=MagickTrue; |
9580 | 0 | if (image_info->compression==JPEGCompression) |
9581 | 0 | jng_alpha_compression_method=8; |
9582 | 0 | } |
9583 | |
|
9584 | 0 | if (transparent) |
9585 | 0 | { |
9586 | 0 | jng_color_type=14; |
9587 | | /* Create JPEG blob, image, and image_info */ |
9588 | 0 | if (logging) |
9589 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9590 | 0 | " Creating jpeg_image_info for opacity."); |
9591 | 0 | jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); |
9592 | 0 | if (jpeg_image_info == (ImageInfo *) NULL) |
9593 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9594 | 0 | image); |
9595 | 0 | if (logging) |
9596 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9597 | 0 | " Creating jpeg_image."); |
9598 | 0 | jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception); |
9599 | 0 | if (jpeg_image == (Image *) NULL) |
9600 | 0 | { |
9601 | 0 | if (jpeg_image_info != (ImageInfo *)NULL) |
9602 | 0 | { |
9603 | 0 | DestroyImageInfo(jpeg_image_info); |
9604 | 0 | } |
9605 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9606 | 0 | image); |
9607 | 0 | } |
9608 | 0 | DestroyBlob(jpeg_image); |
9609 | 0 | jpeg_image->blob=CloneBlobInfo((BlobInfo *) NULL); |
9610 | 0 | status=ChannelImage(jpeg_image,OpacityChannel); |
9611 | 0 | if (status != MagickFalse) |
9612 | 0 | status=NegateImage(jpeg_image,MagickFalse); |
9613 | 0 | if (status == MagickFalse) |
9614 | 0 | { |
9615 | 0 | DestroyImage(jpeg_image); |
9616 | 0 | DestroyImageInfo(jpeg_image_info); |
9617 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9618 | 0 | image); |
9619 | 0 | } |
9620 | 0 | jpeg_image->matte=MagickFalse; |
9621 | 0 | if (jng_quality >= 1000) |
9622 | 0 | jpeg_image_info->quality=jng_quality/1000; |
9623 | 0 | else |
9624 | 0 | jpeg_image_info->quality=jng_quality; |
9625 | 0 | jpeg_image_info->type=GrayscaleType; |
9626 | 0 | status &= SetImageType(jpeg_image,GrayscaleType); |
9627 | 0 | status &= AcquireTemporaryFileName(jpeg_image->filename); |
9628 | 0 | (void) strlcpy(jpeg_image_info->filename,jpeg_image->filename,sizeof(jpeg_image_info->filename)); |
9629 | 0 | } |
9630 | | |
9631 | | /* To do: check bit depth of PNG alpha channel */ |
9632 | | |
9633 | | /* Check if image is grayscale. */ |
9634 | 0 | if (image_info->type != TrueColorMatteType && image_info->type != |
9635 | 0 | TrueColorType && IsGrayImage(image,&image->exception)) |
9636 | 0 | jng_color_type-=2; |
9637 | |
|
9638 | 0 | if (transparent) |
9639 | 0 | { |
9640 | 0 | if (jng_alpha_compression_method==0) |
9641 | 0 | { |
9642 | 0 | const ImageAttribute |
9643 | 0 | *attribute; |
9644 | | |
9645 | | /* Encode opacity as a grayscale PNG blob */ |
9646 | 0 | if (logging) |
9647 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9648 | 0 | " Creating grayscale PNG blob."); |
9649 | 0 | status&=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, |
9650 | 0 | &image->exception); |
9651 | 0 | if (status != MagickFail) |
9652 | 0 | { |
9653 | 0 | length=0; |
9654 | 0 | (void) strlcpy(jpeg_image_info->magick,"PNG",MaxTextExtent); |
9655 | 0 | (void) strlcpy(jpeg_image->magick,"PNG",MaxTextExtent); |
9656 | 0 | jpeg_image_info->interlace=NoInterlace; |
9657 | |
|
9658 | 0 | blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, |
9659 | 0 | &image->exception); |
9660 | 0 | if ((blob == (char *) NULL) || (length == 0)) |
9661 | 0 | { |
9662 | 0 | if (logging) |
9663 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9664 | 0 | " Failed to encode opacity as a" |
9665 | 0 | " grayscale PNG blob!"); |
9666 | 0 | status=MagickFail; |
9667 | 0 | } |
9668 | 0 | else |
9669 | 0 | { |
9670 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9671 | 0 | " Successfully read jpeg_image into a" |
9672 | 0 | " grayscale PNG blob, length=%zu.", |
9673 | 0 | length); |
9674 | 0 | } |
9675 | | /* Retrieve sample depth used */ |
9676 | 0 | attribute=GetImageAttribute(jpeg_image,"[png:bit-depth-written]"); |
9677 | 0 | if ((attribute != (const ImageAttribute *) NULL) && |
9678 | 0 | (attribute->value != (char *) NULL)) |
9679 | 0 | jng_alpha_sample_depth= (unsigned int) attribute->value[0]; |
9680 | 0 | } |
9681 | 0 | } |
9682 | 0 | else |
9683 | 0 | { |
9684 | | /* Encode opacity as a grayscale JPEG blob */ |
9685 | 0 | if (logging) |
9686 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9687 | 0 | " Creating grayscale JPEG blob."); |
9688 | 0 | status &= OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, |
9689 | 0 | &image->exception); |
9690 | 0 | if (status != MagickFail) |
9691 | 0 | { |
9692 | 0 | length=0; |
9693 | 0 | (void) strlcpy(jpeg_image_info->magick,"JPEG",MaxTextExtent); |
9694 | 0 | (void) strlcpy(jpeg_image->magick,"JPEG",MaxTextExtent); |
9695 | 0 | jpeg_image_info->interlace=NoInterlace; |
9696 | 0 | blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, |
9697 | 0 | &image->exception); |
9698 | 0 | jng_alpha_sample_depth=8; |
9699 | 0 | if ((blob == (char *) NULL) || (length == 0)) |
9700 | 0 | { |
9701 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9702 | 0 | " Failed to encode opacity as a" |
9703 | 0 | " grayscale JPEG blob!"); |
9704 | 0 | status=MagickFail; |
9705 | 0 | } |
9706 | 0 | else |
9707 | 0 | { |
9708 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9709 | 0 | " Successfully read jpeg_image into a" |
9710 | 0 | " JPEG blob, length=%zu.", |
9711 | 0 | length); |
9712 | 0 | } |
9713 | 0 | } |
9714 | 0 | } |
9715 | | /* Destroy JPEG image and image_info */ |
9716 | 0 | (void) LiberateTemporaryFile(jpeg_image_info->filename); |
9717 | 0 | DestroyImage(jpeg_image); |
9718 | 0 | DestroyImageInfo(jpeg_image_info); |
9719 | 0 | if (status == MagickFail) |
9720 | 0 | { |
9721 | 0 | MagickFreeMemory(blob); |
9722 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9723 | 0 | image); |
9724 | 0 | } |
9725 | 0 | } |
9726 | | |
9727 | | /* Write JHDR chunk */ |
9728 | 0 | (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */ |
9729 | 0 | PNGType(chunk,mng_JHDR); |
9730 | 0 | LogPNGChunk(logging,mng_JHDR,16L); |
9731 | 0 | PNGLong(chunk+4,image->columns); |
9732 | 0 | PNGLong(chunk+8,image->rows); |
9733 | 0 | chunk[12]=jng_color_type; |
9734 | 0 | chunk[13]=8; /* sample depth */ |
9735 | 0 | chunk[14]=8; /*jng_image_compression_method */ |
9736 | 0 | chunk[15]=(image_info->interlace == LineInterlace) ? 8 : 0; |
9737 | 0 | chunk[16]=jng_alpha_sample_depth; |
9738 | 0 | chunk[17]=jng_alpha_compression_method; |
9739 | 0 | chunk[18]=0; /*jng_alpha_filter_method */ |
9740 | 0 | chunk[19]=0; /*jng_alpha_interlace_method */ |
9741 | 0 | (void) WriteBlob(image,20,(char *) chunk); |
9742 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,20)); |
9743 | 0 | if (logging) |
9744 | 0 | { |
9745 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9746 | 0 | " JNG width:%15lu",image->columns); |
9747 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9748 | 0 | " JNG height:%14lu",image->rows); |
9749 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9750 | 0 | " JNG color type:%10d",jng_color_type); |
9751 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9752 | 0 | " JNG sample depth:%8d",8); |
9753 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9754 | 0 | " JNG compression:%9d",8); |
9755 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9756 | 0 | " JNG interlace:%11d",0); |
9757 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9758 | 0 | " JNG alpha depth:%9d",jng_alpha_sample_depth); |
9759 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9760 | 0 | " JNG alpha compression:%3d", |
9761 | 0 | jng_alpha_compression_method); |
9762 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9763 | 0 | " JNG alpha filter:%8d",0); |
9764 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9765 | 0 | " JNG alpha interlace:%5d",0); |
9766 | 0 | } |
9767 | | |
9768 | | /* |
9769 | | Write leading ancillary chunks |
9770 | | */ |
9771 | |
|
9772 | 0 | if (transparent) |
9773 | 0 | { |
9774 | | /* |
9775 | | Write JNG bKGD chunk |
9776 | | */ |
9777 | |
|
9778 | 0 | char |
9779 | 0 | blue, |
9780 | 0 | green, |
9781 | 0 | red; |
9782 | |
|
9783 | 0 | long |
9784 | 0 | num_bytes; |
9785 | |
|
9786 | 0 | if (jng_color_type == 8 || jng_color_type == 12) |
9787 | 0 | num_bytes=6L; |
9788 | 0 | else |
9789 | 0 | num_bytes=10L; |
9790 | 0 | (void) WriteBlobMSBULong(image,num_bytes-4L); |
9791 | 0 | PNGType(chunk,mng_bKGD); |
9792 | 0 | LogPNGChunk(logging,mng_bKGD,((size_t) num_bytes-4L)); |
9793 | 0 | red=ScaleQuantumToChar(image->background_color.red); |
9794 | 0 | green=ScaleQuantumToChar(image->background_color.green); |
9795 | 0 | blue=ScaleQuantumToChar(image->background_color.blue); |
9796 | 0 | *(chunk+4)=0; |
9797 | 0 | *(chunk+5)=red; |
9798 | 0 | *(chunk+6)=0; |
9799 | 0 | *(chunk+7)=green; |
9800 | 0 | *(chunk+8)=0; |
9801 | 0 | *(chunk+9)=blue; |
9802 | 0 | (void) WriteBlob(image,num_bytes,(char *) chunk); |
9803 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,num_bytes)); |
9804 | 0 | } |
9805 | |
|
9806 | 0 | if ((image_info->colorspace == sRGBColorspace || image->rendering_intent)) |
9807 | 0 | { |
9808 | | /* |
9809 | | Write JNG sRGB chunk |
9810 | | */ |
9811 | 0 | (void) WriteBlobMSBULong(image,1L); |
9812 | 0 | PNGType(chunk,mng_sRGB); |
9813 | 0 | LogPNGChunk(logging,mng_sRGB,1L); |
9814 | 0 | if (image->rendering_intent != UndefinedIntent) |
9815 | 0 | chunk[4]=(int) image->rendering_intent-1; |
9816 | 0 | else |
9817 | 0 | chunk[4]=(int) PerceptualIntent-1; |
9818 | 0 | (void) WriteBlob(image,5,(char *) chunk); |
9819 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); |
9820 | 0 | } |
9821 | 0 | else |
9822 | 0 | { |
9823 | 0 | if (image->gamma) |
9824 | 0 | { |
9825 | | /* |
9826 | | Write JNG gAMA chunk |
9827 | | */ |
9828 | 0 | (void) WriteBlobMSBULong(image,4L); |
9829 | 0 | PNGType(chunk,mng_gAMA); |
9830 | 0 | LogPNGChunk(logging,mng_gAMA,4L); |
9831 | 0 | PNGLong(chunk+4,(unsigned long) (100000*image->gamma+0.5)); |
9832 | 0 | (void) WriteBlob(image,8,(char *) chunk); |
9833 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); |
9834 | 0 | } |
9835 | 0 | if (!mng_info->equal_chrms && image->chromaticity.red_primary.x != 0.0) |
9836 | 0 | { |
9837 | 0 | PrimaryInfo |
9838 | 0 | primary; |
9839 | | |
9840 | | /* |
9841 | | Write JNG cHRM chunk |
9842 | | */ |
9843 | 0 | (void) WriteBlobMSBULong(image,32L); |
9844 | 0 | PNGType(chunk,mng_cHRM); |
9845 | 0 | LogPNGChunk(logging,mng_cHRM,32L); |
9846 | 0 | primary=image->chromaticity.white_point; |
9847 | 0 | PNGLong(chunk+4,(unsigned long) (100000*primary.x+0.5)); |
9848 | 0 | PNGLong(chunk+8,(unsigned long) (100000*primary.y+0.5)); |
9849 | 0 | primary=image->chromaticity.red_primary; |
9850 | 0 | PNGLong(chunk+12,(unsigned long) (100000*primary.x+0.5)); |
9851 | 0 | PNGLong(chunk+16,(unsigned long) (100000*primary.y+0.5)); |
9852 | 0 | primary=image->chromaticity.green_primary; |
9853 | 0 | PNGLong(chunk+20,(unsigned long) (100000*primary.x+0.5)); |
9854 | 0 | PNGLong(chunk+24,(unsigned long) (100000*primary.y+0.5)); |
9855 | 0 | primary=image->chromaticity.blue_primary; |
9856 | 0 | PNGLong(chunk+28,(unsigned long) (100000*primary.x+0.5)); |
9857 | 0 | PNGLong(chunk+32,(unsigned long) (100000*primary.y+0.5)); |
9858 | 0 | (void) WriteBlob(image,36,(char *) chunk); |
9859 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); |
9860 | 0 | } |
9861 | 0 | } |
9862 | 0 | if (image->x_resolution && image->y_resolution && !mng_info->equal_physs) |
9863 | 0 | { |
9864 | | /* |
9865 | | Write JNG pHYs chunk |
9866 | | */ |
9867 | 0 | (void) WriteBlobMSBULong(image,9L); |
9868 | 0 | PNGType(chunk,mng_pHYs); |
9869 | 0 | LogPNGChunk(logging,mng_pHYs,9L); |
9870 | 0 | if (image->units == PixelsPerInchResolution) |
9871 | 0 | { |
9872 | 0 | PNGLong(chunk+4,(unsigned long) |
9873 | 0 | (image->x_resolution*100.0/2.54+0.5)); |
9874 | 0 | PNGLong(chunk+8,(unsigned long) |
9875 | 0 | (image->y_resolution*100.0/2.54+0.5)); |
9876 | 0 | chunk[12]=1; |
9877 | 0 | } |
9878 | 0 | else |
9879 | 0 | { |
9880 | 0 | if (image->units == PixelsPerCentimeterResolution) |
9881 | 0 | { |
9882 | 0 | PNGLong(chunk+4,(unsigned long) |
9883 | 0 | (image->x_resolution*100.0+0.5)); |
9884 | 0 | PNGLong(chunk+8,(unsigned long) |
9885 | 0 | (image->y_resolution*100.0+0.5)); |
9886 | 0 | chunk[12]=1; |
9887 | 0 | } |
9888 | 0 | else |
9889 | 0 | { |
9890 | 0 | PNGLong(chunk+4,(unsigned long) (image->x_resolution+0.5)); |
9891 | 0 | PNGLong(chunk+8,(unsigned long) (image->y_resolution+0.5)); |
9892 | 0 | chunk[12]=0; |
9893 | 0 | } |
9894 | 0 | } |
9895 | 0 | (void) WriteBlob(image,13,(char *) chunk); |
9896 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); |
9897 | 0 | } |
9898 | |
|
9899 | 0 | if (mng_info->write_mng == 0 && (image->page.x || image->page.y)) |
9900 | 0 | { |
9901 | | /* |
9902 | | Write JNG oFFs chunk |
9903 | | */ |
9904 | 0 | (void) WriteBlobMSBULong(image,9L); |
9905 | 0 | PNGType(chunk,mng_oFFs); |
9906 | 0 | LogPNGChunk(logging,mng_oFFs,9L); |
9907 | 0 | PNGsLong(chunk+4,(long) (image->page.x)); |
9908 | 0 | PNGsLong(chunk+8,(long) (image->page.y)); |
9909 | 0 | chunk[12]=0; |
9910 | 0 | (void) WriteBlob(image,13,(char *) chunk); |
9911 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); |
9912 | 0 | } |
9913 | |
|
9914 | 0 | if (transparent) |
9915 | 0 | { |
9916 | 0 | if (jng_alpha_compression_method==0) |
9917 | 0 | { |
9918 | 0 | unsigned long |
9919 | 0 | len; |
9920 | |
|
9921 | 0 | register long |
9922 | 0 | i; |
9923 | | |
9924 | | /* Write IDAT chunk header */ |
9925 | 0 | if (logging) |
9926 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9927 | 0 | " Write IDAT chunks from blob, length=%lu.", |
9928 | 0 | (unsigned long) length); |
9929 | | |
9930 | | /* Copy IDAT chunks */ |
9931 | 0 | len=0; |
9932 | 0 | p=(unsigned char *) (blob+8); |
9933 | 0 | for (i=8; i<(long)length; i+=len+12) |
9934 | 0 | { |
9935 | 0 | len=mng_get_long(p); |
9936 | 0 | p+=4; |
9937 | 0 | if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) |
9938 | 0 | { |
9939 | | /* Found an IDAT chunk. */ |
9940 | 0 | (void) WriteBlobMSBULong(image,(unsigned long) len); |
9941 | 0 | LogPNGChunk(logging,mng_IDAT,len); |
9942 | 0 | (void) WriteBlob(image,(size_t) len+4,(char *) p); |
9943 | 0 | (void) WriteBlobMSBULong(image, |
9944 | 0 | crc32(0,p,len+4)); |
9945 | 0 | } |
9946 | 0 | else |
9947 | 0 | { |
9948 | 0 | if (logging) |
9949 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9950 | 0 | " Skipping %c%c%c%c chunk," |
9951 | 0 | " length=%lu.", |
9952 | 0 | *(p),*(p+1),*(p+2),*(p+3),len); |
9953 | 0 | } |
9954 | 0 | p+=((size_t) 8+len); |
9955 | 0 | } |
9956 | 0 | } |
9957 | 0 | else |
9958 | 0 | { |
9959 | | /* Write JDAA chunk header */ |
9960 | 0 | if (logging) |
9961 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9962 | 0 | " Write JDAA chunk, length=%lu.", |
9963 | 0 | (unsigned long) length); |
9964 | 0 | (void) WriteBlobMSBULong(image,(unsigned long) length); |
9965 | 0 | PNGType(chunk,mng_JDAA); |
9966 | 0 | LogPNGChunk(logging,mng_JDAA,(unsigned long) length); |
9967 | | /* Write JDAT chunk(s) data */ |
9968 | 0 | (void) WriteBlob(image,4,(char *) chunk); |
9969 | 0 | (void) WriteBlob(image,length,(char *) blob); |
9970 | 0 | (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4), |
9971 | 0 | (unsigned char *) blob,(uInt) length)); |
9972 | 0 | } |
9973 | 0 | MagickFreeMemory(blob); |
9974 | 0 | } |
9975 | | |
9976 | | /* Encode image as a JPEG blob */ |
9977 | 0 | if (logging) |
9978 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9979 | 0 | " Creating jpeg_image_info."); |
9980 | 0 | jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); |
9981 | 0 | if (jpeg_image_info == (ImageInfo *) NULL) |
9982 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9983 | 0 | image); |
9984 | |
|
9985 | 0 | if (logging) |
9986 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
9987 | 0 | " Creating jpeg_image."); |
9988 | |
|
9989 | 0 | jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception); |
9990 | 0 | if (jpeg_image == (Image *) NULL) |
9991 | 0 | { |
9992 | 0 | DestroyImageInfo(jpeg_image_info); |
9993 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
9994 | 0 | image); |
9995 | 0 | } |
9996 | 0 | DestroyBlob(jpeg_image); |
9997 | 0 | jpeg_image->blob=CloneBlobInfo((BlobInfo *) NULL); |
9998 | 0 | (void) AcquireTemporaryFileName(jpeg_image->filename); |
9999 | 0 | MagickFormatString(jpeg_image_info->filename,sizeof(jpeg_image_info->filename), |
10000 | 0 | "%.1024s",jpeg_image->filename); |
10001 | |
|
10002 | 0 | status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, |
10003 | 0 | &image->exception); |
10004 | 0 | if (status == MagickFalse) |
10005 | 0 | { |
10006 | 0 | if (jpeg_image != (Image *)NULL) |
10007 | 0 | DestroyImage(jpeg_image); |
10008 | 0 | if (jpeg_image_info != (ImageInfo *)NULL) |
10009 | 0 | DestroyImageInfo(jpeg_image_info); |
10010 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
10011 | 0 | image); |
10012 | 0 | } |
10013 | | |
10014 | 0 | if (logging) |
10015 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10016 | 0 | " Created jpeg_image, %lu x %lu.", |
10017 | 0 | jpeg_image->columns, |
10018 | 0 | jpeg_image->rows); |
10019 | |
|
10020 | 0 | if (jng_color_type == 8 || jng_color_type == 12) |
10021 | 0 | jpeg_image_info->type=GrayscaleType; |
10022 | 0 | jpeg_image_info->quality=jng_quality%1000; |
10023 | 0 | (void) strlcpy(jpeg_image_info->magick,"JPEG",MaxTextExtent); |
10024 | 0 | (void) strlcpy(jpeg_image->magick,"JPEG",MaxTextExtent); |
10025 | 0 | if (logging) |
10026 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10027 | 0 | " Creating blob."); |
10028 | 0 | blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, |
10029 | 0 | &image->exception); |
10030 | 0 | if (blob == (char *) NULL) |
10031 | 0 | { |
10032 | 0 | if (jpeg_image != (Image *)NULL) |
10033 | 0 | DestroyImage(jpeg_image); |
10034 | 0 | if (jpeg_image_info != (ImageInfo *)NULL) |
10035 | 0 | DestroyImageInfo(jpeg_image_info); |
10036 | 0 | return MagickFail; |
10037 | 0 | } |
10038 | 0 | if (logging) |
10039 | 0 | { |
10040 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10041 | 0 | " Successfully read jpeg_image into a blob," |
10042 | 0 | " length=%lu.", |
10043 | 0 | (unsigned long) length); |
10044 | |
|
10045 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10046 | 0 | " Write JDAT chunk, length=%lu.", |
10047 | 0 | (unsigned long) length); |
10048 | 0 | } |
10049 | | /* Write JDAT chunk(s) */ |
10050 | 0 | (void) WriteBlobMSBULong(image,(unsigned long) length); |
10051 | 0 | PNGType(chunk,mng_JDAT); |
10052 | 0 | LogPNGChunk(logging,mng_JDAT,(unsigned long) length); |
10053 | 0 | (void) WriteBlob(image,4,(char *) chunk); |
10054 | 0 | (void) WriteBlob(image,length,(char *) blob); |
10055 | 0 | (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),(unsigned char *) |
10056 | 0 | blob,(uInt)length)); |
10057 | |
|
10058 | 0 | (void) LiberateTemporaryFile(jpeg_image_info->filename); |
10059 | 0 | DestroyImage(jpeg_image); |
10060 | 0 | DestroyImageInfo(jpeg_image_info); |
10061 | 0 | MagickFreeMemory(blob); |
10062 | | |
10063 | | /* Write IEND chunk */ |
10064 | 0 | (void) WriteBlobMSBULong(image,0L); |
10065 | 0 | PNGType(chunk,mng_IEND); |
10066 | 0 | LogPNGChunk(logging,mng_IEND,0); |
10067 | 0 | (void) WriteBlob(image,4,(char *) chunk); |
10068 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); |
10069 | |
|
10070 | 0 | if (logging) |
10071 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10072 | 0 | " exit WriteOneJNGImage()"); |
10073 | 0 | return(status); |
10074 | 0 | } |
10075 | | |
10076 | | |
10077 | | /* |
10078 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10079 | | % % |
10080 | | % % |
10081 | | % % |
10082 | | % W r i t e J N G I m a g e % |
10083 | | % % |
10084 | | % % |
10085 | | % % |
10086 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10087 | | % |
10088 | | % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file. |
10089 | | % |
10090 | | % JNG support written by Glenn Randers-Pehrson, glennrp@image... |
10091 | | % |
10092 | | % The format of the WriteJNGImage method is: |
10093 | | % |
10094 | | % MagickPassFail WriteJNGImage(const ImageInfo *image_info,Image *image) |
10095 | | % |
10096 | | % A description of each parameter follows: |
10097 | | % |
10098 | | % o image_info: the image info. |
10099 | | % |
10100 | | % o image: The image. |
10101 | | % |
10102 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10103 | | */ |
10104 | | static MagickPassFail WriteJNGImage(const ImageInfo *image_info,Image *image) |
10105 | 0 | { |
10106 | 0 | MngInfo |
10107 | 0 | *mng_info; |
10108 | |
|
10109 | 0 | int |
10110 | 0 | have_mng_structure; |
10111 | |
|
10112 | 0 | unsigned int |
10113 | 0 | logging, |
10114 | 0 | status; |
10115 | | |
10116 | | /* |
10117 | | Open image file. |
10118 | | */ |
10119 | 0 | assert(image_info != (const ImageInfo *) NULL); |
10120 | 0 | assert(image_info->signature == MagickSignature); |
10121 | 0 | assert(image != (Image *) NULL); |
10122 | 0 | assert(image->signature == MagickSignature); |
10123 | 0 | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()"); |
10124 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
10125 | 0 | if (status == MagickFalse) |
10126 | 0 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
10127 | | |
10128 | | /* |
10129 | | Allocate a MngInfo structure. |
10130 | | */ |
10131 | 0 | have_mng_structure=MagickFalse; |
10132 | 0 | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
10133 | 0 | if (mng_info == (MngInfo *) NULL) |
10134 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
10135 | | /* |
10136 | | Initialize members of the MngInfo structure. |
10137 | | */ |
10138 | 0 | (void) memset(mng_info,0,sizeof(MngInfo)); |
10139 | 0 | mng_info->image=image; |
10140 | 0 | have_mng_structure=MagickTrue; |
10141 | |
|
10142 | 0 | (void) WriteBlob(image,8,"\213JNG\r\n\032\n"); |
10143 | |
|
10144 | 0 | status=WriteOneJNGImage(mng_info,image_info,image); |
10145 | 0 | status &= CloseBlob(image); |
10146 | |
|
10147 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
10148 | 0 | if (logging) |
10149 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()"); |
10150 | 0 | return (status); |
10151 | 0 | } |
10152 | | #endif |
10153 | | |
10154 | | |
10155 | | |
10156 | | static unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image) |
10157 | 611 | { |
10158 | 611 | Image |
10159 | 611 | *next_image; |
10160 | | |
10161 | 611 | MngInfo |
10162 | 611 | *mng_info; |
10163 | | |
10164 | 611 | int |
10165 | 611 | have_mng_structure, |
10166 | 611 | image_count, |
10167 | 611 | need_iterations, |
10168 | 611 | need_matte; |
10169 | | |
10170 | 611 | volatile int |
10171 | 611 | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
10172 | 611 | defined(PNG_MNG_FEATURES_SUPPORTED) |
10173 | 611 | need_local_plte, |
10174 | 611 | #endif |
10175 | 611 | all_images_are_gray, |
10176 | 611 | logging, |
10177 | 611 | need_defi, |
10178 | 611 | build_palette, |
10179 | 611 | use_global_plte; |
10180 | | |
10181 | 611 | register long |
10182 | 611 | i; |
10183 | | |
10184 | 611 | #if 1 |
10185 | 611 | size_t |
10186 | 611 | chunk_length=0; |
10187 | 611 | #endif |
10188 | | |
10189 | 611 | MagickPassFail |
10190 | 611 | status; |
10191 | | |
10192 | 611 | volatile unsigned int |
10193 | 611 | write_jng, |
10194 | 611 | write_mng; |
10195 | | |
10196 | 611 | volatile unsigned long |
10197 | 611 | scene; |
10198 | | |
10199 | 611 | unsigned long |
10200 | 611 | final_delay=0, |
10201 | 611 | initial_delay; |
10202 | | |
10203 | | #if (PNG_LIBPNG_VER < 10200) |
10204 | | if (image_info->verbose) |
10205 | | printf("Your PNG library (libpng-%s) is rather old.\n", |
10206 | | PNG_LIBPNG_VER_STRING); |
10207 | | #endif |
10208 | | |
10209 | | /* |
10210 | | Open image file. |
10211 | | */ |
10212 | 611 | assert(image_info != (const ImageInfo *) NULL); |
10213 | 611 | assert(image_info->signature == MagickSignature); |
10214 | 611 | assert(image != (Image *) NULL); |
10215 | 611 | assert(image->signature == MagickSignature); |
10216 | 611 | logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()"); |
10217 | 611 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
10218 | 611 | if (status == MagickFalse) |
10219 | 611 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
10220 | | |
10221 | | /* |
10222 | | Allocate a MngInfo structure. |
10223 | | */ |
10224 | 611 | have_mng_structure=MagickFalse; |
10225 | 611 | mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo)); |
10226 | 611 | if (mng_info == (MngInfo *) NULL) |
10227 | 611 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
10228 | | /* |
10229 | | Initialize members of the MngInfo structure. |
10230 | | */ |
10231 | 611 | (void) memset(mng_info,0,sizeof(MngInfo)); |
10232 | 611 | mng_info->image=image; |
10233 | 611 | have_mng_structure=MagickTrue; |
10234 | | |
10235 | 611 | write_mng=LocaleCompare(image_info->magick,"MNG") == 0; |
10236 | | |
10237 | | /* |
10238 | | MNG only supports a color palette up to 256 colors |
10239 | | */ |
10240 | 611 | if ((write_mng != MagickFalse) && (image->storage_class == PseudoClass) && |
10241 | 0 | (image->colors > 256)) |
10242 | 0 | image->storage_class=DirectClass; |
10243 | | |
10244 | 611 | mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; |
10245 | 611 | mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; |
10246 | 611 | mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; |
10247 | 611 | mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0; |
10248 | 611 | mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0; |
10249 | | |
10250 | 611 | write_jng=MagickFalse; |
10251 | 611 | if (image_info->compression==JPEGCompression) |
10252 | 0 | write_jng=MagickTrue; |
10253 | 611 | else |
10254 | 611 | { |
10255 | 611 | Image |
10256 | 611 | *p; |
10257 | | |
10258 | 18.2k | for (p=image; p != (Image *) NULL; p=p->next) |
10259 | 17.6k | { |
10260 | 17.6k | if (p->compression==JPEGCompression) |
10261 | 0 | write_jng=MagickTrue; |
10262 | 17.6k | } |
10263 | 611 | } |
10264 | | |
10265 | 611 | mng_info->adjoin=image_info->adjoin && (image->next != (Image *) NULL) && |
10266 | 433 | write_mng; |
10267 | | |
10268 | 611 | #ifdef GMPNG_BUILD_PALETTE |
10269 | 611 | if (mng_info->write_png8) |
10270 | 0 | build_palette=MagickTrue; |
10271 | 611 | else if (mng_info->write_png24 || mng_info->write_png32 || |
10272 | 611 | mng_info->write_png48 || mng_info->write_png64) |
10273 | 0 | build_palette=MagickFalse; |
10274 | 611 | else |
10275 | 611 | build_palette=(image_info->type == UndefinedType); |
10276 | 611 | #endif |
10277 | | |
10278 | 611 | if (logging) |
10279 | 0 | { |
10280 | | /* Log some info about the input */ |
10281 | 0 | Image |
10282 | 0 | *p; |
10283 | |
|
10284 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10285 | 0 | " Checking input image(s)"); |
10286 | |
|
10287 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10288 | 0 | " Image_info depth: %ld", |
10289 | 0 | image_info->depth); |
10290 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10291 | 0 | " Type: %d",image_info->type); |
10292 | |
|
10293 | 0 | scene=0; |
10294 | 0 | for (p=image; p != (Image *) NULL; p=p->next) |
10295 | 0 | { |
10296 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10297 | 0 | " Scene: %ld",scene++); |
10298 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10299 | 0 | " Image depth: %u",p->depth); |
10300 | 0 | if (p->matte) |
10301 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10302 | 0 | " Matte: True"); |
10303 | 0 | else |
10304 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10305 | 0 | " Matte: False"); |
10306 | 0 | if (p->storage_class == PseudoClass) |
10307 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10308 | 0 | " Storage class: PseudoClass"); |
10309 | 0 | else |
10310 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10311 | 0 | " Storage class: DirectClass"); |
10312 | 0 | if (p->colors) |
10313 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10314 | 0 | " Number of colors: %u",p->colors); |
10315 | 0 | else |
10316 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10317 | 0 | " Number of colors: unspecified"); |
10318 | 0 | if (!mng_info->adjoin) |
10319 | 0 | break; |
10320 | 0 | } |
10321 | 0 | } |
10322 | | |
10323 | | /* |
10324 | | Sometimes we get PseudoClass images whose RGB values don't match |
10325 | | the colors in the colormap. This code syncs the RGB values. |
10326 | | */ |
10327 | 611 | { |
10328 | 611 | Image |
10329 | 611 | *p; |
10330 | | |
10331 | 18.1k | for (p=image; p != (Image *) NULL; p=p->next) |
10332 | 17.6k | { |
10333 | 17.6k | if (p->taint && p->storage_class == PseudoClass) |
10334 | 0 | (void) SyncImage(p); |
10335 | 17.6k | if (!mng_info->adjoin) |
10336 | 178 | break; |
10337 | 17.6k | } |
10338 | 611 | } |
10339 | | |
10340 | 611 | #ifdef GMPNG_BUILD_PALETTE |
10341 | 611 | if (build_palette) |
10342 | 611 | { |
10343 | | /* |
10344 | | Sometimes we get DirectClass images that have 256 colors or fewer. |
10345 | | This code will convert them to PseudoClass and build a colormap. |
10346 | | */ |
10347 | 611 | Image |
10348 | 611 | *p; |
10349 | | |
10350 | 18.1k | for (p=image; p != (Image *) NULL; p=p->next) |
10351 | 17.6k | { |
10352 | 17.6k | if (p->storage_class != PseudoClass) |
10353 | 17.6k | { |
10354 | 17.6k | p->colors=GetNumberColors(p,(FILE *) NULL,&p->exception); |
10355 | 17.6k | if (p->colors <= 256) |
10356 | 17.6k | { |
10357 | 17.6k | p->colors=0; |
10358 | 17.6k | if (p->matte) |
10359 | 0 | status &= SetImageType(p,PaletteMatteType); |
10360 | 17.6k | else |
10361 | 17.6k | status &= SetImageType(p,PaletteType); |
10362 | 17.6k | } |
10363 | 17.6k | } |
10364 | 17.6k | if (!mng_info->adjoin) |
10365 | 178 | break; |
10366 | 17.6k | } |
10367 | 611 | } |
10368 | 611 | #endif |
10369 | | |
10370 | 611 | use_global_plte=MagickFalse; |
10371 | 611 | all_images_are_gray=MagickFalse; |
10372 | 611 | #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
10373 | 611 | need_local_plte=MagickTrue; |
10374 | 611 | #endif |
10375 | 611 | need_defi=MagickFalse; |
10376 | 611 | need_matte=MagickFalse; |
10377 | 611 | mng_info->framing_mode=1; |
10378 | 611 | mng_info->old_framing_mode=1; |
10379 | | |
10380 | 611 | if (write_mng) |
10381 | 611 | if (image_info->page != (char *) NULL) |
10382 | 0 | { |
10383 | | /* |
10384 | | Determine image bounding box. |
10385 | | */ |
10386 | 0 | SetGeometry(image,&mng_info->page); |
10387 | 0 | (void) GetMagickGeometry(image_info->page,&mng_info->page.x, |
10388 | 0 | &mng_info->page.y,&mng_info->page.width, |
10389 | 0 | &mng_info->page.height); |
10390 | 0 | } |
10391 | 611 | if (write_mng) |
10392 | 611 | { |
10393 | 611 | unsigned char |
10394 | 611 | chunk[800]; |
10395 | | |
10396 | 611 | unsigned int |
10397 | 611 | need_geom; |
10398 | | |
10399 | 611 | unsigned short |
10400 | 611 | red, |
10401 | 611 | green, |
10402 | 611 | blue; |
10403 | | |
10404 | 611 | mng_info->page=image->page; |
10405 | 611 | need_geom=MagickTrue; |
10406 | 611 | if (mng_info->page.width || mng_info->page.height) |
10407 | 611 | need_geom=MagickFalse; |
10408 | | /* |
10409 | | Check all the scenes. |
10410 | | */ |
10411 | 611 | initial_delay=(long) image->delay; |
10412 | 611 | need_iterations=MagickFalse; |
10413 | 611 | mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0; |
10414 | 611 | mng_info->equal_physs=MagickTrue, |
10415 | 611 | mng_info->equal_gammas=MagickTrue; |
10416 | 611 | mng_info->equal_srgbs=MagickTrue; |
10417 | 611 | mng_info->equal_backgrounds=MagickTrue; |
10418 | 611 | image_count=0; |
10419 | 611 | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
10420 | 611 | defined(PNG_MNG_FEATURES_SUPPORTED) |
10421 | 611 | all_images_are_gray=MagickTrue; |
10422 | 611 | mng_info->equal_palettes=MagickFalse; |
10423 | 611 | need_local_plte=MagickFalse; |
10424 | 611 | #endif |
10425 | 18.2k | for (next_image=image; next_image != (Image *) NULL; ) |
10426 | 17.6k | { |
10427 | 17.6k | if (need_geom) |
10428 | 0 | { |
10429 | 0 | if ((next_image->columns+next_image->page.x) > |
10430 | 0 | mng_info->page.width) |
10431 | 0 | mng_info->page.width=next_image->columns+next_image->page.x; |
10432 | 0 | if ((next_image->rows+next_image->page.y) > |
10433 | 0 | mng_info->page.height) |
10434 | 0 | mng_info->page.height=next_image->rows+next_image->page.y; |
10435 | 0 | } |
10436 | 17.6k | if (next_image->page.x || next_image->page.y) |
10437 | 0 | need_defi=MagickTrue; |
10438 | 17.6k | if (next_image->matte) |
10439 | 0 | need_matte=MagickTrue; |
10440 | 17.6k | if ((int) next_image->dispose >= BackgroundDispose) |
10441 | 611 | if (next_image->matte || next_image->page.x || |
10442 | 611 | next_image->page.y || |
10443 | 611 | ((next_image->columns < mng_info->page.width) && |
10444 | 0 | (next_image->rows < mng_info->page.height))) |
10445 | 0 | mng_info->need_fram=MagickTrue; |
10446 | 17.6k | if (next_image->iterations) |
10447 | 562 | need_iterations=MagickTrue; |
10448 | 17.6k | final_delay=next_image->delay; |
10449 | 17.6k | if (final_delay != initial_delay || final_delay > 100) |
10450 | 1.84k | mng_info->need_fram=1; |
10451 | 17.6k | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
10452 | 17.6k | defined(PNG_MNG_FEATURES_SUPPORTED) |
10453 | | /* |
10454 | | check for global palette possibility. |
10455 | | */ |
10456 | 17.6k | if (image->matte) |
10457 | 0 | need_local_plte=MagickTrue; |
10458 | 17.6k | if (!need_local_plte) |
10459 | 5.18k | { |
10460 | 5.18k | if (!IsGrayImage(image,&image->exception)) |
10461 | 1.65k | all_images_are_gray=MagickFalse; |
10462 | 5.18k | mng_info->equal_palettes=PalettesAreEqual(image,next_image); |
10463 | 5.18k | if (!use_global_plte) |
10464 | 611 | use_global_plte=mng_info->equal_palettes; |
10465 | 5.18k | need_local_plte=!mng_info->equal_palettes; |
10466 | 5.18k | } |
10467 | 17.6k | #endif |
10468 | 17.6k | if (next_image->next != (Image *) NULL) |
10469 | 17.0k | { |
10470 | 17.0k | if (next_image->background_color.red != |
10471 | 17.0k | next_image->next->background_color.red || |
10472 | 17.0k | next_image->background_color.green != |
10473 | 17.0k | next_image->next->background_color.green || |
10474 | 17.0k | next_image->background_color.blue != |
10475 | 17.0k | next_image->next->background_color.blue) |
10476 | 0 | mng_info->equal_backgrounds=MagickFalse; |
10477 | 17.0k | if (next_image->gamma != next_image->next->gamma) |
10478 | 0 | mng_info->equal_gammas=MagickFalse; |
10479 | 17.0k | if (next_image->rendering_intent != |
10480 | 17.0k | next_image->next->rendering_intent) |
10481 | 0 | mng_info->equal_srgbs=MagickFalse; |
10482 | 17.0k | if ((next_image->units != next_image->next->units) || |
10483 | 17.0k | (next_image->x_resolution != |
10484 | 17.0k | next_image->next->x_resolution) || |
10485 | 17.0k | (next_image->y_resolution != next_image->next->y_resolution)) |
10486 | 0 | mng_info->equal_physs=MagickFalse; |
10487 | 17.0k | if (mng_info->equal_chrms) |
10488 | 0 | { |
10489 | 0 | if (next_image->chromaticity.red_primary.x != |
10490 | 0 | next_image->next->chromaticity.red_primary.x || |
10491 | 0 | next_image->chromaticity.red_primary.y != |
10492 | 0 | next_image->next->chromaticity.red_primary.y || |
10493 | 0 | next_image->chromaticity.green_primary.x != |
10494 | 0 | next_image->next->chromaticity.green_primary.x || |
10495 | 0 | next_image->chromaticity.green_primary.y != |
10496 | 0 | next_image->next->chromaticity.green_primary.y || |
10497 | 0 | next_image->chromaticity.blue_primary.x != |
10498 | 0 | next_image->next->chromaticity.blue_primary.x || |
10499 | 0 | next_image->chromaticity.blue_primary.y != |
10500 | 0 | next_image->next->chromaticity.blue_primary.y || |
10501 | 0 | next_image->chromaticity.white_point.x != |
10502 | 0 | next_image->next->chromaticity.white_point.x || |
10503 | 0 | next_image->chromaticity.white_point.y != |
10504 | 0 | next_image->next->chromaticity.white_point.y) |
10505 | 0 | mng_info->equal_chrms=MagickFalse; |
10506 | 0 | } |
10507 | 17.0k | } |
10508 | 17.6k | image_count++; |
10509 | 17.6k | next_image=next_image->next; |
10510 | 17.6k | } |
10511 | 611 | if (image_count < 2) |
10512 | 178 | { |
10513 | 178 | mng_info->equal_backgrounds=MagickFalse; |
10514 | 178 | mng_info->equal_chrms=MagickFalse; |
10515 | 178 | mng_info->equal_gammas=MagickFalse; |
10516 | 178 | mng_info->equal_srgbs=MagickFalse; |
10517 | 178 | mng_info->equal_physs=MagickFalse; |
10518 | 178 | use_global_plte=MagickFalse; |
10519 | 178 | #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
10520 | 178 | need_local_plte=MagickTrue; |
10521 | 178 | #endif |
10522 | 178 | need_iterations=MagickFalse; |
10523 | 178 | } |
10524 | 611 | if (!mng_info->need_fram) |
10525 | 434 | { |
10526 | | /* |
10527 | | Only certain framing rates 100/n are exactly representable without |
10528 | | the FRAM chunk but we'll allow some slop in VLC files |
10529 | | */ |
10530 | 434 | if (final_delay == 0) |
10531 | 116 | { |
10532 | 116 | if (need_iterations) |
10533 | 0 | { |
10534 | | /* |
10535 | | It's probably a GIF with loop; don't run it *too* fast. |
10536 | | */ |
10537 | 0 | final_delay=10; |
10538 | 0 | (void) ThrowException2(&image->exception,CoderError, |
10539 | 0 | "input has zero delay between" |
10540 | 0 | " all frames; assuming 10 cs", |
10541 | 0 | (char *) NULL); |
10542 | 0 | } |
10543 | 116 | else |
10544 | 116 | mng_info->ticks_per_second=0; |
10545 | 116 | } |
10546 | 434 | if (final_delay) |
10547 | 318 | mng_info->ticks_per_second=100/final_delay; |
10548 | 434 | if (final_delay > 50) |
10549 | 8 | mng_info->ticks_per_second=2; |
10550 | 434 | if (final_delay > 75) |
10551 | 5 | mng_info->ticks_per_second=1; |
10552 | 434 | if (final_delay > 125) |
10553 | 0 | mng_info->need_fram=MagickTrue; |
10554 | 434 | if (need_defi && final_delay > 2 && (final_delay != 4) && |
10555 | 0 | (final_delay != 5) && (final_delay != 10) && |
10556 | 0 | (final_delay != 20) && |
10557 | 0 | (final_delay != 25) && (final_delay != 50) && |
10558 | 0 | (final_delay != 100)) |
10559 | 0 | mng_info->need_fram=MagickTrue; /* make it exact; |
10560 | | cannot be VLC anyway */ |
10561 | 434 | } |
10562 | 611 | if (mng_info->need_fram) |
10563 | 177 | mng_info->ticks_per_second=100; |
10564 | | /* |
10565 | | If pseudocolor, we should also check to see if all the |
10566 | | palettes are identical and write a global PLTE if they are. |
10567 | | ../glennrp Feb 99. |
10568 | | */ |
10569 | | /* |
10570 | | Write the MNG version 1.0 signature and MHDR chunk. |
10571 | | */ |
10572 | 611 | (void) WriteBlob(image,8,"\212MNG\r\n\032\n"); |
10573 | 611 | (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */ |
10574 | 611 | PNGType(chunk,mng_MHDR); |
10575 | 611 | LogPNGChunk(logging,mng_MHDR,28L); |
10576 | 611 | PNGLong(chunk+4,mng_info->page.width); |
10577 | 611 | PNGLong(chunk+8,mng_info->page.height); |
10578 | 611 | PNGLong(chunk+12,mng_info->ticks_per_second); |
10579 | 611 | PNGLong(chunk+16,0L); /* layer count=unknown */ |
10580 | 611 | PNGLong(chunk+20,0L); /* frame count=unknown */ |
10581 | 611 | PNGLong(chunk+24,0L); /* play time=unknown */ |
10582 | 611 | if (write_jng) |
10583 | 0 | { |
10584 | 0 | if (need_matte) |
10585 | 0 | { |
10586 | 0 | if (need_defi || mng_info->need_fram || use_global_plte) |
10587 | 0 | PNGLong(chunk+28,27L); /* simplicity=LC+JNG */ |
10588 | 0 | else |
10589 | 0 | PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */ |
10590 | 0 | } |
10591 | 0 | else |
10592 | 0 | { |
10593 | 0 | if (need_defi || mng_info->need_fram || use_global_plte) |
10594 | 0 | PNGLong(chunk+28,19L); /* simplicity=LC+JNG, |
10595 | | no transparency */ |
10596 | 0 | else |
10597 | 0 | PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, |
10598 | | no transparency */ |
10599 | 0 | } |
10600 | 0 | } |
10601 | 611 | else |
10602 | 611 | { |
10603 | 611 | if (need_matte) |
10604 | 0 | { |
10605 | 0 | if (need_defi || mng_info->need_fram || use_global_plte) |
10606 | 0 | PNGLong(chunk+28,11L); /* simplicity=LC */ |
10607 | 0 | else |
10608 | 0 | PNGLong(chunk+28,9L); /* simplicity=VLC */ |
10609 | 0 | } |
10610 | 611 | else |
10611 | 611 | { |
10612 | 611 | if (need_defi || mng_info->need_fram || use_global_plte) |
10613 | 476 | PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */ |
10614 | 135 | else |
10615 | 135 | PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */ |
10616 | 611 | } |
10617 | 611 | } |
10618 | 611 | (void) WriteBlob(image,32,(char *) chunk); |
10619 | 611 | (void) WriteBlobMSBULong(image,crc32(0,chunk,32)); |
10620 | 611 | #if 1 |
10621 | 611 | if (AccessDefinition(image_info,"mng","need-cacheoff")) |
10622 | 0 | { |
10623 | | /* |
10624 | | Add a "nEED CACHEOFF" request to disable frame caching in libmng. |
10625 | | Unfortunately, standard conformant players will reject the stream |
10626 | | if they do not support a nEED request. |
10627 | | */ |
10628 | 0 | PNGType(chunk,mng_nEED); |
10629 | 0 | chunk_length = (strlcpy((char *) chunk+4, "CACHEOFF",20)); |
10630 | 0 | (void) WriteBlobMSBULong(image,(unsigned long) chunk_length); |
10631 | 0 | LogPNGChunk(logging,mng_nEED,(unsigned long) chunk_length); |
10632 | 0 | chunk_length += 4; |
10633 | 0 | (void) WriteBlob(image,chunk_length,(char *) chunk); |
10634 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) chunk_length)); |
10635 | 0 | } |
10636 | 611 | #endif |
10637 | 611 | if ((image->previous == (Image *) NULL) && |
10638 | 611 | (image->next != (Image *) NULL) && (image->iterations != 1)) |
10639 | 430 | { |
10640 | | /* |
10641 | | Write MNG TERM chunk |
10642 | | */ |
10643 | 430 | (void) WriteBlobMSBULong(image,10L); /* data length=10 */ |
10644 | 430 | PNGType(chunk,mng_TERM); |
10645 | 430 | LogPNGChunk(logging,mng_TERM,10L); |
10646 | 430 | chunk[4]=3; /* repeat animation */ |
10647 | 430 | chunk[5]=0; /* show last frame when done */ |
10648 | 430 | PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second* |
10649 | 430 | final_delay/100)); |
10650 | 430 | if (image->iterations == 0) |
10651 | 382 | PNGLong(chunk+10,PNG_MAX_UINT); |
10652 | 48 | else |
10653 | 48 | PNGLong(chunk+10,(png_uint_32) image->iterations); |
10654 | 430 | if (logging) |
10655 | 0 | { |
10656 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10657 | 0 | " TERM delay: %lu", |
10658 | 0 | (unsigned long) |
10659 | 0 | (mng_info->ticks_per_second* |
10660 | 0 | final_delay/100)); |
10661 | 0 | if (image->iterations == 0) |
10662 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10663 | 0 | " TERM iterations: %lu", |
10664 | 0 | (unsigned long)PNG_MAX_UINT); |
10665 | 0 | else |
10666 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10667 | 0 | " Image iterations: %lu", |
10668 | 0 | image->iterations); |
10669 | 0 | } |
10670 | 430 | (void) WriteBlob(image,14,(char *) chunk); |
10671 | 430 | (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); |
10672 | 430 | } |
10673 | | /* |
10674 | | To do: check for cHRM+gAMA == sRGB, and write sRGB instead. |
10675 | | */ |
10676 | 611 | if ((image_info->colorspace == sRGBColorspace || |
10677 | 611 | image->rendering_intent) && mng_info->equal_srgbs) |
10678 | 0 | { |
10679 | | /* |
10680 | | Write MNG sRGB chunk |
10681 | | */ |
10682 | 0 | (void) WriteBlobMSBULong(image,1L); |
10683 | 0 | PNGType(chunk,mng_sRGB); |
10684 | 0 | LogPNGChunk(logging,mng_sRGB,1L); |
10685 | 0 | if (image->rendering_intent != UndefinedIntent) |
10686 | 0 | chunk[4]=(int) image->rendering_intent-1; |
10687 | 0 | else |
10688 | 0 | chunk[4]=(int) PerceptualIntent-1; |
10689 | 0 | (void) WriteBlob(image,5,(char *) chunk); |
10690 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); |
10691 | 0 | mng_info->have_write_global_srgb=MagickTrue; |
10692 | 0 | } |
10693 | 611 | else |
10694 | 611 | { |
10695 | 611 | if (image->gamma && mng_info->equal_gammas) |
10696 | 0 | { |
10697 | | /* |
10698 | | Write MNG gAMA chunk |
10699 | | */ |
10700 | 0 | (void) WriteBlobMSBULong(image,4L); |
10701 | 0 | PNGType(chunk,mng_gAMA); |
10702 | 0 | LogPNGChunk(logging,mng_gAMA,4L); |
10703 | 0 | PNGLong(chunk+4,(unsigned long) (100000*image->gamma+0.5)); |
10704 | 0 | (void) WriteBlob(image,8,(char *) chunk); |
10705 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); |
10706 | 0 | mng_info->have_write_global_gama=MagickTrue; |
10707 | 0 | } |
10708 | 611 | if (mng_info->equal_chrms) |
10709 | 0 | { |
10710 | 0 | PrimaryInfo |
10711 | 0 | primary; |
10712 | | |
10713 | | /* |
10714 | | Write MNG cHRM chunk |
10715 | | */ |
10716 | 0 | (void) WriteBlobMSBULong(image,32L); |
10717 | 0 | PNGType(chunk,mng_cHRM); |
10718 | 0 | LogPNGChunk(logging,mng_cHRM,32L); |
10719 | 0 | primary=image->chromaticity.white_point; |
10720 | 0 | PNGLong(chunk+4,(unsigned long) (100000*primary.x+0.5)); |
10721 | 0 | PNGLong(chunk+8,(unsigned long) (100000*primary.y+0.5)); |
10722 | 0 | primary=image->chromaticity.red_primary; |
10723 | 0 | PNGLong(chunk+12,(unsigned long) (100000*primary.x+0.5)); |
10724 | 0 | PNGLong(chunk+16,(unsigned long) (100000*primary.y+0.5)); |
10725 | 0 | primary=image->chromaticity.green_primary; |
10726 | 0 | PNGLong(chunk+20,(unsigned long) (100000*primary.x+0.5)); |
10727 | 0 | PNGLong(chunk+24,(unsigned long) (100000*primary.y+0.5)); |
10728 | 0 | primary=image->chromaticity.blue_primary; |
10729 | 0 | PNGLong(chunk+28,(unsigned long) (100000*primary.x+0.5)); |
10730 | 0 | PNGLong(chunk+32,(unsigned long) (100000*primary.y+0.5)); |
10731 | 0 | (void) WriteBlob(image,36,(char *) chunk); |
10732 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); |
10733 | 0 | mng_info->have_write_global_chrm=MagickTrue; |
10734 | 0 | } |
10735 | 611 | } |
10736 | 611 | if (image->x_resolution && image->y_resolution && mng_info->equal_physs) |
10737 | 0 | { |
10738 | | /* |
10739 | | Write MNG pHYs chunk |
10740 | | */ |
10741 | 0 | (void) WriteBlobMSBULong(image,9L); |
10742 | 0 | PNGType(chunk,mng_pHYs); |
10743 | 0 | LogPNGChunk(logging,mng_pHYs,9L); |
10744 | 0 | if (image->units == PixelsPerInchResolution) |
10745 | 0 | { |
10746 | 0 | PNGLong(chunk+4,(unsigned long) |
10747 | 0 | (image->x_resolution*100.0/2.54+0.5)); |
10748 | 0 | PNGLong(chunk+8,(unsigned long) |
10749 | 0 | (image->y_resolution*100.0/2.54+0.5)); |
10750 | 0 | chunk[12]=1; |
10751 | 0 | } |
10752 | 0 | else |
10753 | 0 | { |
10754 | 0 | if (image->units == PixelsPerCentimeterResolution) |
10755 | 0 | { |
10756 | 0 | PNGLong(chunk+4,(unsigned long) |
10757 | 0 | (image->x_resolution*100.0+0.5)); |
10758 | 0 | PNGLong(chunk+8,(unsigned long) |
10759 | 0 | (image->y_resolution*100.0+0.5)); |
10760 | 0 | chunk[12]=1; |
10761 | 0 | } |
10762 | 0 | else |
10763 | 0 | { |
10764 | 0 | PNGLong(chunk+4,(unsigned long) (image->x_resolution+0.5)); |
10765 | 0 | PNGLong(chunk+8,(unsigned long) (image->y_resolution+0.5)); |
10766 | 0 | chunk[12]=0; |
10767 | 0 | } |
10768 | 0 | } |
10769 | 0 | (void) WriteBlob(image,13,(char *) chunk); |
10770 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); |
10771 | 0 | } |
10772 | | /* |
10773 | | Write MNG BACK chunk and global bKGD chunk, if the image is transparent |
10774 | | or does not cover the entire frame. |
10775 | | */ |
10776 | 611 | if (write_mng && (image->matte || image->page.x > 0 || |
10777 | 611 | image->page.y > 0 || |
10778 | 611 | (image->page.width && |
10779 | 611 | (image->page.width+image->page.x < |
10780 | 611 | mng_info->page.width)) |
10781 | 611 | || (image->page.height && |
10782 | 611 | (image->page.height+image->page.y < |
10783 | 611 | mng_info->page.height)))) |
10784 | 0 | { |
10785 | 0 | (void) WriteBlobMSBULong(image,6L); |
10786 | 0 | PNGType(chunk,mng_BACK); |
10787 | 0 | LogPNGChunk(logging,mng_BACK,6L); |
10788 | 0 | red=ScaleQuantumToShort(image->background_color.red); |
10789 | 0 | green=ScaleQuantumToShort(image->background_color.green); |
10790 | 0 | blue=ScaleQuantumToShort(image->background_color.blue); |
10791 | 0 | PNGShort(chunk+4,red); |
10792 | 0 | PNGShort(chunk+6,green); |
10793 | 0 | PNGShort(chunk+8,blue); |
10794 | 0 | (void) WriteBlob(image,10,(char *) chunk); |
10795 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); |
10796 | 0 | if (mng_info->equal_backgrounds) |
10797 | 0 | { |
10798 | 0 | (void) WriteBlobMSBULong(image,6L); |
10799 | 0 | PNGType(chunk,mng_bKGD); |
10800 | 0 | LogPNGChunk(logging,mng_bKGD,6L); |
10801 | 0 | (void) WriteBlob(image,10,(char *) chunk); |
10802 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); |
10803 | 0 | } |
10804 | 0 | } |
10805 | | |
10806 | 611 | #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED |
10807 | 611 | if (!need_local_plte && image->storage_class == PseudoClass |
10808 | 212 | && !all_images_are_gray) |
10809 | 50 | { |
10810 | 50 | unsigned long |
10811 | 50 | data_length; |
10812 | | |
10813 | | /* |
10814 | | Write MNG PLTE chunk |
10815 | | */ |
10816 | 50 | data_length=3*image->colors; |
10817 | 50 | (void) WriteBlobMSBULong(image,data_length); |
10818 | 50 | PNGType(chunk,mng_PLTE); |
10819 | 50 | LogPNGChunk(logging,mng_PLTE,data_length); |
10820 | 100 | for (i=0; i < (long) image->colors; i++) |
10821 | 50 | { |
10822 | 50 | chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff; |
10823 | 50 | chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff; |
10824 | 50 | chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff; |
10825 | 50 | } |
10826 | 50 | (void) WriteBlob(image,(size_t) data_length+4,(char *) chunk); |
10827 | 50 | (void) WriteBlobMSBULong(image,crc32(0,chunk,(int) (data_length+4))); |
10828 | 50 | mng_info->have_write_global_plte=MagickTrue; |
10829 | 50 | } |
10830 | 611 | #endif |
10831 | 611 | } |
10832 | 611 | scene=0; |
10833 | 611 | mng_info->delay=0; |
10834 | 611 | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
10835 | 611 | defined(PNG_MNG_FEATURES_SUPPORTED) |
10836 | 611 | mng_info->equal_palettes=MagickFalse; |
10837 | 611 | #endif |
10838 | 611 | do |
10839 | 17.6k | { |
10840 | 17.6k | unsigned char |
10841 | 17.6k | chunk[800]; |
10842 | | |
10843 | 17.6k | if (mng_info->adjoin) |
10844 | 17.5k | { |
10845 | 17.5k | #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ |
10846 | 17.5k | defined(PNG_MNG_FEATURES_SUPPORTED) |
10847 | | /* |
10848 | | If we aren't using a global palette for the entire MNG, check to |
10849 | | see if we can use one for two or more consecutive images. |
10850 | | */ |
10851 | 17.5k | if (need_local_plte && use_global_plte && !all_images_are_gray) |
10852 | 1.18k | { |
10853 | 1.18k | if (mng_info->IsPalette) |
10854 | 1.09k | { |
10855 | | /* |
10856 | | When equal_palettes is true, this image has the |
10857 | | same palette as the previous PseudoClass image |
10858 | | */ |
10859 | 1.09k | mng_info->have_write_global_plte=mng_info->equal_palettes; |
10860 | 1.09k | mng_info->equal_palettes=PalettesAreEqual(image,image->next); |
10861 | 1.09k | if (mng_info->equal_palettes && |
10862 | 568 | !mng_info->have_write_global_plte) |
10863 | 206 | { |
10864 | | /* |
10865 | | Write MNG PLTE chunk |
10866 | | */ |
10867 | 206 | unsigned long |
10868 | 206 | data_length; |
10869 | | |
10870 | 206 | data_length=3*image->colors; |
10871 | 206 | (void) WriteBlobMSBULong(image,data_length); |
10872 | 206 | PNGType(chunk,mng_PLTE); |
10873 | 206 | LogPNGChunk(logging,mng_PLTE,data_length); |
10874 | 412 | for (i=0; i < (long) image->colors; i++) |
10875 | 206 | { |
10876 | 206 | chunk[4+i*3]= |
10877 | 206 | ScaleQuantumToChar(image->colormap[i].red); |
10878 | 206 | chunk[5+i*3]= |
10879 | 206 | ScaleQuantumToChar(image->colormap[i].green); |
10880 | 206 | chunk[6+i*3]= |
10881 | 206 | ScaleQuantumToChar(image->colormap[i].blue); |
10882 | 206 | } |
10883 | 206 | (void) WriteBlob(image,(size_t) data_length+4,(char *) chunk); |
10884 | 206 | (void) WriteBlobMSBULong(image, |
10885 | 206 | crc32(0,chunk,(int) |
10886 | 206 | (data_length+4))); |
10887 | 206 | mng_info->have_write_global_plte=MagickTrue; |
10888 | 206 | } |
10889 | 1.09k | } |
10890 | 82 | else |
10891 | 82 | mng_info->have_write_global_plte=MagickFalse; |
10892 | 1.18k | } |
10893 | 17.5k | #endif |
10894 | 17.5k | if (need_defi) |
10895 | 0 | { |
10896 | 0 | long |
10897 | 0 | previous_x, |
10898 | 0 | previous_y; |
10899 | |
|
10900 | 0 | if (scene) |
10901 | 0 | { |
10902 | 0 | previous_x=mng_info->page.x; |
10903 | 0 | previous_y=mng_info->page.y; |
10904 | 0 | } |
10905 | 0 | else |
10906 | 0 | { |
10907 | 0 | previous_x=0; |
10908 | 0 | previous_y=0; |
10909 | 0 | } |
10910 | 0 | mng_info->page=image->page; |
10911 | 0 | if ((mng_info->page.x != previous_x) || (mng_info->page.y != |
10912 | 0 | previous_y)) |
10913 | 0 | { |
10914 | 0 | (void) WriteBlobMSBULong(image,12L); /* data length=12 */ |
10915 | 0 | PNGType(chunk,mng_DEFI); |
10916 | 0 | LogPNGChunk(logging,mng_DEFI,12L); |
10917 | 0 | chunk[4]=0; /* object 0 MSB */ |
10918 | 0 | chunk[5]=0; /* object 0 LSB */ |
10919 | 0 | chunk[6]=0; /* visible */ |
10920 | 0 | chunk[7]=0; /* abstract */ |
10921 | 0 | PNGLong(chunk+8,mng_info->page.x); |
10922 | 0 | PNGLong(chunk+12,mng_info->page.y); |
10923 | 0 | (void) WriteBlob(image,16,(char *) chunk); |
10924 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,16)); |
10925 | 0 | } |
10926 | 0 | } |
10927 | 17.5k | } |
10928 | | |
10929 | 17.6k | mng_info->write_mng=write_mng; |
10930 | | |
10931 | 17.6k | if ((int) image->dispose >= 3) |
10932 | 0 | mng_info->framing_mode=3; |
10933 | | |
10934 | 17.6k | if (mng_info->need_fram && mng_info->adjoin && |
10935 | 1.90k | ((image->delay != mng_info->delay) || |
10936 | 1.58k | (mng_info->framing_mode != mng_info->old_framing_mode))) |
10937 | 314 | { |
10938 | 314 | if (image->delay == mng_info->delay) |
10939 | 0 | { |
10940 | | /* |
10941 | | Write a MNG FRAM chunk with the new framing mode. |
10942 | | */ |
10943 | 0 | (void) WriteBlobMSBULong(image,1L); /* data length=1 */ |
10944 | 0 | PNGType(chunk,mng_FRAM); |
10945 | 0 | LogPNGChunk(logging,mng_FRAM,1L); |
10946 | 0 | chunk[4]=(unsigned char) mng_info->framing_mode; |
10947 | 0 | (void) WriteBlob(image,5,(char *) chunk); |
10948 | 0 | (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); |
10949 | 0 | } |
10950 | 314 | else |
10951 | 314 | { |
10952 | | /* |
10953 | | Write a MNG FRAM chunk with the delay. |
10954 | | */ |
10955 | 314 | (void) WriteBlobMSBULong(image,10L); /* data length=10 */ |
10956 | 314 | PNGType(chunk,mng_FRAM); |
10957 | 314 | LogPNGChunk(logging,mng_FRAM,10L); |
10958 | 314 | chunk[4]=(unsigned char) mng_info->framing_mode; |
10959 | 314 | chunk[5]=0; /* frame name separator (no name) */ |
10960 | 314 | chunk[6]=2; /* flag for changing default delay */ |
10961 | 314 | chunk[7]=0; /* flag for changing frame timeout */ |
10962 | 314 | chunk[8]=0; /* flag for changing frame clipping */ |
10963 | 314 | chunk[9]=0; /* flag for changing frame sync_id */ |
10964 | 314 | PNGLong(chunk+10,(png_uint_32) |
10965 | 314 | ((mng_info->ticks_per_second*image->delay)/100)); |
10966 | 314 | (void) WriteBlob(image,14,(char *) chunk); |
10967 | 314 | (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); |
10968 | 314 | mng_info->delay=(long) image->delay; |
10969 | 314 | } |
10970 | 314 | mng_info->old_framing_mode=mng_info->framing_mode; |
10971 | 314 | } |
10972 | | |
10973 | 17.6k | #if defined(JNG_SUPPORTED) |
10974 | 17.6k | if (image->compression == JPEGCompression) |
10975 | 0 | { |
10976 | 0 | if (logging) |
10977 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10978 | 0 | " Writing JNG object."); |
10979 | | /* To do: specify the desired alpha compression method. */ |
10980 | 0 | image->compression=UndefinedCompression; |
10981 | 0 | status=WriteOneJNGImage(mng_info,image_info,image); |
10982 | 0 | } |
10983 | 17.6k | else |
10984 | 17.6k | #endif |
10985 | 17.6k | { |
10986 | 17.6k | if (logging) |
10987 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
10988 | 0 | " Writing PNG object."); |
10989 | 17.6k | status=WriteOnePNGImage(mng_info,image_info,image); |
10990 | 17.6k | } |
10991 | | |
10992 | 17.6k | if (!status) |
10993 | 0 | { |
10994 | 0 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
10995 | 0 | CloseBlob(image); |
10996 | 0 | return (MagickFail); |
10997 | 0 | } |
10998 | 17.6k | (void) CatchImageException(image); |
10999 | 17.6k | if (image->next == (Image *) NULL) |
11000 | 611 | break; |
11001 | 17.0k | image=SyncNextImageInList(image); |
11002 | 17.0k | if (QuantumTick(scene,GetImageListLength(image))) |
11003 | 10.7k | if (!MagickMonitorFormatted(scene++,GetImageListLength(image), |
11004 | 10.7k | &image->exception,SaveImagesText, |
11005 | 10.7k | image->filename)) |
11006 | 0 | break; |
11007 | 17.0k | } while (mng_info->adjoin); |
11008 | 611 | if (write_mng) |
11009 | 611 | { |
11010 | 611 | unsigned char |
11011 | 611 | chunk[16]; |
11012 | | |
11013 | 17.6k | while (image->previous != (Image *) NULL) |
11014 | 17.0k | image=image->previous; |
11015 | | /* |
11016 | | Write the MEND chunk. |
11017 | | */ |
11018 | 611 | (void) WriteBlobMSBULong(image,0x00000000L); |
11019 | 611 | PNGType(chunk,mng_MEND); |
11020 | 611 | LogPNGChunk(logging,mng_MEND,0L); |
11021 | 611 | (void) WriteBlob(image,4,(char *) chunk); |
11022 | 611 | (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); |
11023 | 611 | } |
11024 | | /* |
11025 | | Free memory. |
11026 | | */ |
11027 | 611 | status &= CloseBlob(image); |
11028 | 611 | MngInfoFreeStruct(mng_info,&have_mng_structure); |
11029 | 611 | if (logging) |
11030 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()"); |
11031 | 611 | return(status); |
11032 | 611 | } |
11033 | | #else /* PNG_LIBPNG_VER > 10011 */ |
11034 | | static unsigned int WritePNGImage(const ImageInfo *image_info,Image *image) |
11035 | | { |
11036 | | image=image; |
11037 | | printf("Your PNG library is too old: You have libpng-%s\n", |
11038 | | PNG_LIBPNG_VER_STRING); |
11039 | | ThrowBinaryException(CoderError,PNGLibraryTooOld,image_info->filename); |
11040 | | } |
11041 | | static unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image) |
11042 | | { |
11043 | | return (WritePNGImage(image_info,image)); |
11044 | | } |
11045 | | #endif /* PNG_LIBPNG_VER > 10011 */ |
11046 | | #endif |