Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/png.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            PPPP   N   N   GGGG                              %
7
%                            P   P  NN  N  G                                  %
8
%                            PPPP   N N N  G  GG                              %
9
%                            P      N  NN  G   G                              %
10
%                            P      N   N   GGG                               %
11
%                                                                             %
12
%                                                                             %
13
%              Read/Write Portable Network Graphics Image Format              %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                           Glenn Randers-Pehrson                             %
18
%                               November 1997                                 %
19
%                                                                             %
20
%                                                                             %
21
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
22
%  dedicated to making software imaging solutions freely available.           %
23
%                                                                             %
24
%  You may not use this file except in compliance with the License.  You may  %
25
%  obtain a copy of the License at                                            %
26
%                                                                             %
27
%    https://imagemagick.org/license/                                         %
28
%                                                                             %
29
%  Unless required by applicable law or agreed to in writing, software        %
30
%  distributed under the License is distributed on an "AS IS" BASIS,          %
31
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32
%  See the License for the specific language governing permissions and        %
33
%  limitations under the License.                                             %
34
%                                                                             %
35
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36
%
37
%
38
*/
39

40
/*
41
  Include declarations.
42
*/
43
#include "MagickCore/studio.h"
44
#include "MagickCore/artifact.h"
45
#include "MagickCore/attribute.h"
46
#include "MagickCore/blob.h"
47
#include "MagickCore/blob-private.h"
48
#include "MagickCore/cache.h"
49
#include "MagickCore/channel.h"
50
#include "MagickCore/color.h"
51
#include "MagickCore/color-private.h"
52
#include "MagickCore/colormap.h"
53
#include "MagickCore/colormap-private.h"
54
#include "MagickCore/colorspace.h"
55
#include "MagickCore/colorspace-private.h"
56
#include "MagickCore/constitute.h"
57
#include "MagickCore/enhance.h"
58
#include "MagickCore/exception.h"
59
#include "MagickCore/exception-private.h"
60
#include "MagickCore/geometry.h"
61
#include "MagickCore/histogram.h"
62
#include "MagickCore/image.h"
63
#include "MagickCore/image-private.h"
64
#include "MagickCore/layer.h"
65
#include "MagickCore/list.h"
66
#include "MagickCore/log.h"
67
#include "MagickCore/magick.h"
68
#include "MagickCore/magick-private.h"
69
#include "MagickCore/memory_.h"
70
#include "MagickCore/memory-private.h"
71
#include "MagickCore/module.h"
72
#include "MagickCore/monitor.h"
73
#include "MagickCore/monitor-private.h"
74
#include "MagickCore/option.h"
75
#include "MagickCore/pixel.h"
76
#include "MagickCore/pixel-accessor.h"
77
#include "MagickCore/profile-private.h"
78
#include "MagickCore/property.h"
79
#include "MagickCore/quantum-private.h"
80
#include "MagickCore/resource_.h"
81
#include "MagickCore/semaphore.h"
82
#include "MagickCore/static.h"
83
#include "MagickCore/statistic.h"
84
#include "MagickCore/string_.h"
85
#include "MagickCore/string-private.h"
86
#include "MagickCore/timer-private.h"
87
#include "MagickCore/transform.h"
88
#include "MagickCore/utility.h"
89
#include "coders/coders-private.h"
90
#if defined(MAGICKCORE_PNG_DELEGATE)
91
92
/* Suppress libpng pedantic warnings that were added in
93
 * libpng-1.2.41 and libpng-1.4.0.  If you are working on
94
 * migration to libpng-1.5, remove these defines and then
95
 * fix any code that generates warnings.
96
 */
97
/* #define PNG_DEPRECATED   Use of this function is deprecated */
98
/* #define PNG_USE_RESULT   The result of this function must be checked */
99
/* #define PNG_NORETURN     This function does not return */
100
/* #define PNG_ALLOCATED    The result of the function is new memory */
101
102
#include <png.h>
103
#include <zlib.h>
104

105
#if defined(MAGICKCORE_JPEG_DELEGATE)
106
#  define JNG_SUPPORTED /* Not finished as of 5.5.2.  See "To do" comments. */
107
#endif
108
#define IsPNGColorEqual(color,target) \
109
46.9k
       (((color).red == (target).red) && \
110
46.9k
        ((color).green == (target).green) && \
111
46.9k
        ((color).blue == (target).blue))
112
113
/* Table of recognized sRGB ICC profiles */
114
struct sRGB_info_struct
115
{
116
    png_uint_32 len;
117
    png_uint_32 crc;
118
    png_byte intent;
119
};
120
121
const struct sRGB_info_struct sRGB_info[] =
122
{
123
    /* ICC v2 perceptual sRGB_IEC61966-2-1_black_scaled.icc */
124
    { 3048, 0x3b8772b9UL, 0},
125
126
    /* ICC v2 relative sRGB_IEC61966-2-1_no_black_scaling.icc */
127
    { 3052, 0x427ebb21UL, 1},
128
129
    /* ICC v4 perceptual sRGB_v4_ICC_preference_displayclass.icc */
130
    {60988, 0x306fd8aeUL, 0},
131
132
    /* ICC v4 perceptual sRGB_v4_ICC_preference.icc perceptual */
133
     {60960, 0xbbef7812UL, 0},
134
135
    /* HP? sRGB v2 media-relative sRGB_IEC61966-2-1_noBPC.icc */
136
     { 3024, 0x5d5129ceUL, 1},
137
138
     /* HP-Microsoft sRGB v2 perceptual */
139
     { 3144, 0x182ea552UL, 0},
140
141
     /* HP-Microsoft sRGB v2 media-relative */
142
     { 3144, 0xf29e526dUL, 1},
143
144
     /* Facebook's "2012/01/25 03:41:57", 524, "TINYsRGB.icc" */
145
     {  524, 0xd4938c39UL, 0},
146
147
     /* "2012/11/28 22:35:21", 3212, "Argyll_sRGB.icm") */
148
     { 3212, 0x034af5a1UL, 0},
149
150
     /* Not recognized */
151
     {    0, 0x00000000UL, 0},
152
};
153
154
/* Macros for left-bit-replication to ensure that pixels
155
 * and PixelInfos all have the same image->depth, and for use
156
 * in PNG8 quantization.
157
 */
158
159
/* LBR01: Replicate top bit */
160
161
#define LBR01PacketRed(pixelpacket) \
162
0
     (pixelpacket).red=(ScaleQuantumToChar((Quantum) (pixelpacket).red) < 0x10 ? \
163
0
        0 : QuantumRange);
164
165
#define LBR01PacketGreen(pixelpacket) \
166
0
     (pixelpacket).green=(ScaleQuantumToChar((Quantum) (pixelpacket).green) < 0x10 ? \
167
0
        0 : QuantumRange);
168
169
#define LBR01PacketBlue(pixelpacket) \
170
0
     (pixelpacket).blue=(ScaleQuantumToChar((Quantum) (pixelpacket).blue) < 0x10 ? \
171
0
        0 : QuantumRange);
172
173
#define LBR01PacketAlpha(pixelpacket) \
174
0
     (pixelpacket).alpha=(ScaleQuantumToChar((Quantum) (pixelpacket).alpha) < 0x10 ? \
175
0
        0 : QuantumRange);
176
177
#define LBR01PacketRGB(pixelpacket) \
178
0
        { \
179
0
        LBR01PacketRed((pixelpacket)); \
180
0
        LBR01PacketGreen((pixelpacket)); \
181
0
        LBR01PacketBlue((pixelpacket)); \
182
0
        }
183
184
#define LBR01PacketRGBA(pixelpacket) \
185
0
        { \
186
0
        LBR01PacketRGB((pixelpacket)); \
187
0
        LBR01PacketAlpha((pixelpacket)); \
188
0
        }
189
190
#define LBR01PixelRed(pixel) \
191
0
        (SetPixelRed(image, \
192
0
        ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
193
0
        0 : QuantumRange,(pixel)));
194
195
#define LBR01PixelGreen(pixel) \
196
0
        (SetPixelGreen(image, \
197
0
        ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
198
0
        0 : QuantumRange,(pixel)));
199
200
#define LBR01PixelBlue(pixel) \
201
0
        (SetPixelBlue(image, \
202
0
        ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
203
0
        0 : QuantumRange,(pixel)));
204
205
#define LBR01PixelAlpha(pixel) \
206
0
        (SetPixelAlpha(image, \
207
0
        ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
208
0
        0 : QuantumRange,(pixel)));
209
210
#define LBR01PixelRGB(pixel) \
211
0
        { \
212
0
        LBR01PixelRed((pixel)); \
213
0
        LBR01PixelGreen((pixel)); \
214
0
        LBR01PixelBlue((pixel)); \
215
0
        }
216
217
#define LBR01PixelRGBA(pixel) \
218
0
        { \
219
0
        LBR01PixelRGB((pixel)); \
220
0
        LBR01PixelAlpha((pixel)); \
221
0
        }
222
223
/* LBR02: Replicate top 2 bits */
224
225
#define LBR02PacketRed(pixelpacket) \
226
0
   { \
227
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).red) & 0xc0; \
228
0
     (pixelpacket).red=ScaleCharToQuantum( \
229
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
230
0
   }
231
#define LBR02PacketGreen(pixelpacket) \
232
0
   { \
233
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).green) & 0xc0; \
234
0
     (pixelpacket).green=ScaleCharToQuantum( \
235
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
236
0
   }
237
#define LBR02PacketBlue(pixelpacket) \
238
0
   { \
239
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).blue) & 0xc0; \
240
0
     (pixelpacket).blue=ScaleCharToQuantum( \
241
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
242
0
   }
243
#define LBR02PacketAlpha(pixelpacket) \
244
0
   { \
245
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).alpha) & 0xc0; \
246
0
     (pixelpacket).alpha=ScaleCharToQuantum( \
247
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
248
0
   }
249
250
#define LBR02PacketRGB(pixelpacket) \
251
0
        { \
252
0
        LBR02PacketRed((pixelpacket)); \
253
0
        LBR02PacketGreen((pixelpacket)); \
254
0
        LBR02PacketBlue((pixelpacket)); \
255
0
        }
256
257
#define LBR02PacketRGBA(pixelpacket) \
258
0
        { \
259
0
        LBR02PacketRGB((pixelpacket)); \
260
0
        LBR02PacketAlpha((pixelpacket)); \
261
0
        }
262
263
#define LBR02PixelRed(pixel) \
264
0
   { \
265
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
266
0
       & 0xc0; \
267
0
     SetPixelRed(image, ScaleCharToQuantum( \
268
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
269
0
       (pixel)); \
270
0
   }
271
#define LBR02PixelGreen(pixel) \
272
0
   { \
273
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
274
0
       & 0xc0; \
275
0
     SetPixelGreen(image, ScaleCharToQuantum( \
276
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
277
0
       (pixel)); \
278
0
   }
279
#define LBR02PixelBlue(pixel) \
280
0
   { \
281
0
     unsigned char lbr_bits= \
282
0
       ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
283
0
     SetPixelBlue(image, ScaleCharToQuantum( \
284
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
285
0
       (pixel)); \
286
0
   }
287
#define LBR02PixelAlpha(pixel) \
288
0
   { \
289
0
     unsigned char lbr_bits= \
290
0
       ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
291
0
     SetPixelAlpha(image, ScaleCharToQuantum( \
292
0
       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
293
0
       (pixel) ); \
294
0
   }
295
296
#define LBR02PixelRGB(pixel) \
297
0
        { \
298
0
        LBR02PixelRed((pixel)); \
299
0
        LBR02PixelGreen((pixel)); \
300
0
        LBR02PixelBlue((pixel)); \
301
0
        }
302
303
#define LBR02PixelRGBA(pixel) \
304
0
        { \
305
0
        LBR02PixelRGB((pixel)); \
306
0
        LBR02PixelAlpha((pixel)); \
307
0
        }
308
309
/* LBR03: Replicate top 3 bits (only used with opaque pixels during
310
   PNG8 quantization) */
311
312
#define LBR03PacketRed(pixelpacket) \
313
0
   { \
314
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).red) & 0xe0; \
315
0
     (pixelpacket).red=ScaleCharToQuantum( \
316
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
317
0
   }
318
#define LBR03PacketGreen(pixelpacket) \
319
0
   { \
320
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).green) & 0xe0; \
321
0
     (pixelpacket).green=ScaleCharToQuantum( \
322
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
323
0
   }
324
#define LBR03PacketBlue(pixelpacket) \
325
0
   { \
326
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).blue) & 0xe0; \
327
0
     (pixelpacket).blue=ScaleCharToQuantum( \
328
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
329
0
   }
330
331
#define LBR03PacketRGB(pixelpacket) \
332
0
        { \
333
0
        LBR03PacketRed((pixelpacket)); \
334
0
        LBR03PacketGreen((pixelpacket)); \
335
0
        LBR03PacketBlue((pixelpacket)); \
336
0
        }
337
338
#define LBR03PixelRed(pixel) \
339
0
   { \
340
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
341
0
       & 0xe0; \
342
0
     SetPixelRed(image, ScaleCharToQuantum( \
343
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
344
0
   }
345
#define LBR03Green(pixel) \
346
0
   { \
347
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
348
0
       & 0xe0; \
349
0
     SetPixelGreen(image, ScaleCharToQuantum( \
350
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
351
0
   }
352
#define LBR03Blue(pixel) \
353
0
   { \
354
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
355
0
       & 0xe0; \
356
0
     SetPixelBlue(image, ScaleCharToQuantum( \
357
0
       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
358
0
   }
359
360
#define LBR03RGB(pixel) \
361
0
        { \
362
0
        LBR03PixelRed((pixel)); \
363
0
        LBR03Green((pixel)); \
364
0
        LBR03Blue((pixel)); \
365
0
        }
366
367
/* LBR04: Replicate top 4 bits */
368
369
#define LBR04PacketRed(pixelpacket) \
370
0
   { \
371
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).red) & 0xf0; \
372
0
     (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
373
0
   }
374
#define LBR04PacketGreen(pixelpacket) \
375
0
   { \
376
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).green) & 0xf0; \
377
0
     (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
378
0
   }
379
#define LBR04PacketBlue(pixelpacket) \
380
0
   { \
381
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).blue) & 0xf0; \
382
0
     (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
383
0
   }
384
#define LBR04PacketAlpha(pixelpacket) \
385
0
   { \
386
0
     unsigned char lbr_bits=ScaleQuantumToChar((Quantum) (pixelpacket).alpha) & 0xf0; \
387
0
     (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
388
0
   }
389
390
#define LBR04PacketRGB(pixelpacket) \
391
0
        { \
392
0
        LBR04PacketRed((pixelpacket)); \
393
0
        LBR04PacketGreen((pixelpacket)); \
394
0
        LBR04PacketBlue((pixelpacket)); \
395
0
        }
396
397
#define LBR04PacketRGBA(pixelpacket) \
398
0
        { \
399
0
        LBR04PacketRGB((pixelpacket)); \
400
0
        LBR04PacketAlpha((pixelpacket)); \
401
0
        }
402
403
#define LBR04PixelRed(pixel) \
404
0
   { \
405
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
406
0
       & 0xf0; \
407
0
     SetPixelRed(image,\
408
0
       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
409
0
   }
410
#define LBR04PixelGreen(pixel) \
411
0
   { \
412
0
     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
413
0
       & 0xf0; \
414
0
     SetPixelGreen(image,\
415
0
       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
416
0
   }
417
#define LBR04PixelBlue(pixel) \
418
0
   { \
419
0
     unsigned char lbr_bits= \
420
0
       ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
421
0
     SetPixelBlue(image,\
422
0
       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
423
0
   }
424
#define LBR04PixelAlpha(pixel) \
425
0
   { \
426
0
     unsigned char lbr_bits= \
427
0
       ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
428
0
     SetPixelAlpha(image,\
429
0
       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
430
0
   }
431
432
#define LBR04PixelRGB(pixel) \
433
0
        { \
434
0
        LBR04PixelRed((pixel)); \
435
0
        LBR04PixelGreen((pixel)); \
436
0
        LBR04PixelBlue((pixel)); \
437
0
        }
438
439
#define LBR04PixelRGBA(pixel) \
440
0
        { \
441
0
        LBR04PixelRGB((pixel)); \
442
0
        LBR04PixelAlpha((pixel)); \
443
0
        }
444
445
/*
446
  Establish thread safety.
447
  setjmp/longjmp is claimed to be safe on these platforms:
448
  setjmp/longjmp is alleged to be unsafe on these platforms:
449
*/
450
#ifdef PNG_SETJMP_SUPPORTED
451
# ifndef MAGICKCORE_SETJMP_IS_THREAD_SAFE
452
#   define IMPNG_SETJMP_NOT_THREAD_SAFE
453
# endif
454
455
# ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
456
static SemaphoreInfo
457
  *ping_semaphore = (SemaphoreInfo *) NULL;
458
# endif
459
#endif
460
461
/*
462
  This temporary until I set up malloc'ed object attributes array.
463
  Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
464
  waste more memory.
465
*/
466
917M
#define MNG_MAX_OBJECTS 256
467
#define MNG_MAX_LOOP_NESTING 256
468
48.6M
#define MNG_MAX_LOOP_OPS 1000000
469
470
/*
471
  Maximum valid size_t in PNG/MNG chunks is (2^31)-1
472
  This macro is only defined in libpng-1.0.3 and later.
473
  Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
474
*/
475
#ifndef PNG_UINT_31_MAX
476
#define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
477
#endif
478
479
/*
480
  Constant strings for known chunk types.  If you need to add a chunk,
481
  add a string holding the name here.   To make the code more
482
  portable, we use ASCII numbers like this, not characters.
483
*/
484
485
static const png_byte mng_MHDR[5]={ 77,  72,  68,  82, (png_byte) '\0'};
486
static const png_byte mng_BACK[5]={ 66,  65,  67,  75, (png_byte) '\0'};
487
static const png_byte mng_BASI[5]={ 66,  65,  83,  73, (png_byte) '\0'};
488
static const png_byte mng_CLIP[5]={ 67,  76,  73,  80, (png_byte) '\0'};
489
static const png_byte mng_CLON[5]={ 67,  76,  79,  78, (png_byte) '\0'};
490
static const png_byte mng_DEFI[5]={ 68,  69,  70,  73, (png_byte) '\0'};
491
static const png_byte mng_DHDR[5]={ 68,  72,  68,  82, (png_byte) '\0'};
492
static const png_byte mng_DISC[5]={ 68,  73,  83,  67, (png_byte) '\0'};
493
static const png_byte mng_ENDL[5]={ 69,  78,  68,  76, (png_byte) '\0'};
494
static const png_byte mng_FRAM[5]={ 70,  82,  65,  77, (png_byte) '\0'};
495
static const png_byte mng_IEND[5]={ 73,  69,  78,  68, (png_byte) '\0'};
496
static const png_byte mng_IHDR[5]={ 73,  72,  68,  82, (png_byte) '\0'};
497
static const png_byte mng_JHDR[5]={ 74,  72,  68,  82, (png_byte) '\0'};
498
static const png_byte mng_LOOP[5]={ 76,  79,  79,  80, (png_byte) '\0'};
499
static const png_byte mng_MAGN[5]={ 77,  65,  71,  78, (png_byte) '\0'};
500
static const png_byte mng_MEND[5]={ 77,  69,  78,  68, (png_byte) '\0'};
501
static const png_byte mng_MOVE[5]={ 77,  79,  86,  69, (png_byte) '\0'};
502
static const png_byte mng_PAST[5]={ 80,  65,  83,  84, (png_byte) '\0'};
503
static const png_byte mng_PLTE[5]={ 80,  76,  84,  69, (png_byte) '\0'};
504
static const png_byte mng_SAVE[5]={ 83,  65,  86,  69, (png_byte) '\0'};
505
static const png_byte mng_SEEK[5]={ 83,  69,  69,  75, (png_byte) '\0'};
506
static const png_byte mng_SHOW[5]={ 83,  72,  79,  87, (png_byte) '\0'};
507
static const png_byte mng_TERM[5]={ 84,  69,  82,  77, (png_byte) '\0'};
508
static const png_byte mng_bKGD[5]={ 98,  75,  71,  68, (png_byte) '\0'};
509
static const png_byte mng_caNv[5]={ 99,  97,  78, 118, (png_byte) '\0'};
510
static const png_byte mng_cHRM[5]={ 99,  72,  82,  77, (png_byte) '\0'};
511
static const png_byte mng_eXIf[5]={101,  88,  73, 102, (png_byte) '\0'};
512
static const png_byte mng_gAMA[5]={103,  65,  77,  65, (png_byte) '\0'};
513
static const png_byte mng_iCCP[5]={105,  67,  67,  80, (png_byte) '\0'};
514
static const png_byte mng_nEED[5]={110,  69,  69,  68, (png_byte) '\0'};
515
static const png_byte mng_orNT[5]={111, 114,  78,  84, (png_byte) '\0'};
516
static const png_byte mng_pHYg[5]={112,  72,  89, 103, (png_byte) '\0'};
517
static const png_byte mng_pHYs[5]={112,  72,  89, 115, (png_byte) '\0'};
518
static const png_byte mng_sBIT[5]={115,  66,  73,  84, (png_byte) '\0'};
519
static const png_byte mng_sRGB[5]={115,  82,  71,  66, (png_byte) '\0'};
520
static const png_byte mng_tRNS[5]={116,  82,  78,  83, (png_byte) '\0'};
521
static const png_byte mng_vpAg[5]={118, 112,  65, 103, (png_byte) '\0'};
522
523
#if defined(JNG_SUPPORTED)
524
static const png_byte mng_IDAT[5]={ 73,  68,  65,  84, (png_byte) '\0'};
525
static const png_byte mng_JDAT[5]={ 74,  68,  65,  84, (png_byte) '\0'};
526
static const png_byte mng_JDAA[5]={ 74,  68,  65,  65, (png_byte) '\0'};
527
static const png_byte mng_JdAA[5]={ 74, 100,  65,  65, (png_byte) '\0'};
528
static const png_byte mng_JSEP[5]={ 74,  83,  69,  80, (png_byte) '\0'};
529
static const png_byte mng_oFFs[5]={111,  70,  70, 115, (png_byte) '\0'};
530
#endif
531
532
#if 0
533
/* Other known chunks that are not yet supported by ImageMagick: */
534
static const png_byte mng_hIST[5]={104,  73,  83,  84, (png_byte) '\0'};
535
static const png_byte mng_iTXt[5]={105,  84,  88, 116, (png_byte) '\0'};
536
static const png_byte mng_sPLT[5]={115,  80,  76,  84, (png_byte) '\0'};
537
static const png_byte mng_sTER[5]={115,  84,  69,  82, (png_byte) '\0'};
538
static const png_byte mng_tEXt[5]={116,  69,  88, 116, (png_byte) '\0'};
539
static const png_byte mng_tIME[5]={116,  73,  77,  69, (png_byte) '\0'};
540
static const png_byte mng_zTXt[5]={122,  84,  88, 116, (png_byte) '\0'};
541
#endif
542
543
typedef struct _MngBox
544
{
545
  long
546
    left,
547
    right,
548
    top,
549
    bottom;
550
} MngBox;
551
552
typedef struct _MngPair
553
{
554
  volatile long
555
    a,
556
    b;
557
} MngPair;
558
559
typedef struct _MngReadInfo
560
{
561
  ChromaticityInfo
562
    global_chrm;
563
564
  float
565
    global_gamma;
566
567
  Image
568
    *image;
569
570
  int
571
    framing_mode,
572
    object_id;
573
574
  MagickBooleanType
575
    have_global_bkgd,
576
    have_global_chrm,
577
    have_global_gama,
578
    have_global_phys,
579
    have_global_sbit,
580
    have_global_srgb;
581
582
  MagickOffsetType
583
    loop_jump[MNG_MAX_LOOP_NESTING];
584
585
  MngBox
586
    clip,
587
    frame,
588
    image_box,
589
    object_clip[MNG_MAX_OBJECTS];
590
591
  PixelInfo
592
    mng_global_bkgd;
593
594
  png_byte
595
    global_trns[256];
596
597
  png_color_8
598
    global_sbit;
599
600
  png_colorp
601
    global_plte;
602
603
  png_uint_16
604
    magn_mb,
605
    magn_ml,
606
    magn_mr,
607
    magn_mt,
608
    magn_mx,
609
    magn_my,
610
    magn_methx,
611
    magn_methy;
612
613
  RenderingIntent
614
    global_srgb_intent;
615
616
  ssize_t
617
    image_found,
618
    loop_count[MNG_MAX_LOOP_NESTING],
619
    loop_iteration[MNG_MAX_LOOP_NESTING],
620
    scenes_found,
621
    x_off[MNG_MAX_OBJECTS],
622
    y_off[MNG_MAX_OBJECTS];
623
624
  unsigned char
625
    /* These flags could be combined into one byte */
626
    exists[MNG_MAX_OBJECTS],
627
    frozen[MNG_MAX_OBJECTS],
628
    loop_active[MNG_MAX_LOOP_NESTING],
629
    invisible[MNG_MAX_OBJECTS],
630
    viewable[MNG_MAX_OBJECTS];
631
632
  unsigned long
633
    global_plte_length,
634
    global_trns_length,
635
    global_x_pixels_per_unit,
636
    global_y_pixels_per_unit,
637
    mng_width,
638
    mng_height,
639
    ticks_per_second;
640
641
  unsigned int
642
    basi_warning,
643
    clon_warning,
644
    dhdr_warning,
645
    global_phys_unit_type,
646
    jhdr_warning,
647
    magn_warning,
648
    mng_type,
649
    past_warning,
650
    phyg_warning,
651
    phys_warning,
652
    sbit_warning,
653
    show_warning;
654
} MngReadInfo;
655
656
typedef struct _MngWriteInfo
657
{
658
  Image *
659
    image;
660
661
  RectangleInfo
662
    page;
663
664
  int
665
    framing_mode,
666
    old_framing_mode;
667
668
  unsigned long
669
    delay,
670
    ticks_per_second;
671
672
  MagickBooleanType
673
    adjoin,
674
    need_blob,
675
    equal_backgrounds,
676
    equal_chrms,
677
    equal_gammas,
678
    equal_palettes,
679
    equal_physs,
680
    equal_srgbs,
681
    exclude_bKGD,
682
    exclude_cHRM,
683
    exclude_date,
684
    exclude_eXIf,
685
    exclude_EXIF,
686
    exclude_gAMA,
687
    exclude_iCCP,
688
    exclude_oFFs,
689
    exclude_pHYs,
690
    exclude_sRGB,
691
    exclude_tEXt,
692
    exclude_tIME,
693
    exclude_tRNS,
694
    exclude_caNv,
695
    exclude_zCCP,
696
    exclude_zTXt,
697
    have_global_chrm,
698
    have_global_gama,
699
    have_global_plte,
700
    have_global_srgb,
701
    is_palette,
702
    need_defi,
703
    need_fram,
704
    preserve_colormap,
705
    preserve_iCCP,
706
    write_mng,
707
    write_png8,
708
    write_png24,
709
    write_png32,
710
    write_png48,
711
    write_png64;
712
713
  unsigned int
714
    colortype,
715
    compression_filter,
716
    compression_level,
717
    compression_strategy,
718
    depth;
719
720
} MngWriteInfo;
721

722
/*
723
  Forward declarations.
724
*/
725
static MagickBooleanType
726
  WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
727
728
static MagickBooleanType
729
  WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
730
731
#if defined(JNG_SUPPORTED)
732
static MagickBooleanType
733
  WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
734
#endif
735
736
#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
737
static MagickBooleanType
738
LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
739
395
{
740
    /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
741
     *
742
     * This is true if the high byte and the next highest byte of
743
     * each sample of the image, the colormap, and the background color
744
     * are equal to each other.  We check this by seeing if the samples
745
     * are unchanged when we scale them down to 8 and back up to Quantum.
746
     *
747
     * We don't use the method GetImageDepth() because it doesn't check
748
     * background and doesn't handle PseudoClass specially.
749
     */
750
751
395
#define QuantumToCharToQuantumEqQuantum(quantum) \
752
674M
 (((double) ScaleCharToQuantum((unsigned char) ScaleQuantumToChar((Quantum) quantum))) == (double) quantum)
753
754
395
    MagickBooleanType
755
395
      ok_to_reduce=MagickFalse;
756
757
395
    if (image->depth >= 16)
758
395
      {
759
760
395
        const Quantum
761
395
          *p;
762
763
395
        ok_to_reduce=
764
395
           QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
765
303
           QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
766
280
           QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
767
270
           MagickTrue : MagickFalse;
768
769
395
        if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass && image->colormap != NULL)
770
0
          {
771
0
            int indx;
772
773
0
            for (indx=0; indx < (ssize_t) image->colors; indx++)
774
0
              {
775
0
                ok_to_reduce=(
776
0
                   QuantumToCharToQuantumEqQuantum(
777
0
                   image->colormap[indx].red) &&
778
0
                   QuantumToCharToQuantumEqQuantum(
779
0
                   image->colormap[indx].green) &&
780
0
                   QuantumToCharToQuantumEqQuantum(
781
0
                   image->colormap[indx].blue)) ?
782
0
                   MagickTrue : MagickFalse;
783
784
0
                if (ok_to_reduce == MagickFalse)
785
0
                   break;
786
0
              }
787
0
          }
788
789
395
        if ((ok_to_reduce != MagickFalse) &&
790
270
            (image->storage_class != PseudoClass))
791
270
          {
792
270
            ssize_t
793
270
              y;
794
795
270
            ssize_t
796
270
              x;
797
798
116k
            for (y=0; y < (ssize_t) image->rows; y++)
799
116k
            {
800
116k
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
801
802
116k
              if (p == (const Quantum *) NULL)
803
0
                {
804
0
                  ok_to_reduce = MagickFalse;
805
0
                  break;
806
0
                }
807
808
135M
              for (x=(ssize_t) image->columns-1; x >= 0; x--)
809
134M
              {
810
134M
                ok_to_reduce=
811
134M
                   QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
812
134M
                   QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
813
134M
                   QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
814
134M
                   MagickTrue : MagickFalse;
815
816
134M
                if (ok_to_reduce == MagickFalse)
817
78
                  break;
818
819
134M
                p+=(ptrdiff_t) GetPixelChannels(image);
820
134M
              }
821
116k
              if (x >= 0)
822
78
                break;
823
116k
            }
824
270
          }
825
826
395
        if ((image->debug != MagickFalse) && (ok_to_reduce != MagickFalse))
827
0
          {
828
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
829
0
                "    OK to reduce PNG bit depth to 8 without loss of info");
830
0
          }
831
395
        else
832
395
          {
833
395
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
834
395
                "    Not OK to reduce PNG bit depth to 8 without losing info");
835
395
          }
836
395
      }
837
838
395
    return ok_to_reduce;
839
395
}
840
#endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
841
842
static const char *PngColorTypeToString(const unsigned int color_type)
843
0
{
844
0
  const char
845
0
    *result = "Unknown";
846
847
0
  switch (color_type)
848
0
    {
849
0
    case PNG_COLOR_TYPE_GRAY:
850
0
      result = "Gray";
851
0
      break;
852
0
    case PNG_COLOR_TYPE_GRAY_ALPHA:
853
0
      result = "Gray+Alpha";
854
0
      break;
855
0
    case PNG_COLOR_TYPE_PALETTE:
856
0
      result = "Palette";
857
0
      break;
858
0
    case PNG_COLOR_TYPE_RGB:
859
0
      result = "RGB";
860
0
      break;
861
0
    case PNG_COLOR_TYPE_RGB_ALPHA:
862
0
      result = "RGB+Alpha";
863
0
      break;
864
0
    }
865
866
0
  return result;
867
0
}
868
869
static int
870
Magick_Orientation_to_Exif_Orientation(const OrientationType orientation)
871
4
{
872
4
  switch (orientation)
873
4
  {
874
    /* Convert to Exif orientations as defined in "Exchangeable image file
875
     * format for digital still cameras: Exif Version 2.31",
876
     * http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf
877
     */
878
879
0
    case TopLeftOrientation:
880
0
       return 1;
881
0
    case TopRightOrientation:
882
0
       return 2;
883
0
    case BottomRightOrientation:
884
0
       return 3;
885
0
    case BottomLeftOrientation:
886
0
       return 4;
887
0
    case LeftTopOrientation:
888
0
       return 5;
889
0
    case RightTopOrientation:
890
0
       return 6;
891
0
    case RightBottomOrientation:
892
0
       return 7;
893
0
    case LeftBottomOrientation:
894
0
       return 8;
895
0
    case UndefinedOrientation:
896
4
    default:
897
4
       return 0;
898
4
  }
899
4
}
900
static OrientationType
901
Magick_Orientation_from_Exif_Orientation(const int orientation)
902
12.9k
{
903
12.9k
  switch (orientation)
904
12.9k
  {
905
3.21k
    case 1:
906
3.21k
      return TopLeftOrientation;
907
135
    case 2:
908
135
      return TopRightOrientation;
909
213
    case 3:
910
213
      return BottomRightOrientation;
911
126
    case 4:
912
126
      return BottomLeftOrientation;
913
189
    case 5:
914
189
      return LeftTopOrientation;
915
125
    case 6:
916
125
      return RightTopOrientation;
917
137
    case 7:
918
137
      return RightBottomOrientation;
919
1.44k
    case 8:
920
1.44k
      return LeftBottomOrientation;
921
162
    case 0:
922
7.35k
    default:
923
7.35k
      return UndefinedOrientation;
924
12.9k
  }
925
12.9k
}
926
927
static int
928
Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
929
119k
{
930
119k
  switch (intent)
931
119k
  {
932
87.0k
    case PerceptualIntent:
933
87.0k
       return 0;
934
935
0
    case RelativeIntent:
936
0
       return 1;
937
938
0
    case SaturationIntent:
939
0
       return 2;
940
941
0
    case AbsoluteIntent:
942
0
       return 3;
943
944
32.1k
    default:
945
32.1k
       return -1;
946
119k
  }
947
119k
}
948
949
static RenderingIntent
950
Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
951
223k
{
952
223k
  switch (ping_intent)
953
223k
  {
954
396
    case 0:
955
396
      return PerceptualIntent;
956
957
148
    case 1:
958
148
      return RelativeIntent;
959
960
183k
    case 2:
961
183k
      return SaturationIntent;
962
963
39.0k
    case 3:
964
39.0k
      return AbsoluteIntent;
965
966
786
    default:
967
786
      return UndefinedIntent;
968
223k
    }
969
223k
}
970
971
static const char *
972
Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
973
165
{
974
165
  switch (ping_intent)
975
165
  {
976
155
    case 0:
977
155
      return "Perceptual Intent";
978
979
5
    case 1:
980
5
      return "Relative Intent";
981
982
0
    case 2:
983
0
      return "Saturation Intent";
984
985
5
    case 3:
986
5
      return "Absolute Intent";
987
988
0
    default:
989
0
      return "Undefined Intent";
990
165
    }
991
165
}
992
993
static const char *
994
Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
995
43.7k
{
996
43.7k
  switch (ping_colortype)
997
43.7k
  {
998
31.0k
    case 0:
999
31.0k
      return "Grayscale";
1000
1001
4.69k
    case 2:
1002
4.69k
      return "Truecolor";
1003
1004
1.57k
    case 3:
1005
1.57k
      return "Indexed";
1006
1007
1.14k
    case 4:
1008
1.14k
      return "GrayAlpha";
1009
1010
5.29k
    case 6:
1011
5.29k
      return "RGBA";
1012
1013
0
    default:
1014
0
      return "UndefinedColorType";
1015
43.7k
    }
1016
43.7k
}
1017
1018
#endif /* MAGICKCORE_PNG_DELEGATE */
1019

1020
/*
1021
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022
%                                                                             %
1023
%                                                                             %
1024
%                                                                             %
1025
%   I s M N G                                                                 %
1026
%                                                                             %
1027
%                                                                             %
1028
%                                                                             %
1029
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030
%
1031
%  IsMNG() returns MagickTrue if the image format type, identified by the
1032
%  magick string, is MNG.
1033
%
1034
%  The format of the IsMNG method is:
1035
%
1036
%      MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1037
%
1038
%  A description of each parameter follows:
1039
%
1040
%    o magick: compare image format pattern against these bytes.
1041
%
1042
%    o length: Specifies the length of the magick string.
1043
%
1044
%
1045
*/
1046
static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1047
0
{
1048
0
  if (length < 8)
1049
0
    return(MagickFalse);
1050
1051
0
  if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1052
0
    return(MagickTrue);
1053
1054
0
  return(MagickFalse);
1055
0
}
1056

1057
/*
1058
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1059
%                                                                             %
1060
%                                                                             %
1061
%                                                                             %
1062
%   I s J N G                                                                 %
1063
%                                                                             %
1064
%                                                                             %
1065
%                                                                             %
1066
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067
%
1068
%  IsJNG() returns MagickTrue if the image format type, identified by the
1069
%  magick string, is JNG.
1070
%
1071
%  The format of the IsJNG method is:
1072
%
1073
%      MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1074
%
1075
%  A description of each parameter follows:
1076
%
1077
%    o magick: compare image format pattern against these bytes.
1078
%
1079
%    o length: Specifies the length of the magick string.
1080
%
1081
%
1082
*/
1083
static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1084
0
{
1085
0
  if (length < 8)
1086
0
    return(MagickFalse);
1087
1088
0
  if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1089
0
    return(MagickTrue);
1090
1091
0
  return(MagickFalse);
1092
0
}
1093

1094
/*
1095
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096
%                                                                             %
1097
%                                                                             %
1098
%                                                                             %
1099
%   I s P N G                                                                 %
1100
%                                                                             %
1101
%                                                                             %
1102
%                                                                             %
1103
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104
%
1105
%  IsPNG() returns MagickTrue if the image format type, identified by the
1106
%  magick string, is PNG.
1107
%
1108
%  The format of the IsPNG method is:
1109
%
1110
%      MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1111
%
1112
%  A description of each parameter follows:
1113
%
1114
%    o magick: compare image format pattern against these bytes.
1115
%
1116
%    o length: Specifies the length of the magick string.
1117
%
1118
*/
1119
static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1120
0
{
1121
0
  if (length < 8)
1122
0
    return(MagickFalse);
1123
1124
0
  if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1125
0
    return(MagickTrue);
1126
1127
0
  return(MagickFalse);
1128
0
}
1129

1130
#if defined(MAGICKCORE_PNG_DELEGATE)
1131
#if defined(__cplusplus) || defined(c_plusplus)
1132
extern "C" {
1133
#endif
1134
1135
static size_t WriteBlobMSBULong(Image *image,const size_t value)
1136
16.9k
{
1137
16.9k
  unsigned char
1138
16.9k
    buffer[4];
1139
1140
16.9k
  assert(image != (Image *) NULL);
1141
16.9k
  assert(image->signature == MagickCoreSignature);
1142
16.9k
  buffer[0]=(unsigned char) (value >> 24);
1143
16.9k
  buffer[1]=(unsigned char) (value >> 16);
1144
16.9k
  buffer[2]=(unsigned char) (value >> 8);
1145
16.9k
  buffer[3]=(unsigned char) value;
1146
16.9k
  return((size_t) WriteBlob(image,4,buffer));
1147
16.9k
}
1148
1149
static void PNGLong(png_bytep p,png_uint_32 value)
1150
6.78k
{
1151
6.78k
  *p++=(png_byte) ((value >> 24) & 0xff);
1152
6.78k
  *p++=(png_byte) ((value >> 16) & 0xff);
1153
6.78k
  *p++=(png_byte) ((value >> 8) & 0xff);
1154
6.78k
  *p++=(png_byte) (value & 0xff);
1155
6.78k
}
1156
1157
static void PNGsLong(png_bytep p,png_int_32 value)
1158
76
{
1159
76
  *p++=(png_byte) ((value >> 24) & 0xff);
1160
76
  *p++=(png_byte) ((value >> 16) & 0xff);
1161
76
  *p++=(png_byte) ((value >> 8) & 0xff);
1162
76
  *p++=(png_byte) (value & 0xff);
1163
76
}
1164
1165
static void PNGShort(png_bytep p,png_uint_16 value)
1166
0
{
1167
0
  *p++=(png_byte) ((value >> 8) & 0xff);
1168
0
  *p++=(png_byte) (value & 0xff);
1169
0
}
1170
1171
static void PNGType(png_bytep p,const png_byte *type)
1172
8.48k
{
1173
8.48k
  (void) memcpy(p,type,4*sizeof(png_byte));
1174
8.48k
}
1175
1176
static void LogPNGChunk(MagickBooleanType logging, const png_byte *type,
1177
   size_t length)
1178
8.48k
{
1179
8.48k
  if (logging != MagickFalse)
1180
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1181
0
      "  Writing %c%c%c%c chunk, length: %.17g",
1182
0
      type[0],type[1],type[2],type[3],(double) length);
1183
8.48k
}
1184
1185
#if defined(__cplusplus) || defined(c_plusplus)
1186
}
1187
#endif
1188
1189
/*
1190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191
%                                                                             %
1192
%                                                                             %
1193
%                                                                             %
1194
%   R e a d P N G I m a g e                                                   %
1195
%                                                                             %
1196
%                                                                             %
1197
%                                                                             %
1198
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199
%
1200
%  ReadPNGImage() reads a Portable Network Graphics (PNG) or
1201
%  Multiple-image Network Graphics (MNG) image file and returns it.  It
1202
%  allocates the memory necessary for the new Image structure and returns a
1203
%  pointer to the new image or set of images.
1204
%
1205
%  MNG support written by Glenn Randers-Pehrson, glennrp@image...
1206
%
1207
%  The format of the ReadPNGImage method is:
1208
%
1209
%     Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1210
%
1211
%  A description of each parameter follows:
1212
%
1213
%    o image_info: the image info.
1214
%
1215
%    o exception: return any errors or warnings in this structure.
1216
%
1217
%  To do, more or less in chronological order (as of version 5.5.2,
1218
%   November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1219
%
1220
%    Get 16-bit cheap transparency working.
1221
%
1222
%    (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1223
%
1224
%    Preserve all unknown and not-yet-handled known chunks found in input
1225
%    PNG file and copy them into output PNG files according to the PNG
1226
%    copying rules.
1227
%
1228
%    (At this point, PNG encoding should be in full MNG compliance)
1229
%
1230
%    Provide options for choice of background to use when the MNG BACK
1231
%    chunk is not present or is not mandatory (i.e., leave transparent,
1232
%    user specified, MNG BACK, PNG bKGD)
1233
%
1234
%    Implement LOOP/ENDL [done, but could do discretionary loops more
1235
%    efficiently by linking in the duplicate frames.].
1236
%
1237
%    Decode and act on the MHDR simplicity profile (offer option to reject
1238
%    files or attempt to process them anyway when the profile isn't LC or VLC).
1239
%
1240
%    Upgrade to full MNG without Delta-PNG.
1241
%
1242
%        o  BACK [done a while ago except for background image ID]
1243
%        o  MOVE [done 15 May 1999]
1244
%        o  CLIP [done 15 May 1999]
1245
%        o  DISC [done 19 May 1999]
1246
%        o  SAVE [partially done 19 May 1999 (marks objects frozen)]
1247
%        o  SEEK [partially done 19 May 1999 (discard function only)]
1248
%        o  SHOW
1249
%        o  PAST
1250
%        o  BASI
1251
%        o  MNG-level tEXt/iTXt/zTXt
1252
%        o  pHYg
1253
%        o  pHYs
1254
%        o  sBIT
1255
%        o  bKGD
1256
%        o  iTXt (wait for libpng implementation).
1257
%
1258
%    Use the scene signature to discover when an identical scene is
1259
%    being reused, and just point to the original image->exception instead
1260
%    of storing another set of pixels.  This not specific to MNG
1261
%    but could be applied generally.
1262
%
1263
%    Upgrade to full MNG with Delta-PNG.
1264
%
1265
%    JNG tEXt/iTXt/zTXt
1266
%
1267
%    We will not attempt to read files containing the CgBI chunk.
1268
%    They are really Xcode files meant for display on the iPhone.
1269
%    These are not valid PNG files and it is impossible to recover
1270
%    the original PNG from files that have been converted to Xcode-PNG,
1271
%    since irretrievable loss of color data has occurred due to the
1272
%    use of premultiplied alpha.
1273
*/
1274
1275
#if defined(__cplusplus) || defined(c_plusplus)
1276
extern "C" {
1277
#endif
1278
1279
typedef struct _PNGErrorInfo
1280
{
1281
  Image
1282
    *image;
1283
1284
  ExceptionInfo
1285
    *exception;
1286
} PNGErrorInfo;
1287
1288
static void MagickPNGError(png_struct *ping,const ExceptionType severity,
1289
  png_const_charp message)
1290
55.3k
{
1291
55.3k
  ExceptionInfo
1292
55.3k
    *exception;
1293
1294
55.3k
  Image
1295
55.3k
    *image;
1296
1297
55.3k
  PNGErrorInfo
1298
55.3k
    *error_info;
1299
1300
55.3k
  error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1301
55.3k
  image=error_info->image;
1302
55.3k
  exception=error_info->exception;
1303
1304
55.3k
  if (image->debug != MagickFalse)
1305
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1306
0
      "  libpng-%s error: %s", png_get_libpng_ver(NULL),message);
1307
1308
55.3k
  (void) ThrowMagickException(exception,GetMagickModule(),severity,message,
1309
55.3k
    "`%s'",image->filename);
1310
1311
#if (PNG_LIBPNG_VER < 10500)
1312
  /* A warning about deprecated use of jmpbuf here is unavoidable if you
1313
   * are building with libpng-1.4.x and can be ignored.
1314
   */
1315
  longjmp(ping->jmpbuf,1);
1316
#else
1317
55.3k
  png_longjmp(ping,1);
1318
55.3k
#endif
1319
55.3k
}
1320
1321
/*
1322
  This the function that does the actual reading of data.  It is
1323
  the same as the one supplied in libpng, except that it receives the
1324
  datastream from the ReadBlob() function instead of standard input.
1325
*/
1326
static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1327
2.34M
{
1328
2.34M
  Image
1329
2.34M
    *image;
1330
1331
2.34M
  image=(Image *) png_get_io_ptr(png_ptr);
1332
2.34M
  if (length != 0)
1333
2.34M
    {
1334
2.34M
      png_size_t
1335
2.34M
        check;
1336
1337
2.34M
      check=(png_size_t) ReadBlob(image,(size_t) length,data);
1338
2.34M
      if (check != length)
1339
40.7k
        {
1340
40.7k
          char
1341
40.7k
            msg[MagickPathExtent];
1342
1343
40.7k
          if (check < length)
1344
40.7k
            (void) memset(data+check,0,length-check);
1345
40.7k
          (void) FormatLocaleString(msg,MagickPathExtent,
1346
40.7k
            "Expected %.17g bytes; found %.17g bytes",(double) length,
1347
40.7k
            (double) check);
1348
40.7k
          png_warning(png_ptr,msg);
1349
40.7k
          MagickPNGError(png_ptr,CorruptImageError,"UnexpectedEndOfFile");
1350
40.7k
        }
1351
2.34M
    }
1352
2.34M
}
1353
1354
static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1355
89.6k
{
1356
89.6k
  Image
1357
89.6k
    *image;
1358
1359
89.6k
  image=(Image *) png_get_io_ptr(png_ptr);
1360
89.6k
  if (length != 0)
1361
89.3k
    {
1362
89.3k
      png_size_t
1363
89.3k
        check;
1364
1365
89.3k
      check=(png_size_t) WriteBlob(image,(size_t) length,data);
1366
1367
89.3k
      if (check != length)
1368
0
        MagickPNGError(png_ptr,BlobError,"UnableToWriteBlob");
1369
89.3k
    }
1370
89.6k
}
1371
1372
static void png_flush_data(png_structp png_ptr)
1373
0
{
1374
0
  (void) png_ptr;
1375
0
}
1376
1377
static MagickBooleanType PalettesAreEqual(Image *a,Image *b)
1378
0
{
1379
0
  ssize_t
1380
0
    i;
1381
1382
0
  if ((a == (Image *) NULL) || (b == (Image *) NULL))
1383
0
    return(MagickFalse);
1384
1385
0
  if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1386
0
    return(MagickFalse);
1387
1388
0
  if (a->colors != b->colors)
1389
0
    return(MagickFalse);
1390
1391
0
  for (i=0; i < (ssize_t) a->colors; i++)
1392
0
  {
1393
0
    if ((a->colormap[i].red != b->colormap[i].red) ||
1394
0
        (a->colormap[i].green != b->colormap[i].green) ||
1395
0
        (a->colormap[i].blue != b->colormap[i].blue))
1396
0
      return(MagickFalse);
1397
0
  }
1398
1399
0
  return(MagickTrue);
1400
0
}
1401
1402
static void MngReadInfoDiscardObject(MngReadInfo *mng_info,int i)
1403
242M
{
1404
242M
  if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngReadInfo *) NULL) &&
1405
241M
      mng_info->exists[i] && !mng_info->frozen[i])
1406
19.4k
    {
1407
19.4k
      mng_info->exists[i]=MagickFalse;
1408
19.4k
      mng_info->invisible[i]=MagickFalse;
1409
19.4k
      mng_info->viewable[i]=MagickFalse;
1410
19.4k
      mng_info->frozen[i]=MagickFalse;
1411
19.4k
      mng_info->x_off[i]=0;
1412
19.4k
      mng_info->y_off[i]=0;
1413
19.4k
      mng_info->object_clip[i].left=0;
1414
19.4k
      mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1415
19.4k
      mng_info->object_clip[i].top=0;
1416
19.4k
      mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1417
19.4k
    }
1418
242M
}
1419
1420
static MngReadInfo *MngReadInfoFreeStruct(MngReadInfo *mng_info)
1421
89.1k
{
1422
89.1k
  int
1423
89.1k
    i;
1424
1425
89.1k
  if (mng_info == (MngReadInfo *) NULL)
1426
0
    return((MngReadInfo *) NULL);
1427
1428
22.8M
  for (i=1; i < MNG_MAX_OBJECTS; i++)
1429
22.7M
    MngReadInfoDiscardObject(mng_info,i);
1430
1431
89.1k
  mng_info->global_plte=(png_colorp)
1432
89.1k
    RelinquishMagickMemory(mng_info->global_plte);
1433
1434
89.1k
  return((MngReadInfo *) RelinquishMagickMemory(mng_info));
1435
89.1k
}
1436
1437
static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1438
11.3M
{
1439
11.3M
  MngBox
1440
11.3M
    box;
1441
1442
11.3M
  box=box1;
1443
11.3M
  if (box.left < box2.left)
1444
124
    box.left=box2.left;
1445
1446
11.3M
  if (box.top < box2.top)
1447
218
    box.top=box2.top;
1448
1449
11.3M
  if (box.right > box2.right)
1450
5.01M
    box.right=box2.right;
1451
1452
11.3M
  if (box.bottom > box2.bottom)
1453
4.01M
    box.bottom=box2.bottom;
1454
1455
11.3M
  return box;
1456
11.3M
}
1457
1458
static long mng_get_long(unsigned char *p)
1459
37.9M
{
1460
37.9M
  return ((long) (((png_uint_32) p[0] << 24) | ((png_uint_32) p[1] << 16) |
1461
37.9M
    ((png_uint_32) p[2] << 8) | (png_uint_32) p[3]));
1462
37.9M
}
1463
1464
static MngBox mng_read_box(MngBox previous_box,char delta_type,
1465
  unsigned char *p)
1466
6.01M
{
1467
6.01M
   MngBox
1468
6.01M
      box;
1469
1470
  /*
1471
    Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1472
  */
1473
6.01M
  box.left=mng_get_long(p);
1474
6.01M
  box.right=mng_get_long(&p[4]);
1475
6.01M
  box.top=mng_get_long(&p[8]);
1476
6.01M
  box.bottom=mng_get_long(&p[12]);
1477
6.01M
  if (delta_type != 0)
1478
5.00M
    {
1479
5.00M
      box.left+=previous_box.left;
1480
5.00M
      box.right+=previous_box.right;
1481
5.00M
      box.top+=previous_box.top;
1482
5.00M
      box.bottom+=previous_box.bottom;
1483
5.00M
    }
1484
1485
6.01M
  return(box);
1486
6.01M
}
1487
1488
static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1489
  unsigned char *p)
1490
669k
{
1491
669k
  MngPair
1492
669k
    pair;
1493
1494
  /*
1495
    Read two ssize_t's from CLON, MOVE or PAST chunk
1496
  */
1497
669k
  pair.a=mng_get_long(p);
1498
669k
  pair.b=mng_get_long(&p[4]);
1499
669k
  if (delta_type != 0)
1500
668k
    {
1501
668k
      pair.a+=previous_pair.a;
1502
668k
      pair.b+=previous_pair.b;
1503
668k
    }
1504
1505
669k
  return(pair);
1506
669k
}
1507
1508
static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1509
14.6k
{
1510
14.6k
  MagickPNGError(ping,CoderError,message);
1511
14.6k
}
1512
1513
static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1514
1.15M
{
1515
1.15M
  ExceptionInfo
1516
1.15M
    *exception;
1517
1518
1.15M
  Image
1519
1.15M
    *image;
1520
1521
1.15M
  PNGErrorInfo
1522
1.15M
    *error_info;
1523
1524
1.15M
  if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1525
0
    png_error(ping, message);
1526
1527
1.15M
  error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1528
1.15M
  image=error_info->image;
1529
1.15M
  exception=error_info->exception;
1530
1.15M
  if (image->debug != MagickFalse)
1531
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1532
0
      "  libpng-%s warning: %s", png_get_libpng_ver(NULL),message);
1533
1534
1.15M
  (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1535
1.15M
    message,"`%s'",image->filename);
1536
1.15M
}
1537
1538
#ifdef PNG_USER_MEM_SUPPORTED
1539
#if PNG_LIBPNG_VER >= 10400
1540
static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1541
#else
1542
static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1543
#endif
1544
1.30M
{
1545
1.30M
  (void) png_ptr;
1546
1.30M
  return((png_voidp) AcquireQuantumMemory(1,(size_t) size));
1547
1.30M
}
1548
1549
/*
1550
  Free a pointer.  It is removed from the list at the same time.
1551
*/
1552
static void Magick_png_free(png_structp png_ptr,png_voidp ptr)
1553
1.30M
{
1554
1.30M
  (void) png_ptr;
1555
1.30M
  ptr=RelinquishMagickMemory(ptr);
1556
1.30M
}
1557
#endif
1558
1559
#if defined(__cplusplus) || defined(c_plusplus)
1560
}
1561
#endif
1562
1563
static int
1564
Magick_png_read_raw_profile(png_struct *ping,Image *image,
1565
   const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1566
5
{
1567
5
  png_charp
1568
5
    ep;
1569
1570
5
  ssize_t
1571
5
    i;
1572
1573
5
  unsigned char
1574
5
    *dp;
1575
1576
5
  png_charp
1577
5
    sp;
1578
1579
5
  size_t
1580
5
    extent,
1581
5
    nibbles;
1582
1583
5
  ssize_t
1584
5
    length=0;
1585
1586
5
  StringInfo
1587
5
    *profile;
1588
1589
5
  static const unsigned char
1590
5
    unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1591
5
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1592
5
                 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1593
5
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1594
5
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1595
5
                 13,14,15};
1596
1597
5
  sp=text[ii].text+1;
1598
5
  extent=text[ii].text_length;
1599
5
  ep=text[ii].text+extent;
1600
5
  if (ep <= sp)
1601
0
    {
1602
0
      png_warning(ping,"invalid profile length");
1603
0
      return(MagickFalse);
1604
0
    }
1605
  /* look for newline */
1606
40
  while ((extent != 0) && (*sp != '\n') && extent--)
1607
35
    sp++;
1608
1609
  /* look for length */
1610
30
  while ((extent != 0) && ((*sp == '\0' || *sp == ' ' || *sp == '\n')) && extent--)
1611
25
     sp++;
1612
1613
5
  if (extent == 0)
1614
0
    {
1615
0
      png_warning(ping,"invalid profile length");
1616
0
      return(MagickFalse);
1617
0
    }
1618
1619
5
  if (extent >= 8)
1620
5
    length=StringToLong(sp);
1621
1622
5
  if (image->debug != MagickFalse)
1623
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1624
0
         "      length: %lu",(unsigned long) length);
1625
1626
25
  while ((extent != 0) && (*sp != ' ' && *sp != '\n') && extent--)
1627
20
    sp++;
1628
1629
5
  if (extent == 0)
1630
0
    {
1631
0
      png_warning(ping,"missing profile length");
1632
0
      return(MagickFalse);
1633
0
    }
1634
1635
  /* allocate space */
1636
5
  if (length == 0)
1637
0
  {
1638
0
    png_warning(ping,"invalid profile length");
1639
0
    return(MagickFalse);
1640
0
  }
1641
1642
5
  profile=AcquireProfileStringInfo(&text[ii].key[17],(size_t) length,
1643
5
    exception);
1644
1645
5
  if (profile == (StringInfo *) NULL)
1646
0
    return(MagickTrue);
1647
1648
  /* copy profile, skipping white space and column 1 "=" signs */
1649
5
  dp=GetStringInfoDatum(profile);
1650
5
  nibbles=(size_t) length*2;
1651
1652
68.7k
  for (i=0; i < (ssize_t) nibbles; i++)
1653
68.7k
  {
1654
69.7k
    while ((extent != 0) && (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f'))
1655
955
    {
1656
955
      if (*sp == '\0')
1657
0
        {
1658
0
          png_warning(ping, "ran out of profile data");
1659
0
          profile=DestroyStringInfo(profile);
1660
0
          return(MagickFalse);
1661
0
        }
1662
955
      sp++;
1663
955
      extent--;
1664
955
    }
1665
68.7k
    if (extent != 0)
1666
68.7k
      {
1667
68.7k
        if (i % 2 == 0)
1668
34.3k
          *dp=(unsigned char) (16*unhex[(int) *sp++]);
1669
34.3k
        else
1670
34.3k
          (*dp++)+=unhex[(int) *sp++];
1671
68.7k
        extent--;
1672
68.7k
      }
1673
68.7k
    if (extent == 0)
1674
0
      break;
1675
68.7k
  }
1676
  /*
1677
    We have already read "Raw profile type.
1678
  */
1679
5
  (void) SetImageProfilePrivate(image,profile,exception);
1680
1681
5
  if (image_info->verbose)
1682
0
    (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1683
1684
5
  return(MagickTrue);
1685
5
}
1686
1687
static int PNGSetExifProfile(Image *image,png_byte *data,png_size_t size,
1688
  ExceptionInfo *exception)
1689
41.5k
{
1690
41.5k
  StringInfo
1691
41.5k
    *profile;
1692
1693
41.5k
  if ((data == (png_byte *) NULL) || (size < 6))
1694
11.6k
    return(1);
1695
29.8k
  if ((data[0] == 'E') && (data[1] == 'x') && (data[2] == 'i') &&
1696
9.13k
      (data[3] == 'f') && (data[4] == '\0') && (data[5] == '\0'))
1697
1.99k
    profile=BlobToProfileStringInfo("exif",(const void *) data,size,exception);
1698
27.9k
  else
1699
27.9k
    {
1700
27.9k
      unsigned char
1701
27.9k
        *p;
1702
1703
27.9k
      profile=AcquireProfileStringInfo("exif",size+6,exception);
1704
27.9k
      if (profile != (StringInfo *) NULL)
1705
27.9k
        {
1706
27.9k
          p=GetStringInfoDatum(profile);
1707
27.9k
          *p++ ='E';
1708
27.9k
          *p++ ='x';
1709
27.9k
          *p++ ='i';
1710
27.9k
          *p++ ='f';
1711
27.9k
          *p++ ='\0';
1712
27.9k
          *p++ ='\0';
1713
27.9k
          (void) CopyMagickMemory(p,data,size);
1714
27.9k
        }
1715
27.9k
    }
1716
29.8k
  if (profile != (StringInfo*)NULL)
1717
29.8k
    (void) SetImageProfilePrivate(image,profile,exception);
1718
29.8k
  return(1);
1719
41.5k
}
1720
1721
#if defined(PNG_READ_eXIf_SUPPORTED)
1722
static void read_eXIf_chunk(Image *image,png_struct *ping,png_info *info,
1723
  ExceptionInfo *exception)
1724
74.6k
{
1725
74.6k
  png_uint_32
1726
74.6k
    size;
1727
1728
74.6k
  png_bytep
1729
74.6k
    data;
1730
1731
74.6k
#if PNG_LIBPNG_VER > 10631
1732
74.6k
  if (png_get_eXIf_1(ping,info,&size,&data))
1733
16
    (void) PNGSetExifProfile(image,data,size,exception);
1734
74.6k
#endif
1735
74.6k
}
1736
#endif
1737
1738
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1739
static int PNGParseiTXt(Image *image,png_byte *data,png_size_t size,
1740
  ExceptionInfo *exception)
1741
175k
{
1742
175k
  char
1743
175k
    compressed,
1744
175k
    key[MagickPathExtent],
1745
175k
    language[MagickPathExtent],
1746
175k
    method;
1747
1748
175k
  ssize_t
1749
175k
    offset;
1750
1751
175k
  StringInfo
1752
175k
    *profile,
1753
175k
    *property;
1754
1755
175k
  if ((size > 19) && (LocaleNCompare((const char *) data,
1756
43.9k
      "XML:com.adobe.xmp",17) == 0) && (data[18] == 0) && (data[19] == 0))
1757
2.93k
    {
1758
      /*
1759
        XMP profile.
1760
      */
1761
2.93k
      offset=20;
1762
15.4k
      while (offset < (ssize_t) size)
1763
14.9k
      {
1764
14.9k
        if (data[offset++] == 0)
1765
2.49k
          break;
1766
14.9k
      }
1767
10.3k
      while (offset < (ssize_t) size)
1768
9.89k
      {
1769
9.89k
        if (data[offset++] == 0)
1770
2.44k
          break;
1771
9.89k
      }
1772
2.93k
      if (((MagickOffsetType) size-offset) < 1)
1773
497
        return(0);
1774
2.44k
      profile=BlobToProfileStringInfo("xmp",(const void *) (data+offset),
1775
2.44k
        size-(size_t) offset,exception);
1776
2.44k
      (void) SetImageProfilePrivate(image,profile,exception);
1777
2.44k
      return(1);
1778
2.93k
    }
1779
  /*
1780
    iTXt chunk.
1781
  */
1782
172k
  profile=BlobToStringInfo((const void *) data,size);
1783
172k
  if (profile == (StringInfo *) NULL)
1784
0
    {
1785
0
      (void) ThrowMagickException(exception,GetMagickModule(),
1786
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1787
0
      return(-1);
1788
0
    }
1789
172k
  (void) FormatLocaleString(key,MagickPathExtent,"%s",(const char *)
1790
172k
    GetStringInfoDatum(profile));
1791
172k
  offset=(ssize_t) strlen(key)+1;
1792
172k
  if (((MagickOffsetType) size-offset) < 1)
1793
5.50k
    {
1794
5.50k
      profile=DestroyStringInfo(profile);
1795
5.50k
      return(0);
1796
5.50k
    }
1797
166k
  compressed=(char) data[offset++];
1798
166k
  if ((((MagickOffsetType) size-offset) < 1) || (compressed != 0))
1799
5.11k
    {
1800
5.11k
      profile=DestroyStringInfo(profile);
1801
5.11k
      return(0);
1802
5.11k
    }
1803
161k
  method=(char) data[offset++];
1804
161k
  if ((((MagickOffsetType) size-offset) < 1) || (method != 0))
1805
5.81k
    {
1806
5.81k
      profile=DestroyStringInfo(profile);
1807
5.81k
      return(0);
1808
5.81k
    }
1809
155k
  (void) FormatLocaleString(language,MagickPathExtent,"%s",(const char *)
1810
155k
    GetStringInfoDatum(profile)+offset++);
1811
155k
  offset+=(ssize_t) strlen(language)+1;
1812
155k
  if (((MagickOffsetType) size-offset) < 1)
1813
2.51k
    {
1814
2.51k
      profile=DestroyStringInfo(profile);
1815
2.51k
      return(0);
1816
2.51k
    }
1817
153k
  property=BlobToStringInfo((const void *) (GetStringInfoDatum(profile)+offset),
1818
153k
    size-(size_t) offset);
1819
153k
  if (property == (StringInfo *) NULL)
1820
0
    {
1821
0
      profile=DestroyStringInfo(profile);
1822
0
      (void) ThrowMagickException(exception,GetMagickModule(),
1823
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1824
0
      return(-1);
1825
0
    }
1826
153k
  (void) SetImageProperty(image,key,(const char *) GetStringInfoDatum(property),
1827
153k
    exception);
1828
153k
  property=DestroyStringInfo(property);
1829
153k
  profile=DestroyStringInfo(profile);
1830
153k
  return(1);
1831
153k
}
1832
1833
static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1834
304k
{
1835
304k
  Image
1836
304k
    *image;
1837
1838
304k
  PNGErrorInfo
1839
304k
    *error_info;
1840
1841
  /* The unknown chunk structure contains the chunk data:
1842
     png_byte name[5];
1843
     png_byte *data;
1844
     png_size_t size;
1845
1846
     Note that libpng has already taken care of the CRC handling.
1847
1848
     Returns one of the following:
1849
         return(-n);  chunk had an error
1850
         return(0);  did not recognize
1851
         return(n);  success
1852
  */
1853
1854
304k
  if (IsEventLogging() != MagickFalse)
1855
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1856
0
       "    read_user_chunk: found %c%c%c%c chunk",
1857
0
         chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
1858
1859
304k
  if ((chunk->name[0] == 101) &&
1860
56.2k
      ((chunk->name[1] == 88) || (chunk->name[1] == 120)) &&
1861
53.3k
      (chunk->name[2] ==  73) && (chunk->name[3] == 102))
1862
41.5k
    {
1863
41.5k
      image=(Image *) png_get_user_chunk_ptr(ping);
1864
1865
41.5k
      error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1866
1867
41.5k
      return(PNGSetExifProfile(image,chunk->data,chunk->size,
1868
41.5k
        error_info->exception));
1869
41.5k
    }
1870
1871
  /* orNT */
1872
263k
  if ((chunk->name[0] == 111) && (chunk->name[1] == 114) &&
1873
20.4k
      (chunk->name[2] ==  78) && (chunk->name[3] ==  84))
1874
12.9k
    {
1875
12.9k
     if (chunk->size != 1)
1876
18
       return(-1);
1877
1878
12.9k
     image=(Image *) png_get_user_chunk_ptr(ping);
1879
1880
12.9k
     image->orientation=
1881
12.9k
       Magick_Orientation_from_Exif_Orientation((int) chunk->data[0]);
1882
1883
12.9k
     return(1);
1884
12.9k
    }
1885
1886
  /* vpAg (deprecated, replaced by caNv) */
1887
250k
  if ((chunk->name[0] == 118) && (chunk->name[1] == 112) &&
1888
6.69k
      (chunk->name[2] ==  65) && (chunk->name[3] == 103))
1889
2.10k
    {
1890
2.10k
      if (chunk->size != 9)
1891
36
        return(-1);
1892
1893
       /* ImageMagick requires pixel units */
1894
2.06k
      if (chunk->data[8] != 0)
1895
844
        return(0);
1896
1897
1.22k
      image=(Image *) png_get_user_chunk_ptr(ping);
1898
1899
1.22k
      image->page.width=(size_t)mng_get_long(chunk->data);
1900
1.22k
      image->page.height=(size_t)mng_get_long(&chunk->data[4]);
1901
1902
1.22k
      return(1);
1903
2.06k
    }
1904
1905
  /* caNv */
1906
248k
  if ((chunk->name[0] == 99) && (chunk->name[1] ==  97) &&
1907
6.76k
      (chunk->name[2] == 78) && (chunk->name[3] == 118))
1908
2.88k
    {
1909
2.88k
      if (chunk->size != 16)
1910
44
        return(-1); /* Error return */
1911
1912
2.84k
      image=(Image *) png_get_user_chunk_ptr(ping);
1913
1914
2.84k
      image->page.width=(size_t) mng_get_long(chunk->data);
1915
2.84k
      image->page.height=(size_t) mng_get_long(&chunk->data[4]);
1916
2.84k
      image->page.x=(ssize_t) ((int) mng_get_long(&chunk->data[8]));
1917
2.84k
      image->page.y=(ssize_t) ((int) mng_get_long(&chunk->data[12]));
1918
1919
2.84k
      return(1);
1920
2.88k
    }
1921
1922
  /* acTL */
1923
245k
  if ((chunk->name[0] == 97) && (chunk->name[1] == 99) &&
1924
7.58k
      (chunk->name[2] == 84) && (chunk->name[3] == 76))
1925
4.88k
    {
1926
4.88k
      image=(Image *) png_get_user_chunk_ptr(ping);
1927
4.88k
      error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1928
1929
4.88k
      (void) SetImageProperty(image,"png:acTL","chunk was found",
1930
4.88k
        error_info->exception);
1931
1932
4.88k
      return(1);
1933
4.88k
    }
1934
1935
  /* iTXt */
1936
240k
  if ((chunk->name[0] == 105) && (chunk->name[1] ==  84) &&
1937
181k
      (chunk->name[2] ==  88) && (chunk->name[3] == 116))
1938
175k
    {
1939
175k
      image=(Image *) png_get_user_chunk_ptr(ping);
1940
1941
175k
      error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1942
1943
175k
      return(PNGParseiTXt(image,chunk->data,chunk->size,
1944
175k
        error_info->exception));
1945
175k
    }
1946
1947
65.1k
  return(0); /* Did not recognize */
1948
240k
}
1949
#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */
1950
1951
#if defined(PNG_tIME_SUPPORTED)
1952
static void read_tIME_chunk(Image *image,png_struct *ping,png_info *info,
1953
  ExceptionInfo *exception)
1954
74.6k
{
1955
74.6k
  png_timep
1956
74.6k
    time;
1957
1958
74.6k
  if (png_get_tIME(ping,info,&time))
1959
50
    {
1960
50
      char
1961
50
        timestamp[21];
1962
1963
50
      FormatLocaleString(timestamp,21,"%04d-%02d-%02dT%02d:%02d:%02dZ",
1964
50
        time->year,time->month,time->day,time->hour,time->minute,time->second);
1965
50
      SetImageProperty(image,"png:tIME",timestamp,exception);
1966
50
    }
1967
74.6k
}
1968
#endif
1969
1970
/*
1971
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972
%                                                                             %
1973
%                                                                             %
1974
%                                                                             %
1975
%   R e a d O n e P N G I m a g e                                             %
1976
%                                                                             %
1977
%                                                                             %
1978
%                                                                             %
1979
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980
%
1981
%  ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1982
%  (minus the 8-byte signature)  and returns it.  It allocates the memory
1983
%  necessary for the new Image structure and returns a pointer to the new
1984
%  image.
1985
%
1986
%  The format of the ReadOnePNGImage method is:
1987
%
1988
%      Image *ReadOnePNGImage(MngReadInfo *mng_info,const ImageInfo *image_info,
1989
%        ExceptionInfo *exception)
1990
%
1991
%  A description of each parameter follows:
1992
%
1993
%    o mng_info: Specifies a pointer to a MngReadInfo structure.
1994
%
1995
%    o image_info: the image info.
1996
%
1997
%    o exception: return any errors or warnings in this structure.
1998
%
1999
*/
2000
static Image *ReadOnePNGImage(MngReadInfo *mng_info,
2001
  const ImageInfo *image_info,ExceptionInfo *exception)
2002
87.0k
{
2003
  /* Read one PNG image */
2004
2005
  /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2006
2007
87.0k
  double
2008
87.0k
    file_gamma;
2009
2010
87.0k
  Image
2011
87.0k
    *image;
2012
2013
87.0k
  int
2014
87.0k
    intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2015
87.0k
    num_raw_profiles,
2016
87.0k
    num_text,
2017
87.0k
    num_text_total,
2018
87.0k
    num_passes,
2019
87.0k
    number_colors = 0,
2020
87.0k
    pass,
2021
87.0k
    ping_bit_depth = 0,
2022
87.0k
    ping_color_type = 0,
2023
87.0k
    ping_file_depth = 0,
2024
87.0k
    ping_interlace_method = 0,
2025
87.0k
    ping_compression_method = 0,
2026
87.0k
    ping_filter_method = 0,
2027
87.0k
    ping_num_trans = 0,
2028
87.0k
    unit_type = 0;
2029
2030
87.0k
  MagickBooleanType
2031
87.0k
    logging = MagickFalse,
2032
87.0k
    ping_found_cHRM,
2033
87.0k
    ping_found_gAMA,
2034
87.0k
    ping_found_iCCP,
2035
87.0k
    ping_found_sRGB,
2036
87.0k
    ping_preserve_iCCP,
2037
87.0k
    status;
2038
2039
87.0k
  MemoryInfo
2040
87.0k
    *volatile pixel_info;
2041
2042
87.0k
  PixelInfo
2043
87.0k
    transparent_color;
2044
2045
87.0k
  PNGErrorInfo
2046
87.0k
    error_info;
2047
2048
87.0k
  png_bytep
2049
87.0k
     ping_trans_alpha = NULL;
2050
2051
87.0k
  png_color_16p
2052
87.0k
     ping_background = (png_color_16p) NULL,
2053
87.0k
     ping_trans_color = (png_color_16p) NULL;
2054
2055
87.0k
  png_info
2056
87.0k
    *end_info,
2057
87.0k
    *ping_info;
2058
2059
87.0k
  png_struct
2060
87.0k
    *ping;
2061
2062
87.0k
  png_textp
2063
87.0k
    text;
2064
2065
87.0k
  png_uint_32
2066
87.0k
    ping_height = 0,
2067
87.0k
    ping_width = 0,
2068
87.0k
    x_resolution,
2069
87.0k
    y_resolution;
2070
2071
87.0k
  QuantumInfo
2072
87.0k
    *volatile quantum_info;
2073
2074
87.0k
  Quantum
2075
87.0k
    *volatile quantum_scanline;
2076
2077
87.0k
  Quantum
2078
87.0k
    *q;
2079
2080
87.0k
  size_t
2081
87.0k
    length,
2082
87.0k
    ping_rowbytes = 0,
2083
87.0k
    row_offset;
2084
2085
87.0k
  ssize_t
2086
87.0k
    i,
2087
87.0k
    j,
2088
87.0k
    x,
2089
87.0k
    y;
2090
2091
87.0k
  unsigned char
2092
87.0k
    *p,
2093
87.0k
    *ping_pixels;
2094
2095
87.0k
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2096
87.0k
  static const png_byte unused_chunks[]=
2097
87.0k
  {
2098
87.0k
    104,  73,  83,  84, (png_byte) '\0',   /* hIST */
2099
87.0k
    105,  84,  88, 116, (png_byte) '\0',   /* iTXt */
2100
87.0k
    112,  67,  65,  76, (png_byte) '\0',   /* pCAL */
2101
87.0k
    115,  67,  65,  76, (png_byte) '\0',   /* sCAL */
2102
87.0k
    115,  80,  76,  84, (png_byte) '\0',   /* sPLT */
2103
#if !defined(PNG_tIME_SUPPORTED)
2104
    116,  73,  77,  69, (png_byte) '\0',   /* tIME */
2105
#endif
2106
87.0k
#ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2107
                          /* ignore the APNG chunks */
2108
87.0k
     97,  99,  84,  76, (png_byte) '\0',   /* acTL */
2109
87.0k
    102,  99,  84,  76, (png_byte) '\0',   /* fcTL */
2110
87.0k
    102, 100,  65,  84, (png_byte) '\0',   /* fdAT */
2111
87.0k
#endif
2112
87.0k
  };
2113
87.0k
#endif
2114
2115
87.0k
  logging=IsEventLogging();
2116
87.0k
  if (logging != MagickFalse)
2117
0
    {
2118
0
      char
2119
0
        im_vers[32],
2120
0
        libpng_runv[32],
2121
0
        libpng_vers[32],
2122
0
        zlib_runv[32],
2123
0
        zlib_vers[32];
2124
2125
0
      *im_vers='\0';
2126
0
      (void) ConcatenateMagickString(im_vers,
2127
0
             MagickLibVersionText,32);
2128
0
      (void) ConcatenateMagickString(im_vers,
2129
0
             MagickLibAddendum,32);
2130
2131
0
      *libpng_vers='\0';
2132
0
      (void) ConcatenateMagickString(libpng_vers,
2133
0
             PNG_LIBPNG_VER_STRING,32);
2134
0
      *libpng_runv='\0';
2135
0
      (void) ConcatenateMagickString(libpng_runv,
2136
0
             png_get_libpng_ver(NULL),32);
2137
2138
0
      *zlib_vers='\0';
2139
0
      (void) ConcatenateMagickString(zlib_vers,
2140
0
             ZLIB_VERSION,32);
2141
0
      *zlib_runv='\0';
2142
0
      (void) ConcatenateMagickString(zlib_runv,
2143
0
             zlib_version,32);
2144
2145
0
      LogMagickEvent(CoderEvent,GetMagickModule(),
2146
0
         "  Enter ReadOnePNGImage()\n"
2147
0
         "    IM version     = %s\n"
2148
0
         "    Libpng version = %s",
2149
0
         im_vers, libpng_vers);
2150
2151
0
      if (LocaleCompare(libpng_vers,libpng_runv) != 0)
2152
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2153
0
          "      running with   %s", libpng_runv);
2154
0
      if (LocaleCompare(libpng_vers,zlib_vers) != 0)
2155
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156
0
          "    Zlib version   = %s", zlib_vers);
2157
0
      if (LocaleCompare(zlib_vers,zlib_runv) != 0)
2158
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2159
0
          "      running with   %s", zlib_runv);
2160
0
    }
2161
2162
87.0k
  quantum_info = (QuantumInfo *) NULL;
2163
87.0k
  image=mng_info->image;
2164
2165
87.0k
  if (logging != MagickFalse)
2166
0
  {
2167
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2168
0
       "    Before reading:\n"
2169
0
       "      image->alpha_trait=%d\n"
2170
0
       "      image->rendering_intent=%d\n"
2171
0
       "      image->colorspace=%d\n"
2172
0
       "      image->gamma=%f",
2173
0
       (int) image->alpha_trait, (int) image->rendering_intent,
2174
0
       (int) image->colorspace, image->gamma);
2175
0
  }
2176
87.0k
  intent=
2177
87.0k
    Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2178
2179
  /* Set to an out-of-range color unless tRNS chunk is present */
2180
87.0k
  transparent_color.red=65537;
2181
87.0k
  transparent_color.green=65537;
2182
87.0k
  transparent_color.blue=65537;
2183
87.0k
  transparent_color.alpha=65537;
2184
2185
87.0k
  number_colors=0;
2186
87.0k
  num_text = 0;
2187
87.0k
  num_text_total = 0;
2188
87.0k
  num_raw_profiles = 0;
2189
2190
87.0k
  ping_found_cHRM = MagickFalse;
2191
87.0k
  ping_found_gAMA = MagickFalse;
2192
87.0k
  ping_found_iCCP = MagickFalse;
2193
87.0k
  ping_found_sRGB = MagickFalse;
2194
87.0k
  ping_preserve_iCCP = MagickFalse;
2195
2196
2197
  /*
2198
    Allocate the PNG structures
2199
  */
2200
87.0k
#ifdef PNG_USER_MEM_SUPPORTED
2201
87.0k
 error_info.image=image;
2202
87.0k
 error_info.exception=exception;
2203
87.0k
 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2204
87.0k
   MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2205
87.0k
   (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2206
#else
2207
  ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2208
    MagickPNGErrorHandler,MagickPNGWarningHandler);
2209
#endif
2210
87.0k
  if (ping == (png_struct *) NULL)
2211
87.0k
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2212
2213
87.0k
  ping_info=png_create_info_struct(ping);
2214
2215
87.0k
  if (ping_info == (png_info *) NULL)
2216
0
    {
2217
0
      png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2218
0
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2219
0
    }
2220
2221
87.0k
  end_info=png_create_info_struct(ping);
2222
2223
87.0k
  if (end_info == (png_info *) NULL)
2224
0
    {
2225
0
      png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2226
0
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2227
0
    }
2228
2229
87.0k
  pixel_info=(MemoryInfo *) NULL;
2230
87.0k
  quantum_scanline = (Quantum *) NULL;
2231
87.0k
  quantum_info = (QuantumInfo *) NULL;
2232
2233
87.0k
  if (setjmp(png_jmpbuf(ping)))
2234
55.3k
    {
2235
      /*
2236
        PNG image is corrupt.
2237
      */
2238
55.3k
      png_destroy_read_struct(&ping,&ping_info,&end_info);
2239
2240
55.3k
      if (pixel_info != (MemoryInfo *) NULL)
2241
12.1k
        pixel_info=RelinquishVirtualMemory(pixel_info);
2242
2243
55.3k
      if (quantum_info != (QuantumInfo *) NULL)
2244
10.7k
        quantum_info=DestroyQuantumInfo(quantum_info);
2245
2246
55.3k
      quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2247
2248
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
2249
      UnlockSemaphoreInfo(ping_semaphore);
2250
#endif
2251
2252
55.3k
      if (logging != MagickFalse)
2253
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2254
0
          "  exit ReadOnePNGImage() with error.");
2255
2256
55.3k
      if (image != (Image *) NULL)
2257
55.3k
        image=DestroyImageList(image);
2258
55.3k
      return(image);
2259
55.3k
    }
2260
2261
  /* {  For navigation to end of SETJMP-protected block.  Within this
2262
   *    block, use png_error() instead of Throwing an Exception, to ensure
2263
   *    that libpng is able to clean up, and that the semaphore is unlocked.
2264
   */
2265
2266
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
2267
  LockSemaphoreInfo(ping_semaphore);
2268
#endif
2269
2270
31.6k
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
2271
  /* Allow benign errors */
2272
31.6k
  png_set_benign_errors(ping, 1);
2273
31.6k
#endif
2274
2275
31.6k
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2276
31.6k
  {
2277
31.6k
    const char
2278
31.6k
      *option;
2279
2280
    /* Reject images with too many rows or columns */
2281
31.6k
    png_set_user_limits(ping,(png_uint_32) MagickMin(PNG_UINT_31_MAX,
2282
31.6k
      GetMagickResourceLimit(WidthResource)),(png_uint_32)
2283
31.6k
      MagickMin(PNG_UINT_31_MAX,GetMagickResourceLimit(HeightResource)));
2284
2285
31.6k
#if (PNG_LIBPNG_VER >= 10400)
2286
31.6k
    option=GetImageOption(image_info,"png:chunk-cache-max");
2287
31.6k
    if (option != (const char *) NULL)
2288
0
      png_set_chunk_cache_max(ping,(png_uint_32) MagickMin(PNG_UINT_32_MAX,
2289
0
        StringToLong(option)));
2290
31.6k
    else
2291
31.6k
      png_set_chunk_cache_max(ping,32767);
2292
31.6k
#endif
2293
2294
31.6k
#if (PNG_LIBPNG_VER >= 10401)
2295
31.6k
    option=GetImageOption(image_info,"png:chunk-malloc-max");
2296
31.6k
    if (option != (const char *) NULL)
2297
0
      png_set_chunk_malloc_max(ping,(png_alloc_size_t) MagickMin(
2298
0
        MAGICK_SSIZE_MAX,(size_t) StringToLong(option)));
2299
31.6k
#endif
2300
31.6k
  }
2301
31.6k
#endif /* PNG_SET_USER_LIMITS_SUPPORTED */
2302
2303
  /*
2304
    Prepare PNG for reading.
2305
  */
2306
2307
31.6k
  mng_info->image_found++;
2308
31.6k
  png_set_sig_bytes(ping,8);
2309
2310
31.6k
  if (LocaleCompare(image_info->magick,"MNG") == 0)
2311
16.6k
    (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2312
31.6k
  png_set_read_fn(ping,image,png_get_data);
2313
2314
31.6k
  {
2315
31.6k
    const char
2316
31.6k
      *value;
2317
2318
31.6k
    value=GetImageOption(image_info,"png:ignore-crc");
2319
31.6k
    if (IsStringTrue(value) != MagickFalse)
2320
0
    {
2321
       /* Turn off CRC checking while reading */
2322
0
       png_set_crc_action(ping, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
2323
#ifdef PNG_IGNORE_ADLER32
2324
       /* Turn off ADLER32 checking while reading */
2325
       png_set_option(ping, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
2326
#endif
2327
0
     }
2328
2329
31.6k
    value=GetImageOption(image_info,"profile:skip");
2330
2331
31.6k
    if (IsOptionMember("ICC",value) == MagickFalse)
2332
87.0k
    {
2333
2334
87.0k
       value=GetImageOption(image_info,"png:preserve-iCCP");
2335
2336
87.0k
       if (value == NULL)
2337
87.0k
          value=GetImageArtifact(image,"png:preserve-iCCP");
2338
2339
87.0k
       if (value != NULL)
2340
0
          ping_preserve_iCCP=MagickTrue;
2341
2342
87.0k
#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
2343
       /* Don't let libpng check for ICC/sRGB profile because we're going
2344
        * to do that anyway.  This feature was added at libpng-1.6.12.
2345
        * If logging, go ahead and check and issue a warning as appropriate.
2346
        */
2347
87.0k
       if (logging == MagickFalse)
2348
87.0k
          png_set_option(ping, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
2349
87.0k
#endif
2350
87.0k
    }
2351
18.4E
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2352
18.4E
    else
2353
18.4E
    {
2354
18.4E
       png_set_keep_unknown_chunks(ping, 1, (png_bytep) mng_iCCP, 1);
2355
18.4E
    }
2356
31.6k
#endif
2357
31.6k
  }
2358
31.6k
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2359
  /* Ignore unused chunks and all unknown chunks except for caNv and vpAg */
2360
# if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
2361
  png_set_keep_unknown_chunks(ping, 2, NULL, 0);
2362
# else
2363
31.6k
  png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2364
31.6k
# endif
2365
31.6k
  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_caNv, 1);
2366
31.6k
  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_vpAg, 1);
2367
31.6k
  png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2368
31.6k
     (int)sizeof(unused_chunks)/5);
2369
  /* Callback for other unknown chunks */
2370
31.6k
  png_set_read_user_chunk_fn(ping, image, read_user_chunk_callback);
2371
31.6k
#endif
2372
2373
31.6k
#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2374
    /* Disable new libpng-1.5.10 feature */
2375
31.6k
    png_set_check_for_invalid_index (ping, 0);
2376
31.6k
#endif
2377
2378
#if (PNG_LIBPNG_VER < 10400)
2379
#  if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2380
   (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2381
  /* Disable thread-unsafe features of pnggccrd */
2382
  if (png_access_version_number() >= 10200)
2383
  {
2384
    png_uint_32 mmx_disable_mask=0;
2385
    png_uint_32 asm_flags;
2386
2387
    mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
2388
                        | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
2389
                        | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
2390
                        | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2391
    asm_flags=png_get_asm_flags(ping);
2392
    png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2393
  }
2394
#  endif
2395
#endif
2396
2397
31.6k
  png_read_info(ping,ping_info);
2398
2399
31.6k
  png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2400
31.6k
               &ping_bit_depth,&ping_color_type,
2401
31.6k
               &ping_interlace_method,&ping_compression_method,
2402
31.6k
               &ping_filter_method);
2403
2404
31.6k
  ping_file_depth = ping_bit_depth;
2405
2406
  /* Swap bytes if requested */
2407
31.6k
  if (ping_file_depth == 16)
2408
9.69k
  {
2409
9.69k
     const char
2410
9.69k
       *value;
2411
2412
9.69k
     value=GetImageOption(image_info,"png:swap-bytes");
2413
2414
9.69k
     if (value == NULL)
2415
9.69k
        value=GetImageArtifact(image,"png:swap-bytes");
2416
2417
9.69k
     if (value != NULL)
2418
0
        png_set_swap(ping);
2419
9.69k
  }
2420
2421
  /* Save bit-depth and color-type in case we later want to write a PNG00 */
2422
31.6k
  {
2423
31.6k
      char
2424
31.6k
        msg[MagickPathExtent];
2425
2426
31.6k
      (void) FormatLocaleString(msg,MagickPathExtent,"%d",
2427
31.6k
         (int) ping_color_type);
2428
31.6k
      (void) SetImageProperty(image,"png:IHDR.color-type-orig",msg,exception);
2429
2430
31.6k
      (void) FormatLocaleString(msg,MagickPathExtent,"%d",
2431
31.6k
         (int) ping_bit_depth);
2432
31.6k
      (void) SetImageProperty(image,"png:IHDR.bit-depth-orig",msg,exception);
2433
31.6k
  }
2434
2435
31.6k
  (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2436
31.6k
                      &ping_trans_color);
2437
2438
31.6k
  (void) png_get_bKGD(ping, ping_info, &ping_background);
2439
2440
31.6k
  if (ping_bit_depth < 8)
2441
25.4k
    {
2442
25.4k
       png_set_packing(ping);
2443
25.4k
       ping_bit_depth = 8;
2444
25.4k
    }
2445
2446
31.6k
  image->depth=(size_t) ping_bit_depth;
2447
31.6k
  image->depth=GetImageQuantumDepth(image,MagickFalse);
2448
31.6k
  image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2449
2450
31.6k
  if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2451
12.7k
      ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2452
32.1k
    {
2453
32.1k
      image->rendering_intent=UndefinedIntent;
2454
32.1k
      intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2455
32.1k
      (void) memset(&image->chromaticity,0,sizeof(image->chromaticity));
2456
32.1k
    }
2457
2458
31.6k
  if (logging != MagickFalse)
2459
0
    {
2460
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2461
0
        "    PNG width: %.17g, height: %.17g\n"
2462
0
        "    PNG color_type: %d, bit_depth: %d\n"
2463
0
        "    PNG compression_method: %d\n"
2464
0
        "    PNG interlace_method: %d, filter_method: %d",
2465
0
        (double) ping_width, (double) ping_height,
2466
0
        ping_color_type, ping_bit_depth,
2467
0
        ping_compression_method,
2468
0
        ping_interlace_method,ping_filter_method);
2469
2470
0
    }
2471
2472
31.6k
  if (png_get_valid(ping,ping_info, PNG_INFO_iCCP))
2473
3.77k
    {
2474
3.77k
      ping_found_iCCP=MagickTrue;
2475
3.77k
      if (logging != MagickFalse)
2476
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2477
0
          "    Found PNG iCCP chunk.");
2478
3.77k
    }
2479
2480
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2481
635
    {
2482
635
      ping_found_gAMA=MagickTrue;
2483
635
      if (logging != MagickFalse)
2484
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2485
0
          "    Found PNG gAMA chunk.");
2486
635
    }
2487
2488
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2489
54
    {
2490
54
      ping_found_cHRM=MagickTrue;
2491
54
      if (logging != MagickFalse)
2492
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2493
0
          "    Found PNG cHRM chunk.");
2494
54
    }
2495
2496
39.9k
  if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info,
2497
39.9k
      PNG_INFO_sRGB))
2498
202
    {
2499
202
      ping_found_sRGB=MagickTrue;
2500
202
      if (logging != MagickFalse)
2501
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2502
0
          "    Found PNG sRGB chunk.");
2503
202
    }
2504
2505
31.6k
#ifdef PNG_READ_iCCP_SUPPORTED
2506
31.6k
    if (ping_found_iCCP !=MagickTrue &&
2507
39.9k
      ping_found_sRGB != MagickTrue &&
2508
39.7k
      png_get_valid(ping,ping_info, PNG_INFO_iCCP))
2509
0
    {
2510
0
      ping_found_iCCP=MagickTrue;
2511
0
      if (logging != MagickFalse)
2512
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2513
0
          "    Found PNG iCCP chunk.");
2514
0
    }
2515
2516
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2517
3.77k
    {
2518
3.77k
      int
2519
3.77k
        compression;
2520
2521
#if (PNG_LIBPNG_VER < 10500)
2522
      png_charp
2523
        info;
2524
#else
2525
3.77k
      png_bytep
2526
3.77k
        info;
2527
3.77k
#endif
2528
2529
3.77k
      png_charp
2530
3.77k
        name;
2531
2532
3.77k
      png_uint_32
2533
3.77k
        profile_length;
2534
2535
3.77k
      (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2536
3.77k
        &profile_length);
2537
2538
3.77k
      if (profile_length != 0)
2539
3.77k
        {
2540
3.77k
          StringInfo
2541
3.77k
            *profile;
2542
2543
3.77k
          if (logging != MagickFalse)
2544
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2545
0
              "    Reading PNG iCCP chunk.");
2546
2547
3.77k
          profile=BlobToProfileStringInfo("icc",info,(size_t) profile_length,
2548
3.77k
            exception);
2549
2550
3.77k
          if (profile != (StringInfo *) NULL)
2551
3.77k
          {
2552
3.77k
            if (ping_preserve_iCCP != MagickFalse)
2553
0
              (void) SetImageProfilePrivate(image,profile,exception);
2554
3.77k
            else
2555
3.77k
            {
2556
3.77k
              int
2557
3.77k
                icheck,
2558
3.77k
                got_crc=0;
2559
2560
2561
3.77k
              png_uint_32
2562
3.77k
                profile_crc=0;
2563
2564
3.77k
              unsigned char
2565
3.77k
                *data;
2566
2567
3.77k
              profile_length=(png_uint_32) GetStringInfoLength(profile);
2568
2569
37.7k
              for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
2570
33.9k
              {
2571
33.9k
                if (profile_length == sRGB_info[icheck].len)
2572
549
                {
2573
549
                  if (got_crc == 0)
2574
333
                  {
2575
333
                    if (logging != MagickFalse)
2576
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2577
0
                        "    Got a %lu-byte ICC profile (potentially sRGB)",
2578
0
                        (unsigned long) profile_length);
2579
2580
333
                    data=GetStringInfoDatum(profile);
2581
333
                    profile_crc=crc32(0,data,profile_length);
2582
2583
333
                    if (logging != MagickFalse)
2584
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2585
0
                        "      with crc=%8x",(unsigned int) profile_crc);
2586
333
                    got_crc++;
2587
333
                  }
2588
2589
549
                  if (profile_crc == sRGB_info[icheck].crc)
2590
12
                  {
2591
12
                    if (logging != MagickFalse)
2592
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593
0
                          "      It is sRGB with rendering intent = %s",
2594
0
                    Magick_RenderingIntentString_from_PNG_RenderingIntent(
2595
0
                          sRGB_info[icheck].intent));
2596
12
                    if (image->rendering_intent==UndefinedIntent)
2597
0
                    {
2598
0
                      image->rendering_intent=
2599
0
                      Magick_RenderingIntent_from_PNG_RenderingIntent(
2600
0
                          sRGB_info[icheck].intent);
2601
0
                    }
2602
12
                    break;
2603
12
                  }
2604
549
                }
2605
33.9k
              }
2606
3.77k
              if (sRGB_info[icheck].len != 0)
2607
12
                profile=DestroyStringInfo(profile);
2608
3.76k
              else
2609
3.76k
                {
2610
3.76k
                  if (logging != MagickFalse)
2611
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2612
0
                        "    Got %lu-byte ICC profile not recognized as sRGB",
2613
0
                        (unsigned long) profile_length);
2614
3.76k
                  (void) SetImageProfilePrivate(image,profile,exception);
2615
3.76k
                }
2616
3.77k
            }
2617
3.77k
          }
2618
3.77k
      }
2619
3.77k
    }
2620
31.6k
#endif
2621
2622
31.6k
#if defined(PNG_READ_sRGB_SUPPORTED)
2623
31.6k
  {
2624
39.9k
    if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info,
2625
39.9k
        PNG_INFO_sRGB))
2626
202
    {
2627
202
      if (png_get_sRGB(ping,ping_info,&intent))
2628
202
      {
2629
202
        if (image->rendering_intent == UndefinedIntent)
2630
58
          image->rendering_intent=
2631
58
             Magick_RenderingIntent_from_PNG_RenderingIntent (intent);
2632
2633
202
        if (logging != MagickFalse)
2634
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2635
0
            "    Reading PNG sRGB chunk: rendering_intent: %d",intent);
2636
202
      }
2637
202
    }
2638
2639
31.4k
    else if (mng_info->have_global_srgb != MagickFalse)
2640
165
      {
2641
165
        if (image->rendering_intent == UndefinedIntent)
2642
109
          image->rendering_intent=
2643
109
            Magick_RenderingIntent_from_PNG_RenderingIntent
2644
109
            ((int) mng_info->global_srgb_intent);
2645
165
      }
2646
31.6k
  }
2647
31.6k
#endif
2648
2649
2650
31.6k
  {
2651
31.6k
     if (!png_get_gAMA(ping,ping_info,&file_gamma))
2652
43.1k
       if (mng_info->have_global_gama != MagickFalse)
2653
117
         png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2654
2655
31.6k
     if (png_get_gAMA(ping,ping_info,&file_gamma))
2656
750
       {
2657
750
         image->gamma=file_gamma;
2658
750
         if (logging != MagickFalse)
2659
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2660
0
             "    Reading PNG gAMA chunk: gamma: %f",file_gamma);
2661
750
       }
2662
31.6k
  }
2663
2664
31.6k
  if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2665
43.6k
    {
2666
43.6k
      if (mng_info->have_global_chrm != MagickFalse)
2667
59
        {
2668
59
          (void) png_set_cHRM(ping,ping_info,
2669
59
            mng_info->global_chrm.white_point.x,
2670
59
            mng_info->global_chrm.white_point.y,
2671
59
            mng_info->global_chrm.red_primary.x,
2672
59
            mng_info->global_chrm.red_primary.y,
2673
59
            mng_info->global_chrm.green_primary.x,
2674
59
            mng_info->global_chrm.green_primary.y,
2675
59
            mng_info->global_chrm.blue_primary.x,
2676
59
            mng_info->global_chrm.blue_primary.y);
2677
59
        }
2678
43.6k
    }
2679
2680
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2681
109
    {
2682
109
      (void) png_get_cHRM(ping,ping_info,
2683
109
        &image->chromaticity.white_point.x,
2684
109
        &image->chromaticity.white_point.y,
2685
109
        &image->chromaticity.red_primary.x,
2686
109
        &image->chromaticity.red_primary.y,
2687
109
        &image->chromaticity.green_primary.x,
2688
109
        &image->chromaticity.green_primary.y,
2689
109
        &image->chromaticity.blue_primary.x,
2690
109
        &image->chromaticity.blue_primary.y);
2691
2692
109
       ping_found_cHRM=MagickTrue;
2693
109
    }
2694
2695
31.6k
#if defined(PNG_oFFs_SUPPORTED)
2696
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2697
44
    {
2698
44
      image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2699
44
      image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2700
2701
44
      if (logging != MagickFalse)
2702
0
        if (image->page.x || image->page.y)
2703
0
          if (logging != MagickFalse)
2704
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2705
0
              "    Reading PNG oFFs chunk: x: %.17g, y: %.17g.",(double)
2706
0
              image->page.x,(double) image->page.y);
2707
44
    }
2708
31.6k
#endif
2709
31.6k
#if defined(PNG_pHYs_SUPPORTED)
2710
31.6k
  if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2711
43.5k
    {
2712
43.5k
      if (mng_info->have_global_phys != MagickFalse)
2713
149
        {
2714
149
          png_set_pHYs(ping,ping_info,
2715
149
                       mng_info->global_x_pixels_per_unit,
2716
149
                       mng_info->global_y_pixels_per_unit,
2717
149
                       (int) mng_info->global_phys_unit_type);
2718
149
        }
2719
43.5k
    }
2720
2721
31.6k
  x_resolution=0;
2722
31.6k
  y_resolution=0;
2723
31.6k
  unit_type=0;
2724
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2725
351
    {
2726
      /*
2727
        Set image resolution.
2728
      */
2729
351
      (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2730
351
        &unit_type);
2731
351
      image->resolution.x=(double) x_resolution;
2732
351
      image->resolution.y=(double) y_resolution;
2733
2734
351
      if (unit_type == PNG_RESOLUTION_METER)
2735
152
        {
2736
152
          image->units=PixelsPerCentimeterResolution;
2737
152
          image->resolution.x=(double) x_resolution/100.0;
2738
152
          image->resolution.y=(double) y_resolution/100.0;
2739
152
        }
2740
2741
351
      if (logging != MagickFalse)
2742
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2743
0
          "    Reading PNG pHYs chunk: xres: %.17g, yres: %.17g, units: %d.",
2744
0
          (double) x_resolution,(double) y_resolution,unit_type);
2745
351
    }
2746
31.6k
#endif
2747
2748
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2749
1.72k
    {
2750
1.72k
      png_colorp
2751
1.72k
        palette = (png_colorp) NULL;
2752
2753
1.72k
      (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2754
2755
1.72k
      if ((number_colors == 0) &&
2756
37
          ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2757
0
        {
2758
0
          if (mng_info->global_plte_length)
2759
0
            {
2760
0
              png_set_PLTE(ping,ping_info,mng_info->global_plte,
2761
0
                (int) mng_info->global_plte_length);
2762
2763
0
              if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2764
0
              {
2765
0
                if (mng_info->global_trns_length)
2766
0
                  {
2767
0
                    png_warning(ping,
2768
0
                      "global tRNS has more entries than global PLTE");
2769
0
                  }
2770
0
                else
2771
0
                  {
2772
0
                     png_set_tRNS(ping,ping_info,mng_info->global_trns,
2773
0
                       (int) mng_info->global_trns_length,NULL);
2774
0
                  }
2775
0
               }
2776
0
#ifdef PNG_READ_bKGD_SUPPORTED
2777
0
              if (
2778
0
                   png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2779
0
                    {
2780
0
                      png_color_16
2781
0
                         background = { 0, 0, 0, 0, 0 };
2782
2783
0
                      if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2784
0
                        background.index=ping_background->index;
2785
2786
0
                      if (background.index >= mng_info->global_plte_length)
2787
0
                        png_error(ping,"bKGD index exceeds global PLTE");
2788
0
                      else
2789
0
                        {
2790
0
                          background.red=(png_uint_16)
2791
0
                            mng_info->global_plte[background.index].red;
2792
2793
0
                          background.green=(png_uint_16)
2794
0
                            mng_info->global_plte[background.index].green;
2795
2796
0
                          background.blue=(png_uint_16)
2797
0
                            mng_info->global_plte[background.index].blue;
2798
2799
0
                          background.gray=(png_uint_16)
2800
0
                            mng_info->global_plte[background.index].green;
2801
2802
0
                          png_set_bKGD(ping,ping_info,&background);
2803
0
                       }
2804
0
                    }
2805
0
#endif
2806
0
                }
2807
0
              else
2808
0
                png_error(ping,"No global PLTE in file");
2809
0
            }
2810
1.72k
        }
2811
2812
31.6k
#ifdef PNG_READ_bKGD_SUPPORTED
2813
31.6k
  if (mng_info->have_global_bkgd != MagickFalse &&
2814
207
          (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2815
207
      image->background_color=mng_info->mng_global_bkgd;
2816
2817
31.6k
  if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2818
222
    {
2819
222
      unsigned int
2820
222
        bkgd_scale;
2821
2822
      /* Set image background color.
2823
       * Scale background components to 16-bit, then scale
2824
       * to quantum depth
2825
       */
2826
2827
222
        bkgd_scale = 1;
2828
2829
222
        if (ping_bit_depth == 1)
2830
0
           bkgd_scale = 255;
2831
2832
222
        else if (ping_bit_depth == 2)
2833
0
           bkgd_scale = 85;
2834
2835
222
        else if (ping_bit_depth == 4)
2836
0
           bkgd_scale = 17;
2837
2838
222
        if (ping_bit_depth <= 8)
2839
185
           bkgd_scale *= 257;
2840
2841
222
        ping_background->red *= (png_uint_16) bkgd_scale;
2842
222
        ping_background->green *= (png_uint_16) bkgd_scale;
2843
222
        ping_background->blue *= (png_uint_16) bkgd_scale;
2844
2845
222
        if (logging != MagickFalse)
2846
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2847
0
              "    Reading PNG bKGD chunk, raw ping_background=(%d,%d,%d)\n"
2848
0
              "    bkgd_scale=%d.  ping_background=(%d,%d,%d)",
2849
0
              ping_background->red,ping_background->green,
2850
0
              ping_background->blue,bkgd_scale,ping_background->red,
2851
0
              ping_background->green,ping_background->blue);
2852
2853
222
        image->background_color.red=
2854
222
            ScaleShortToQuantum(ping_background->red);
2855
2856
222
        image->background_color.green=
2857
222
            ScaleShortToQuantum(ping_background->green);
2858
2859
222
        image->background_color.blue=
2860
222
          ScaleShortToQuantum(ping_background->blue);
2861
2862
222
        image->background_color.alpha=OpaqueAlpha;
2863
2864
222
        if (logging != MagickFalse)
2865
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2866
0
            "    image->background_color=(%.17g,%.17g,%.17g).",
2867
0
            (double) image->background_color.red,
2868
0
            (double) image->background_color.green,
2869
0
            (double) image->background_color.blue);
2870
222
    }
2871
31.6k
#endif /* PNG_READ_bKGD_SUPPORTED */
2872
2873
31.6k
  if ((png_get_valid(ping,ping_info,PNG_INFO_tRNS)) &&
2874
1.35k
      (ping_trans_color != (png_color_16p) NULL))
2875
1.35k
    {
2876
      /*
2877
        Image has a tRNS chunk.
2878
      */
2879
1.35k
      int
2880
1.35k
        max_sample;
2881
2882
1.35k
      size_t
2883
1.35k
        one = 1;
2884
2885
1.35k
      if (logging != MagickFalse)
2886
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2887
0
          "    Reading PNG tRNS chunk.");
2888
2889
1.35k
      max_sample = (int) ((one << ping_file_depth) - 1);
2890
2891
1.35k
      if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2892
474
          (int)ping_trans_color->gray > max_sample) ||
2893
1.27k
          (ping_color_type == PNG_COLOR_TYPE_RGB &&
2894
598
          ((int)ping_trans_color->red > max_sample ||
2895
550
          (int)ping_trans_color->green > max_sample ||
2896
515
          (int)ping_trans_color->blue > max_sample)))
2897
214
        {
2898
214
          if (logging != MagickFalse)
2899
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2900
0
              "    Ignoring PNG tRNS chunk with out-of-range sample.");
2901
214
          png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2902
214
          png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2903
214
          image->alpha_trait=UndefinedPixelTrait;
2904
214
        }
2905
1.13k
      else
2906
1.13k
        {
2907
1.13k
          int
2908
1.13k
            scale_to_short;
2909
2910
1.13k
          scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2911
2912
          /* Scale transparent_color to short */
2913
1.13k
          transparent_color.red= scale_to_short*ping_trans_color->red;
2914
1.13k
          transparent_color.green= scale_to_short*ping_trans_color->green;
2915
1.13k
          transparent_color.blue= scale_to_short*ping_trans_color->blue;
2916
1.13k
          transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2917
2918
1.13k
          if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2919
394
            {
2920
394
              if (logging != MagickFalse)
2921
0
              {
2922
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2923
0
                  "    Raw tRNS graylevel = %d, scaled graylevel = %d.",
2924
0
                  (int) ping_trans_color->gray,(int) transparent_color.alpha);
2925
2926
0
              }
2927
394
              transparent_color.red=transparent_color.alpha;
2928
394
              transparent_color.green=transparent_color.alpha;
2929
394
              transparent_color.blue=transparent_color.alpha;
2930
394
            }
2931
1.13k
        }
2932
1.35k
    }
2933
31.6k
#if defined(PNG_READ_sBIT_SUPPORTED)
2934
31.6k
  if (mng_info->have_global_sbit != MagickFalse)
2935
109
    {
2936
109
      if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2937
109
        png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2938
109
    }
2939
31.6k
#endif
2940
31.6k
  num_passes=png_set_interlace_handling(ping);
2941
2942
31.6k
  png_read_update_info(ping,ping_info);
2943
2944
31.6k
  ping_rowbytes=png_get_rowbytes(ping,ping_info);
2945
2946
  /*
2947
    Initialize image structure.
2948
  */
2949
31.6k
  mng_info->image_box.left=0;
2950
31.6k
  mng_info->image_box.right=(ssize_t) ping_width;
2951
31.6k
  mng_info->image_box.top=0;
2952
31.6k
  mng_info->image_box.bottom=(ssize_t) ping_height;
2953
31.6k
  if (mng_info->mng_type == 0)
2954
41.1k
    {
2955
41.1k
      mng_info->mng_width=ping_width;
2956
41.1k
      mng_info->mng_height=ping_height;
2957
41.1k
      mng_info->frame=mng_info->image_box;
2958
41.1k
      mng_info->clip=mng_info->image_box;
2959
41.1k
    }
2960
2961
18.4E
  else
2962
18.4E
    {
2963
18.4E
      image->page.y=mng_info->y_off[mng_info->object_id];
2964
18.4E
    }
2965
2966
31.6k
  image->compression=ZipCompression;
2967
31.6k
  image->columns=ping_width;
2968
31.6k
  image->rows=ping_height;
2969
2970
31.6k
  if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2971
12.7k
      ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2972
32.1k
    {
2973
32.1k
      double
2974
32.1k
        image_gamma = image->gamma;
2975
2976
32.1k
      if (logging != MagickFalse)
2977
0
        (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2978
0
           "    image->gamma=%g",image_gamma);
2979
2980
32.1k
      if (image_gamma > 0.75)
2981
213
        {
2982
          /* Set image->rendering_intent to Undefined,
2983
           * image->colorspace to GRAY, and reset image->chromaticity.
2984
           */
2985
213
          SetImageColorspace(image,LinearGRAYColorspace,exception);
2986
213
        }
2987
31.9k
      else
2988
31.9k
        {
2989
31.9k
          RenderingIntent
2990
31.9k
            save_rendering_intent = image->rendering_intent;
2991
31.9k
          ChromaticityInfo
2992
31.9k
            save_chromaticity = image->chromaticity;
2993
2994
31.9k
          SetImageColorspace(image,GRAYColorspace,exception);
2995
31.9k
          image->rendering_intent = save_rendering_intent;
2996
31.9k
          image->chromaticity = save_chromaticity;
2997
31.9k
        }
2998
2999
32.1k
      image->gamma = image_gamma;
3000
32.1k
    }
3001
18.4E
  else
3002
18.4E
    {
3003
18.4E
      double
3004
18.4E
        image_gamma = image->gamma;
3005
3006
18.4E
      if (logging != MagickFalse)
3007
0
        (void)LogMagickEvent(CoderEvent,GetMagickModule(),
3008
0
           "    image->gamma=%g",image_gamma);
3009
3010
18.4E
      if (image_gamma > 0.75)
3011
417
        {
3012
          /* Set image->rendering_intent to Undefined,
3013
           * image->colorspace to GRAY, and reset image->chromaticity.
3014
           */
3015
417
          image->intensity = Rec709LuminancePixelIntensityMethod;
3016
417
          SetImageColorspace(image,RGBColorspace,exception);
3017
417
        }
3018
18.4E
      else
3019
18.4E
        {
3020
18.4E
          RenderingIntent
3021
18.4E
            save_rendering_intent = image->rendering_intent;
3022
18.4E
          ChromaticityInfo
3023
18.4E
            save_chromaticity = image->chromaticity;
3024
3025
18.4E
          if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3026
0
            (void) SetImageColorspace(image,sRGBColorspace,exception);
3027
18.4E
          image->rendering_intent = save_rendering_intent;
3028
18.4E
          image->chromaticity = save_chromaticity;
3029
18.4E
        }
3030
3031
18.4E
      image->gamma = image_gamma;
3032
18.4E
    }
3033
3034
31.6k
  if (logging != MagickFalse)
3035
0
    (void)LogMagickEvent(CoderEvent,GetMagickModule(),
3036
0
      "    image->colorspace=%d",(int) image->colorspace);
3037
3038
31.6k
  if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
3039
42.1k
      ((int) ping_bit_depth < 16 &&
3040
32.4k
      (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
3041
26.2k
    {
3042
26.2k
      size_t
3043
26.2k
        one;
3044
3045
26.2k
      image->storage_class=PseudoClass;
3046
26.2k
      one=1;
3047
26.2k
      image->colors=one << ping_file_depth;
3048
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
3049
      if (image->colors > 256)
3050
        image->colors=256;
3051
#else
3052
26.2k
      if (image->colors > 65536L)
3053
0
        image->colors=65536L;
3054
26.2k
#endif
3055
26.2k
      if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3056
1.57k
        {
3057
1.57k
          png_colorp
3058
1.57k
            palette = (png_colorp) NULL;
3059
3060
1.57k
          (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
3061
1.57k
          image->colors=(size_t) number_colors;
3062
3063
1.57k
          if (logging != MagickFalse)
3064
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3065
0
              "    Reading PNG PLTE chunk: number_colors: %d.",number_colors);
3066
1.57k
        }
3067
26.2k
    }
3068
3069
31.6k
  if (image->storage_class == PseudoClass)
3070
26.2k
    {
3071
      /*
3072
        Initialize image colormap.
3073
      */
3074
26.2k
      if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
3075
0
        png_error(ping,"Memory allocation failed");
3076
3077
26.2k
      if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3078
1.57k
        {
3079
1.57k
          png_colorp
3080
1.57k
            palette = (png_colorp) NULL;
3081
3082
1.57k
          (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
3083
3084
29.1k
          for (i=0; i < (ssize_t) number_colors; i++)
3085
27.6k
          {
3086
27.6k
            image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
3087
27.6k
            image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
3088
27.6k
            image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
3089
27.6k
          }
3090
3091
1.57k
          for ( ; i < (ssize_t) image->colors; i++)
3092
0
          {
3093
0
            image->colormap[i].red=0;
3094
0
            image->colormap[i].green=0;
3095
0
            image->colormap[i].blue=0;
3096
0
          }
3097
1.57k
        }
3098
26.2k
    }
3099
3100
   /* Set some properties for reporting by "identify" */
3101
31.6k
    {
3102
31.6k
      char
3103
31.6k
        msg[MagickPathExtent];
3104
3105
     /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
3106
        ping_interlace_method in value */
3107
3108
31.6k
     (void) FormatLocaleString(msg,MagickPathExtent,
3109
31.6k
         "%d, %d",(int) ping_width, (int) ping_height);
3110
31.6k
     (void) SetImageProperty(image,"png:IHDR.width,height",msg,exception);
3111
3112
31.6k
     (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_file_depth);
3113
31.6k
     (void) SetImageProperty(image,"png:IHDR.bit_depth",msg,exception);
3114
3115
31.6k
     (void) FormatLocaleString(msg,MagickPathExtent,"%d (%s)",
3116
31.6k
         (int) ping_color_type,
3117
31.6k
         Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
3118
31.6k
     (void) SetImageProperty(image,"png:IHDR.color_type",msg,exception);
3119
3120
31.6k
     if (ping_interlace_method == 0)
3121
21.8k
       {
3122
21.8k
         (void) FormatLocaleString(msg,MagickPathExtent,"%d (Not interlaced)",
3123
21.8k
            (int) ping_interlace_method);
3124
21.8k
       }
3125
9.81k
     else if (ping_interlace_method == 1)
3126
21.9k
       {
3127
21.9k
         (void) FormatLocaleString(msg,MagickPathExtent,"%d (Adam7 method)",
3128
21.9k
            (int) ping_interlace_method);
3129
21.9k
       }
3130
18.4E
     else
3131
18.4E
       {
3132
18.4E
         (void) FormatLocaleString(msg,MagickPathExtent,"%d (Unknown method)",
3133
18.4E
            (int) ping_interlace_method);
3134
18.4E
       }
3135
31.6k
       (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
3136
3137
31.6k
     if (number_colors != 0)
3138
1.68k
       {
3139
1.68k
         (void) FormatLocaleString(msg,MagickPathExtent,"%d",
3140
1.68k
            (int) number_colors);
3141
1.68k
         (void) SetImageProperty(image,"png:PLTE.number_colors",msg,exception);
3142
1.68k
       }
3143
31.6k
   }
3144
31.6k
#if defined(PNG_tIME_SUPPORTED)
3145
31.6k
   read_tIME_chunk(image,ping,ping_info,exception);
3146
31.6k
#endif
3147
31.6k
#if defined(PNG_READ_eXIf_SUPPORTED)
3148
31.6k
  read_eXIf_chunk(image,ping,ping_info,exception);
3149
31.6k
#endif
3150
3151
3152
  /*
3153
    Read image scanlines.
3154
  */
3155
31.6k
  if (image->delay != 0)
3156
791
    mng_info->scenes_found++;
3157
3158
43.5k
  if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
3159
43.5k
      (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
3160
0
      (image_info->scene+image_info->number_scenes))))
3161
205
    {
3162
      /* This happens later in non-ping decodes */
3163
205
      if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3164
8
        image->storage_class=DirectClass;
3165
205
      image->alpha_trait=
3166
205
        (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3167
200
         ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3168
199
         (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3169
191
        BlendPixelTrait : UndefinedPixelTrait;
3170
3171
205
      if (logging != MagickFalse)
3172
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3173
0
          "    Skipping PNG image data for scene %.17g",(double)
3174
0
          mng_info->scenes_found-1);
3175
205
      png_destroy_read_struct(&ping,&ping_info,&end_info);
3176
3177
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3178
      UnlockSemaphoreInfo(ping_semaphore);
3179
#endif
3180
3181
205
      if (logging != MagickFalse)
3182
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3183
0
          "  exit ReadOnePNGImage().");
3184
3185
205
      return(image);
3186
205
    }
3187
3188
31.4k
  if (logging != MagickFalse)
3189
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3190
0
      "    Reading PNG IDAT chunk(s)");
3191
3192
31.4k
  status=SetImageExtent(image,image->columns,image->rows,exception);
3193
31.4k
  if (status != MagickFalse)
3194
43.0k
    status=ResetImagePixels(image,exception);
3195
31.4k
  if (status == MagickFalse)
3196
497
    {
3197
497
      png_destroy_read_struct(&ping,&ping_info,&end_info);
3198
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3199
      UnlockSemaphoreInfo(ping_semaphore);
3200
#endif
3201
497
      return(DestroyImageList(image));
3202
497
    }
3203
3204
30.9k
  if (num_passes > 1)
3205
21.3k
    pixel_info=AcquireVirtualMemory(image->rows,ping_rowbytes*
3206
21.3k
      sizeof(*ping_pixels));
3207
9.53k
  else
3208
9.53k
    pixel_info=AcquireVirtualMemory(ping_rowbytes,sizeof(*ping_pixels));
3209
3210
30.9k
  if (pixel_info == (MemoryInfo *) NULL)
3211
0
    png_error(ping,"Memory allocation failed");
3212
30.9k
  ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
3213
3214
30.9k
  if (logging != MagickFalse)
3215
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3216
0
      "    Converting PNG pixels to pixel packets");
3217
  /*
3218
    Convert PNG pixels to pixel packets.
3219
  */
3220
30.9k
  quantum_info=AcquireQuantumInfo(image_info,image);
3221
3222
30.9k
  if (quantum_info == (QuantumInfo *) NULL)
3223
0
     png_error(ping,"Failed to allocate quantum_info");
3224
3225
30.9k
  (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3226
3227
30.9k
  {
3228
3229
30.9k
   MagickBooleanType
3230
30.9k
     found_transparent_pixel;
3231
3232
30.9k
  found_transparent_pixel=MagickFalse;
3233
3234
30.9k
  if ((image->storage_class == DirectClass) ||
3235
25.7k
      (image_info->stream != (StreamHandler) NULL))
3236
17.5k
    {
3237
64.0k
      for (pass=0; pass < num_passes; pass++)
3238
46.5k
      {
3239
        /*
3240
          Convert image to DirectClass pixel packets.
3241
        */
3242
46.5k
        image->alpha_trait=
3243
46.5k
            (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3244
23.6k
            ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3245
20.8k
            (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3246
27.3k
            BlendPixelTrait : UndefinedPixelTrait;
3247
3248
2.07M
        for (y=0; y < (ssize_t) image->rows; y++)
3249
2.03M
        {
3250
2.03M
          if (num_passes > 1)
3251
1.75M
            row_offset=ping_rowbytes*(size_t) y;
3252
3253
278k
          else
3254
278k
            row_offset=0;
3255
3256
2.03M
          png_read_row(ping,ping_pixels+row_offset,NULL);
3257
3258
2.03M
          if (pass < num_passes-1)
3259
1.63M
            continue;
3260
3261
391k
          q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3262
3263
391k
          if (q == (Quantum *) NULL)
3264
0
            break;
3265
3266
391k
          if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3267
182k
            (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3268
182k
              GrayQuantum,ping_pixels+row_offset,exception);
3269
3270
209k
          else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3271
32.6k
            (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3272
32.6k
              GrayAlphaQuantum,ping_pixels+row_offset,exception);
3273
3274
176k
          else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3275
69.9k
            (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3276
69.9k
              RGBAQuantum,ping_pixels+row_offset,exception);
3277
3278
106k
          else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3279
0
            (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3280
0
              IndexQuantum,ping_pixels+row_offset,exception);
3281
3282
106k
          else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3283
106k
            (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3284
106k
              RGBQuantum,ping_pixels+row_offset,exception);
3285
3286
391k
          if (found_transparent_pixel == MagickFalse)
3287
283k
            {
3288
              /* Is there a transparent pixel in the row? */
3289
283k
              if (y== 0 && logging != MagickFalse)
3290
0
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3291
0
                   "    Looking for cheap transparent pixel");
3292
3293
25.4M
              for (x=(ssize_t) image->columns-1; x >= 0; x--)
3294
25.1M
              {
3295
25.1M
                if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3296
25.0M
                    ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3297
172k
                   (GetPixelAlpha(image,q) != OpaqueAlpha))
3298
5.06k
                  {
3299
5.06k
                    if (logging != MagickFalse)
3300
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3301
0
                        "    ...got one.");
3302
3303
5.06k
                    found_transparent_pixel = MagickTrue;
3304
5.06k
                    break;
3305
5.06k
                  }
3306
25.1M
                if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3307
5.46M
                    ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3308
25.0M
                    (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3309
25.0M
                    transparent_color.red &&
3310
27.3k
                    ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3311
27.3k
                    transparent_color.green &&
3312
12.4k
                    ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3313
12.4k
                    transparent_color.blue))
3314
176
                  {
3315
176
                    if (logging != MagickFalse)
3316
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3317
0
                        "    ...got one.");
3318
176
                    found_transparent_pixel = MagickTrue;
3319
176
                    break;
3320
176
                  }
3321
25.1M
                q+=(ptrdiff_t) GetPixelChannels(image);
3322
25.1M
              }
3323
283k
            }
3324
3325
391k
          if (num_passes == 1)
3326
274k
            {
3327
274k
              status=SetImageProgress(image,LoadImageTag,
3328
274k
                  (MagickOffsetType) y, image->rows);
3329
3330
274k
              if (status == MagickFalse)
3331
0
                break;
3332
274k
            }
3333
391k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
3334
0
            break;
3335
391k
        }
3336
46.5k
        if (y < (long) image->rows)
3337
0
          break;
3338
3339
46.5k
        if (num_passes != 1)
3340
32.7k
          {
3341
32.7k
            status=SetImageProgress(image,LoadImageTag,pass,(MagickSizeType)
3342
32.7k
              num_passes);
3343
32.7k
            if (status == MagickFalse)
3344
0
              break;
3345
32.7k
          }
3346
46.5k
      }
3347
17.5k
    }
3348
3349
13.4k
  else /* image->storage_class != DirectClass */
3350
3351
119k
    for (pass=0; pass < num_passes; pass++)
3352
109k
    {
3353
109k
      Quantum
3354
109k
        *r;
3355
3356
      /*
3357
        Convert grayscale image to PseudoClass pixel packets.
3358
      */
3359
109k
      if (logging != MagickFalse)
3360
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3361
0
          "    Converting grayscale pixels to pixel packets");
3362
3363
109k
      image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3364
109k
        BlendPixelTrait : UndefinedPixelTrait;
3365
3366
109k
      quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3367
109k
        (image->alpha_trait  == BlendPixelTrait?  2 : 1)*
3368
109k
        sizeof(*quantum_scanline));
3369
3370
109k
      if (quantum_scanline == (Quantum *) NULL)
3371
0
        png_error(ping,"Memory allocation failed");
3372
3373
979k
      for (y=0; y < (ssize_t) image->rows; y++)
3374
873k
      {
3375
873k
        Quantum
3376
873k
           alpha;
3377
3378
873k
        if (num_passes > 1)
3379
652k
          row_offset=ping_rowbytes*(size_t) y;
3380
3381
221k
        else
3382
221k
          row_offset=0;
3383
3384
873k
        png_read_row(ping,ping_pixels+row_offset,NULL);
3385
3386
873k
        if (pass < num_passes-1)
3387
596k
          continue;
3388
3389
277k
        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3390
3391
277k
        if (q == (Quantum *) NULL)
3392
0
          break;
3393
3394
277k
        p=ping_pixels+row_offset;
3395
277k
        r=quantum_scanline;
3396
3397
277k
        switch (ping_bit_depth)
3398
277k
        {
3399
272k
          case 8:
3400
272k
          {
3401
3402
272k
            if (ping_color_type == 4)
3403
0
              for (x=(ssize_t) image->columns-1; x >= 0; x--)
3404
0
              {
3405
0
                *r++=*p++;
3406
3407
0
                alpha=ScaleCharToQuantum((unsigned char)*p++);
3408
3409
0
                SetPixelAlpha(image,alpha,q);
3410
3411
0
                if (alpha != OpaqueAlpha)
3412
0
                  found_transparent_pixel = MagickTrue;
3413
3414
0
                q+=(ptrdiff_t) GetPixelChannels(image);
3415
0
              }
3416
3417
272k
            else
3418
26.6M
              for (x=(ssize_t) image->columns-1; x >= 0; x--)
3419
26.3M
                *r++=*p++;
3420
3421
272k
            break;
3422
0
          }
3423
3424
0
          case 16:
3425
0
          {
3426
0
            for (x=(ssize_t) image->columns-1; x >= 0; x--)
3427
0
            {
3428
0
#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
3429
0
              unsigned long
3430
0
                quantum;
3431
3432
0
              if (image->colors > 256)
3433
0
                quantum=(((unsigned int) *p++) << 8);
3434
3435
0
              else
3436
0
                quantum=0;
3437
3438
0
              quantum|=(*p++);
3439
0
              *r=ScaleShortToQuantum((unsigned short) quantum);
3440
0
              r++;
3441
3442
0
              if (ping_color_type == 4)
3443
0
                {
3444
0
                  if (image->colors > 256)
3445
0
                    quantum=(((unsigned int) *p++) << 8);
3446
0
                  else
3447
0
                    quantum=0;
3448
3449
0
                  quantum|=(*p++);
3450
3451
0
                  alpha=ScaleShortToQuantum((unsigned short) quantum);
3452
0
                  SetPixelAlpha(image,alpha,q);
3453
3454
0
                  if (alpha != OpaqueAlpha)
3455
0
                    found_transparent_pixel = MagickTrue;
3456
3457
0
                  q+=(ptrdiff_t) GetPixelChannels(image);
3458
0
                }
3459
3460
#else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3461
              *r++=(*p++);
3462
              p++; /* strip low byte */
3463
3464
              if (ping_color_type == 4)
3465
                {
3466
                  SetPixelAlpha(image,*p++,q);
3467
3468
                  if (GetPixelAlpha(image,q) != OpaqueAlpha)
3469
                    found_transparent_pixel = MagickTrue;
3470
3471
                  p++;
3472
                  q+=(ptrdiff_t) GetPixelChannels(image);
3473
                }
3474
#endif
3475
0
            }
3476
3477
0
            break;
3478
0
          }
3479
3480
0
          default:
3481
0
            break;
3482
277k
        }
3483
3484
272k
        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3485
0
          break;
3486
3487
        /*
3488
          Transfer image scanline.
3489
        */
3490
272k
        r=quantum_scanline;
3491
3492
272k
        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3493
3494
272k
        if (q == (Quantum *) NULL)
3495
0
          break;
3496
26.6M
        for (x=0; x < (ssize_t) image->columns; x++)
3497
26.3M
        {
3498
26.3M
          ssize_t index=ConstrainColormapIndex(image,(ssize_t) *r,exception);
3499
26.3M
          SetPixelRed(image,ClampToQuantum(image->colormap[index].red),q);
3500
26.3M
          SetPixelGreen(image,ClampToQuantum(image->colormap[index].green),q);
3501
26.3M
          SetPixelBlue(image,ClampToQuantum(image->colormap[index].blue),q);
3502
26.3M
          SetPixelIndex(image,(Quantum) index,q);
3503
26.3M
          r++;
3504
26.3M
          q+=(ptrdiff_t) GetPixelChannels(image);
3505
26.3M
        }
3506
3507
272k
        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3508
0
          break;
3509
3510
272k
        if (num_passes == 1)
3511
219k
          {
3512
219k
            status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3513
219k
              image->rows);
3514
3515
219k
            if (status == MagickFalse)
3516
0
              break;
3517
219k
          }
3518
272k
      }
3519
105k
      quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3520
105k
      if (y < (long) image->rows)
3521
0
        break;
3522
105k
      if (num_passes != 1)
3523
97.5k
        {
3524
97.5k
          status=SetImageProgress(image,LoadImageTag,pass,(MagickSizeType)
3525
97.5k
            num_passes);
3526
3527
97.5k
          if (status == MagickFalse)
3528
0
            break;
3529
97.5k
        }
3530
105k
    }
3531
3532
26.8k
    image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3533
26.8k
      UndefinedPixelTrait;
3534
3535
26.8k
    if (logging != MagickFalse)
3536
0
      {
3537
0
        if (found_transparent_pixel != MagickFalse)
3538
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3539
0
            "    Found transparent pixel");
3540
0
        else
3541
0
          {
3542
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3543
0
              "    No transparent pixel was found");
3544
3545
0
            ping_color_type&=0x03;
3546
0
          }
3547
0
      }
3548
26.8k
  }
3549
0
  quantum_info=DestroyQuantumInfo(quantum_info);
3550
3551
26.8k
  png_read_end(ping,end_info);
3552
3553
26.8k
  if (logging != MagickFalse)
3554
0
  {
3555
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3556
0
       "  image->storage_class=%d\n",(int) image->storage_class);
3557
0
  }
3558
3559
26.8k
  if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3560
0
      (ssize_t) image_info->scene && image->delay != 0)
3561
0
    {
3562
0
      png_destroy_read_struct(&ping,&ping_info,&end_info);
3563
0
      pixel_info=RelinquishVirtualMemory(pixel_info);
3564
0
      if (AcquireImageColormap(image,2,exception) == MagickFalse)
3565
0
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3566
0
      (void) SetImageBackgroundColor(image,exception);
3567
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3568
      UnlockSemaphoreInfo(ping_semaphore);
3569
#endif
3570
0
      if (logging != MagickFalse)
3571
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3572
0
          "  exit ReadOnePNGImage() early.");
3573
0
      return(image);
3574
0
    }
3575
3576
26.8k
  if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3577
575
    {
3578
575
      ClassType
3579
575
        storage_class;
3580
3581
      /*
3582
        Image has a transparent background.
3583
      */
3584
575
      storage_class=image->storage_class;
3585
575
      image->alpha_trait=BlendPixelTrait;
3586
3587
/* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3588
3589
575
      if (storage_class == PseudoClass)
3590
323
        {
3591
323
          if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3592
113
            {
3593
2.50k
              for (x=0; x < ping_num_trans; x++)
3594
2.38k
              {
3595
2.38k
                 image->colormap[x].alpha_trait=BlendPixelTrait;
3596
2.38k
                 image->colormap[x].alpha=OpaqueAlpha;
3597
2.38k
                 if (ping_trans_alpha != (png_bytep) NULL)
3598
2.38k
                   image->colormap[x].alpha=ScaleCharToQuantum(
3599
2.38k
                     (unsigned char) ping_trans_alpha[x]);
3600
2.38k
              }
3601
113
            }
3602
3603
210
          else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3604
210
            {
3605
4.41k
              for (x=0; x < (int) image->colors; x++)
3606
4.20k
              {
3607
4.20k
                 if (ScaleQuantumToShort((Quantum) image->colormap[x].red) ==
3608
4.20k
                     transparent_color.alpha)
3609
210
                 {
3610
210
                    image->colormap[x].alpha_trait=BlendPixelTrait;
3611
210
                    image->colormap[x].alpha = (Quantum) TransparentAlpha;
3612
210
                 }
3613
4.20k
              }
3614
210
            }
3615
323
          (void) SyncImage(image,exception);
3616
323
        }
3617
3618
252
#if 1 /* Should have already been done above, but glennrp problem P10
3619
       * needs this.
3620
       */
3621
252
      else
3622
252
        {
3623
10.5k
          for (y=0; y < (ssize_t) image->rows; y++)
3624
10.2k
          {
3625
10.2k
            image->storage_class=storage_class;
3626
10.2k
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3627
3628
10.2k
            if (q == (Quantum *) NULL)
3629
0
              break;
3630
3631
3632
            /* Caution: on a Q8 build, this does not distinguish between
3633
             * 16-bit colors that differ only in the low byte
3634
             */
3635
531k
            for (x=(ssize_t) image->columns-1; x >= 0; x--)
3636
521k
            {
3637
521k
              if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3638
521k
                  transparent_color.red &&
3639
71.3k
                  ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3640
71.3k
                  transparent_color.green &&
3641
69.3k
                  ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3642
69.3k
                  transparent_color.blue)
3643
67.3k
                {
3644
67.3k
                  SetPixelAlpha(image,TransparentAlpha,q);
3645
67.3k
                }
3646
454k
              else
3647
454k
                {
3648
454k
                  SetPixelAlpha(image,OpaqueAlpha,q);
3649
454k
                }
3650
3651
521k
              q+=(ptrdiff_t) GetPixelChannels(image);
3652
521k
            }
3653
3654
10.2k
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
3655
0
               break;
3656
10.2k
          }
3657
252
        }
3658
575
#endif
3659
575
    }
3660
3661
88.7k
  for (j = 0; j < 2; j++)
3662
61.8k
  {
3663
61.8k
    if (j == 0)
3664
30.9k
      status=png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3665
30.3k
        MagickTrue : MagickFalse;
3666
30.9k
    else
3667
30.9k
      status=png_get_text(ping,end_info,&text,&num_text) != 0 ?
3668
30.3k
        MagickTrue : MagickFalse;
3669
3670
61.8k
    if (status != MagickFalse)
3671
33.5k
      for (i=0; i < (ssize_t) num_text; i++)
3672
32.3k
      {
3673
        /* Check for a profile */
3674
3675
32.3k
        if (logging != MagickFalse)
3676
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3677
0
            "    Reading PNG text chunk");
3678
3679
32.3k
        if (strlen(text[i].key) > 16 &&
3680
457
            memcmp(text[i].key, "Raw profile type ",17) == 0)
3681
5
          {
3682
5
            const char
3683
5
              *value;
3684
3685
5
            value=GetImageOption(image_info,"profile:skip");
3686
3687
5
            if (IsOptionMember(text[i].key+17,value) == MagickFalse)
3688
5
            {
3689
5
               (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3690
5
                  (int) i,exception);
3691
5
               num_raw_profiles++;
3692
5
               if (logging != MagickFalse)
3693
0
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3694
0
                   "    Read raw profile %s",text[i].key+17);
3695
5
            }
3696
0
            else
3697
0
            {
3698
0
               if (logging != MagickFalse)
3699
0
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3700
0
                   "    Skipping raw profile %s",text[i].key+17);
3701
0
            }
3702
5
          }
3703
3704
32.3k
        else
3705
32.3k
          {
3706
32.3k
            char
3707
32.3k
              *value;
3708
3709
32.3k
            length=text[i].text_length;
3710
32.3k
            value=(char *) AcquireQuantumMemory(length+MagickPathExtent,
3711
32.3k
              sizeof(*value));
3712
32.3k
            if (value == (char *) NULL)
3713
0
              {
3714
0
                png_error(ping,"Memory allocation failed");
3715
0
                break;
3716
0
              }
3717
32.3k
            *value='\0';
3718
32.3k
            (void) ConcatenateMagickString(value,text[i].text,length+2);
3719
3720
            /* Don't save "density" or "units" property if we have a pHYs
3721
             * chunk
3722
             */
3723
32.3k
            if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3724
1.13k
                (LocaleCompare(text[i].key,"density") != 0 &&
3725
1.13k
                LocaleCompare(text[i].key,"units") != 0))
3726
32.3k
              {
3727
32.3k
                char
3728
32.3k
                  key[MagickPathExtent];
3729
3730
32.3k
                (void) FormatLocaleString(key,MagickPathExtent,"%s",
3731
32.3k
                  text[i].key);
3732
32.3k
                if ((LocaleCompare(key,"version") == 0) ||
3733
32.3k
                    (LocaleCompare(key,"width") == 0))
3734
0
                  (void) FormatLocaleString(key,MagickPathExtent,"png:%s",
3735
0
                    text[i].key);
3736
32.3k
                (void) SetImageProperty(image,key,value,exception);
3737
32.3k
              }
3738
3739
32.3k
            if (logging != MagickFalse)
3740
0
            {
3741
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3742
0
                "      length: %lu\n"
3743
0
                "      Keyword: %s",
3744
0
                (unsigned long) length,
3745
0
                text[i].key);
3746
0
            }
3747
3748
32.3k
            value=DestroyString(value);
3749
32.3k
          }
3750
32.3k
      }
3751
61.8k
    num_text_total += num_text;
3752
61.8k
  }
3753
3754
  /* Set image->alpha_trait to MagickTrue if the input colortype supports
3755
  * alpha or if a valid tRNS chunk is present, no matter whether there
3756
  * is actual transparency present.
3757
  */
3758
26.8k
  image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3759
26.9k
      ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3760
26.8k
      (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3761
22.1k
      BlendPixelTrait : UndefinedPixelTrait;
3762
26.8k
  if (((image->alpha_trait & BlendPixelTrait) != 0) ||
3763
26.2k
      ((image->alpha_trait & UpdatePixelTrait) != 0))
3764
4.68k
    {
3765
4.68k
      if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3766
107
        image->type=GrayscaleAlphaType;
3767
4.58k
      else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3768
113
        image->type=PaletteAlphaType;
3769
4.46k
      else
3770
4.46k
        image->type=TrueColorAlphaType;
3771
4.68k
    }
3772
22.1k
  else
3773
22.1k
    {
3774
22.1k
      if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3775
24.2k
        image->type=GrayscaleType;
3776
18.4E
      else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3777
920
        image->type=PaletteType;
3778
18.4E
      else
3779
18.4E
        image->type=TrueColorType;
3780
22.1k
    }
3781
3782
   /* Set more properties for identify to retrieve */
3783
26.8k
   {
3784
26.8k
     char
3785
26.8k
       msg[MagickPathExtent];
3786
3787
26.8k
     if (num_text_total != 0)
3788
955
       {
3789
         /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3790
955
         (void) FormatLocaleString(msg,MagickPathExtent,
3791
955
            "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3792
955
         (void) SetImageProperty(image,"png:text",msg,exception);
3793
955
       }
3794
3795
26.8k
     if (num_raw_profiles != 0)
3796
5
       {
3797
5
         (void) FormatLocaleString(msg,MagickPathExtent,
3798
5
            "%d were found", num_raw_profiles);
3799
5
         (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3800
5
                exception);
3801
5
       }
3802
3803
     /* cHRM chunk: */
3804
26.8k
     if (ping_found_cHRM != MagickFalse)
3805
87
       {
3806
87
         (void) FormatLocaleString(msg,MagickPathExtent,"%s",
3807
87
            "chunk was found (see Chromaticity, above)");
3808
87
         (void) SetImageProperty(image,"png:cHRM",msg,exception);
3809
87
       }
3810
3811
     /* bKGD chunk: */
3812
26.8k
     if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3813
168
       {
3814
168
         (void) FormatLocaleString(msg,MagickPathExtent,"%s",
3815
168
            "chunk was found (see Background color, above)");
3816
168
         (void) SetImageProperty(image,"png:bKGD",msg,exception);
3817
168
       }
3818
3819
26.8k
     (void) FormatLocaleString(msg,MagickPathExtent,"%s",
3820
26.8k
        "chunk was found");
3821
3822
26.8k
#if defined(PNG_iCCP_SUPPORTED)
3823
     /* iCCP chunk: */
3824
26.8k
     if (ping_found_iCCP != MagickFalse)
3825
3.42k
        (void) SetImageProperty(image,"png:iCCP",msg,exception);
3826
26.8k
#endif
3827
3828
26.8k
     if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3829
575
        (void) SetImageProperty(image,"png:tRNS",msg,exception);
3830
3831
26.8k
#if defined(PNG_sRGB_SUPPORTED)
3832
     /* sRGB chunk: */
3833
26.8k
     if (ping_found_sRGB != MagickFalse)
3834
165
       {
3835
165
         (void) FormatLocaleString(msg,MagickPathExtent,
3836
165
            "intent=%d (%s)",
3837
165
            (int) intent,
3838
165
            Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3839
165
         (void) SetImageProperty(image,"png:sRGB",msg,exception);
3840
165
       }
3841
26.8k
#endif
3842
3843
     /* gAMA chunk: */
3844
26.8k
     if (ping_found_gAMA != MagickFalse)
3845
403
       {
3846
403
         (void) FormatLocaleString(msg,MagickPathExtent,
3847
403
            "gamma=%.8g (See Gamma, above)",
3848
403
            file_gamma);
3849
403
         (void) SetImageProperty(image,"png:gAMA",msg,exception);
3850
403
       }
3851
3852
26.8k
#if defined(PNG_pHYs_SUPPORTED)
3853
     /* pHYs chunk: */
3854
26.8k
     if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3855
295
       {
3856
295
         (void) FormatLocaleString(msg,MagickPathExtent,
3857
295
            "x_res=%.10g, y_res=%.10g, units=%d",
3858
295
            (double) x_resolution,(double) y_resolution, unit_type);
3859
295
         (void) SetImageProperty(image,"png:pHYs",msg,exception);
3860
295
       }
3861
26.8k
#endif
3862
3863
26.8k
#if defined(PNG_oFFs_SUPPORTED)
3864
     /* oFFs chunk: */
3865
26.8k
     if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3866
29
       {
3867
29
         (void) FormatLocaleString(msg,MagickPathExtent,
3868
29
            "x_off=%.17g, y_off=%.17g",
3869
29
            (double) image->page.x,(double) image->page.y);
3870
29
         (void) SetImageProperty(image,"png:oFFs",msg,exception);
3871
29
       }
3872
26.8k
#endif
3873
3874
26.8k
#if defined(PNG_tIME_SUPPORTED)
3875
26.8k
     read_tIME_chunk(image,ping,end_info,exception);
3876
26.8k
#endif
3877
26.8k
#if defined(PNG_READ_eXIf_SUPPORTED)
3878
26.8k
    read_eXIf_chunk(image,ping,end_info,exception);
3879
26.8k
#endif
3880
3881
     /* caNv chunk: */
3882
26.8k
     if ((image->page.width != 0 && image->page.width != image->columns) ||
3883
27.6k
         (image->page.height != 0 && image->page.height != image->rows) ||
3884
26.4k
         (image->page.x != 0 || image->page.y != 0))
3885
5.94k
       {
3886
5.94k
         (void) FormatLocaleString(msg,MagickPathExtent,
3887
5.94k
            "width=%.17g, height=%.17g, x_offset=%.17g, y_offset=%.17g",
3888
5.94k
            (double) image->page.width,(double) image->page.height,
3889
5.94k
            (double) image->page.x,(double) image->page.y);
3890
5.94k
         (void) SetImageProperty(image,"png:caNv",msg,exception);
3891
5.94k
       }
3892
26.8k
   }
3893
3894
  /*
3895
    Relinquish resources.
3896
  */
3897
26.8k
  png_destroy_read_struct(&ping,&ping_info,&end_info);
3898
3899
26.8k
  pixel_info=RelinquishVirtualMemory(pixel_info);
3900
3901
26.8k
  if (logging != MagickFalse)
3902
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3903
0
      "  exit ReadOnePNGImage()");
3904
3905
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3906
  UnlockSemaphoreInfo(ping_semaphore);
3907
#endif
3908
3909
  /* }  for navigation to beginning of SETJMP-protected block, revert to
3910
   *    Throwing an Exception when an error occurs.
3911
   */
3912
26.8k
  image->depth=(size_t) ping_file_depth;
3913
26.8k
  return(image);
3914
3915
/* end of reading one PNG image */
3916
26.8k
}
3917
3918
static Image *ReadPNGImage(const ImageInfo *image_info,
3919
  ExceptionInfo *exception)
3920
71.0k
{
3921
71.0k
  Image
3922
71.0k
    *image;
3923
3924
71.0k
  MagickBooleanType
3925
71.0k
    logging = MagickFalse,
3926
71.0k
    status;
3927
3928
71.0k
  MngReadInfo
3929
71.0k
    *mng_info;
3930
3931
71.0k
  char
3932
71.0k
    magic_number[MagickPathExtent];
3933
3934
71.0k
  ssize_t
3935
71.0k
    count;
3936
3937
  /*
3938
    Open image file.
3939
  */
3940
71.0k
  assert(image_info != (const ImageInfo *) NULL);
3941
71.0k
  assert(image_info->signature == MagickCoreSignature);
3942
71.0k
  assert(exception != (ExceptionInfo *) NULL);
3943
71.0k
  assert(exception->signature == MagickCoreSignature);
3944
71.0k
  if (IsEventLogging() != MagickFalse)
3945
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3946
0
      image_info->filename);
3947
71.0k
  image=AcquireImage(image_info,exception);
3948
71.0k
  if (image->debug != MagickFalse)
3949
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3950
71.0k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3951
3952
71.0k
  if (status == MagickFalse)
3953
0
    return(DestroyImageList(image));
3954
3955
  /*
3956
    Verify PNG signature.
3957
  */
3958
71.0k
  count=ReadBlob(image,8,(unsigned char *) magic_number);
3959
3960
71.0k
  if ((count < 8) || (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0))
3961
70.4k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3962
3963
  /*
3964
     Verify that file size large enough to contain a PNG datastream.
3965
  */
3966
70.4k
  if (GetBlobSize(image) < 61)
3967
70.3k
    ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
3968
3969
70.3k
  mng_info=(MngReadInfo *) AcquireMagickMemory(sizeof(*mng_info));
3970
70.3k
  if (mng_info == (MngReadInfo *) NULL)
3971
70.3k
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3972
70.3k
  (void) memset(mng_info,0,sizeof(*mng_info));
3973
70.3k
  mng_info->image=image;
3974
3975
70.3k
  image=ReadOnePNGImage(mng_info,image_info,exception);
3976
70.3k
  mng_info=MngReadInfoFreeStruct(mng_info);
3977
3978
70.3k
  if (image == (Image *) NULL)
3979
53.0k
    {
3980
53.0k
      if (logging != MagickFalse)
3981
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3982
0
          "exit ReadPNGImage() with error");
3983
3984
53.0k
      return((Image *) NULL);
3985
53.0k
    }
3986
3987
17.3k
  (void) CloseBlob(image);
3988
3989
17.3k
  if ((image->columns == 0) || (image->rows == 0))
3990
0
    {
3991
0
      if (logging != MagickFalse)
3992
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3993
0
          "exit ReadPNGImage() with error.");
3994
3995
0
      ThrowReaderException(CorruptImageError,"CorruptImage");
3996
0
    }
3997
3998
17.3k
  if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3999
3.17k
      (image->gamma > .75) &&
4000
1
           !(image->chromaticity.red_primary.x>0.6399 &&
4001
1
           image->chromaticity.red_primary.x<0.6401 &&
4002
1
           image->chromaticity.red_primary.y>0.3299 &&
4003
1
           image->chromaticity.red_primary.y<0.3301 &&
4004
1
           image->chromaticity.green_primary.x>0.2999 &&
4005
1
           image->chromaticity.green_primary.x<0.3001 &&
4006
1
           image->chromaticity.green_primary.y>0.5999 &&
4007
1
           image->chromaticity.green_primary.y<0.6001 &&
4008
1
           image->chromaticity.blue_primary.x>0.1499 &&
4009
1
           image->chromaticity.blue_primary.x<0.1501 &&
4010
1
           image->chromaticity.blue_primary.y>0.0599 &&
4011
1
           image->chromaticity.blue_primary.y<0.0601 &&
4012
1
           image->chromaticity.white_point.x>0.3126 &&
4013
1
           image->chromaticity.white_point.x<0.3128 &&
4014
1
           image->chromaticity.white_point.y>0.3289 &&
4015
1
           image->chromaticity.white_point.y<0.3291))
4016
0
    {
4017
0
      if (logging != MagickFalse)
4018
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4019
0
          "SetImageColorspace to RGBColorspace");
4020
0
      SetImageColorspace(image,RGBColorspace,exception);
4021
0
    }
4022
4023
17.3k
  if (logging != MagickFalse)
4024
0
    {
4025
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4026
0
           "  page.w: %.17g, page.h: %.17g,page.x: %.17g, page.y: %.17g.",
4027
0
               (double) image->page.width,(double) image->page.height,
4028
0
               (double) image->page.x,(double) image->page.y);
4029
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4030
0
           "  image->colorspace: %d", (int) image->colorspace);
4031
0
    }
4032
4033
17.3k
  if (logging != MagickFalse)
4034
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
4035
4036
17.3k
  return(image);
4037
17.3k
}
4038
4039
4040
4041
#if defined(JNG_SUPPORTED)
4042
/*
4043
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4044
%                                                                             %
4045
%                                                                             %
4046
%                                                                             %
4047
%   R e a d O n e J N G I m a g e                                             %
4048
%                                                                             %
4049
%                                                                             %
4050
%                                                                             %
4051
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4052
%
4053
%  ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
4054
%  (minus the 8-byte signature)  and returns it.  It allocates the memory
4055
%  necessary for the new Image structure and returns a pointer to the new
4056
%  image.
4057
%
4058
%  JNG support written by Glenn Randers-Pehrson, glennrp@image...
4059
%
4060
%  The format of the ReadOneJNGImage method is:
4061
%
4062
%      Image *ReadOneJNGImage(MngReadInfo *mng_info,const ImageInfo *image_info,
4063
%         ExceptionInfo *exception)
4064
%
4065
%  A description of each parameter follows:
4066
%
4067
%    o mng_info: Specifies a pointer to a MngReadInfo structure.
4068
%
4069
%    o image_info: the image info.
4070
%
4071
%    o exception: return any errors or warnings in this structure.
4072
%
4073
*/
4074
static void
4075
DestroyJNG(unsigned char *chunk,Image **color_image,
4076
  ImageInfo **color_image_info,Image **alpha_image,
4077
  ImageInfo **alpha_image_info)
4078
10.1k
{
4079
10.1k
  (void) RelinquishMagickMemory(chunk);
4080
10.1k
  if (color_image_info && *color_image_info)
4081
321
  {
4082
321
    DestroyImageInfo(*color_image_info);
4083
321
    *color_image_info = (ImageInfo *)NULL;
4084
321
  }
4085
10.1k
  if (alpha_image_info && *alpha_image_info)
4086
552
  {
4087
552
    DestroyImageInfo(*alpha_image_info);
4088
552
    *alpha_image_info = (ImageInfo *)NULL;
4089
552
  }
4090
10.1k
  if (color_image && *color_image)
4091
321
  {
4092
321
    if (*(*color_image)->filename != '\0')
4093
321
      (void) RelinquishUniqueFileResource((*color_image)->filename);
4094
321
    DestroyImageList(*color_image);
4095
321
    *color_image = (Image *)NULL;
4096
321
  }
4097
10.1k
  if (alpha_image && *alpha_image)
4098
552
  {
4099
552
    if (*(*alpha_image)->filename != '\0')
4100
552
      (void) RelinquishUniqueFileResource((*alpha_image)->filename);
4101
552
    DestroyImageList(*alpha_image);
4102
552
    *alpha_image = (Image *)NULL;
4103
552
  }
4104
10.1k
}
4105
static Image *ReadOneJNGImage(MngReadInfo *mng_info,
4106
  const ImageInfo *image_info,ExceptionInfo *exception)
4107
19.6k
{
4108
19.6k
  Image
4109
19.6k
    *alpha_image,
4110
19.6k
    *color_image,
4111
19.6k
    *image,
4112
19.6k
    *jng_image;
4113
4114
19.6k
  ImageInfo
4115
19.6k
    *alpha_image_info,
4116
19.6k
    *color_image_info;
4117
4118
19.6k
  MagickBooleanType
4119
19.6k
    logging = MagickFalse;
4120
4121
19.6k
  ssize_t
4122
19.6k
    y;
4123
4124
19.6k
  MagickBooleanType
4125
19.6k
    status;
4126
4127
19.6k
  png_uint_32
4128
19.6k
    jng_height,
4129
19.6k
    jng_width;
4130
4131
19.6k
  png_byte
4132
19.6k
    jng_color_type,
4133
19.6k
    jng_image_sample_depth,
4134
19.6k
    jng_image_compression_method,
4135
19.6k
    jng_image_interlace_method,
4136
19.6k
    jng_alpha_sample_depth,
4137
19.6k
    jng_alpha_compression_method,
4138
19.6k
    jng_alpha_filter_method,
4139
19.6k
    jng_alpha_interlace_method;
4140
4141
19.6k
  const Quantum
4142
19.6k
    *s;
4143
4144
19.6k
  ssize_t
4145
19.6k
    i,
4146
19.6k
    x;
4147
4148
19.6k
  Quantum
4149
19.6k
    *q;
4150
4151
19.6k
  unsigned char
4152
19.6k
    *p;
4153
4154
19.6k
  unsigned int
4155
19.6k
    read_JSEP,
4156
19.6k
    reading_idat;
4157
4158
19.6k
  size_t
4159
19.6k
    length;
4160
4161
19.6k
  jng_alpha_compression_method=0;
4162
19.6k
  jng_alpha_sample_depth=8;
4163
19.6k
  jng_color_type=0;
4164
19.6k
  jng_height=0;
4165
19.6k
  jng_width=0;
4166
19.6k
  alpha_image=(Image *) NULL;
4167
19.6k
  color_image=(Image *) NULL;
4168
19.6k
  alpha_image_info=(ImageInfo *) NULL;
4169
19.6k
  color_image_info=(ImageInfo *) NULL;
4170
4171
19.6k
  if (IsEventLogging() != MagickFalse)
4172
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),
4173
0
      "  Enter ReadOneJNGImage()");
4174
4175
19.6k
  image=mng_info->image;
4176
4177
19.6k
  if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4178
0
    {
4179
      /*
4180
        Allocate next image structure.
4181
      */
4182
0
      if (logging != MagickFalse)
4183
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4184
0
           "  AcquireNextImage()");
4185
4186
0
      AcquireNextImage(image_info,image,exception);
4187
4188
0
      if (GetNextImageInList(image) == (Image *) NULL)
4189
0
        return(DestroyImageList(image));
4190
4191
0
      image=SyncNextImageInList(image);
4192
0
    }
4193
19.6k
  mng_info->image=image;
4194
4195
  /*
4196
    Signature bytes have already been read.
4197
  */
4198
4199
19.6k
  read_JSEP=MagickFalse;
4200
19.6k
  reading_idat=MagickFalse;
4201
19.6k
  for (;;)
4202
82.5k
  {
4203
82.5k
    char
4204
82.5k
      type[MagickPathExtent];
4205
4206
82.5k
    unsigned char
4207
82.5k
      *chunk;
4208
4209
82.5k
    unsigned int
4210
82.5k
      count;
4211
4212
    /*
4213
      Read a new JNG chunk.
4214
    */
4215
82.5k
    status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4216
82.5k
      2*GetBlobSize(image));
4217
4218
82.5k
    if (status == MagickFalse)
4219
0
      break;
4220
4221
82.5k
    type[0]='\0';
4222
82.5k
    (void) ConcatenateMagickString(type,"errr",MagickPathExtent);
4223
82.5k
    length=(size_t) ReadBlobMSBLong(image);
4224
82.5k
    count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4225
4226
82.5k
    if (logging != MagickFalse)
4227
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4228
0
        "  Reading JNG chunk type %c%c%c%c, length: %.17g",
4229
0
        type[0],type[1],type[2],type[3],(double) length);
4230
4231
82.5k
    if (length > PNG_UINT_31_MAX || count == 0)
4232
587
      {
4233
587
        DestroyJNG(NULL,&color_image,&color_image_info,
4234
587
          &alpha_image,&alpha_image_info);
4235
587
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4236
0
      }
4237
81.9k
    if (length > GetBlobSize(image))
4238
291
      {
4239
291
        DestroyJNG(NULL,&color_image,&color_image_info,
4240
291
          &alpha_image,&alpha_image_info);
4241
291
        ThrowReaderException(CorruptImageError,
4242
291
          "InsufficientImageDataInFile");
4243
0
      }
4244
4245
81.6k
    p=NULL;
4246
81.6k
    chunk=(unsigned char *) NULL;
4247
4248
81.6k
    if (length != 0)
4249
60.1k
      {
4250
60.1k
        chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4251
4252
60.1k
        if (chunk == (unsigned char *) NULL)
4253
0
          {
4254
0
            DestroyJNG(NULL,&color_image,&color_image_info,
4255
0
              &alpha_image,&alpha_image_info);
4256
0
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4257
0
          }
4258
4259
6.75M
        for (i=0; i < (ssize_t) length; i++)
4260
6.70M
        {
4261
6.70M
          int
4262
6.70M
            c;
4263
4264
6.70M
          c=ReadBlobByte(image);
4265
6.70M
          if (c == EOF)
4266
8.23k
            break;
4267
6.69M
          chunk[i]=(unsigned char) c;
4268
6.69M
        }
4269
614k
        for ( ; i < (ssize_t) length; i++)
4270
554k
          chunk[i]='\0';
4271
4272
60.1k
        p=chunk;
4273
60.1k
      }
4274
4275
81.6k
    (void) ReadBlobMSBLong(image);  /* read crc word */
4276
4277
81.6k
    if (memcmp(type,mng_JHDR,4) == 0)
4278
17.3k
      {
4279
17.3k
        if (length == 16)
4280
11.7k
          {
4281
11.7k
            jng_width=(png_uint_32)mng_get_long(p);
4282
11.7k
            jng_height=(png_uint_32)mng_get_long(&p[4]);
4283
11.7k
            if ((jng_width == 0) || (jng_height == 0))
4284
12
              {
4285
12
                DestroyJNG(chunk,&color_image,&color_image_info,
4286
12
                  &alpha_image,&alpha_image_info);
4287
12
                ThrowReaderException(CorruptImageError,
4288
12
                  "NegativeOrZeroImageSize");
4289
0
              }
4290
11.7k
            jng_color_type=p[8];
4291
11.7k
            jng_image_sample_depth=p[9];
4292
11.7k
            jng_image_compression_method=p[10];
4293
11.7k
            jng_image_interlace_method=p[11];
4294
4295
11.7k
            image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4296
11.7k
              NoInterlace;
4297
4298
11.7k
            jng_alpha_sample_depth=p[12];
4299
11.7k
            jng_alpha_compression_method=p[13];
4300
11.7k
            jng_alpha_filter_method=p[14];
4301
11.7k
            jng_alpha_interlace_method=p[15];
4302
4303
11.7k
            if (logging != MagickFalse)
4304
0
              {
4305
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4306
0
                  "    jng_width:      %16lu,    jng_height:     %16lu\n"
4307
0
                  "    jng_color_type: %16d,     jng_image_sample_depth: %3d\n"
4308
0
                  "    jng_image_compression_method:%3d",
4309
0
                  (unsigned long) jng_width, (unsigned long) jng_height,
4310
0
                  jng_color_type, jng_image_sample_depth,
4311
0
                  jng_image_compression_method);
4312
4313
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4314
0
                  "    jng_image_interlace_method:  %3d"
4315
0
                  "    jng_alpha_sample_depth:      %3d",
4316
0
                  jng_image_interlace_method,
4317
0
                  jng_alpha_sample_depth);
4318
4319
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4320
0
                  "    jng_alpha_compression_method:%3d\n"
4321
0
                  "    jng_alpha_filter_method:     %3d\n"
4322
0
                  "    jng_alpha_interlace_method:  %3d",
4323
0
                  jng_alpha_compression_method,
4324
0
                  jng_alpha_filter_method,
4325
0
                  jng_alpha_interlace_method);
4326
0
              }
4327
11.7k
          }
4328
4329
17.3k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4330
4331
17.3k
        if ((jng_width > 65535) || (jng_height > 65535) ||
4332
17.1k
            (MagickSizeType) jng_width > GetMagickResourceLimit(WidthResource) ||
4333
17.1k
            (MagickSizeType) jng_height > GetMagickResourceLimit(HeightResource))
4334
157
          {
4335
157
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4336
157
               "    JNG width or height too large: (%lu x %lu)",
4337
157
                (long) jng_width, (long) jng_height);
4338
157
            DestroyJNG(chunk,&color_image,&color_image_info,
4339
157
              &alpha_image,&alpha_image_info);
4340
157
            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4341
0
          }
4342
4343
17.1k
        continue;
4344
17.3k
      }
4345
4346
4347
64.3k
    if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4348
27.0k
        ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4349
9.39k
         (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4350
18.8k
      {
4351
        /*
4352
           o create color_image
4353
           o open color_blob, attached to color_image
4354
           o if (color type has alpha)
4355
               open alpha_blob, attached to alpha_image
4356
        */
4357
4358
18.8k
        color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4359
4360
18.8k
        if (color_image_info == (ImageInfo *) NULL)
4361
0
        {
4362
0
          DestroyJNG(chunk,&color_image,&color_image_info,
4363
0
              &alpha_image,&alpha_image_info);
4364
0
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4365
0
        }
4366
4367
18.8k
        GetImageInfo(color_image_info);
4368
18.8k
        color_image=AcquireImage(color_image_info,exception);
4369
4370
18.8k
        if (color_image == (Image *) NULL)
4371
0
        {
4372
0
          DestroyJNG(chunk,&color_image,&color_image_info,
4373
0
              &alpha_image,&alpha_image_info);
4374
0
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4375
0
        }
4376
4377
18.8k
        if (logging != MagickFalse)
4378
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4379
0
            "    Creating color_blob.");
4380
4381
18.8k
        (void) AcquireUniqueFilename(color_image->filename);
4382
18.8k
        status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4383
18.8k
          exception);
4384
4385
18.8k
        if (status == MagickFalse)
4386
0
          {
4387
0
            DestroyJNG(chunk,&color_image,&color_image_info,
4388
0
              &alpha_image,&alpha_image_info);
4389
0
            return(DestroyImageList(image));
4390
0
          }
4391
4392
18.8k
        if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4393
2.44k
          {
4394
2.44k
            if ((jng_alpha_compression_method != 0) &&
4395
172
                (jng_alpha_compression_method != 8))
4396
4
              {
4397
4
                DestroyJNG(chunk,&color_image,&color_image_info,&alpha_image,
4398
4
                  &alpha_image_info);
4399
4
                ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4400
0
              }
4401
2.43k
            alpha_image_info=(ImageInfo *)
4402
2.43k
              AcquireMagickMemory(sizeof(ImageInfo));
4403
4404
2.43k
            if (alpha_image_info == (ImageInfo *) NULL)
4405
0
              {
4406
0
                DestroyJNG(chunk,&color_image,&color_image_info,
4407
0
                  &alpha_image,&alpha_image_info);
4408
0
                ThrowReaderException(ResourceLimitError,
4409
0
                  "MemoryAllocationFailed");
4410
0
              }
4411
4412
2.43k
            GetImageInfo(alpha_image_info);
4413
2.43k
            alpha_image=AcquireImage(alpha_image_info,exception);
4414
4415
2.43k
            if (alpha_image == (Image *) NULL)
4416
0
              {
4417
0
                DestroyJNG(chunk,&color_image,&color_image_info,
4418
0
                  &alpha_image,&alpha_image_info);
4419
0
                ThrowReaderException(ResourceLimitError,
4420
0
                  "MemoryAllocationFailed");
4421
0
              }
4422
4423
2.43k
            if (logging != MagickFalse)
4424
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4425
0
                "    Creating alpha_blob.");
4426
4427
2.43k
            (void) AcquireUniqueFilename(alpha_image->filename);
4428
2.43k
            status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4429
2.43k
              exception);
4430
4431
2.43k
            if (status == MagickFalse)
4432
0
              {
4433
0
                DestroyJNG(chunk,&color_image,&color_image_info,
4434
0
                  &alpha_image,&alpha_image_info);
4435
0
                return(DestroyImageList(image));
4436
0
              }
4437
4438
2.43k
            if (jng_alpha_compression_method == 0)
4439
2.26k
              {
4440
2.26k
                unsigned char
4441
2.26k
                  data[18];
4442
4443
2.26k
                if (logging != MagickFalse)
4444
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4445
0
                    "    Writing IHDR chunk to alpha_blob.");
4446
4447
2.26k
                (void) WriteBlob(alpha_image,8,(const unsigned char *)
4448
2.26k
                  "\211PNG\r\n\032\n");
4449
4450
2.26k
                (void) WriteBlobMSBULong(alpha_image,13L);
4451
2.26k
                PNGType(data,mng_IHDR);
4452
2.26k
                LogPNGChunk(logging,mng_IHDR,13L);
4453
2.26k
                PNGLong(data+4,jng_width);
4454
2.26k
                PNGLong(data+8,jng_height);
4455
2.26k
                data[12]=jng_alpha_sample_depth;
4456
2.26k
                data[13]=0; /* color_type gray */
4457
2.26k
                data[14]=0; /* compression method 0 */
4458
2.26k
                data[15]=0; /* filter_method 0 */
4459
2.26k
                data[16]=0; /* interlace_method 0 */
4460
2.26k
                (void) WriteBlob(alpha_image,17,data);
4461
2.26k
                (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4462
2.26k
              }
4463
2.43k
          }
4464
18.8k
        reading_idat=MagickTrue;
4465
18.8k
      }
4466
4467
64.3k
    if (memcmp(type,mng_JDAT,4) == 0)
4468
23.1k
      {
4469
        /* Copy chunk to color_image->blob */
4470
4471
23.1k
        if (logging != MagickFalse)
4472
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4473
0
            "    Copying JDAT chunk data to color_blob.");
4474
4475
23.1k
        if ((length != 0) && (color_image != (Image *) NULL))
4476
22.6k
          (void) WriteBlob(color_image,length,chunk);
4477
23.1k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4478
23.1k
        continue;
4479
23.1k
      }
4480
4481
41.2k
    if (memcmp(type,mng_IDAT,4) == 0)
4482
4.35k
      {
4483
4.35k
        png_byte
4484
4.35k
           data[5];
4485
4486
        /* Copy IDAT header and chunk data to alpha_image->blob */
4487
4488
4.35k
        if (alpha_image != NULL && image_info->ping == MagickFalse)
4489
3.80k
          {
4490
3.80k
            if (logging != MagickFalse)
4491
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4492
0
                "    Copying IDAT chunk data to alpha_blob.");
4493
4494
3.80k
            (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4495
3.80k
            PNGType(data,mng_IDAT);
4496
3.80k
            LogPNGChunk(logging,mng_IDAT,length);
4497
3.80k
            (void) WriteBlob(alpha_image,4,data);
4498
3.80k
            (void) WriteBlob(alpha_image,length,chunk);
4499
3.80k
            (void) WriteBlobMSBULong(alpha_image,
4500
3.80k
              crc32(crc32(0,data,4),chunk,(uInt) length));
4501
3.80k
          }
4502
4503
4.35k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4504
4505
4.35k
        continue;
4506
4.35k
      }
4507
4508
36.8k
    if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4509
4.36k
      {
4510
        /* Copy chunk data to alpha_image->blob */
4511
4512
4.36k
        if ((alpha_image != NULL) && (image_info->ping == MagickFalse) &&
4513
2.94k
            (length != 0))
4514
2.67k
          {
4515
2.67k
            if (logging != MagickFalse)
4516
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4517
0
                "    Copying JDAA chunk data to alpha_blob.");
4518
4519
2.67k
            (void) WriteBlob(alpha_image,length,chunk);
4520
2.67k
          }
4521
4522
4.36k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4523
4524
4.36k
        continue;
4525
4.36k
      }
4526
4527
32.4k
    if (memcmp(type,mng_JSEP,4) == 0)
4528
381
      {
4529
381
        read_JSEP=MagickTrue;
4530
4531
381
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4532
4533
381
        continue;
4534
381
      }
4535
4536
32.1k
    if (memcmp(type,mng_bKGD,4) == 0)
4537
1.20k
      {
4538
1.20k
        if (length == 2)
4539
404
          {
4540
404
            image->background_color.red=ScaleCharToQuantum(p[1]);
4541
404
            image->background_color.green=image->background_color.red;
4542
404
            image->background_color.blue=image->background_color.red;
4543
404
          }
4544
4545
1.20k
        if (length == 6)
4546
417
          {
4547
417
            image->background_color.red=ScaleCharToQuantum(p[1]);
4548
417
            image->background_color.green=ScaleCharToQuantum(p[3]);
4549
417
            image->background_color.blue=ScaleCharToQuantum(p[5]);
4550
417
          }
4551
4552
1.20k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4553
1.20k
        continue;
4554
1.20k
      }
4555
4556
30.9k
    if (memcmp(type,mng_gAMA,4) == 0)
4557
753
      {
4558
753
        if (length == 4)
4559
418
          image->gamma=((double) mng_get_long(p))*0.00001;
4560
4561
753
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4562
753
        continue;
4563
753
      }
4564
4565
30.1k
    if (memcmp(type,mng_cHRM,4) == 0)
4566
678
      {
4567
678
        if (length == 32)
4568
412
          {
4569
412
            image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4570
412
            image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4571
412
            image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4572
412
            image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4573
412
            image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4574
412
            image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4575
412
            image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4576
412
            image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4577
412
          }
4578
4579
678
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4580
678
        continue;
4581
678
      }
4582
4583
29.4k
    if (memcmp(type,mng_sRGB,4) == 0)
4584
975
      {
4585
975
        if (length == 1)
4586
660
          {
4587
660
            image->rendering_intent=
4588
660
              Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4589
660
            image->gamma=0.45455f;
4590
660
            image->chromaticity.red_primary.x=0.6400f;
4591
660
            image->chromaticity.red_primary.y=0.3300f;
4592
660
            image->chromaticity.green_primary.x=0.3000f;
4593
660
            image->chromaticity.green_primary.y=0.6000f;
4594
660
            image->chromaticity.blue_primary.x=0.1500f;
4595
660
            image->chromaticity.blue_primary.y=0.0600f;
4596
660
            image->chromaticity.white_point.x=0.3127f;
4597
660
            image->chromaticity.white_point.y=0.3290f;
4598
660
          }
4599
4600
975
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4601
975
        continue;
4602
975
      }
4603
4604
28.4k
    if (memcmp(type,mng_oFFs,4) == 0)
4605
723
      {
4606
723
        if (length > 8)
4607
316
          {
4608
316
            image->page.x=(ssize_t) mng_get_long(p);
4609
316
            image->page.y=(ssize_t) mng_get_long(&p[4]);
4610
4611
316
            if ((int) p[8] != 0)
4612
175
              {
4613
175
                image->page.x/=10000;
4614
175
                image->page.y/=10000;
4615
175
              }
4616
316
          }
4617
4618
723
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4619
4620
723
        continue;
4621
723
      }
4622
4623
27.7k
    if (memcmp(type,mng_pHYs,4) == 0)
4624
1.11k
      {
4625
1.11k
        if (length > 8)
4626
662
          {
4627
662
            image->resolution.x=(double) mng_get_long(p);
4628
662
            image->resolution.y=(double) mng_get_long(&p[4]);
4629
662
            if ((int) p[8] == PNG_RESOLUTION_METER)
4630
293
              {
4631
293
                image->units=PixelsPerCentimeterResolution;
4632
293
                image->resolution.x=image->resolution.x/100.0;
4633
293
                image->resolution.y=image->resolution.y/100.0;
4634
293
              }
4635
662
          }
4636
4637
1.11k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4638
1.11k
        continue;
4639
1.11k
      }
4640
4641
#if 0
4642
    if (memcmp(type,mng_iCCP,4) == 0)
4643
      {
4644
        /* To do: */
4645
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4646
4647
        continue;
4648
      }
4649
#endif
4650
4651
26.6k
    chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4652
4653
26.6k
    if (memcmp(type,mng_IEND,4))
4654
8.08k
      continue;
4655
4656
18.5k
    break;
4657
26.6k
  }
4658
4659
4660
  /* IEND found */
4661
4662
  /*
4663
    Finish up reading image data:
4664
4665
       o read main image from color_blob.
4666
4667
       o close color_blob.
4668
4669
       o if (color_type has alpha)
4670
            if alpha_encoding is PNG
4671
               read secondary image from alpha_blob via ReadPNG
4672
            if alpha_encoding is JPEG
4673
               read secondary image from alpha_blob via ReadJPEG
4674
4675
       o close alpha_blob.
4676
4677
       o copy intensity of secondary image into
4678
         alpha samples of main image.
4679
4680
       o destroy the secondary image.
4681
  */
4682
4683
18.5k
  if (color_image_info == (ImageInfo *) NULL)
4684
6
    {
4685
6
      assert(color_image == (Image *) NULL);
4686
6
      assert(alpha_image == (Image *) NULL);
4687
6
      if (color_image != (Image *) NULL)
4688
0
        color_image=DestroyImageList(color_image);
4689
6
      return(DestroyImageList(image));
4690
6
    }
4691
4692
18.5k
  if (color_image == (Image *) NULL)
4693
0
    {
4694
0
      assert(alpha_image == (Image *) NULL);
4695
0
      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
4696
0
    }
4697
4698
18.5k
  (void) SeekBlob(color_image,0,SEEK_SET);
4699
4700
18.5k
  if (logging != MagickFalse)
4701
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4702
0
      "    Reading jng_image from color_blob.");
4703
4704
18.5k
  assert(color_image_info != (ImageInfo *) NULL);
4705
18.5k
  (void) FormatLocaleString(color_image_info->filename,MagickPathExtent,
4706
18.5k
    "jpeg:%s",color_image->filename);
4707
4708
18.5k
  color_image_info->ping=MagickFalse;   /* To do: avoid this */
4709
18.5k
  CloseBlob(color_image);
4710
18.5k
  jng_image=ReadImage(color_image_info,exception);
4711
18.5k
  (void) RelinquishUniqueFileResource(color_image->filename);
4712
18.5k
  color_image=DestroyImageList(color_image);
4713
18.5k
  color_image_info=DestroyImageInfo(color_image_info);
4714
4715
18.5k
  if (jng_image == (Image *) NULL)
4716
4.03k
  {
4717
4.03k
    DestroyJNG(NULL,NULL,NULL,&alpha_image,&alpha_image_info);
4718
4.03k
    return(DestroyImageList(image));
4719
4.03k
  }
4720
4721
4722
14.5k
  if (logging != MagickFalse)
4723
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4724
0
      "    Copying jng_image pixels to main image.");
4725
4726
14.5k
  image->rows=jng_height;
4727
14.5k
  image->columns=jng_width;
4728
4729
14.5k
  status=SetImageExtent(image,image->columns,image->rows,exception);
4730
14.5k
  if (status == MagickFalse)
4731
4.71k
    {
4732
4.71k
      DestroyJNG(NULL,&color_image,&color_image_info,&alpha_image,
4733
4.71k
        &alpha_image_info);
4734
4.71k
      jng_image=DestroyImageList(jng_image);
4735
4.71k
      return(DestroyImageList(image));
4736
4.71k
    }
4737
9.81k
  if ((image->columns != jng_image->columns) ||
4738
9.47k
      (image->rows != jng_image->rows))
4739
358
    {
4740
358
      DestroyJNG(NULL,&color_image,&color_image_info,&alpha_image,
4741
358
        &alpha_image_info);
4742
358
      jng_image=DestroyImageList(jng_image);
4743
358
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4744
0
    }
4745
2.16M
  for (y=0; y < (ssize_t) image->rows; y++)
4746
2.15M
  {
4747
2.15M
    s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4748
2.15M
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4749
2.15M
    if ((s == (const Quantum *)  NULL) || (q == (Quantum *) NULL))
4750
0
      break;
4751
45.3M
    for (x=(ssize_t) image->columns; x != 0; x--)
4752
43.1M
    {
4753
43.1M
      SetPixelRed(image,GetPixelRed(jng_image,s),q);
4754
43.1M
      SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4755
43.1M
      SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4756
43.1M
      q+=(ptrdiff_t) GetPixelChannels(image);
4757
43.1M
      s+=(ptrdiff_t) GetPixelChannels(jng_image);
4758
43.1M
    }
4759
4760
2.15M
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
4761
0
      break;
4762
2.15M
  }
4763
4764
9.45k
  jng_image=DestroyImage(jng_image);
4765
4766
9.45k
  if ((image_info->ping == MagickFalse) && (alpha_image != (Image *) NULL) &&
4767
1.88k
      (jng_color_type >= 12))
4768
1.70k
    {
4769
1.70k
      switch (jng_alpha_compression_method)
4770
1.70k
      {
4771
1.63k
        case 0:
4772
1.63k
        {
4773
1.63k
          png_byte
4774
1.63k
            data[5];
4775
4776
1.63k
          (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent,
4777
1.63k
            "png:%s",alpha_image->filename);
4778
1.63k
          (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4779
1.63k
          PNGType(data,mng_IEND);
4780
1.63k
          LogPNGChunk(logging,mng_IEND,0L);
4781
1.63k
          (void) WriteBlob(alpha_image,4,data);
4782
1.63k
          (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4783
1.63k
          break;
4784
0
        }
4785
72
        case 8:
4786
72
        {
4787
72
          (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent,
4788
72
            "jpeg:%s",alpha_image->filename);
4789
72
          break;
4790
0
        }
4791
3
        default:
4792
3
        {
4793
3
          (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent,
4794
3
            "alpha:%s",alpha_image->filename);
4795
3
          break;
4796
0
        }
4797
1.70k
      }
4798
1.70k
      (void) CloseBlob(alpha_image);
4799
4800
1.70k
      if (logging != MagickFalse)
4801
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4802
0
          "    Reading alpha from alpha_blob.");
4803
1.70k
      jng_image=ReadImage(alpha_image_info,exception);
4804
4805
1.70k
      if (jng_image != (Image *) NULL)
4806
460
        {
4807
460
          const struct stat
4808
460
            *alpha_properties = GetBlobProperties(alpha_image),
4809
460
            *jng_properties = GetBlobProperties(jng_image);
4810
4811
460
          if ((alpha_properties->st_dev != jng_properties->st_dev) ||
4812
460
              (alpha_properties->st_ino != jng_properties->st_ino))
4813
0
            {
4814
0
              DestroyJNG(NULL,&color_image,&color_image_info,&alpha_image,
4815
0
                &alpha_image_info);
4816
0
              jng_image=DestroyImageList(jng_image);
4817
0
              ThrowReaderException(PolicyError,"NotAuthorized");
4818
0
            }
4819
460
          image->alpha_trait=BlendPixelTrait;
4820
22.1k
          for (y=0; y < (ssize_t) image->rows; y++)
4821
21.6k
          {
4822
21.6k
            s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4823
21.6k
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4824
21.6k
            if ((s == (const Quantum *)  NULL) || (q == (Quantum *) NULL))
4825
0
              break;
4826
4827
3.73M
            for (x=(ssize_t) image->columns; x != 0; x--)
4828
3.71M
            {
4829
3.71M
              SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4830
3.71M
              q+=(ptrdiff_t) GetPixelChannels(image);
4831
3.71M
              s+=(ptrdiff_t) GetPixelChannels(jng_image);
4832
3.71M
            }
4833
21.6k
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
4834
0
              break;
4835
21.6k
          }
4836
460
        }
4837
1.70k
      (void) RelinquishUniqueFileResource(alpha_image->filename);
4838
1.70k
      alpha_image=DestroyImageList(alpha_image);
4839
1.70k
      alpha_image_info=DestroyImageInfo(alpha_image_info);
4840
1.70k
      if (jng_image != (Image *) NULL)
4841
460
        jng_image=DestroyImageList(jng_image);
4842
1.70k
    }
4843
4844
9.45k
  if (alpha_image != (Image *) NULL)
4845
175
    alpha_image=DestroyImageList(alpha_image);
4846
9.45k
  if (alpha_image_info != (ImageInfo *) NULL)
4847
175
    alpha_image_info=DestroyImageInfo(alpha_image_info);
4848
4849
  /* Read the JNG image.  */
4850
4851
9.45k
  if (mng_info->mng_type == 0)
4852
8.99k
    {
4853
8.99k
      mng_info->mng_width=jng_width;
4854
8.99k
      mng_info->mng_height=jng_height;
4855
8.99k
    }
4856
4857
9.45k
  if (image->page.width == 0 && image->page.height == 0)
4858
2.25k
    {
4859
2.25k
      image->page.width=jng_width;
4860
2.25k
      image->page.height=jng_height;
4861
2.25k
    }
4862
4863
9.45k
  if (image->page.x == 0 && image->page.y == 0)
4864
9.31k
    {
4865
9.31k
      image->page.x=mng_info->x_off[mng_info->object_id];
4866
9.31k
      image->page.y=mng_info->y_off[mng_info->object_id];
4867
9.31k
    }
4868
4869
143
  else
4870
143
    {
4871
143
      image->page.y=mng_info->y_off[mng_info->object_id];
4872
143
    }
4873
4874
9.45k
  mng_info->image_found++;
4875
9.45k
  status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4876
9.45k
    2*GetBlobSize(image));
4877
4878
9.45k
  if (status == MagickFalse)
4879
0
    return(DestroyImageList(image));
4880
4881
9.45k
  if (logging != MagickFalse)
4882
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4883
0
      "  exit ReadOneJNGImage()");
4884
4885
9.45k
  return(image);
4886
9.45k
}
4887

4888
/*
4889
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890
%                                                                             %
4891
%                                                                             %
4892
%                                                                             %
4893
%   R e a d J N G I m a g e                                                   %
4894
%                                                                             %
4895
%                                                                             %
4896
%                                                                             %
4897
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4898
%
4899
%  ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4900
%  (including the 8-byte signature)  and returns it.  It allocates the memory
4901
%  necessary for the new Image structure and returns a pointer to the new
4902
%  image.
4903
%
4904
%  JNG support written by Glenn Randers-Pehrson, glennrp@image...
4905
%
4906
%  The format of the ReadJNGImage method is:
4907
%
4908
%      Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4909
%         *exception)
4910
%
4911
%  A description of each parameter follows:
4912
%
4913
%    o image_info: the image info.
4914
%
4915
%    o exception: return any errors or warnings in this structure.
4916
%
4917
*/
4918
4919
static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4920
7.28k
{
4921
7.28k
  char
4922
7.28k
    magic_number[MagickPathExtent];
4923
4924
7.28k
  Image
4925
7.28k
    *image;
4926
4927
7.28k
  MagickBooleanType
4928
7.28k
    logging = MagickFalse,
4929
7.28k
    status;
4930
4931
7.28k
  MngReadInfo
4932
7.28k
    *mng_info;
4933
4934
7.28k
  size_t
4935
7.28k
    count;
4936
4937
  /*
4938
    Open image file.
4939
  */
4940
7.28k
  assert(image_info != (const ImageInfo *) NULL);
4941
7.28k
  assert(image_info->signature == MagickCoreSignature);
4942
7.28k
  assert(exception != (ExceptionInfo *) NULL);
4943
7.28k
  assert(exception->signature == MagickCoreSignature);
4944
7.28k
  if (IsEventLogging() != MagickFalse)
4945
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4946
0
       image_info->filename);
4947
7.28k
  image=AcquireImage(image_info,exception);
4948
7.28k
  if (image->debug != MagickFalse)
4949
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4950
7.28k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4951
4952
7.28k
  if (status == MagickFalse)
4953
0
    return(DestroyImageList(image));
4954
4955
7.28k
  if (LocaleCompare(image_info->magick,"JNG") != 0)
4956
7.28k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4957
4958
  /* Verify JNG signature.  */
4959
4960
7.28k
  count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4961
4962
7.28k
  if ((count < 8) || (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0))
4963
7.22k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4964
4965
  /*
4966
     Verify that file size large enough to contain a JNG datastream.
4967
  */
4968
7.22k
  if (GetBlobSize(image) < 147)
4969
7.20k
    ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
4970
4971
7.20k
  mng_info=(MngReadInfo *) AcquireMagickMemory(sizeof(*mng_info));
4972
7.20k
  if (mng_info == (MngReadInfo *) NULL)
4973
7.20k
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4974
7.20k
  (void) memset(mng_info,0,sizeof(*mng_info));
4975
4976
7.20k
  mng_info->image=image;
4977
7.20k
  image=ReadOneJNGImage(mng_info,image_info,exception);
4978
7.20k
  mng_info=MngReadInfoFreeStruct(mng_info);
4979
4980
7.20k
  if (image == (Image *) NULL)
4981
5.81k
    {
4982
5.81k
      if (logging != MagickFalse)
4983
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4984
0
          "exit ReadJNGImage() with error");
4985
4986
5.81k
      return((Image *) NULL);
4987
5.81k
    }
4988
1.39k
  (void) CloseBlob(image);
4989
4990
1.39k
  if (image->columns == 0 || image->rows == 0)
4991
0
    {
4992
0
      if (logging != MagickFalse)
4993
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4994
0
          "exit ReadJNGImage() with error");
4995
4996
0
      ThrowReaderException(CorruptImageError,"CorruptImage");
4997
0
    }
4998
4999
1.39k
  if (logging != MagickFalse)
5000
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
5001
5002
1.39k
  return(image);
5003
1.39k
}
5004
#endif
5005
5006
static Image *ReadOneMNGImage(MngReadInfo* mng_info,
5007
  const ImageInfo *image_info,ExceptionInfo *exception)
5008
11.5k
{
5009
11.5k
  char
5010
11.5k
    page_geometry[MagickPathExtent];
5011
5012
11.5k
  Image
5013
11.5k
    *image;
5014
5015
11.5k
  MagickBooleanType
5016
11.5k
    logging;
5017
5018
11.5k
  volatile int
5019
11.5k
    first_mng_object,
5020
11.5k
    object_id,
5021
11.5k
    term_chunk_found,
5022
11.5k
    skip_to_iend;
5023
5024
11.5k
  volatile ssize_t
5025
11.5k
    image_count=0;
5026
5027
11.5k
  MagickBooleanType
5028
11.5k
    status;
5029
5030
11.5k
  MagickOffsetType
5031
11.5k
    offset;
5032
5033
11.5k
  MngBox
5034
11.5k
    default_fb,
5035
11.5k
    fb,
5036
11.5k
    previous_fb;
5037
5038
11.5k
  PixelInfo
5039
11.5k
    mng_background_color;
5040
5041
11.5k
  ssize_t
5042
11.5k
    i;
5043
5044
11.5k
  size_t
5045
11.5k
    count;
5046
5047
11.5k
  ssize_t
5048
11.5k
    loop_level;
5049
5050
11.5k
  unsigned char
5051
11.5k
    *p;
5052
5053
11.5k
  volatile short
5054
11.5k
    skipping_loop;
5055
5056
11.5k
  unsigned int
5057
11.5k
    mandatory_back=0;
5058
5059
11.5k
  volatile unsigned int
5060
11.5k
    mng_type=0;   /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
5061
5062
11.5k
  size_t
5063
11.5k
    default_frame_timeout,
5064
11.5k
    frame_timeout,
5065
11.5k
    image_height,
5066
11.5k
    image_width,
5067
11.5k
    length;
5068
5069
  /* These delays are all measured in image ticks_per_second,
5070
   * not in MNG ticks_per_second
5071
   */
5072
11.5k
  volatile size_t
5073
11.5k
    default_frame_delay,
5074
11.5k
    final_delay,
5075
11.5k
    final_image_delay,
5076
11.5k
    frame_delay,
5077
11.5k
    insert_layers,
5078
11.5k
    number_loop_ops=0,
5079
11.5k
    mng_iterations=1,
5080
11.5k
    simplicity=0,
5081
11.5k
    subframe_height=0,
5082
11.5k
    subframe_width=0;
5083
5084
11.5k
  previous_fb.top=0;
5085
11.5k
  previous_fb.bottom=0;
5086
11.5k
  previous_fb.left=0;
5087
11.5k
  previous_fb.right=0;
5088
11.5k
  default_fb.top=0;
5089
11.5k
  default_fb.bottom=0;
5090
11.5k
  default_fb.left=0;
5091
11.5k
  default_fb.right=0;
5092
5093
11.5k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
5094
11.5k
    "  Enter ReadOneMNGImage()");
5095
5096
11.5k
  image=mng_info->image;
5097
5098
11.5k
  if (LocaleCompare(image_info->magick,"MNG") == 0)
5099
11.5k
    {
5100
11.5k
      char
5101
11.5k
        magic_number[MagickPathExtent];
5102
5103
      /* Verify MNG signature.  */
5104
11.5k
      count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
5105
11.5k
      if ((count < 8) || (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0))
5106
11.5k
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5107
5108
      /* Initialize some nonzero members of the MngReadInfo structure.  */
5109
2.96M
      for (i=0; i < MNG_MAX_OBJECTS; i++)
5110
2.95M
      {
5111
2.95M
        mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
5112
2.95M
        mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
5113
2.95M
      }
5114
11.5k
      mng_info->exists[0]=MagickTrue;
5115
11.5k
    }
5116
5117
11.5k
  skipping_loop=(-1);
5118
11.5k
  first_mng_object=MagickTrue;
5119
11.5k
  mng_type=0;
5120
11.5k
  insert_layers=MagickFalse; /* should be False during convert or mogrify */
5121
11.5k
  default_frame_delay=0;
5122
11.5k
  default_frame_timeout=0;
5123
11.5k
  frame_delay=0;
5124
11.5k
  final_delay=1;
5125
11.5k
  mng_info->ticks_per_second=(unsigned long) image->ticks_per_second;
5126
11.5k
  object_id=0;
5127
11.5k
  skip_to_iend=MagickFalse;
5128
11.5k
  term_chunk_found=MagickFalse;
5129
11.5k
  mng_info->framing_mode=1;
5130
11.5k
  mandatory_back=MagickFalse;
5131
11.5k
  mng_background_color=image->background_color;
5132
11.5k
  default_fb=mng_info->frame;
5133
11.5k
  previous_fb=mng_info->frame;
5134
11.5k
  do
5135
90.8M
  {
5136
90.8M
    char
5137
90.8M
      type[MagickPathExtent] = "\0";
5138
5139
90.8M
    if (LocaleCompare(image_info->magick,"MNG") == 0)
5140
90.8M
      {
5141
90.8M
        unsigned char
5142
90.8M
          *chunk;
5143
5144
        /*
5145
          Read a new chunk.
5146
        */
5147
90.8M
        type[0]='\0';
5148
90.8M
        (void) ConcatenateMagickString(type,"errr",MagickPathExtent);
5149
90.8M
        length=(size_t) ReadBlobMSBLong(image);
5150
90.8M
        count=(size_t) ReadBlob(image,4,(unsigned char *) type);
5151
5152
90.8M
        if (logging != MagickFalse)
5153
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5154
0
           "  Reading MNG chunk type %c%c%c%c, length: %.17g",
5155
0
           type[0],type[1],type[2],type[3],(double) length);
5156
5157
90.8M
        if ((length > PNG_UINT_31_MAX) || (length > GetBlobSize(image)) ||
5158
90.8M
            (count < 4))
5159
90.8M
          ThrowReaderException(CorruptImageError,"CorruptImage");
5160
5161
90.8M
        p=NULL;
5162
90.8M
        chunk=(unsigned char *) NULL;
5163
90.8M
        if (length != 0)
5164
80.1M
          {
5165
80.1M
            chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
5166
80.1M
            if (chunk == (unsigned char *) NULL)
5167
80.1M
              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
5168
80.1M
            if (ReadBlob(image,length,chunk) != (ssize_t) length)
5169
57
              {
5170
57
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5171
57
                ThrowReaderException(CorruptImageError,"CorruptImage");
5172
0
              }
5173
80.1M
            p=chunk;
5174
80.1M
          }
5175
90.8M
        (void) ReadBlobMSBLong(image);  /* read crc word */
5176
5177
#if !defined(JNG_SUPPORTED)
5178
        if (memcmp(type,mng_JHDR,4) == 0)
5179
          {
5180
            skip_to_iend=MagickTrue;
5181
5182
            if (mng_info->jhdr_warning == 0)
5183
              (void) ThrowMagickException(exception,GetMagickModule(),
5184
                CoderError,"JNGCompressNotSupported","`%s'",image->filename);
5185
5186
            mng_info->jhdr_warning++;
5187
          }
5188
#endif
5189
90.8M
        if (memcmp(type,mng_DHDR,4) == 0)
5190
1.00M
          {
5191
1.00M
            skip_to_iend=MagickTrue;
5192
5193
1.00M
            if (mng_info->dhdr_warning == 0)
5194
38
              (void) ThrowMagickException(exception,GetMagickModule(),
5195
38
                CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
5196
5197
1.00M
            mng_info->dhdr_warning++;
5198
1.00M
          }
5199
90.8M
        if (memcmp(type,mng_MEND,4) == 0)
5200
1.31k
          {
5201
1.31k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5202
1.31k
            break;
5203
1.31k
          }
5204
5205
90.8M
        if (skip_to_iend)
5206
3.56M
          {
5207
3.56M
            if (memcmp(type,mng_IEND,4) == 0)
5208
1.28M
              skip_to_iend=MagickFalse;
5209
5210
3.56M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5211
5212
3.56M
            if (logging != MagickFalse)
5213
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5214
0
                "  Skip to IEND.");
5215
5216
3.56M
            continue;
5217
3.56M
          }
5218
5219
87.2M
        if (memcmp(type,mng_MHDR,4) == 0)
5220
262k
          {
5221
262k
            if (length != 28)
5222
7
              {
5223
7
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5224
7
                ThrowReaderException(CorruptImageError,"CorruptImage");
5225
0
              }
5226
5227
262k
            mng_info->mng_width=(unsigned long)mng_get_long(p);
5228
262k
            mng_info->mng_height=(unsigned long)mng_get_long(&p[4]);
5229
5230
262k
            if (logging != MagickFalse)
5231
0
              {
5232
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5233
0
                  "  MNG width: %.17g",(double) mng_info->mng_width);
5234
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5235
0
                  "  MNG height: %.17g",(double) mng_info->mng_height);
5236
0
              }
5237
5238
262k
            p+=(ptrdiff_t) 8;
5239
262k
            mng_info->ticks_per_second=(size_t) mng_get_long(p);
5240
5241
262k
            if (mng_info->ticks_per_second == 0)
5242
4.83k
              default_frame_delay=0;
5243
5244
257k
            else
5245
257k
              default_frame_delay=(size_t) image->ticks_per_second/
5246
257k
                (size_t) mng_info->ticks_per_second;
5247
5248
262k
            frame_delay=default_frame_delay;
5249
262k
            simplicity=0;
5250
5251
262k
            p+=(ptrdiff_t) 16;
5252
262k
            simplicity=(size_t) mng_get_long(p);
5253
5254
262k
            mng_type=1;    /* Full MNG */
5255
5256
262k
            if ((simplicity != 0) && ((simplicity | 11) == 11))
5257
5.79k
              mng_type=2; /* LC */
5258
5259
262k
            if ((simplicity != 0) && ((simplicity | 9) == 9))
5260
4.43k
              mng_type=3; /* VLC */
5261
5262
262k
            if (mng_type != 3)
5263
257k
              insert_layers=MagickTrue;
5264
262k
            if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5265
1.46k
              {
5266
                /* Allocate next image structure.  */
5267
1.46k
                AcquireNextImage(image_info,image,exception);
5268
5269
1.46k
                if (GetNextImageInList(image) == (Image *) NULL)
5270
0
                  return((Image *) NULL);
5271
5272
1.46k
                image=SyncNextImageInList(image);
5273
1.46k
                mng_info->image=image;
5274
1.46k
              }
5275
5276
262k
            if ((mng_info->mng_width > 65535L) ||
5277
262k
                (mng_info->mng_height > 65535L))
5278
52
              {
5279
52
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5280
52
                ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5281
0
              }
5282
5283
262k
            (void) FormatLocaleString(page_geometry,MagickPathExtent,
5284
262k
              "%.17gx%.17g+0+0",(double) mng_info->mng_width,(double)
5285
262k
              mng_info->mng_height);
5286
5287
262k
            mng_info->frame.left=0;
5288
262k
            mng_info->frame.right=(ssize_t) mng_info->mng_width;
5289
262k
            mng_info->frame.top=0;
5290
262k
            mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5291
262k
            mng_info->clip=default_fb=previous_fb=mng_info->frame;
5292
5293
67.3M
            for (i=0; i < MNG_MAX_OBJECTS; i++)
5294
67.0M
              mng_info->object_clip[i]=mng_info->frame;
5295
5296
262k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5297
262k
            continue;
5298
262k
          }
5299
5300
86.9M
        if (memcmp(type,mng_TERM,4) == 0)
5301
3.52M
          {
5302
3.52M
            int
5303
3.52M
              repeat=0;
5304
5305
3.52M
            if (length != 0)
5306
1.25M
              repeat=p[0];
5307
5308
3.52M
            if (repeat == 3 && length > 9)
5309
1.25M
              {
5310
1.25M
                final_delay=(png_uint_32) mng_get_long(&p[2]);
5311
1.25M
                mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5312
5313
1.25M
                if (mng_iterations == PNG_UINT_31_MAX)
5314
1.13M
                  mng_iterations=0;
5315
5316
1.25M
                image->iterations=mng_iterations;
5317
1.25M
                term_chunk_found=MagickTrue;
5318
1.25M
              }
5319
5320
3.52M
            if (logging != MagickFalse)
5321
0
              {
5322
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5323
0
                  "    repeat=%d,  final_delay=%.17g,  iterations=%.17g",
5324
0
                  repeat,(double) final_delay, (double) image->iterations);
5325
0
              }
5326
5327
3.52M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5328
3.52M
            continue;
5329
3.52M
          }
5330
83.4M
        if (memcmp(type,mng_DEFI,4) == 0)
5331
2.22M
          {
5332
2.22M
            if (mng_type == 3)
5333
65.6k
              {
5334
65.6k
                (void) ThrowMagickException(exception,GetMagickModule(),
5335
65.6k
                  CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5336
65.6k
                  image->filename);
5337
65.6k
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5338
65.6k
                continue;
5339
65.6k
              }
5340
5341
2.15M
            if (length < 2)
5342
4
              {
5343
4
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5344
4
                ThrowReaderException(CorruptImageError,"CorruptImage");
5345
0
              }
5346
5347
2.15M
            object_id=(int) (((unsigned int) p[0] << 8) | (unsigned int) p[1]);
5348
5349
2.15M
            if (mng_type == 2 && object_id != 0)
5350
6.76k
              (void) ThrowMagickException(exception,GetMagickModule(),
5351
6.76k
                CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5352
6.76k
                image->filename);
5353
5354
2.15M
            if (object_id >= MNG_MAX_OBJECTS)
5355
152k
              {
5356
                /*
5357
                  Instead of using a warning we should allocate a larger
5358
                  MngReadInfo structure and continue.
5359
                */
5360
152k
                (void) ThrowMagickException(exception,GetMagickModule(),
5361
152k
                  CoderError,"object id too large","`%s'",image->filename);
5362
152k
                object_id=MNG_MAX_OBJECTS-1;
5363
152k
              }
5364
5365
2.15M
            if (mng_info->exists[object_id])
5366
2.13M
              if (mng_info->frozen[object_id])
5367
101k
                {
5368
101k
                  chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5369
101k
                  (void) ThrowMagickException(exception,
5370
101k
                    GetMagickModule(),CoderError,
5371
101k
                    "DEFI cannot redefine a frozen MNG object","`%s'",
5372
101k
                    image->filename);
5373
101k
                  continue;
5374
101k
                }
5375
5376
2.05M
            mng_info->exists[object_id]=MagickTrue;
5377
5378
2.05M
            if (length > 2)
5379
17.4k
              mng_info->invisible[object_id]=p[2];
5380
5381
            /*
5382
              Extract object offset info.
5383
            */
5384
2.05M
            if (length > 11)
5385
8.30k
              {
5386
8.30k
                mng_info->x_off[object_id]=(ssize_t) mng_get_long(&p[4]);
5387
8.30k
                mng_info->y_off[object_id]=(ssize_t) mng_get_long(&p[8]);
5388
8.30k
                if (logging != MagickFalse)
5389
0
                  {
5390
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5391
0
                      "  x_off[%d]: %.17g,  y_off[%d]: %.17g",
5392
0
                      object_id,(double) mng_info->x_off[object_id],
5393
0
                      object_id,(double) mng_info->y_off[object_id]);
5394
0
                  }
5395
8.30k
              }
5396
5397
            /*
5398
              Extract object clipping info.
5399
            */
5400
2.05M
            if (length > 27)
5401
6.92k
              mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5402
6.92k
                &p[12]);
5403
5404
2.05M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5405
2.05M
            continue;
5406
2.15M
          }
5407
81.2M
        if (memcmp(type,mng_bKGD,4) == 0)
5408
66.5k
          {
5409
66.5k
            mng_info->have_global_bkgd=MagickFalse;
5410
5411
66.5k
            if (length > 5)
5412
65.8k
              {
5413
65.8k
                mng_info->mng_global_bkgd.red=ScaleShortToQuantum(
5414
65.8k
                  (unsigned short) (((unsigned int) p[0] << 8) | p[1]));
5415
65.8k
                mng_info->mng_global_bkgd.green=ScaleShortToQuantum(
5416
65.8k
                  (unsigned short) (((unsigned int) p[2] << 8) | p[3]));
5417
65.8k
                mng_info->mng_global_bkgd.blue=ScaleShortToQuantum(
5418
65.8k
                  (unsigned short) (((unsigned int) p[4] << 8) | p[5]));
5419
65.8k
                mng_info->have_global_bkgd=MagickTrue;
5420
65.8k
              }
5421
5422
66.5k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5423
66.5k
            continue;
5424
66.5k
          }
5425
81.1M
        if (memcmp(type,mng_BACK,4) == 0)
5426
2.06M
          {
5427
2.06M
            if (length > 6)
5428
1.00M
              mandatory_back=p[6];
5429
5430
1.06M
            else
5431
1.06M
              mandatory_back=0;
5432
5433
2.06M
            if (mandatory_back && length > 5)
5434
1.00M
              {
5435
1.00M
                mng_background_color.red=ScaleShortToQuantum((unsigned short)
5436
1.00M
                  (((unsigned int) p[0] << 8) | p[1]));
5437
1.00M
                mng_background_color.green=ScaleShortToQuantum((unsigned short)
5438
1.00M
                  (((unsigned int) p[2] << 8) | p[3]));
5439
1.00M
                mng_background_color.blue=ScaleShortToQuantum((unsigned short)
5440
1.00M
                  (((unsigned int) p[4] << 8) | p[5]));
5441
1.00M
                mng_background_color.alpha=OpaqueAlpha;
5442
1.00M
              }
5443
2.06M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5444
2.06M
            continue;
5445
2.06M
          }
5446
5447
79.1M
        if (memcmp(type,mng_PLTE,4) == 0)
5448
1.07M
          {
5449
            /* Read global PLTE.  */
5450
5451
1.07M
            if (length && (length < 769))
5452
1.07M
              {
5453
                /* Read global PLTE.  */
5454
5455
1.07M
                if (mng_info->global_plte == (png_colorp) NULL)
5456
50
                  mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5457
50
                    sizeof(*mng_info->global_plte));
5458
5459
1.07M
                if (mng_info->global_plte == (png_colorp) NULL)
5460
0
                  {
5461
0
                    mng_info->global_plte_length=0;
5462
0
                    chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5463
0
                    ThrowReaderException(ResourceLimitError,
5464
0
                      "MemoryAllocationFailed");
5465
0
                  }
5466
5467
1.09M
                for (i=0; i < (ssize_t) (length/3); i++)
5468
17.2k
                {
5469
17.2k
                  mng_info->global_plte[i].red=p[3*i];
5470
17.2k
                  mng_info->global_plte[i].green=p[3*i+1];
5471
17.2k
                  mng_info->global_plte[i].blue=p[3*i+2];
5472
17.2k
                }
5473
5474
1.07M
                mng_info->global_plte_length=(unsigned int) (length/3);
5475
1.07M
              }
5476
5.83k
            else
5477
5.83k
              mng_info->global_plte_length=0;
5478
5479
1.07M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5480
1.07M
            continue;
5481
1.07M
          }
5482
5483
78.0M
        if (memcmp(type,mng_tRNS,4) == 0)
5484
1.06M
          {
5485
            /* read global tRNS */
5486
5487
1.06M
            if (length > 0 && length < 257)
5488
1.86k
              for (i=0; i < (ssize_t) length; i++)
5489
1.59k
                mng_info->global_trns[i]=p[i];
5490
1.06M
            mng_info->global_trns_length=(unsigned int) length;
5491
1.06M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5492
1.06M
            continue;
5493
1.06M
          }
5494
76.9M
        if (memcmp(type,mng_gAMA,4) == 0)
5495
445k
          {
5496
445k
            if (length == 4)
5497
379k
              {
5498
379k
                ssize_t
5499
379k
                  igamma;
5500
5501
379k
                igamma=mng_get_long(p);
5502
379k
                mng_info->global_gamma=((float) igamma)*0.00001f;
5503
379k
                mng_info->have_global_gama=MagickTrue;
5504
379k
              }
5505
5506
65.6k
            else
5507
65.6k
              mng_info->have_global_gama=MagickFalse;
5508
5509
445k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5510
445k
            continue;
5511
445k
          }
5512
5513
76.5M
        if (memcmp(type,mng_cHRM,4) == 0)
5514
1.00M
          {
5515
            /* Read global cHRM */
5516
5517
1.00M
            if (length == 32)
5518
381
              {
5519
381
                mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5520
381
                mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5521
381
                mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5522
381
                mng_info->global_chrm.red_primary.y=0.00001*
5523
381
                  mng_get_long(&p[12]);
5524
381
                mng_info->global_chrm.green_primary.x=0.00001*
5525
381
                  mng_get_long(&p[16]);
5526
381
                mng_info->global_chrm.green_primary.y=0.00001*
5527
381
                  mng_get_long(&p[20]);
5528
381
                mng_info->global_chrm.blue_primary.x=0.00001*
5529
381
                  mng_get_long(&p[24]);
5530
381
                mng_info->global_chrm.blue_primary.y=0.00001*
5531
381
                  mng_get_long(&p[28]);
5532
381
                mng_info->have_global_chrm=MagickTrue;
5533
381
              }
5534
1.00M
            else
5535
1.00M
              mng_info->have_global_chrm=MagickFalse;
5536
5537
1.00M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5538
1.00M
            continue;
5539
1.00M
          }
5540
5541
75.5M
        if (memcmp(type,mng_sRGB,4) == 0)
5542
353k
          {
5543
            /*
5544
              Read global sRGB.
5545
            */
5546
353k
            if (length != 0)
5547
222k
              {
5548
222k
                mng_info->global_srgb_intent=
5549
222k
                  Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5550
222k
                mng_info->have_global_srgb=MagickTrue;
5551
222k
              }
5552
130k
            else
5553
130k
              mng_info->have_global_srgb=MagickFalse;
5554
5555
353k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5556
353k
            continue;
5557
353k
          }
5558
5559
75.1M
        if (memcmp(type,mng_iCCP,4) == 0)
5560
508
          {
5561
            /* To do: */
5562
5563
            /*
5564
              Read global iCCP.
5565
            */
5566
508
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5567
5568
508
            continue;
5569
508
          }
5570
5571
75.1M
        if (memcmp(type,mng_FRAM,4) == 0)
5572
11.3M
          {
5573
11.3M
            if (mng_type == 3)
5574
557
              (void) ThrowMagickException(exception,GetMagickModule(),
5575
557
                CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5576
557
                image->filename);
5577
5578
11.3M
            if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5579
5.20M
              image->delay=frame_delay;
5580
5581
11.3M
            frame_delay=default_frame_delay;
5582
11.3M
            frame_timeout=default_frame_timeout;
5583
11.3M
            fb=default_fb;
5584
5585
11.3M
            if (length != 0)
5586
10.3M
              if (p[0])
5587
8.20M
                mng_info->framing_mode=p[0];
5588
5589
11.3M
            if (logging != MagickFalse)
5590
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5591
0
                "    Framing_mode=%d",mng_info->framing_mode);
5592
5593
11.3M
            if (length > 6)
5594
9.36M
              {
5595
                /* Note the delay and frame clipping boundaries.  */
5596
5597
9.36M
                p++; /* framing mode */
5598
5599
49.5M
                while (((p-chunk) < (long) length) && *p)
5600
40.1M
                  p++;  /* frame name */
5601
5602
9.36M
                p++;  /* frame name terminator */
5603
5604
9.36M
                if ((p-chunk) < (ssize_t) (length-4))
5605
8.27M
                  {
5606
8.27M
                    int
5607
8.27M
                      change_delay,
5608
8.27M
                      change_timeout,
5609
8.27M
                      change_clipping;
5610
5611
8.27M
                    change_delay=(*p++);
5612
8.27M
                    change_timeout=(*p++);
5613
8.27M
                    change_clipping=(*p++);
5614
8.27M
                    p++; /* change_sync */
5615
5616
8.27M
                    if (change_delay && ((p-chunk)+4 <= (ssize_t) length))
5617
2.13M
                      {
5618
2.13M
                        frame_delay=(size_t) image->ticks_per_second*
5619
2.13M
                          (size_t) mng_get_long(p);
5620
5621
2.13M
                        if (mng_info->ticks_per_second != 0)
5622
2.13M
                          frame_delay/=mng_info->ticks_per_second;
5623
5624
1.01k
                        else
5625
1.01k
                          frame_delay=PNG_UINT_31_MAX;
5626
5627
2.13M
                        if (change_delay == 2)
5628
1.00M
                          default_frame_delay=frame_delay;
5629
5630
2.13M
                        p+=(ptrdiff_t) 4;
5631
5632
2.13M
                        if (logging != MagickFalse)
5633
0
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5634
0
                            "    Framing_delay=%.17g",(double) frame_delay);
5635
2.13M
                      }
5636
5637
8.27M
                    if (change_timeout && ((p-chunk)+4 <= (ssize_t) length))
5638
3.13M
                      {
5639
3.13M
                        frame_timeout=(size_t) image->ticks_per_second*
5640
3.13M
                          (size_t) mng_get_long(p);
5641
5642
3.13M
                        if (mng_info->ticks_per_second != 0)
5643
2.13M
                          frame_timeout/=mng_info->ticks_per_second;
5644
5645
1.00M
                        else
5646
1.00M
                          frame_timeout=PNG_UINT_31_MAX;
5647
5648
3.13M
                        if (change_timeout == 2)
5649
3
                          default_frame_timeout=frame_timeout;
5650
5651
3.13M
                        p+=(ptrdiff_t) 4;
5652
5653
3.13M
                        if (logging != MagickFalse)
5654
0
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5655
0
                            "    Framing_timeout=%.17g",(double) frame_timeout);
5656
3.13M
                      }
5657
5658
8.27M
                    if (change_clipping && ((p-chunk) < (ssize_t) (length-16)))
5659
5.00M
                      {
5660
5.00M
                        fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5661
5.00M
                        p+=(ptrdiff_t) 16;
5662
5.00M
                        previous_fb=fb;
5663
5664
5.00M
                        if (logging != MagickFalse)
5665
0
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5666
0
                            "    Frame_clip: L=%.17g R=%.17g T=%.17g B=%.17g",
5667
0
                            (double) fb.left,(double) fb.right,(double) fb.top,
5668
0
                            (double) fb.bottom);
5669
5670
5.00M
                        if (change_clipping == 2)
5671
1.00M
                          default_fb=fb;
5672
5.00M
                      }
5673
8.27M
                  }
5674
9.36M
              }
5675
11.3M
            mng_info->clip=fb;
5676
11.3M
            mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5677
5678
11.3M
            subframe_width=(size_t) (mng_info->clip.right
5679
11.3M
               -mng_info->clip.left);
5680
5681
11.3M
            subframe_height=(size_t) (mng_info->clip.bottom
5682
11.3M
               -mng_info->clip.top);
5683
            /*
5684
              Insert a background layer behind the frame if framing_mode is 4.
5685
            */
5686
11.3M
            if (logging != MagickFalse)
5687
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5688
0
                "   subframe_width=%.17g, subframe_height=%.17g",(double)
5689
0
                subframe_width,(double) subframe_height);
5690
5691
11.3M
            if (insert_layers && (mng_info->framing_mode == 4) &&
5692
3.06M
                (subframe_width) && (subframe_height))
5693
1.96k
              {
5694
                /* Allocate next image structure.  */
5695
1.96k
                if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5696
67
                  {
5697
67
                    AcquireNextImage(image_info,image,exception);
5698
5699
67
                    if (GetNextImageInList(image) == (Image *) NULL)
5700
0
                      return(DestroyImageList(image));
5701
5702
67
                    image=SyncNextImageInList(image);
5703
67
                  }
5704
5705
1.96k
                mng_info->image=image;
5706
5707
1.96k
                if (term_chunk_found)
5708
98
                  {
5709
98
                    image->start_loop=MagickTrue;
5710
98
                    image->iterations=mng_iterations;
5711
98
                    term_chunk_found=MagickFalse;
5712
98
                  }
5713
5714
1.86k
                else
5715
1.86k
                    image->start_loop=MagickFalse;
5716
5717
1.96k
                image->columns=subframe_width;
5718
1.96k
                image->rows=subframe_height;
5719
1.96k
                image->page.width=subframe_width;
5720
1.96k
                image->page.height=subframe_height;
5721
1.96k
                image->page.x=mng_info->clip.left;
5722
1.96k
                image->page.y=mng_info->clip.top;
5723
1.96k
                image->background_color=mng_background_color;
5724
1.96k
                image->alpha_trait=UndefinedPixelTrait;
5725
1.96k
                image->delay=0;
5726
1.96k
                if (SetImageBackgroundColor(image,exception) == MagickFalse)
5727
97
                  {
5728
97
                    chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5729
97
                    return(DestroyImageList(image));
5730
97
                  }
5731
1.86k
                if (logging != MagickFalse)
5732
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5733
0
                    "  Insert backgd layer, L=%.17g, R=%.17g T=%.17g, B=%.17g",
5734
0
                    (double) mng_info->clip.left,
5735
0
                    (double) mng_info->clip.right,
5736
0
                    (double) mng_info->clip.top,
5737
0
                    (double) mng_info->clip.bottom);
5738
1.86k
              }
5739
11.3M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5740
11.3M
            continue;
5741
11.3M
          }
5742
5743
63.7M
        if (memcmp(type,mng_CLIP,4) == 0)
5744
2.00M
          {
5745
2.00M
            unsigned int
5746
2.00M
              first_object,
5747
2.00M
              last_object;
5748
5749
            /*
5750
              Read CLIP.
5751
            */
5752
2.00M
            if (length > 3)
5753
1.00M
              {
5754
1.00M
                first_object=(unsigned int) ((p[0] << 8) | p[1]);
5755
1.00M
                last_object=(unsigned int) ((p[2] << 8) | p[3]);
5756
1.00M
                p+=(ptrdiff_t) 4;
5757
5758
247M
                for (i=(int) first_object; i <= (int) last_object; i++)
5759
246M
                {
5760
246M
                  if ((i < 0) || (i >= MNG_MAX_OBJECTS))
5761
174M
                    continue;
5762
5763
71.8M
                  if (mng_info->exists[i] && !mng_info->frozen[i])
5764
1.00M
                    {
5765
1.00M
                      MngBox
5766
1.00M
                        box;
5767
5768
1.00M
                      box=mng_info->object_clip[i];
5769
1.00M
                      if ((p-chunk) < (ssize_t) (length-17))
5770
1.00M
                        mng_info->object_clip[i]=
5771
1.00M
                           mng_read_box(box,(char) p[0],&p[1]);
5772
1.00M
                    }
5773
71.8M
                }
5774
5775
1.00M
              }
5776
2.00M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5777
2.00M
            continue;
5778
2.00M
          }
5779
5780
61.7M
        if (memcmp(type,mng_SAVE,4) == 0)
5781
137k
          {
5782
35.2M
            for (i=1; i < MNG_MAX_OBJECTS; i++)
5783
35.0M
              if (mng_info->exists[i])
5784
101k
                 mng_info->frozen[i]=MagickTrue;
5785
5786
137k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5787
5788
137k
            continue;
5789
137k
          }
5790
5791
61.6M
        if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5792
935k
          {
5793
            /* Read DISC or SEEK.  */
5794
5795
935k
            if ((length == 0) || (length % 2) || !memcmp(type,mng_SEEK,4))
5796
859k
              {
5797
220M
                for (i=1; i < MNG_MAX_OBJECTS; i++)
5798
219M
                  MngReadInfoDiscardObject(mng_info,(int) i);
5799
859k
              }
5800
5801
75.9k
            else
5802
75.9k
              {
5803
75.9k
                ssize_t
5804
75.9k
                  j;
5805
5806
273k
                for (j=1; j < (ssize_t) length; j+=2)
5807
197k
                {
5808
197k
                  i=p[j-1] << 8 | p[j];
5809
197k
                  MngReadInfoDiscardObject(mng_info,(int) i);
5810
197k
                }
5811
75.9k
              }
5812
5813
935k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5814
5815
935k
            continue;
5816
935k
          }
5817
5818
60.7M
        if (memcmp(type,mng_MOVE,4) == 0)
5819
741k
          {
5820
741k
            size_t
5821
741k
              first_object,
5822
741k
              last_object;
5823
5824
            /* read MOVE */
5825
5826
741k
            if (length > 3)
5827
740k
            {
5828
740k
              first_object=(unsigned int) ((p[0] << 8) | p[1]);
5829
740k
              last_object=(unsigned int) ((p[2] << 8) | p[3]);
5830
740k
              p+=(ptrdiff_t) 4;
5831
5832
78.5M
              for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5833
77.7M
              {
5834
77.7M
                if ((i < 0) || (i >= MNG_MAX_OBJECTS))
5835
15.9M
                  continue;
5836
5837
61.8M
                if (mng_info->exists[i] && !mng_info->frozen[i] &&
5838
731k
                    (p-chunk) < (ssize_t) (length-8))
5839
669k
                  {
5840
669k
                    MngPair
5841
669k
                      new_pair;
5842
5843
669k
                    MngPair
5844
669k
                      old_pair;
5845
5846
669k
                    old_pair.a=(volatile long) mng_info->x_off[i];
5847
669k
                    old_pair.b=(volatile long) mng_info->y_off[i];
5848
669k
                    new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]);
5849
669k
                    mng_info->x_off[i]=new_pair.a;
5850
669k
                    mng_info->y_off[i]=new_pair.b;
5851
669k
                  }
5852
61.8M
              }
5853
740k
            }
5854
5855
741k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5856
741k
            continue;
5857
741k
          }
5858
5859
59.9M
        if (memcmp(type,mng_LOOP,4) == 0)
5860
3.54M
          {
5861
3.54M
            ssize_t loop_iters=1;
5862
3.54M
            if (number_loop_ops > MNG_MAX_LOOP_OPS)
5863
5
              {
5864
5
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5865
5
                ThrowReaderException(ResourceLimitError,"too many LOOP/ENDL ops");
5866
0
              }
5867
3.54M
            number_loop_ops+=1;
5868
3.54M
            if (length > 4)
5869
3.03M
              {
5870
3.03M
                loop_level=chunk[0];
5871
3.03M
                mng_info->loop_active[loop_level]=1;  /* mark loop active */
5872
5873
                /* Record starting point.  */
5874
3.03M
                loop_iters=mng_get_long(&chunk[1]);
5875
5876
3.03M
                if (logging != MagickFalse)
5877
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5878
0
                    "  LOOP level %.17g has %.17g iterations ",
5879
0
                    (double) loop_level, (double) loop_iters);
5880
5881
3.03M
                if (loop_iters <= 0)
5882
930k
                  skipping_loop=(volatile short) loop_level;
5883
5884
2.10M
                else
5885
2.10M
                  {
5886
2.10M
                    if (loop_iters >= 2147483647L)
5887
833k
                      loop_iters=2147483647L;
5888
2.10M
                    if (image_info->number_scenes != 0)
5889
0
                      if (loop_iters > (ssize_t) image_info->number_scenes)
5890
0
                        loop_iters=(ssize_t) image_info->number_scenes;
5891
2.10M
                    mng_info->loop_jump[loop_level]=TellBlob(image);
5892
2.10M
                    mng_info->loop_count[loop_level]=loop_iters;
5893
2.10M
                  }
5894
5895
3.03M
                mng_info->loop_iteration[loop_level]=0;
5896
3.03M
              }
5897
3.54M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5898
3.54M
            continue;
5899
3.54M
          }
5900
5901
56.4M
        if (memcmp(type,mng_ENDL,4) == 0)
5902
45.0M
          {
5903
45.0M
            if (number_loop_ops > MNG_MAX_LOOP_OPS)
5904
37
              {
5905
37
                chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5906
37
                ThrowReaderException(ResourceLimitError,"too many LOOP/ENDL ops");
5907
0
              }
5908
45.0M
            number_loop_ops+=1;
5909
45.0M
            if (length > 0)
5910
44.5M
              {
5911
44.5M
                loop_level=chunk[0];
5912
5913
44.5M
                if (skipping_loop > 0)
5914
72.5k
                  {
5915
72.5k
                    if (skipping_loop == loop_level)
5916
72.2k
                      {
5917
                        /*
5918
                          Found end of zero-iteration loop.
5919
                        */
5920
72.2k
                        skipping_loop=(-1);
5921
72.2k
                        mng_info->loop_active[loop_level]=0;
5922
72.2k
                      }
5923
72.5k
                  }
5924
5925
44.5M
                else
5926
44.5M
                  {
5927
44.5M
                    if (mng_info->loop_active[loop_level] == 1)
5928
43.6M
                      {
5929
43.6M
                        mng_info->loop_count[loop_level]--;
5930
43.6M
                        mng_info->loop_iteration[loop_level]++;
5931
5932
43.6M
                        if (logging != MagickFalse)
5933
0
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5934
0
                          "  ENDL: LOOP level %.17g has %.17g remaining iters",
5935
0
                            (double) loop_level,(double)
5936
0
                            mng_info->loop_count[loop_level]);
5937
5938
43.6M
                        if (mng_info->loop_count[loop_level] > 0)
5939
43.3M
                          {
5940
43.3M
                            offset=SeekBlob(image,
5941
43.3M
                              mng_info->loop_jump[loop_level],SEEK_SET);
5942
5943
43.3M
                            if (offset < 0)
5944
0
                              {
5945
0
                                chunk=(unsigned char *) RelinquishMagickMemory(
5946
0
                                  chunk);
5947
0
                                ThrowReaderException(CorruptImageError,
5948
0
                                  "ImproperImageHeader");
5949
0
                              }
5950
43.3M
                          }
5951
5952
339k
                        else
5953
339k
                          {
5954
339k
                            short
5955
339k
                              last_level;
5956
5957
                            /*
5958
                              Finished loop.
5959
                            */
5960
339k
                            mng_info->loop_active[loop_level]=0;
5961
339k
                            last_level=(-1);
5962
1.11M
                            for (i=0; i < loop_level; i++)
5963
776k
                              if (mng_info->loop_active[i] == 1)
5964
4.94k
                                last_level=(short) i;
5965
339k
                            loop_level=last_level;
5966
339k
                          }
5967
43.6M
                      }
5968
44.5M
                  }
5969
44.5M
              }
5970
5971
45.0M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5972
45.0M
            continue;
5973
45.0M
          }
5974
5975
11.3M
        if (memcmp(type,mng_CLON,4) == 0)
5976
457k
          {
5977
457k
            if (mng_info->clon_warning == 0)
5978
28
              (void) ThrowMagickException(exception,GetMagickModule(),
5979
28
                CoderError,"CLON is not implemented yet","`%s'",
5980
28
                image->filename);
5981
5982
457k
            mng_info->clon_warning++;
5983
457k
          }
5984
5985
11.3M
        if (memcmp(type,mng_MAGN,4) == 0)
5986
4.99M
          {
5987
4.99M
            png_uint_16
5988
4.99M
              magn_first,
5989
4.99M
              magn_last,
5990
4.99M
              magn_mb,
5991
4.99M
              magn_ml,
5992
4.99M
              magn_mr,
5993
4.99M
              magn_mt,
5994
4.99M
              magn_mx,
5995
4.99M
              magn_my,
5996
4.99M
              magn_methx,
5997
4.99M
              magn_methy;
5998
5999
4.99M
            if (length > 1)
6000
4.93M
              magn_first=(p[0] << 8) | p[1];
6001
6002
56.9k
            else
6003
56.9k
              magn_first=0;
6004
6005
4.99M
            if (length > 3)
6006
4.92M
              magn_last=(p[2] << 8) | p[3];
6007
6008
61.2k
            else
6009
61.2k
              magn_last=magn_first;
6010
4.99M
            if (magn_first || magn_last)
6011
3.46M
              if (mng_info->magn_warning == 0)
6012
130
                {
6013
130
                  (void) ThrowMagickException(exception,
6014
130
                     GetMagickModule(),CoderError,
6015
130
                     "MAGN is not implemented yet for nonzero objects",
6016
130
                     "`%s'",image->filename);
6017
6018
130
                   mng_info->magn_warning++;
6019
130
                }
6020
4.99M
            if (length > 4)
6021
3.92M
              magn_methx=p[4];
6022
6023
1.06M
            else
6024
1.06M
              magn_methx=0;
6025
6026
4.99M
            if (length > 6)
6027
2.92M
              magn_mx=(p[5] << 8) | p[6];
6028
6029
2.06M
            else
6030
2.06M
              magn_mx=1;
6031
6032
4.99M
            if (magn_mx == 0)
6033
2.92M
              magn_mx=1;
6034
6035
4.99M
            if (length > 8)
6036
2.92M
              magn_my=(p[7] << 8) | p[8];
6037
6038
2.06M
            else
6039
2.06M
              magn_my=magn_mx;
6040
6041
4.99M
            if (magn_my == 0)
6042
4.14k
              magn_my=1;
6043
6044
4.99M
            if (length > 10)
6045
10.1k
              magn_ml=(p[9] << 8) | p[10];
6046
6047
4.98M
            else
6048
4.98M
              magn_ml=magn_mx;
6049
6050
4.99M
            if (magn_ml == 0)
6051
4.17k
              magn_ml=1;
6052
6053
4.99M
            if (length > 12)
6054
9.92k
              magn_mr=(p[11] << 8) | p[12];
6055
6056
4.98M
            else
6057
4.98M
              magn_mr=magn_mx;
6058
6059
4.99M
            if (magn_mr == 0)
6060
9.15k
              magn_mr=1;
6061
6062
4.99M
            if (length > 14)
6063
9.44k
              magn_mt=(p[13] << 8) | p[14];
6064
6065
4.98M
            else
6066
4.98M
              magn_mt=magn_my;
6067
6068
4.99M
            if (magn_mt == 0)
6069
9.21k
              magn_mt=1;
6070
6071
4.99M
            if (length > 16)
6072
5.76k
              magn_mb=(p[15] << 8) | p[16];
6073
6074
4.98M
            else
6075
4.98M
              magn_mb=magn_my;
6076
6077
4.99M
            if (magn_mb == 0)
6078
5.68k
              magn_mb=1;
6079
6080
4.99M
            if (length > 17)
6081
5.76k
              magn_methy=p[17];
6082
6083
4.98M
            else
6084
4.98M
              magn_methy=magn_methx;
6085
6086
6087
4.99M
            if (magn_methx > 5 || magn_methy > 5)
6088
9.92k
              if (mng_info->magn_warning == 0)
6089
12
                {
6090
12
                  (void) ThrowMagickException(exception,
6091
12
                     GetMagickModule(),CoderError,
6092
12
                     "Unknown MAGN method in MNG datastream","`%s'",
6093
12
                     image->filename);
6094
6095
12
                   mng_info->magn_warning++;
6096
12
                }
6097
4.99M
            if (magn_first == 0 || magn_last == 0)
6098
3.98M
              {
6099
                /* Save the magnification factors for object 0 */
6100
3.98M
                mng_info->magn_mb=magn_mb;
6101
3.98M
                mng_info->magn_ml=magn_ml;
6102
3.98M
                mng_info->magn_mr=magn_mr;
6103
3.98M
                mng_info->magn_mt=magn_mt;
6104
3.98M
                mng_info->magn_mx=magn_mx;
6105
3.98M
                mng_info->magn_my=magn_my;
6106
3.98M
                mng_info->magn_methx=magn_methx;
6107
3.98M
                mng_info->magn_methy=magn_methy;
6108
3.98M
              }
6109
4.99M
          }
6110
6111
11.3M
        if (memcmp(type,mng_PAST,4) == 0)
6112
657k
          {
6113
657k
            if (mng_info->past_warning == 0)
6114
11
              (void) ThrowMagickException(exception,GetMagickModule(),
6115
11
                CoderError,"PAST is not implemented yet","`%s'",
6116
11
                image->filename);
6117
6118
657k
            mng_info->past_warning++;
6119
657k
          }
6120
6121
11.3M
        if (memcmp(type,mng_SHOW,4) == 0)
6122
424k
          {
6123
424k
            if (mng_info->show_warning == 0)
6124
29
              (void) ThrowMagickException(exception,GetMagickModule(),
6125
29
                CoderError,"SHOW is not implemented yet","`%s'",
6126
29
                image->filename);
6127
6128
424k
            mng_info->show_warning++;
6129
424k
          }
6130
6131
11.3M
        if (memcmp(type,mng_sBIT,4) == 0)
6132
1.05k
          {
6133
1.05k
            if (length < 4)
6134
358
              mng_info->have_global_sbit=MagickFalse;
6135
6136
693
            else
6137
693
              {
6138
693
                mng_info->global_sbit.gray=p[0];
6139
693
                mng_info->global_sbit.red=p[0];
6140
693
                mng_info->global_sbit.green=p[1];
6141
693
                mng_info->global_sbit.blue=p[2];
6142
693
                mng_info->global_sbit.alpha=p[3];
6143
693
                mng_info->have_global_sbit=MagickTrue;
6144
693
             }
6145
1.05k
          }
6146
11.3M
        if (memcmp(type,mng_pHYs,4) == 0)
6147
67.4k
          {
6148
67.4k
            if (length > 8)
6149
66.5k
              {
6150
66.5k
                mng_info->global_x_pixels_per_unit=
6151
66.5k
                    (size_t) mng_get_long(p);
6152
66.5k
                mng_info->global_y_pixels_per_unit=
6153
66.5k
                    (size_t) mng_get_long(&p[4]);
6154
66.5k
                mng_info->global_phys_unit_type=p[8];
6155
66.5k
                mng_info->have_global_phys=MagickTrue;
6156
66.5k
              }
6157
6158
897
            else
6159
897
              mng_info->have_global_phys=MagickFalse;
6160
67.4k
          }
6161
11.3M
        if (memcmp(type,mng_pHYg,4) == 0)
6162
337k
          {
6163
337k
            if (mng_info->phyg_warning == 0)
6164
24
              (void) ThrowMagickException(exception,GetMagickModule(),
6165
24
                CoderError,"pHYg is not implemented.","`%s'",image->filename);
6166
6167
337k
            mng_info->phyg_warning++;
6168
337k
          }
6169
11.3M
        if (memcmp(type,mng_BASI,4) == 0)
6170
280k
          {
6171
280k
            skip_to_iend=MagickTrue;
6172
6173
280k
            if (mng_info->basi_warning == 0)
6174
16
              (void) ThrowMagickException(exception,GetMagickModule(),
6175
16
                CoderError,"BASI is not implemented yet","`%s'",
6176
16
                image->filename);
6177
6178
280k
            mng_info->basi_warning++;
6179
280k
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6180
280k
            continue;
6181
280k
          }
6182
6183
11.0M
        if (memcmp(type,mng_IHDR,4)
6184
11.0M
#if defined(JNG_SUPPORTED)
6185
11.0M
            && memcmp(type,mng_JHDR,4)
6186
11.0M
#endif
6187
11.0M
            )
6188
11.0M
          {
6189
            /* Not an IHDR or JHDR chunk */
6190
11.0M
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6191
6192
11.0M
            continue;
6193
11.0M
          }
6194
/* Process IHDR */
6195
29.5k
        if (logging != MagickFalse)
6196
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6197
0
            "  Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6198
6199
29.5k
        mng_info->exists[object_id]=MagickTrue;
6200
29.5k
        mng_info->viewable[object_id]=MagickTrue;
6201
6202
29.5k
        if (mng_info->invisible[object_id])
6203
460
          {
6204
460
            if (logging != MagickFalse)
6205
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6206
0
                "  Skipping invisible object");
6207
6208
460
            skip_to_iend=MagickTrue;
6209
460
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6210
460
            continue;
6211
460
          }
6212
29.0k
        if (length < 8)
6213
6
          {
6214
6
            chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6215
6
            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6216
0
          }
6217
6218
29.0k
        image_width=(size_t) mng_get_long(p);
6219
29.0k
        image_height=(size_t) mng_get_long(&p[4]);
6220
29.0k
        chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6221
6222
        /*
6223
          Insert a transparent background layer behind the entire animation
6224
          if it is not full screen.
6225
        */
6226
29.0k
        if (insert_layers && mng_type && first_mng_object)
6227
646
          {
6228
646
            if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6229
575
                (image_width < mng_info->mng_width) ||
6230
225
                (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6231
224
                (image_height < mng_info->mng_height) ||
6232
153
                (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6233
495
              {
6234
495
                if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6235
0
                  {
6236
                    /*
6237
                      Allocate next image structure.
6238
                    */
6239
0
                    AcquireNextImage(image_info,image,exception);
6240
6241
0
                    if (GetNextImageInList(image) == (Image *) NULL)
6242
0
                      return(DestroyImageList(image));
6243
6244
0
                    image=SyncNextImageInList(image);
6245
0
                  }
6246
495
                mng_info->image=image;
6247
6248
495
                if (term_chunk_found)
6249
1
                  {
6250
1
                    image->start_loop=MagickTrue;
6251
1
                    image->iterations=mng_iterations;
6252
1
                    term_chunk_found=MagickFalse;
6253
1
                  }
6254
6255
494
                else
6256
494
                    image->start_loop=MagickFalse;
6257
6258
                /* Make a background rectangle.  */
6259
6260
495
                image->delay=0;
6261
495
                image->columns=mng_info->mng_width;
6262
495
                image->rows=mng_info->mng_height;
6263
495
                image->page.width=mng_info->mng_width;
6264
495
                image->page.height=mng_info->mng_height;
6265
495
                image->page.x=0;
6266
495
                image->page.y=0;
6267
495
                image->background_color=mng_background_color;
6268
495
                (void) SetImageBackgroundColor(image,exception);
6269
495
                if (logging != MagickFalse)
6270
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6271
0
                    "  Inserted transparent background layer, W=%.17g, H=%.17g",
6272
0
                    (double) mng_info->mng_width,(double) mng_info->mng_height);
6273
495
              }
6274
646
          }
6275
        /*
6276
          Insert a background layer behind the upcoming image if
6277
          framing_mode is 3, and we haven't already inserted one.
6278
        */
6279
29.0k
        if (insert_layers && (mng_info->framing_mode == 3) &&
6280
530
                (subframe_width) && (subframe_height) && (simplicity == 0 ||
6281
366
                (simplicity & 0x08)))
6282
199
          {
6283
199
            if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6284
63
            {
6285
              /*
6286
                Allocate next image structure.
6287
              */
6288
63
              AcquireNextImage(image_info,image,exception);
6289
6290
63
              if (GetNextImageInList(image) == (Image *) NULL)
6291
0
                return(DestroyImageList(image));
6292
6293
63
              image=SyncNextImageInList(image);
6294
63
            }
6295
6296
199
            mng_info->image=image;
6297
6298
199
            if (term_chunk_found)
6299
21
              {
6300
21
                image->start_loop=MagickTrue;
6301
21
                image->iterations=mng_iterations;
6302
21
                term_chunk_found=MagickFalse;
6303
21
              }
6304
6305
178
            else
6306
178
                image->start_loop=MagickFalse;
6307
6308
199
            image->delay=0;
6309
199
            image->columns=subframe_width;
6310
199
            image->rows=subframe_height;
6311
199
            image->page.width=subframe_width;
6312
199
            image->page.height=subframe_height;
6313
199
            image->page.x=mng_info->clip.left;
6314
199
            image->page.y=mng_info->clip.top;
6315
199
            image->background_color=mng_background_color;
6316
199
            image->alpha_trait=UndefinedPixelTrait;
6317
199
            (void) SetImageBackgroundColor(image,exception);
6318
6319
199
            if (logging != MagickFalse)
6320
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6321
0
                "  Insert background layer, L=%.17g, R=%.17g T=%.17g, B=%.17g",
6322
0
                (double) mng_info->clip.left,(double) mng_info->clip.right,
6323
0
                (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6324
199
          }
6325
29.0k
        first_mng_object=MagickFalse;
6326
6327
29.0k
        if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6328
18.5k
          {
6329
            /*
6330
              Allocate next image structure.
6331
            */
6332
18.5k
            AcquireNextImage(image_info,image,exception);
6333
6334
18.5k
            if (GetNextImageInList(image) == (Image *) NULL)
6335
0
              return(DestroyImageList(image));
6336
6337
18.5k
            image=SyncNextImageInList(image);
6338
18.5k
          }
6339
29.0k
        mng_info->image=image;
6340
29.0k
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6341
29.0k
          GetBlobSize(image));
6342
6343
29.0k
        if (status == MagickFalse)
6344
0
          break;
6345
6346
29.0k
        if (term_chunk_found)
6347
43
          {
6348
43
            image->start_loop=MagickTrue;
6349
43
            term_chunk_found=MagickFalse;
6350
43
          }
6351
6352
29.0k
        else
6353
29.0k
            image->start_loop=MagickFalse;
6354
6355
29.0k
        if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6356
28.8k
          {
6357
28.8k
            image->delay=frame_delay;
6358
28.8k
            frame_delay=default_frame_delay;
6359
28.8k
          }
6360
6361
165
        else
6362
165
          image->delay=0;
6363
6364
29.0k
        if (mng_info->framing_mode == 3)
6365
547
          image->dispose=BackgroundDispose;
6366
28.5k
        else
6367
28.5k
          image->dispose=NoneDispose;
6368
6369
29.0k
        image->page.width=mng_info->mng_width;
6370
29.0k
        image->page.height=mng_info->mng_height;
6371
29.0k
        image->page.x=mng_info->x_off[object_id];
6372
29.0k
        image->page.y=mng_info->y_off[object_id];
6373
29.0k
        image->iterations=mng_iterations;
6374
6375
        /*
6376
          Seek back to the beginning of the IHDR or JHDR chunk's length field.
6377
        */
6378
6379
29.0k
        if (logging != MagickFalse)
6380
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6381
0
            "  Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6382
0
            type[2],type[3]);
6383
6384
29.0k
        offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6385
6386
29.0k
        if (offset < 0)
6387
29.0k
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6388
29.0k
      }
6389
6390
29.0k
    mng_info->image=image;
6391
29.0k
    mng_info->mng_type=mng_type;
6392
29.0k
    mng_info->object_id=object_id;
6393
6394
29.0k
    if (memcmp(type,mng_IHDR,4) == 0)
6395
16.6k
      image=ReadOnePNGImage(mng_info,image_info,exception);
6396
6397
12.4k
#if defined(JNG_SUPPORTED)
6398
12.4k
    else
6399
12.4k
      image=ReadOneJNGImage(mng_info,image_info,exception);
6400
29.0k
#endif
6401
6402
29.0k
    if (image == (Image *) NULL)
6403
7.19k
      {
6404
7.19k
        if (logging != MagickFalse)
6405
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6406
0
            "exit ReadJNGImage() with error");
6407
7.19k
        return((Image *) NULL);
6408
7.19k
      }
6409
6410
21.8k
    if (image->columns == 0 || image->rows == 0)
6411
0
      {
6412
0
        (void) CloseBlob(image);
6413
0
        return(DestroyImageList(image));
6414
0
      }
6415
6416
21.8k
    if (exception->severity > ErrorException)
6417
86
      {
6418
86
        (void) CloseBlob(image);
6419
86
        return(DestroyImageList(image));
6420
86
      }
6421
6422
21.7k
    mng_info->image=image;
6423
6424
21.7k
    if (mng_type)
6425
2.95k
      {
6426
2.95k
        MngBox
6427
2.95k
          crop_box;
6428
6429
2.95k
        if (((mng_info->magn_methx > 0) && (mng_info->magn_methx <= 5)) &&
6430
457
            ((mng_info->magn_methy > 0) && (mng_info->magn_methy <= 5)))
6431
432
          {
6432
432
            size_t
6433
432
               magnified_height,
6434
432
               magnified_width;
6435
6436
432
            if (logging != MagickFalse)
6437
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6438
0
                "  Processing MNG MAGN chunk");
6439
6440
432
            if (image->columns == 1)
6441
219
              mng_info->magn_methx = 1;
6442
432
            if (image->rows == 1)
6443
219
              mng_info->magn_methy = 1;
6444
432
            if (mng_info->magn_methx == 1)
6445
253
              {
6446
253
                magnified_width=(size_t) mng_info->magn_ml;
6447
6448
253
                if (image->columns > 1)
6449
34
                   magnified_width += mng_info->magn_mr;
6450
6451
253
                if (image->columns > 2)
6452
34
                  {
6453
34
                    size_t extra_width;
6454
34
                    if (HeapOverflowSanityCheckGetSize(image->columns-2,mng_info->magn_mx,&extra_width) != MagickFalse)
6455
34
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6456
34
                    if (((size_t) MAGICK_SSIZE_MAX-magnified_width) < extra_width)
6457
34
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6458
34
                    magnified_width+=extra_width;
6459
34
                  }
6460
253
              }
6461
6462
179
            else
6463
179
              {
6464
179
                magnified_width=(size_t) image->columns;
6465
6466
179
                if (image->columns > 1)
6467
179
                   magnified_width += mng_info->magn_ml-1;
6468
6469
179
                if (image->columns > 2)
6470
179
                   magnified_width += mng_info->magn_mr-1;
6471
6472
179
                if (image->columns > 3)
6473
179
                  {
6474
179
                    size_t extra_width;
6475
179
                    if (HeapOverflowSanityCheckGetSize(image->columns-3,mng_info->magn_mx-1,&extra_width) != MagickFalse)
6476
178
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6477
178
                    if (((size_t) MAGICK_SSIZE_MAX-magnified_width) < extra_width)
6478
178
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6479
178
                    magnified_width+=extra_width;
6480
178
                  }
6481
179
              }
6482
6483
431
            if (mng_info->magn_methy == 1)
6484
253
              {
6485
253
                magnified_height=(size_t) mng_info->magn_mt;
6486
6487
253
                if (image->rows > 1)
6488
34
                   magnified_height += mng_info->magn_mb;
6489
6490
253
                if (image->rows > 2)
6491
34
                  {
6492
34
                    size_t extra_height;
6493
34
                    if (HeapOverflowSanityCheckGetSize(image->rows-2,mng_info->magn_my,&extra_height) != MagickFalse)
6494
34
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6495
34
                    if (((size_t) MAGICK_SSIZE_MAX-magnified_height) < extra_height)
6496
34
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6497
34
                    magnified_height+=extra_height;
6498
34
                  }
6499
253
              }
6500
6501
178
            else
6502
178
              {
6503
178
                magnified_height=(size_t) image->rows;
6504
6505
178
                if (image->rows > 1)
6506
178
                   magnified_height += mng_info->magn_mt-1;
6507
6508
178
                if (image->rows > 2)
6509
178
                   magnified_height += mng_info->magn_mb-1;
6510
6511
178
                if (image->rows > 3)
6512
178
                  {
6513
178
                    size_t extra_height;
6514
178
                    if (HeapOverflowSanityCheckGetSize(image->rows-3,mng_info->magn_my-1,&extra_height) != MagickFalse)
6515
177
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6516
177
                    if (((size_t) MAGICK_SSIZE_MAX-magnified_height) < extra_height)
6517
177
                      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6518
177
                    magnified_height+=extra_height;
6519
177
                  }
6520
178
              }
6521
6522
430
            if (magnified_height > image->rows ||
6523
113
                magnified_width > image->columns)
6524
397
              {
6525
397
                Image
6526
397
                  *large_image;
6527
6528
397
                int
6529
397
                  yy;
6530
6531
397
                Quantum
6532
397
                  *next,
6533
397
                  *prev;
6534
6535
397
                png_uint_16
6536
397
                  magn_methx,
6537
397
                  magn_methy;
6538
6539
397
                ssize_t
6540
397
                  m,
6541
397
                  y;
6542
6543
397
                Quantum
6544
397
                  *n,
6545
397
                  *q;
6546
6547
397
                ssize_t
6548
397
                  x;
6549
6550
                /* Allocate next image structure.  */
6551
6552
397
                if (logging != MagickFalse)
6553
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6554
0
                    "    Allocate magnified image");
6555
6556
397
                AcquireNextImage(image_info,image,exception);
6557
6558
397
                if (GetNextImageInList(image) == (Image *) NULL)
6559
0
                  return(DestroyImageList(image));
6560
6561
397
                large_image=SyncNextImageInList(image);
6562
6563
397
                large_image->columns=magnified_width;
6564
397
                large_image->rows=magnified_height;
6565
6566
397
                status=SetImageExtent(image,image->columns,image->rows,exception);
6567
397
                if (status == MagickFalse)
6568
0
                  return(DestroyImageList(image));
6569
6570
397
                magn_methx=mng_info->magn_methx;
6571
397
                magn_methy=mng_info->magn_methy;
6572
6573
#if (MAGICKCORE_QUANTUM_DEPTH > 16)
6574
#define QM unsigned short
6575
                if (magn_methx != 1 || magn_methy != 1)
6576
                  {
6577
                  /*
6578
                     Scale pixels to unsigned shorts to prevent
6579
                     overflow of intermediate values of interpolations
6580
                  */
6581
                     for (y=0; y < (ssize_t) image->rows; y++)
6582
                     {
6583
                       q=GetAuthenticPixels(image,0,y,image->columns,1,
6584
                          exception);
6585
                       if (q == (Quantum *) NULL)
6586
                         break;
6587
                       for (x=(ssize_t) image->columns-1; x >= 0; x--)
6588
                       {
6589
                          SetPixelRed(image,ScaleQuantumToShort(
6590
                            GetPixelRed(image,q)),q);
6591
                          SetPixelGreen(image,ScaleQuantumToShort(
6592
                            GetPixelGreen(image,q)),q);
6593
                          SetPixelBlue(image,ScaleQuantumToShort(
6594
                            GetPixelBlue(image,q)),q);
6595
                          SetPixelAlpha(image,ScaleQuantumToShort(
6596
                            GetPixelAlpha(image,q)),q);
6597
                          q+=(ptrdiff_t) GetPixelChannels(image);
6598
                       }
6599
6600
                       if (SyncAuthenticPixels(image,exception) == MagickFalse)
6601
                         break;
6602
                     }
6603
                  }
6604
#else
6605
397
#define QM Quantum
6606
397
#endif
6607
6608
397
                if (image->alpha_trait != UndefinedPixelTrait)
6609
98
                   (void) SetImageBackgroundColor(large_image,exception);
6610
6611
299
                else
6612
299
                  {
6613
299
                    large_image->background_color.alpha=OpaqueAlpha;
6614
299
                    (void) SetImageBackgroundColor(large_image,exception);
6615
6616
299
                    if (magn_methx == 4)
6617
53
                      magn_methx=2;
6618
6619
299
                    if (magn_methx == 5)
6620
28
                      magn_methx=3;
6621
6622
299
                    if (magn_methy == 4)
6623
53
                      magn_methy=2;
6624
6625
299
                    if (magn_methy == 5)
6626
28
                      magn_methy=3;
6627
299
                  }
6628
6629
                /* magnify the rows into the right side of the large image */
6630
6631
397
                if (logging != MagickFalse)
6632
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6633
0
                    "    Magnify the rows to %.17g",
6634
0
                    (double) large_image->rows);
6635
397
                m=(ssize_t) mng_info->magn_mt;
6636
397
                yy=0;
6637
397
                length=(size_t) GetPixelChannels(image)*image->columns;
6638
397
                next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6639
397
                prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6640
6641
397
                if ((prev == (Quantum *) NULL) ||
6642
397
                    (next == (Quantum *) NULL))
6643
0
                  {
6644
0
                    if (prev != (Quantum *) NULL)
6645
0
                      prev=(Quantum *) RelinquishMagickMemory(prev);
6646
0
                    if (next != (Quantum *) NULL)
6647
0
                      next=(Quantum *) RelinquishMagickMemory(next);
6648
0
                    image=DestroyImageList(image);
6649
0
                    ThrowReaderException(ResourceLimitError,
6650
0
                      "MemoryAllocationFailed");
6651
0
                  }
6652
6653
397
                n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6654
397
                (void) memcpy(next,n,length*sizeof(*next));
6655
6656
45.3k
                for (y=0; y < (ssize_t) image->rows; y++)
6657
44.9k
                {
6658
44.9k
                  if (y == 0)
6659
397
                    m=(ssize_t) mng_info->magn_mt;
6660
6661
44.5k
                  else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6662
177
                    m=(ssize_t) mng_info->magn_mb;
6663
6664
44.3k
                  else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6665
34
                    m=(ssize_t) mng_info->magn_mb;
6666
6667
44.3k
                  else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6668
177
                    m=1;
6669
6670
44.1k
                  else
6671
44.1k
                    m=(ssize_t) mng_info->magn_my;
6672
6673
44.9k
                  n=prev;
6674
44.9k
                  prev=next;
6675
44.9k
                  next=n;
6676
6677
44.9k
                  if (y < (ssize_t) image->rows-1)
6678
44.5k
                    {
6679
44.5k
                      n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6680
44.5k
                        exception);
6681
44.5k
                      (void) memcpy(next,n,length*sizeof(*next));
6682
44.5k
                    }
6683
6684
230k
                  for (i=0; i < m; i++, yy++)
6685
192k
                  {
6686
192k
                    Quantum
6687
192k
                      *pixels;
6688
6689
192k
                    assert(yy < (ssize_t) large_image->rows);
6690
192k
                    pixels=prev;
6691
192k
                    n=next;
6692
192k
                    q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6693
192k
                      1,exception);
6694
192k
                    if (q == (Quantum *) NULL)
6695
7.45k
                      break;
6696
185k
                    q+=(ptrdiff_t) (large_image->columns-image->columns)*
6697
185k
                      GetPixelChannels(large_image);
6698
6699
2.78M
                    for (x=(ssize_t) image->columns-1; x >= 0; x--)
6700
2.60M
                    {
6701
                      /* To do: get color as function of indexes[x] */
6702
                      /*
6703
                      if (image->storage_class == PseudoClass)
6704
                        {
6705
                        }
6706
                      */
6707
6708
2.60M
                      if (magn_methy <= 1)
6709
391k
                        {
6710
                          /* replicate previous */
6711
391k
                          SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6712
391k
                          SetPixelGreen(large_image,GetPixelGreen(image,
6713
391k
                             pixels),q);
6714
391k
                          SetPixelBlue(large_image,GetPixelBlue(image,
6715
391k
                             pixels),q);
6716
391k
                          SetPixelAlpha(large_image,GetPixelAlpha(image,
6717
391k
                             pixels),q);
6718
391k
                        }
6719
6720
2.21M
                      else if (magn_methy == 2 || magn_methy == 4)
6721
1.10M
                        {
6722
1.10M
                          if (i == 0)
6723
295k
                            {
6724
295k
                              SetPixelRed(large_image,GetPixelRed(image,
6725
295k
                                 pixels),q);
6726
295k
                              SetPixelGreen(large_image,GetPixelGreen(image,
6727
295k
                                 pixels),q);
6728
295k
                              SetPixelBlue(large_image,GetPixelBlue(image,
6729
295k
                                 pixels),q);
6730
295k
                              SetPixelAlpha(large_image,GetPixelAlpha(image,
6731
295k
                                 pixels),q);
6732
295k
                            }
6733
6734
808k
                          else
6735
808k
                            {
6736
                              /* Interpolate */
6737
808k
                              SetPixelRed(large_image,((QM) (((ssize_t)
6738
808k
                                 (2*i*(GetPixelRed(image,n)
6739
808k
                                 -GetPixelRed(image,pixels)+m))/
6740
808k
                                 ((ssize_t) (m*2))
6741
808k
                                 +GetPixelRed(image,pixels)))),q);
6742
808k
                              SetPixelGreen(large_image,((QM) (((ssize_t)
6743
808k
                                 (2*i*(GetPixelGreen(image,n)
6744
808k
                                 -GetPixelGreen(image,pixels)+m))/
6745
808k
                                 ((ssize_t) (m*2))
6746
808k
                                 +GetPixelGreen(image,pixels)))),q);
6747
808k
                              SetPixelBlue(large_image,((QM) (((ssize_t)
6748
808k
                                 (2*i*(GetPixelBlue(image,n)
6749
808k
                                 -GetPixelBlue(image,pixels)+m))/
6750
808k
                                 ((ssize_t) (m*2))
6751
808k
                                 +GetPixelBlue(image,pixels)))),q);
6752
6753
808k
                              if (image->alpha_trait != UndefinedPixelTrait)
6754
96.2k
                                 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6755
96.2k
                                    (2*i*(GetPixelAlpha(image,n)
6756
96.2k
                                    -GetPixelAlpha(image,pixels)+m))
6757
96.2k
                                    /((ssize_t) (m*2))+
6758
96.2k
                                   GetPixelAlpha(image,pixels)))),q);
6759
808k
                            }
6760
6761
1.10M
                          if (magn_methy == 4)
6762
98.3k
                            {
6763
                              /* Replicate nearest */
6764
98.3k
                              if (i <= ((m+1) << 1))
6765
98.3k
                                 SetPixelAlpha(large_image,GetPixelAlpha(image,
6766
98.3k
                                    pixels),q);
6767
0
                              else
6768
0
                                 SetPixelAlpha(large_image,GetPixelAlpha(image,
6769
0
                                    n),q);
6770
98.3k
                            }
6771
1.10M
                        }
6772
6773
1.10M
                      else /* if (magn_methy == 3 || magn_methy == 5) */
6774
1.10M
                        {
6775
                          /* Replicate nearest */
6776
1.10M
                          if (i <= ((m+1) << 1))
6777
1.10M
                          {
6778
1.10M
                             SetPixelRed(large_image,GetPixelRed(image,
6779
1.10M
                                    pixels),q);
6780
1.10M
                             SetPixelGreen(large_image,GetPixelGreen(image,
6781
1.10M
                                    pixels),q);
6782
1.10M
                             SetPixelBlue(large_image,GetPixelBlue(image,
6783
1.10M
                                    pixels),q);
6784
1.10M
                             SetPixelAlpha(large_image,GetPixelAlpha(image,
6785
1.10M
                                    pixels),q);
6786
1.10M
                          }
6787
6788
0
                          else
6789
0
                          {
6790
0
                             SetPixelRed(large_image,GetPixelRed(image,n),q);
6791
0
                             SetPixelGreen(large_image,GetPixelGreen(image,n),
6792
0
                                    q);
6793
0
                             SetPixelBlue(large_image,GetPixelBlue(image,n),
6794
0
                                    q);
6795
0
                             SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6796
0
                                    q);
6797
0
                          }
6798
6799
1.10M
                          if (magn_methy == 5)
6800
223k
                            {
6801
223k
                              SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6802
223k
                                 (GetPixelAlpha(image,n)
6803
223k
                                 -GetPixelAlpha(image,pixels))
6804
223k
                                 +m))/((ssize_t) (m*2))
6805
223k
                                 +GetPixelAlpha(image,pixels)),q);
6806
223k
                            }
6807
1.10M
                        }
6808
2.60M
                      n+=(ptrdiff_t) GetPixelChannels(image);
6809
2.60M
                      q+=(ptrdiff_t) GetPixelChannels(large_image);
6810
2.60M
                      pixels+=(ptrdiff_t) GetPixelChannels(image);
6811
2.60M
                    } /* x */
6812
6813
185k
                    if (SyncAuthenticPixels(large_image,exception) == 0)
6814
0
                      break;
6815
6816
185k
                  } /* i */
6817
44.9k
                } /* y */
6818
6819
397
                prev=(Quantum *) RelinquishMagickMemory(prev);
6820
397
                next=(Quantum *) RelinquishMagickMemory(next);
6821
6822
397
                length=image->columns;
6823
6824
397
                if (logging != MagickFalse)
6825
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6826
0
                    "    Delete original image");
6827
6828
397
                DeleteImageFromList(&image);
6829
6830
397
                image=large_image;
6831
6832
397
                mng_info->image=image;
6833
6834
                /* magnify the columns */
6835
397
                if (logging != MagickFalse)
6836
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6837
0
                    "    Magnify the columns to %.17g",
6838
0
                    (double) image->columns);
6839
6840
193k
                for (y=0; y < (ssize_t) image->rows; y++)
6841
193k
                {
6842
193k
                  Quantum
6843
193k
                    *pixels;
6844
6845
193k
                  q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6846
193k
                  if (q == (Quantum *) NULL)
6847
40
                    break;
6848
193k
                  pixels=q+(image->columns-length)*GetPixelChannels(image);
6849
193k
                  n=pixels+GetPixelChannels(image);
6850
6851
193k
                  for (x=(ssize_t) (image->columns-length);
6852
2.90M
                    x < (ssize_t) image->columns; x++)
6853
2.71M
                  {
6854
                    /* To do: Rewrite using Get/Set***PixelChannel() */
6855
6856
2.71M
                    if (x == (ssize_t) (image->columns-length))
6857
193k
                      m=(ssize_t) mng_info->magn_ml;
6858
6859
2.51M
                    else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6860
135k
                      m=(ssize_t) mng_info->magn_mr;
6861
6862
2.38M
                    else if (magn_methx <= 1 &&
6863
353k
                        x == (ssize_t) image->columns-1)
6864
22.0k
                      m=(ssize_t) mng_info->magn_mr;
6865
6866
2.36M
                    else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6867
135k
                      m=1;
6868
6869
2.22M
                    else
6870
2.22M
                      m=(ssize_t) mng_info->magn_mx;
6871
6872
229M
                    for (i=0; i < m; i++)
6873
226M
                    {
6874
226M
                      if (magn_methx <= 1)
6875
57.2M
                        {
6876
                          /* replicate previous */
6877
57.2M
                          SetPixelRed(image,GetPixelRed(image,pixels),q);
6878
57.2M
                          SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6879
57.2M
                          SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6880
57.2M
                          SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6881
57.2M
                        }
6882
6883
169M
                      else if (magn_methx == 2 || magn_methx == 4)
6884
88.0M
                        {
6885
88.0M
                          if (i == 0)
6886
1.15M
                          {
6887
1.15M
                            SetPixelRed(image,GetPixelRed(image,pixels),q);
6888
1.15M
                            SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6889
1.15M
                            SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6890
1.15M
                            SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6891
1.15M
                          }
6892
6893
                          /* To do: Rewrite using Get/Set***PixelChannel() */
6894
86.9M
                          else
6895
86.9M
                            {
6896
                              /* Interpolate */
6897
86.9M
                              SetPixelRed(image,(QM) ((2*i*(
6898
86.9M
                                 GetPixelRed(image,n)
6899
86.9M
                                 -GetPixelRed(image,pixels))+m)
6900
86.9M
                                 /((ssize_t) (m*2))+
6901
86.9M
                                 GetPixelRed(image,pixels)),q);
6902
6903
86.9M
                              SetPixelGreen(image,(QM) ((2*i*(
6904
86.9M
                                 GetPixelGreen(image,n)
6905
86.9M
                                 -GetPixelGreen(image,pixels))+m)
6906
86.9M
                                 /((ssize_t) (m*2))+
6907
86.9M
                                 GetPixelGreen(image,pixels)),q);
6908
6909
86.9M
                              SetPixelBlue(image,(QM) ((2*i*(
6910
86.9M
                                 GetPixelBlue(image,n)
6911
86.9M
                                 -GetPixelBlue(image,pixels))+m)
6912
86.9M
                                 /((ssize_t) (m*2))+
6913
86.9M
                                 GetPixelBlue(image,pixels)),q);
6914
86.9M
                              if (image->alpha_trait != UndefinedPixelTrait)
6915
0
                                 SetPixelAlpha(image,(QM) ((2*i*(
6916
0
                                   GetPixelAlpha(image,n)
6917
0
                                   -GetPixelAlpha(image,pixels))+m)
6918
0
                                   /((ssize_t) (m*2))+
6919
0
                                   GetPixelAlpha(image,pixels)),q);
6920
86.9M
                            }
6921
6922
88.0M
                          if (magn_methx == 4)
6923
4.82M
                            {
6924
                              /* Replicate nearest */
6925
4.82M
                              if (i <= ((m+1) << 1))
6926
4.82M
                              {
6927
4.82M
                                 SetPixelAlpha(image,
6928
4.82M
                                   GetPixelAlpha(image,pixels)+0,q);
6929
4.82M
                              }
6930
0
                              else
6931
0
                              {
6932
0
                                 SetPixelAlpha(image,
6933
0
                                   GetPixelAlpha(image,n)+0,q);
6934
0
                              }
6935
4.82M
                            }
6936
88.0M
                        }
6937
6938
81.1M
                      else /* if (magn_methx == 3 || magn_methx == 5) */
6939
81.1M
                        {
6940
                          /* Replicate nearest */
6941
81.1M
                          if (i <= ((m+1) << 1))
6942
81.1M
                          {
6943
81.1M
                             SetPixelRed(image,GetPixelRed(image,pixels),q);
6944
81.1M
                             SetPixelGreen(image,GetPixelGreen(image,
6945
81.1M
                                 pixels),q);
6946
81.1M
                             SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6947
81.1M
                             SetPixelAlpha(image,GetPixelAlpha(image,
6948
81.1M
                                 pixels),q);
6949
81.1M
                          }
6950
6951
0
                          else
6952
0
                          {
6953
0
                             SetPixelRed(image,GetPixelRed(image,n),q);
6954
0
                             SetPixelGreen(image,GetPixelGreen(image,n),q);
6955
0
                             SetPixelBlue(image,GetPixelBlue(image,n),q);
6956
0
                             SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6957
0
                          }
6958
6959
81.1M
                          if (magn_methx == 5)
6960
9.50M
                            {
6961
                              /* Interpolate */
6962
9.50M
                              SetPixelAlpha(image,
6963
9.50M
                                 (QM) ((2*i*( GetPixelAlpha(image,n)
6964
9.50M
                                 -GetPixelAlpha(image,pixels))+m)/
6965
9.50M
                                 ((ssize_t) (m*2))
6966
9.50M
                                 +GetPixelAlpha(image,pixels)),q);
6967
9.50M
                            }
6968
81.1M
                        }
6969
226M
                      q+=(ptrdiff_t) GetPixelChannels(image);
6970
226M
                    }
6971
2.71M
                    n+=(ptrdiff_t) GetPixelChannels(image);
6972
2.71M
                  }
6973
6974
193k
                  if (SyncAuthenticPixels(image,exception) == MagickFalse)
6975
0
                    break;
6976
193k
                }
6977
#if (MAGICKCORE_QUANTUM_DEPTH > 16)
6978
              if (magn_methx != 1 || magn_methy != 1)
6979
                {
6980
                /*
6981
                   Rescale pixels to Quantum
6982
                */
6983
                   for (y=0; y < (ssize_t) image->rows; y++)
6984
                   {
6985
                     q=GetAuthenticPixels(image,0,y,image->columns,1,
6986
                       exception);
6987
                     if (q == (Quantum *) NULL)
6988
                       break;
6989
6990
                     for (x=(ssize_t) image->columns-1; x >= 0; x--)
6991
                     {
6992
                        SetPixelRed(image,ScaleShortToQuantum(
6993
                          (unsigned short) GetPixelRed(image,q)),q);
6994
                        SetPixelGreen(image,ScaleShortToQuantum(
6995
                          (unsigned short) GetPixelGreen(image,q)),q);
6996
                        SetPixelBlue(image,ScaleShortToQuantum(
6997
                          (unsigned short) GetPixelBlue(image,q)),q);
6998
                        SetPixelAlpha(image,ScaleShortToQuantum(
6999
                          (unsigned short) GetPixelAlpha(image,q)),q);
7000
                        q+=(ptrdiff_t) GetPixelChannels(image);
7001
                     }
7002
7003
                     if (SyncAuthenticPixels(image,exception) == MagickFalse)
7004
                       break;
7005
                   }
7006
                }
7007
#endif
7008
397
                if (logging != MagickFalse)
7009
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7010
0
                    "  Finished MAGN processing");
7011
397
              }
7012
430
          }
7013
7014
        /*
7015
          Crop_box is with respect to the upper left corner of the MNG.
7016
        */
7017
2.95k
        crop_box.left=mng_info->image_box.left+(long) mng_info->x_off[object_id];
7018
2.95k
        crop_box.right=mng_info->image_box.right+(long) mng_info->x_off[object_id];
7019
2.95k
        crop_box.top=mng_info->image_box.top+(long) mng_info->y_off[object_id];
7020
2.95k
        crop_box.bottom=mng_info->image_box.bottom+(long) mng_info->y_off[object_id];
7021
2.95k
        crop_box=mng_minimum_box(crop_box,mng_info->clip);
7022
2.95k
        crop_box=mng_minimum_box(crop_box,mng_info->frame);
7023
2.95k
        crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
7024
2.95k
        if ((crop_box.left != (mng_info->image_box.left
7025
2.95k
            +mng_info->x_off[object_id])) ||
7026
2.83k
            (crop_box.right != (mng_info->image_box.right
7027
2.83k
            +mng_info->x_off[object_id])) ||
7028
2.40k
            (crop_box.top != (mng_info->image_box.top
7029
2.40k
            +mng_info->y_off[object_id])) ||
7030
2.30k
            (crop_box.bottom != (mng_info->image_box.bottom
7031
2.30k
            +mng_info->y_off[object_id])))
7032
818
          {
7033
818
            if (logging != MagickFalse)
7034
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7035
0
                "  Crop the PNG image");
7036
7037
818
            if ((crop_box.left < crop_box.right) &&
7038
267
                (crop_box.top < crop_box.bottom))
7039
0
              {
7040
0
                Image
7041
0
                  *im;
7042
7043
0
                RectangleInfo
7044
0
                  crop_info;
7045
7046
                /*
7047
                  Crop_info is with respect to the upper left corner of
7048
                  the image.
7049
                */
7050
0
                crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
7051
0
                crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
7052
0
                crop_info.width=(size_t) (crop_box.right-crop_box.left);
7053
0
                crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
7054
0
                image->page.width=image->columns;
7055
0
                image->page.height=image->rows;
7056
0
                image->page.x=0;
7057
0
                image->page.y=0;
7058
0
                im=CropImage(image,&crop_info,exception);
7059
7060
0
                if (im != (Image *) NULL)
7061
0
                  {
7062
0
                    image->columns=im->columns;
7063
0
                    image->rows=im->rows;
7064
0
                    im=DestroyImage(im);
7065
0
                    image->page.width=image->columns;
7066
0
                    image->page.height=image->rows;
7067
0
                    image->page.x=crop_box.left;
7068
0
                    image->page.y=crop_box.top;
7069
0
                  }
7070
0
              }
7071
7072
818
            else
7073
818
              {
7074
                /*
7075
                  No pixels in crop area.  The MNG spec still requires
7076
                  a layer, though, so make a single transparent pixel in
7077
                  the top left corner.
7078
                */
7079
818
                image->columns=1;
7080
818
                image->rows=1;
7081
818
                image->colors=2;
7082
818
                (void) SetImageBackgroundColor(image,exception);
7083
818
                image->page.width=1;
7084
818
                image->page.height=1;
7085
818
                image->page.x=0;
7086
818
                image->page.y=0;
7087
818
              }
7088
818
          }
7089
2.95k
      }
7090
7091
#if (MAGICKCORE_QUANTUM_DEPTH > 16)
7092
      /* PNG does not handle depths greater than 16 so reduce it even
7093
       * if lossy.
7094
       */
7095
      if (image->depth > 16)
7096
         image->depth=16;
7097
#endif
7098
7099
21.7k
#if (MAGICKCORE_QUANTUM_DEPTH > 8)
7100
21.7k
      if (image->depth > 8)
7101
8.18k
        {
7102
          /* To do: fill low byte properly */
7103
8.18k
          image->depth=16;
7104
8.18k
        }
7105
7106
21.7k
#endif
7107
7108
21.7k
      if (image_info->number_scenes != 0)
7109
0
        {
7110
0
          if (mng_info->scenes_found >
7111
0
             (ssize_t) (image_info->scene+image_info->number_scenes))
7112
0
            break;
7113
0
        }
7114
7115
21.7k
      if (logging != MagickFalse)
7116
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7117
0
          "  Finished reading image datastream.");
7118
7119
90.8M
  } while (LocaleCompare(image_info->magick,"MNG") == 0);
7120
7121
1.31k
  (void) CloseBlob(image);
7122
7123
1.31k
  if (logging != MagickFalse)
7124
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7125
0
      "  Finished reading all image datastreams.");
7126
7127
1.31k
  if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
7128
326
       (mng_info->mng_height))
7129
323
    {
7130
      /*
7131
        Insert a background layer if nothing else was found.
7132
      */
7133
323
      if (logging != MagickFalse)
7134
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7135
0
          "  No images found.  Inserting a background layer.");
7136
7137
323
      if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
7138
0
        {
7139
          /*
7140
            Allocate next image structure.
7141
          */
7142
0
          AcquireNextImage(image_info,image,exception);
7143
0
          if (GetNextImageInList(image) == (Image *) NULL)
7144
0
            {
7145
0
              if (logging != MagickFalse)
7146
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7147
0
                  "  Allocation failed, returning NULL.");
7148
7149
0
              return(DestroyImageList(image));;
7150
0
            }
7151
0
          image=SyncNextImageInList(image);
7152
0
        }
7153
323
      image->columns=mng_info->mng_width;
7154
323
      image->rows=mng_info->mng_height;
7155
323
      image->page.width=mng_info->mng_width;
7156
323
      image->page.height=mng_info->mng_height;
7157
323
      image->page.x=0;
7158
323
      image->page.y=0;
7159
323
      image->background_color=mng_background_color;
7160
323
      image->alpha_trait=UndefinedPixelTrait;
7161
7162
323
      if (image_info->ping == MagickFalse)
7163
322
        (void) SetImageBackgroundColor(image,exception);
7164
7165
323
      mng_info->image_found++;
7166
323
    }
7167
1.31k
  image->iterations=mng_iterations;
7168
7169
1.31k
  if (mng_iterations == 1)
7170
1.26k
    image->start_loop=MagickTrue;
7171
7172
4.43k
  while (GetPreviousImageInList(image) != (Image *) NULL)
7173
3.11k
  {
7174
3.11k
    image_count+=1;
7175
3.11k
    if (image_count > 10*mng_info->image_found)
7176
0
      {
7177
0
        if (logging != MagickFalse)
7178
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  No beginning");
7179
7180
0
        (void) ThrowMagickException(exception,GetMagickModule(),
7181
0
          CoderError,"Linked list is corrupted, beginning of list not found",
7182
0
          "`%s'",image_info->filename);
7183
7184
0
        return(DestroyImageList(image));
7185
0
      }
7186
7187
3.11k
    image=GetPreviousImageInList(image);
7188
7189
3.11k
    if (GetNextImageInList(image) == (Image *) NULL)
7190
0
      {
7191
0
        if (logging != MagickFalse)
7192
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Corrupt list");
7193
7194
0
        (void) ThrowMagickException(exception,GetMagickModule(),
7195
0
          CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
7196
0
          image_info->filename);
7197
0
      }
7198
3.11k
  }
7199
7200
1.31k
  if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
7201
410
             GetNextImageInList(image) ==
7202
410
     (Image *) NULL)
7203
0
    {
7204
0
      if (logging != MagickFalse)
7205
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7206
0
            "  First image null");
7207
7208
0
      (void) ThrowMagickException(exception,GetMagickModule(),
7209
0
        CoderError,"image->next for first image is NULL but shouldn't be.",
7210
0
        "`%s'",image_info->filename);
7211
0
    }
7212
7213
1.31k
  if (mng_info->image_found == 0)
7214
27
    {
7215
27
      if (logging != MagickFalse)
7216
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7217
0
          "  No visible images found.");
7218
7219
27
      (void) ThrowMagickException(exception,GetMagickModule(),
7220
27
        CoderError,"No visible images in file","`%s'",image_info->filename);
7221
7222
27
      return(DestroyImageList(image));
7223
27
    }
7224
7225
1.29k
  if (mng_info->ticks_per_second)
7226
1.25k
    final_delay=(size_t) MagickMax(image->ticks_per_second,1L)*
7227
1.25k
            final_delay/mng_info->ticks_per_second;
7228
7229
38
  else
7230
38
    image->start_loop=MagickTrue;
7231
7232
  /* Find final nonzero image delay */
7233
1.29k
  final_image_delay=0;
7234
7235
4.40k
  while (GetNextImageInList(image) != (Image *) NULL)
7236
3.11k
    {
7237
3.11k
      if (image->delay)
7238
389
        final_image_delay=image->delay;
7239
7240
3.11k
      image=GetNextImageInList(image);
7241
3.11k
    }
7242
7243
1.29k
  if (final_delay < final_image_delay)
7244
29
    final_delay=final_image_delay;
7245
7246
1.29k
  image->delay=final_delay;
7247
7248
1.29k
  if (logging != MagickFalse)
7249
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7250
0
        "  image->delay=%.17g, final_delay=%.17g",(double) image->delay,
7251
0
        (double) final_delay);
7252
7253
1.29k
  if (logging != MagickFalse)
7254
0
    {
7255
0
      int
7256
0
        scene;
7257
7258
0
      scene=0;
7259
0
      image=GetFirstImageInList(image);
7260
7261
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7262
0
        "  Before coalesce:");
7263
7264
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7265
0
        "    scene 0 delay=%.17g",(double) image->delay);
7266
7267
0
      while (GetNextImageInList(image) != (Image *) NULL)
7268
0
      {
7269
0
        image=GetNextImageInList(image);
7270
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7271
0
          "    scene %.17g delay=%.17g",(double) scene++,
7272
0
          (double) image->delay);
7273
0
      }
7274
0
    }
7275
7276
1.29k
  image=GetFirstImageInList(image);
7277
1.29k
  if (insert_layers && image->next)
7278
480
    {
7279
480
      Image
7280
480
        *next_image,
7281
480
        *next;
7282
7283
480
      size_t
7284
480
        scene;
7285
7286
480
      if (logging != MagickFalse)
7287
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7288
0
          "  Coalesce Images");
7289
7290
480
      scene=image->scene;
7291
480
      next_image=CoalesceImages(image,exception);
7292
480
      image=DestroyImageList(image);
7293
480
      if (next_image == (Image *) NULL)
7294
51
        return((Image *) NULL);
7295
429
      image=next_image;
7296
7297
2.12k
      for (next=image; next != (Image *) NULL; next=next_image)
7298
2.12k
      {
7299
2.12k
         next->page.width=mng_info->mng_width;
7300
2.12k
         next->page.height=mng_info->mng_height;
7301
2.12k
         next->page.x=0;
7302
2.12k
         next->page.y=0;
7303
2.12k
         next->scene=scene++;
7304
2.12k
         next_image=GetNextImageInList(next);
7305
7306
2.12k
         if (next_image == (Image *) NULL)
7307
429
           break;
7308
7309
1.69k
         if (next->delay == 0)
7310
1.31k
           {
7311
1.31k
             scene--;
7312
1.31k
             next_image->previous=GetPreviousImageInList(next);
7313
1.31k
             if (GetPreviousImageInList(next) == (Image *) NULL)
7314
1.26k
               image=next_image;
7315
50
             else
7316
50
               next->previous->next=next_image;
7317
1.31k
             next=DestroyImage(next);
7318
1.31k
           }
7319
1.69k
      }
7320
429
    }
7321
7322
2.98k
  while (GetNextImageInList(image) != (Image *) NULL)
7323
1.74k
      image=GetNextImageInList(image);
7324
7325
1.24k
  image->dispose=BackgroundDispose;
7326
7327
1.24k
  if (logging != MagickFalse)
7328
0
    {
7329
0
      int
7330
0
        scene;
7331
7332
0
      scene=0;
7333
0
      image=GetFirstImageInList(image);
7334
7335
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7336
0
        "  After coalesce:");
7337
7338
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7339
0
        "    scene 0 delay=%.17g dispose=%.17g",(double) image->delay,
7340
0
        (double) image->dispose);
7341
7342
0
      while (GetNextImageInList(image) != (Image *) NULL)
7343
0
      {
7344
0
        image=GetNextImageInList(image);
7345
7346
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7347
0
          "    scene %.17g delay=%.17g dispose=%.17g",(double) scene++,
7348
0
          (double) image->delay,(double) image->dispose);
7349
0
      }
7350
0
   }
7351
7352
1.24k
  if (logging != MagickFalse)
7353
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7354
0
      "  exit ReadOneMNGImage();");
7355
7356
1.24k
  return(image);
7357
1.29k
}
7358
7359
static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7360
11.5k
{
7361
11.5k
  Image
7362
11.5k
    *image;
7363
7364
11.5k
  MagickBooleanType
7365
11.5k
    logging = MagickFalse,
7366
11.5k
    status;
7367
7368
11.5k
  MngReadInfo
7369
11.5k
    *mng_info;
7370
7371
  /* Open image file.  */
7372
7373
11.5k
  assert(image_info != (const ImageInfo *) NULL);
7374
11.5k
  assert(image_info->signature == MagickCoreSignature);
7375
11.5k
  assert(exception != (ExceptionInfo *) NULL);
7376
11.5k
  assert(exception->signature == MagickCoreSignature);
7377
11.5k
  if (IsEventLogging() != MagickFalse)
7378
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
7379
0
       image_info->filename);
7380
11.5k
  image=AcquireImage(image_info,exception);
7381
11.5k
  if (image->debug != MagickFalse)
7382
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
7383
11.5k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
7384
7385
11.5k
  if (status == MagickFalse)
7386
0
    return(DestroyImageList(image));
7387
7388
11.5k
  mng_info=(MngReadInfo *) AcquireMagickMemory(sizeof(*mng_info));
7389
7390
11.5k
  if (mng_info == (MngReadInfo *) NULL)
7391
11.5k
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7392
7393
11.5k
  (void) memset(mng_info,0,sizeof(*mng_info));
7394
11.5k
  mng_info->image=image;
7395
11.5k
  image=ReadOneMNGImage(mng_info,image_info,exception);
7396
11.5k
  mng_info=MngReadInfoFreeStruct(mng_info);
7397
7398
11.5k
  if (image == (Image *) NULL)
7399
10.3k
    {
7400
10.3k
      if (logging != MagickFalse)
7401
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7402
0
          "exit ReadMNGImage() with error");
7403
7404
10.3k
      return((Image *) NULL);
7405
10.3k
    }
7406
1.24k
  (void) CloseBlob(image);
7407
7408
1.24k
  if (logging != MagickFalse)
7409
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7410
7411
1.24k
  return(GetFirstImageInList(image));
7412
11.5k
}
7413
#endif
7414

7415
/*
7416
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7417
%                                                                             %
7418
%                                                                             %
7419
%                                                                             %
7420
%   R e g i s t e r P N G I m a g e                                           %
7421
%                                                                             %
7422
%                                                                             %
7423
%                                                                             %
7424
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7425
%
7426
%  RegisterPNGImage() adds properties for the PNG image format to
7427
%  the list of supported formats.  The properties include the image format
7428
%  tag, a method to read and/or write the format, whether the format
7429
%  supports the saving of more than one frame to the same file or blob,
7430
%  whether the format supports native in-memory I/O, and a brief
7431
%  description of the format.
7432
%
7433
%  The format of the RegisterPNGImage method is:
7434
%
7435
%      size_t RegisterPNGImage(void)
7436
%
7437
*/
7438
ModuleExport size_t RegisterPNGImage(void)
7439
23
{
7440
23
  char
7441
23
    version[MagickPathExtent];
7442
7443
23
  MagickInfo
7444
23
    *entry;
7445
7446
23
  static const char
7447
23
    PNGNote[] =
7448
23
    {
7449
23
      "See http://www.libpng.org/ for details about the PNG format."
7450
23
    },
7451
7452
23
    JNGNote[] =
7453
23
    {
7454
23
      "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7455
23
      "format."
7456
23
    },
7457
7458
23
    MNGNote[] =
7459
23
    {
7460
23
      "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7461
23
      "format."
7462
23
    };
7463
7464
23
  *version='\0';
7465
7466
23
#if defined(PNG_LIBPNG_VER_STRING)
7467
23
  (void) ConcatenateMagickString(version,"libpng ",MagickPathExtent);
7468
23
  (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,
7469
23
   MagickPathExtent);
7470
7471
23
  if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7472
0
    {
7473
0
      (void) ConcatenateMagickString(version,",",MagickPathExtent);
7474
0
      (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7475
0
            MagickPathExtent);
7476
0
    }
7477
23
#endif
7478
7479
23
  entry=AcquireMagickInfo("PNG","MNG","Multiple-image Network Graphics");
7480
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7481
7482
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7483
23
  entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7484
23
  entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7485
23
#endif
7486
7487
23
  entry->magick=(IsImageFormatHandler *) IsMNG;
7488
7489
23
  if (*version != '\0')
7490
23
    entry->version=ConstantString(version);
7491
7492
23
  entry->mime_type=ConstantString("video/x-mng");
7493
23
  entry->note=ConstantString(MNGNote);
7494
23
  (void) RegisterMagickInfo(entry);
7495
7496
23
  entry=AcquireMagickInfo("PNG","PNG","Portable Network Graphics");
7497
7498
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7499
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7500
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7501
23
#endif
7502
7503
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7504
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7505
23
  entry->flags^=CoderAdjoinFlag;
7506
23
  entry->mime_type=ConstantString("image/png");
7507
7508
23
  if (*version != '\0')
7509
23
    entry->version=ConstantString(version);
7510
7511
23
  entry->note=ConstantString(PNGNote);
7512
23
  (void) RegisterMagickInfo(entry);
7513
7514
23
  entry=AcquireMagickInfo("PNG","PNG8",
7515
23
    "8-bit indexed with optional binary transparency");
7516
7517
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7518
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7519
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7520
23
#endif
7521
7522
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7523
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7524
23
  entry->flags^=CoderAdjoinFlag;
7525
23
  entry->mime_type=ConstantString("image/png");
7526
23
  (void) RegisterMagickInfo(entry);
7527
7528
23
  entry=AcquireMagickInfo("PNG","PNG24",
7529
23
    "opaque or binary transparent 24-bit RGB");
7530
23
  *version='\0';
7531
7532
23
  if (*version != '\0')
7533
0
    entry->version=ConstantString(version);
7534
7535
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7536
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7537
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7538
23
#endif
7539
7540
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7541
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7542
23
  entry->flags^=CoderAdjoinFlag;
7543
23
  entry->mime_type=ConstantString("image/png");
7544
23
  (void) RegisterMagickInfo(entry);
7545
7546
23
  entry=AcquireMagickInfo("PNG","PNG32","opaque or transparent 32-bit RGBA");
7547
7548
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7549
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7550
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7551
23
#endif
7552
7553
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7554
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7555
23
  entry->flags^=CoderAdjoinFlag;
7556
23
  entry->mime_type=ConstantString("image/png");
7557
23
  (void) RegisterMagickInfo(entry);
7558
7559
23
  entry=AcquireMagickInfo("PNG","PNG48",
7560
23
    "opaque or binary transparent 48-bit RGB");
7561
7562
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7563
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7564
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7565
23
#endif
7566
7567
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7568
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7569
23
  entry->flags^=CoderAdjoinFlag;
7570
23
  entry->mime_type=ConstantString("image/png");
7571
23
  (void) RegisterMagickInfo(entry);
7572
7573
23
  entry=AcquireMagickInfo("PNG","PNG64","opaque or transparent 64-bit RGBA");
7574
7575
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7576
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7577
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7578
23
#endif
7579
7580
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7581
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7582
23
  entry->flags^=CoderAdjoinFlag;
7583
23
  entry->mime_type=ConstantString("image/png");
7584
23
  (void) RegisterMagickInfo(entry);
7585
7586
23
  entry=AcquireMagickInfo("PNG","PNG00",
7587
23
    "PNG inheriting bit-depth, color-type from original, if possible");
7588
7589
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7590
23
  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7591
23
  entry->encoder=(EncodeImageHandler *) WritePNGImage;
7592
23
#endif
7593
7594
23
  entry->magick=(IsImageFormatHandler *) IsPNG;
7595
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7596
23
  entry->flags^=CoderAdjoinFlag;
7597
23
  entry->mime_type=ConstantString("image/png");
7598
23
  (void) RegisterMagickInfo(entry);
7599
7600
23
  entry=AcquireMagickInfo("PNG","JNG","JPEG Network Graphics");
7601
7602
23
#if defined(JNG_SUPPORTED)
7603
23
#if defined(MAGICKCORE_PNG_DELEGATE)
7604
23
  entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7605
23
  entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7606
23
#endif
7607
23
#endif
7608
7609
23
  entry->magick=(IsImageFormatHandler *) IsJNG;
7610
23
  entry->flags|=CoderDecoderSeekableStreamFlag;
7611
23
  entry->flags^=CoderAdjoinFlag;
7612
23
  entry->mime_type=ConstantString("image/x-jng");
7613
23
  entry->note=ConstantString(JNGNote);
7614
23
  (void) RegisterMagickInfo(entry);
7615
7616
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
7617
  ping_semaphore=AcquireSemaphoreInfo();
7618
#endif
7619
7620
23
  return(MagickImageCoderSignature);
7621
23
}
7622

7623
/*
7624
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7625
%                                                                             %
7626
%                                                                             %
7627
%                                                                             %
7628
%   U n r e g i s t e r P N G I m a g e                                       %
7629
%                                                                             %
7630
%                                                                             %
7631
%                                                                             %
7632
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7633
%
7634
%  UnregisterPNGImage() removes format registrations made by the
7635
%  PNG module from the list of supported formats.
7636
%
7637
%  The format of the UnregisterPNGImage method is:
7638
%
7639
%      UnregisterPNGImage(void)
7640
%
7641
*/
7642
ModuleExport void UnregisterPNGImage(void)
7643
0
{
7644
0
  (void) UnregisterMagickInfo("MNG");
7645
0
  (void) UnregisterMagickInfo("PNG");
7646
0
  (void) UnregisterMagickInfo("PNG8");
7647
0
  (void) UnregisterMagickInfo("PNG24");
7648
0
  (void) UnregisterMagickInfo("PNG32");
7649
0
  (void) UnregisterMagickInfo("PNG48");
7650
0
  (void) UnregisterMagickInfo("PNG64");
7651
0
  (void) UnregisterMagickInfo("PNG00");
7652
0
  (void) UnregisterMagickInfo("JNG");
7653
7654
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
7655
  if (ping_semaphore != (SemaphoreInfo *) NULL)
7656
    RelinquishSemaphoreInfo(&ping_semaphore);
7657
#endif
7658
0
}
7659

7660
#if defined(MAGICKCORE_PNG_DELEGATE)
7661
/*
7662
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7663
%                                                                             %
7664
%                                                                             %
7665
%                                                                             %
7666
%   W r i t e M N G I m a g e                                                 %
7667
%                                                                             %
7668
%                                                                             %
7669
%                                                                             %
7670
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7671
%
7672
%  WriteMNGImage() writes an image in the Portable Network Graphics
7673
%  Group's "Multiple-image Network Graphics" encoded image format.
7674
%
7675
%  MNG support written by Glenn Randers-Pehrson, glennrp@image...
7676
%
7677
%  The format of the WriteMNGImage method is:
7678
%
7679
%      MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7680
%        Image *image,ExceptionInfo *exception)
7681
%
7682
%  A description of each parameter follows.
7683
%
7684
%    o image_info: the image info.
7685
%
7686
%    o image:  The image.
7687
%
7688
%    o exception: return any errors or warnings in this structure.
7689
%
7690
%  To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7691
%    "To do" under ReadPNGImage):
7692
%
7693
%    Preserve all unknown and not-yet-handled known chunks found in input
7694
%    PNG file and copy them  into output PNG files according to the PNG
7695
%    copying rules.
7696
%
7697
%    Write the iCCP chunk at MNG level when (icc profile length > 0)
7698
%
7699
%    Improve selection of color type (use indexed-color or indexed-color
7700
%    with tRNS when 256 or fewer unique RGBA values are present).
7701
%
7702
%    Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7703
%    This will be complicated if we limit ourselves to generating MNG-LC
7704
%    files.  For now we ignore disposal method 3 and simply overlay the next
7705
%    image on it.
7706
%
7707
%    Check for identical PLTE's or PLTE/tRNS combinations and use a
7708
%    global MNG PLTE or PLTE/tRNS combination when appropriate.
7709
%    [mostly done 15 June 1999 but still need to take care of tRNS]
7710
%
7711
%    Check for identical sRGB and replace with a global sRGB (and remove
7712
%    gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7713
%    replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7714
%    local gAMA/cHRM with local sRGB if appropriate).
7715
%
7716
%    Check for identical sBIT chunks and write global ones.
7717
%
7718
%    Provide option to skip writing the signature tEXt chunks.
7719
%
7720
%    Use signatures to detect identical objects and reuse the first
7721
%    instance of such objects instead of writing duplicate objects.
7722
%
7723
%    Use a smaller-than-32k value of compression window size when
7724
%    appropriate.
7725
%
7726
%    Encode JNG datastreams.  Mostly done as of 5.5.2; need to write
7727
%    ancillary text chunks and save profiles.
7728
%
7729
%    Provide an option to force LC files (to ensure exact framing rate)
7730
%    instead of VLC.
7731
%
7732
%    Provide an option to force VLC files instead of LC, even when offsets
7733
%    are present.  This will involve expanding the embedded images with a
7734
%    transparent region at the top and/or left.
7735
*/
7736
7737
static void Magick_png_write_raw_profile(const ImageInfo *image_info,
7738
  png_struct *ping,png_info *ping_info,unsigned char *profile_type,
7739
  unsigned char *profile_description,unsigned char *profile_data,
7740
  png_uint_32 length,ExceptionInfo *exception)
7741
18
{
7742
18
   png_charp
7743
18
     dp;
7744
7745
18
   png_textp
7746
18
     text;
7747
7748
18
   png_uint_32
7749
18
     allocated_length,
7750
18
     description_length;
7751
7752
18
   ssize_t
7753
18
     i;
7754
7755
18
   unsigned char
7756
18
     hex[16] =
7757
18
       { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' },
7758
18
     *sp;
7759
7760
18
   if ((length > 10) && (*profile_type != '\0'))
7761
18
     {
7762
18
       if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7763
0
          return;
7764
18
     }
7765
18
   if (image_info->verbose != MagickFalse)
7766
0
     {
7767
0
       (void) printf("writing raw profile: type=%s, length=%.17g\n",
7768
0
         (char *) profile_type, (double) length);
7769
0
     }
7770
18
   description_length=(png_uint_32) strlen((const char *) profile_description);
7771
18
   allocated_length=(png_uint_32) (2*length+(length >> 5)+description_length+
7772
18
     20);
7773
18
   if ((allocated_length < length) || (length >= (PNG_UINT_31_MAX / 2)))
7774
0
     {
7775
0
       (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7776
0
         "maximum profile length exceeded","`%s'",image_info->filename);
7777
0
       return;
7778
0
     }
7779
18
#if PNG_LIBPNG_VER >= 10400
7780
18
   text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7781
#else
7782
   text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7783
#endif
7784
18
#if PNG_LIBPNG_VER >= 10400
7785
18
   text[0].text=(png_charp) png_malloc(ping,(png_alloc_size_t)
7786
18
     allocated_length);
7787
18
   text[0].key=(png_charp) png_malloc(ping,(png_alloc_size_t) 80);
7788
#else
7789
   text[0].text=(png_charp) png_malloc(ping,(png_size_t) allocated_length);
7790
   text[0].key=(png_charp) png_malloc(ping,(png_size_t) 80);
7791
#endif
7792
18
   text[0].key[0]='\0';
7793
18
   (void) ConcatenateMagickString(text[0].key,"Raw profile type ",
7794
18
     MagickPathExtent);
7795
18
   (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7796
18
   sp=profile_data;
7797
18
   dp=text[0].text;
7798
18
   *dp++='\n';
7799
18
   (void) CopyMagickString(dp,(const char *) profile_description,
7800
18
     allocated_length);
7801
18
   dp+=description_length;
7802
18
   *dp++='\n';
7803
18
   (void) FormatLocaleString(dp,allocated_length-
7804
18
     (png_size_t) (dp-text[0].text),"%8lu",(unsigned long) length);
7805
18
   dp+=8;
7806
7807
48.3k
   for (i=0; i < (ssize_t) length; i++)
7808
48.3k
   {
7809
48.3k
     if (i%36 == 0)
7810
1.34k
       *dp++='\n';
7811
48.3k
     *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7812
48.3k
     *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7813
48.3k
   }
7814
7815
18
   *dp++='\n';
7816
18
   *dp='\0';
7817
18
   text[0].text_length=(png_size_t) (dp-text[0].text);
7818
18
   text[0].compression=image_info->compression == NoCompression ||
7819
18
     (image_info->compression == UndefinedCompression &&
7820
18
     text[0].text_length < 128) ? -1 : 0;
7821
7822
18
   if (text[0].text_length <= allocated_length)
7823
18
     png_set_text(ping,ping_info,text,1);
7824
7825
18
   png_free(ping,text[0].text);
7826
18
   png_free(ping,text[0].key);
7827
18
   png_free(ping,text);
7828
18
}
7829
7830
static inline MagickBooleanType IsColorEqual(const Image *image,
7831
  const Quantum *p, const PixelInfo *q)
7832
275M
{
7833
275M
  MagickRealType
7834
275M
    blue,
7835
275M
    green,
7836
275M
    red;
7837
7838
275M
  red=(MagickRealType) GetPixelRed(image,p);
7839
275M
  green=(MagickRealType) GetPixelGreen(image,p);
7840
275M
  blue=(MagickRealType) GetPixelBlue(image,p);
7841
275M
  if ((AbsolutePixelValue(red-q->red) < MagickEpsilon) &&
7842
275M
      (AbsolutePixelValue(green-q->green) < MagickEpsilon) &&
7843
275M
      (AbsolutePixelValue(blue-q->blue) < MagickEpsilon))
7844
275M
    return(MagickTrue);
7845
598k
  return(MagickFalse);
7846
275M
}
7847
7848
545M
#define PNGPaletteHashSize  1024
7849
7850
static inline size_t PNGPaletteHash(const Quantum red,const Quantum green,
7851
  const Quantum blue,const Quantum alpha)
7852
544M
{
7853
544M
  size_t
7854
544M
    hash;
7855
7856
  /*
7857
    Colors that compare equal share a hash (barring HDRI values within
7858
    MagickEpsilon of a rounding edge), so a probe that stops at the first
7859
    empty slot finds them.
7860
  */
7861
544M
  hash=(size_t) ScaleQuantumToChar(red);
7862
544M
  hash=31*hash+(size_t) ScaleQuantumToChar(green);
7863
544M
  hash=31*hash+(size_t) ScaleQuantumToChar(blue);
7864
544M
  hash=31*hash+(size_t) ScaleQuantumToChar(alpha);
7865
544M
  return(hash & (PNGPaletteHashSize-1));
7866
544M
}
7867
7868
#if defined(PNG_tIME_SUPPORTED)
7869
static void write_tIME_chunk(Image *image,png_struct *ping,png_info *info,
7870
  const char *timestamp,ExceptionInfo *exception)
7871
1.68k
{
7872
1.68k
  int
7873
1.68k
    ret;
7874
7875
1.68k
  int
7876
1.68k
    day,
7877
1.68k
    hour,
7878
1.68k
    minute,
7879
1.68k
    month,
7880
1.68k
    second,
7881
1.68k
    year;
7882
7883
1.68k
  int
7884
1.68k
    addhours=0,
7885
1.68k
    addminutes=0;
7886
7887
1.68k
  png_time
7888
1.68k
    ptime;
7889
7890
1.68k
  assert(timestamp != (const char *) NULL);
7891
1.68k
  LogMagickEvent(CoderEvent,GetMagickModule(),
7892
1.68k
      "  Writing tIME chunk: timestamp property is %30s\n",timestamp);
7893
1.68k
  ret=MagickSscanf(timestamp,"%d-%d-%dT%d:%d:%d",&year,&month,&day,&hour,
7894
1.68k
      &minute, &second);
7895
1.68k
  addhours=0;
7896
1.68k
  addminutes=0;
7897
1.68k
  ret=MagickSscanf(timestamp,"%d-%d-%dT%d:%d:%d%d:%d",&year,&month,&day,&hour,
7898
1.68k
      &minute, &second, &addhours, &addminutes);
7899
1.68k
    LogMagickEvent(CoderEvent,GetMagickModule(),
7900
1.68k
      "   Date format specified for png:tIME=%s" ,timestamp);
7901
1.68k
    LogMagickEvent(CoderEvent,GetMagickModule(),
7902
1.68k
      "      ret=%d,y=%d, m=%d, d=%d, h=%d, m=%d, s=%d, ah=%d, as=%d",
7903
1.68k
      ret,year,month,day,hour,minute,second,addhours,addminutes);
7904
1.68k
  if (ret < 6)
7905
0
  {
7906
0
    LogMagickEvent(CoderEvent,GetMagickModule(),
7907
0
      "      Invalid date, ret=%d",ret);
7908
0
    (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7909
0
      "Invalid date format specified for png:tIME","`%s' (ret=%d)",
7910
0
      image->filename,ret);
7911
0
    return;
7912
0
  }
7913
1.68k
  if (addhours < 0)
7914
0
  {
7915
0
    addhours+=24;
7916
0
    addminutes=-addminutes;
7917
0
    day--;
7918
0
  }
7919
1.68k
  hour+=addhours;
7920
1.68k
  minute+=addminutes;
7921
1.68k
  if (day == 0)
7922
0
  {
7923
0
    month--;
7924
0
    day=31;
7925
0
    if(month == 2)
7926
0
      day=28;
7927
0
    else
7928
0
    {
7929
0
      if(month == 4 || month == 6 || month == 9 || month == 11)
7930
0
        day=30;
7931
0
      else
7932
0
        day=31;
7933
0
    }
7934
0
  }
7935
1.68k
  if (month == 0)
7936
0
  {
7937
0
    month++;
7938
0
    year--;
7939
0
  }
7940
1.68k
  if (minute > 59)
7941
0
  {
7942
0
     hour++;
7943
0
     minute-=60;
7944
0
  }
7945
1.68k
  if (hour > 23)
7946
0
  {
7947
0
     day ++;
7948
0
     hour -=24;
7949
0
  }
7950
1.68k
  if (hour < 0)
7951
0
  {
7952
0
     day --;
7953
0
     hour +=24;
7954
0
  }
7955
  /* To do: fix this for leap years */
7956
1.68k
  if (day > 31 || (month == 2 && day > 28) || ((month == 4 || month == 6 ||
7957
1.67k
      month == 9 || month == 11) && day > 30))
7958
0
  {
7959
0
     month++;
7960
0
     day = 1;
7961
0
  }
7962
1.68k
  if (month > 12)
7963
0
  {
7964
0
     year++;
7965
0
     month=1;
7966
0
  }
7967
7968
1.68k
  ptime.year = (png_uint_16) year;
7969
1.68k
  ptime.month = (png_byte) month;
7970
1.68k
  ptime.day = (png_byte) day;
7971
1.68k
  ptime.hour = (png_byte) hour;
7972
1.68k
  ptime.minute = (png_byte) minute;
7973
1.68k
  ptime.second = (png_byte) second;
7974
1.68k
  png_convert_from_time_t(&ptime,GetMagickTime());
7975
1.68k
  LogMagickEvent(CoderEvent,GetMagickModule(),
7976
1.68k
      "      png_set_tIME: y=%d, m=%d, d=%d, h=%d, m=%d, s=%d, ah=%d, am=%d",
7977
1.68k
      ptime.year, ptime.month, ptime.day, ptime.hour, ptime.minute,
7978
1.68k
      ptime.second, addhours, addminutes);
7979
1.68k
  png_set_tIME(ping,info,&ptime);
7980
1.68k
}
7981
#endif
7982
7983
static void Magick_png_set_text(png_struct *ping,png_info *ping_info,
7984
  MngWriteInfo *mng_info, const ImageInfo *image_info,const char* key,
7985
  const char *value)
7986
6.56k
{
7987
6.56k
#if PNG_LIBPNG_VER >= 10600
7988
6.56k
  const char
7989
6.56k
    *c;
7990
7991
6.56k
  MagickBooleanType
7992
6.56k
    write_itxt=MagickFalse;
7993
6.56k
#endif
7994
7995
6.56k
  int
7996
6.56k
    compresion_none=PNG_TEXT_COMPRESSION_NONE,
7997
6.56k
    compresion_zTXt=PNG_TEXT_COMPRESSION_zTXt;
7998
7999
6.56k
  png_textp
8000
6.56k
    text;
8001
8002
6.56k
  size_t
8003
6.56k
    length;
8004
8005
6.56k
#if PNG_LIBPNG_VER >= 10600
8006
  /*
8007
    Check if the string contains non-Latin1 characters.
8008
  */
8009
6.56k
  c=value;
8010
170k
  while(*c != '\0')
8011
164k
  {
8012
164k
      if (((const unsigned char) *c) > 127) {
8013
68
        write_itxt=MagickTrue;
8014
68
        compresion_none=PNG_ITXT_COMPRESSION_NONE;
8015
68
        compresion_zTXt=PNG_ITXT_COMPRESSION_zTXt;
8016
68
        break;
8017
68
      }
8018
164k
      c++;
8019
164k
  }
8020
6.56k
#endif
8021
6.56k
#if PNG_LIBPNG_VER >= 10400
8022
6.56k
  text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
8023
#else
8024
  text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
8025
#endif
8026
6.56k
  if (text == (png_textp) NULL)
8027
0
    return;
8028
6.56k
  (void) memset(text,0,sizeof(png_text));
8029
6.56k
  text[0].key=(char *) key;
8030
6.56k
  text[0].text=(char *) value;
8031
6.56k
  length=strlen(value);
8032
6.56k
#if PNG_LIBPNG_VER >= 10600
8033
6.56k
  if (write_itxt != MagickFalse)
8034
68
    text[0].itxt_length=length;
8035
6.49k
  else
8036
6.49k
#endif
8037
6.49k
    text[0].text_length=length;
8038
6.56k
  if (mng_info->exclude_tEXt != MagickFalse)
8039
0
    text[0].compression=compresion_zTXt;
8040
6.56k
  else
8041
6.56k
    if (mng_info->exclude_zTXt != MagickFalse)
8042
0
      text[0].compression=compresion_none;
8043
6.56k
    else
8044
6.56k
      text[0].compression=
8045
6.56k
        image_info->compression == NoCompression ||
8046
6.56k
        (image_info->compression == UndefinedCompression &&
8047
6.56k
        (length < 128)) ?  compresion_none : compresion_zTXt;
8048
6.56k
  png_set_text(ping,ping_info,text,1);
8049
6.56k
  png_free(ping,text);
8050
6.56k
}
8051
8052
/* Write one PNG image */
8053
static MagickBooleanType WriteOnePNGImage(MngWriteInfo *mng_info,
8054
  const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
8055
2.27k
{
8056
2.27k
  Image
8057
2.27k
    *volatile image;
8058
8059
2.27k
  ImageInfo
8060
2.27k
    *image_info;
8061
8062
2.27k
  char
8063
2.27k
    *name,
8064
2.27k
    s[2];
8065
8066
2.27k
  const char
8067
2.27k
    *property,
8068
2.27k
    *value;
8069
8070
2.27k
  const StringInfo
8071
2.27k
    *profile;
8072
8073
2.27k
  int
8074
2.27k
    num_passes,
8075
2.27k
    pass,
8076
2.27k
    ping_wrote_caNv;
8077
8078
2.27k
  png_byte
8079
2.27k
     ping_trans_alpha[257];
8080
8081
2.27k
  png_color
8082
2.27k
     palette[257];
8083
8084
2.27k
  png_color_16
8085
2.27k
    ping_background,
8086
2.27k
    ping_trans_color;
8087
8088
2.27k
  png_info
8089
2.27k
    *ping_info;
8090
8091
2.27k
  png_struct
8092
2.27k
    *ping;
8093
8094
2.27k
  png_uint_32
8095
2.27k
    ping_height,
8096
2.27k
    ping_width;
8097
8098
2.27k
  ssize_t
8099
2.27k
    y;
8100
8101
2.27k
  MagickBooleanType
8102
2.27k
    image_matte,
8103
2.27k
    logging = MagickFalse,
8104
2.27k
    matte,
8105
8106
2.27k
    ping_exclude_iCCP,
8107
2.27k
    ping_exclude_zCCP,
8108
8109
2.27k
    ping_have_cheap_transparency,
8110
2.27k
    ping_have_color,
8111
2.27k
    ping_have_non_bw,
8112
2.27k
    ping_have_PLTE,
8113
2.27k
    ping_have_bKGD,
8114
2.27k
    ping_have_eXIf,
8115
2.27k
    ping_have_iCCP,
8116
2.27k
    ping_have_pHYs,
8117
2.27k
    ping_have_sRGB,
8118
2.27k
    ping_have_tRNS,
8119
8120
2.27k
    ping_need_colortype_warning,
8121
8122
2.27k
    status,
8123
2.27k
    tried_332,
8124
2.27k
    tried_333,
8125
2.27k
    tried_444;
8126
8127
2.27k
  volatile MagickBooleanType
8128
2.27k
    ping_have_blob;
8129
8130
2.27k
  MemoryInfo
8131
2.27k
    *volatile pixel_info;
8132
8133
2.27k
  QuantumInfo
8134
2.27k
    *volatile quantum_info;
8135
8136
2.27k
  PNGErrorInfo
8137
2.27k
    error_info;
8138
8139
2.27k
  ssize_t
8140
2.27k
    i,
8141
2.27k
    x;
8142
8143
2.27k
  unsigned char
8144
2.27k
    *ping_pixels;
8145
8146
2.27k
  volatile int
8147
2.27k
    image_colors,
8148
2.27k
    ping_bit_depth,
8149
2.27k
    ping_color_type,
8150
2.27k
    ping_interlace_method,
8151
2.27k
    ping_compression_method,
8152
2.27k
    ping_filter_method,
8153
2.27k
    ping_num_trans;
8154
8155
2.27k
  volatile size_t
8156
2.27k
    image_depth,
8157
2.27k
    old_bit_depth;
8158
8159
2.27k
  size_t
8160
2.27k
    quality,
8161
2.27k
    rowbytes,
8162
2.27k
    save_image_depth;
8163
8164
2.27k
  int
8165
2.27k
    j,
8166
2.27k
    number_colors,
8167
2.27k
    number_opaque,
8168
2.27k
    number_semitransparent,
8169
2.27k
    number_transparent,
8170
2.27k
    ping_pHYs_unit_type;
8171
8172
2.27k
  png_uint_32
8173
2.27k
    ping_pHYs_x_resolution,
8174
2.27k
    ping_pHYs_y_resolution;
8175
8176
2.27k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
8177
2.27k
    "  Enter WriteOnePNGImage()");
8178
8179
2.27k
  image = CloneImage(IMimage,0,0,MagickFalse,exception);
8180
2.27k
  if (image == (Image *) NULL)
8181
0
    return(MagickFalse);
8182
2.27k
  image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
8183
8184
  /* Initialize some stuff */
8185
2.27k
  ping_bit_depth=0,
8186
2.27k
  ping_color_type=0,
8187
2.27k
  ping_interlace_method=0,
8188
2.27k
  ping_compression_method=0,
8189
2.27k
  ping_filter_method=0,
8190
2.27k
  ping_num_trans = 0;
8191
8192
2.27k
  ping_background.red = 0;
8193
2.27k
  ping_background.green = 0;
8194
2.27k
  ping_background.blue = 0;
8195
2.27k
  ping_background.gray = 0;
8196
2.27k
  ping_background.index = 0;
8197
8198
2.27k
  ping_trans_color.red=0;
8199
2.27k
  ping_trans_color.green=0;
8200
2.27k
  ping_trans_color.blue=0;
8201
2.27k
  ping_trans_color.gray=0;
8202
8203
2.27k
  ping_pHYs_unit_type = 0;
8204
2.27k
  ping_pHYs_x_resolution = 0;
8205
2.27k
  ping_pHYs_y_resolution = 0;
8206
8207
2.27k
  ping_have_blob=MagickFalse;
8208
2.27k
  ping_have_cheap_transparency=MagickFalse;
8209
2.27k
  ping_have_color=MagickTrue;
8210
2.27k
  ping_have_non_bw=MagickTrue;
8211
2.27k
  ping_have_PLTE=MagickFalse;
8212
2.27k
  ping_have_bKGD=MagickFalse;
8213
2.27k
  ping_have_eXIf=MagickTrue;
8214
2.27k
  ping_have_iCCP=MagickFalse;
8215
2.27k
  ping_have_pHYs=MagickFalse;
8216
2.27k
  ping_have_sRGB=MagickFalse;
8217
2.27k
  ping_have_tRNS=MagickFalse;
8218
8219
2.27k
  ping_exclude_iCCP=mng_info->exclude_iCCP;
8220
2.27k
  ping_exclude_zCCP=mng_info->exclude_zCCP;
8221
8222
2.27k
  ping_need_colortype_warning = MagickFalse;
8223
8224
  /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
8225
   * i.e., eliminate the ICC profile and set image->rendering_intent.
8226
   * Note that this will not involve any changes to the actual pixels
8227
   * but merely passes information to applications that read the resulting
8228
   * PNG image.
8229
   *
8230
   * To do: recognize other variants of the sRGB profile, using the CRC to
8231
   * verify all recognized variants including the 7 already known.
8232
   *
8233
   * Work around libpng16+ rejecting some "known invalid sRGB profiles".
8234
   *
8235
   * Use something other than image->rendering_intent to record the fact
8236
   * that the sRGB profile was found.
8237
   *
8238
   * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC
8239
   * profile.  Record the Blackpoint Compensation, if any.
8240
   */
8241
2.27k
   if (mng_info->exclude_sRGB == MagickFalse && mng_info->preserve_iCCP == MagickFalse)
8242
1.96k
   {
8243
1.96k
      ResetImageProfileIterator(image);
8244
2.08k
      for (name=GetNextImageProfile(image); name != (char *) NULL; )
8245
123
      {
8246
123
        profile=GetImageProfile(image,name);
8247
8248
123
        if (profile != (StringInfo *) NULL)
8249
123
          {
8250
123
            if ((LocaleCompare(name,"ICC") == 0) ||
8251
105
                (LocaleCompare(name,"ICM") == 0))
8252
8253
18
             {
8254
18
                 int
8255
18
                   icheck,
8256
18
                   got_crc=0;
8257
8258
8259
18
                 png_uint_32
8260
18
                   length,
8261
18
                   profile_crc=0;
8262
8263
18
                 unsigned char
8264
18
                   *data;
8265
8266
18
                 length=(png_uint_32) GetStringInfoLength(profile);
8267
8268
180
                 for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
8269
162
                 {
8270
162
                   if (length == sRGB_info[icheck].len)
8271
0
                   {
8272
0
                     if (got_crc == 0)
8273
0
                     {
8274
0
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8275
0
                         "    Got a %lu-byte ICC profile (potentially sRGB)",
8276
0
                         (unsigned long) length);
8277
8278
0
                       data=GetStringInfoDatum(profile);
8279
0
                       profile_crc=crc32(0,data,length);
8280
8281
0
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8282
0
                           "      with crc=%8x",(unsigned int) profile_crc);
8283
0
                       got_crc++;
8284
0
                     }
8285
8286
0
                     if (profile_crc == sRGB_info[icheck].crc)
8287
0
                     {
8288
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8289
0
                            "      It is sRGB with rendering intent = %s",
8290
0
                        Magick_RenderingIntentString_from_PNG_RenderingIntent(
8291
0
                             sRGB_info[icheck].intent));
8292
0
                        if (image->rendering_intent==UndefinedIntent)
8293
0
                        {
8294
0
                          image->rendering_intent=
8295
0
                          Magick_RenderingIntent_from_PNG_RenderingIntent(
8296
0
                             sRGB_info[icheck].intent);
8297
0
                        }
8298
0
                        ping_exclude_iCCP = MagickTrue;
8299
0
                        ping_exclude_zCCP = MagickTrue;
8300
0
                        ping_have_sRGB = MagickTrue;
8301
0
                        break;
8302
0
                     }
8303
0
                   }
8304
162
                 }
8305
18
                 if (sRGB_info[icheck].len == 0)
8306
18
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307
18
                        "    Got %lu-byte ICC profile not recognized as sRGB",
8308
18
                        (unsigned long) length);
8309
18
              }
8310
123
          }
8311
123
        name=GetNextImageProfile(image);
8312
123
      }
8313
1.96k
  }
8314
8315
2.27k
  number_opaque = 0;
8316
2.27k
  number_semitransparent = 0;
8317
2.27k
  number_transparent = 0;
8318
8319
2.27k
  if (logging != MagickFalse)
8320
0
    {
8321
0
      if (image->storage_class == UndefinedClass)
8322
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8323
0
          "    image->storage_class=UndefinedClass");
8324
0
      if (image->storage_class == DirectClass)
8325
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8326
0
          "    image->storage_class=DirectClass");
8327
0
      if (image->storage_class == PseudoClass)
8328
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8329
0
          "    image->storage_class=PseudoClass");
8330
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(), image->taint ?
8331
0
          "    image->taint=MagickTrue":
8332
0
          "    image->taint=MagickFalse");
8333
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8334
0
          "    image->gamma=%g", image->gamma);
8335
0
    }
8336
8337
2.27k
  if (image->storage_class == PseudoClass &&
8338
658
     ((mng_info->write_png8 != MagickFalse) ||
8339
337
      (mng_info->write_png24 != MagickFalse) ||
8340
337
      (mng_info->write_png32 != MagickFalse) ||
8341
337
      (mng_info->write_png48 != MagickFalse) ||
8342
337
      (mng_info->write_png64 != MagickFalse) ||
8343
337
      (mng_info->colortype == 3) || // PNG_COLOR_TYPE_RGB
8344
337
      (mng_info->colortype == 7))) // PNG_COLOR_TYPE_RGB_ALPHA
8345
321
    {
8346
321
      (void) SyncImage(image,exception);
8347
321
      image->storage_class = DirectClass;
8348
321
    }
8349
8350
2.27k
  if (mng_info->preserve_colormap == MagickFalse)
8351
2.27k
    {
8352
2.27k
      if ((image->storage_class != PseudoClass) &&
8353
1.93k
          (image->colormap != (PixelInfo *) NULL))
8354
933
        {
8355
          /* Free the bogus colormap; it can cause trouble later */
8356
933
           if (logging != MagickFalse)
8357
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8358
0
              "    Freeing bogus colormap");
8359
933
           image->colormap=(PixelInfo *) RelinquishMagickMemory(
8360
933
             image->colormap);
8361
933
        }
8362
2.27k
    }
8363
8364
2.27k
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8365
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
8366
8367
  /*
8368
    Sometimes we get PseudoClass images whose RGB values don't match
8369
    the colors in the colormap.  This code syncs the RGB values.
8370
  */
8371
2.27k
  image->depth=GetImageQuantumDepth(image,MagickFalse);
8372
2.27k
  if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
8373
0
     (void) SyncImage(image,exception);
8374
8375
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
8376
  if (image->depth > 8)
8377
    {
8378
      if (logging != MagickFalse)
8379
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8380
          "    Reducing PNG bit depth to 8 since this is a Q8 build.");
8381
8382
      image->depth=8;
8383
    }
8384
#endif
8385
8386
  /* Respect the -depth option */
8387
2.27k
  if (image->depth < 4)
8388
0
    {
8389
0
       Quantum
8390
0
         *r;
8391
8392
0
       if (image->depth > 2)
8393
0
         {
8394
           /* Scale to 4-bit */
8395
0
           LBR04PacketRGBA(image->background_color);
8396
8397
0
           for (y=0; y < (ssize_t) image->rows; y++)
8398
0
           {
8399
0
             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8400
8401
0
             if (r == (Quantum *) NULL)
8402
0
               break;
8403
8404
0
             for (x=0; x < (ssize_t) image->columns; x++)
8405
0
             {
8406
0
                LBR04PixelRGBA(r);
8407
0
                r+=(ptrdiff_t) GetPixelChannels(image);
8408
0
             }
8409
8410
0
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
8411
0
                break;
8412
0
           }
8413
8414
0
           if (image->storage_class == PseudoClass && image->colormap != NULL)
8415
0
           {
8416
0
             for (i=0; i < (ssize_t) image->colors; i++)
8417
0
             {
8418
0
               LBR04PacketRGBA(image->colormap[i]);
8419
0
             }
8420
0
           }
8421
0
         }
8422
0
       else if (image->depth > 1)
8423
0
         {
8424
           /* Scale to 2-bit */
8425
0
           LBR02PacketRGBA(image->background_color);
8426
8427
0
           for (y=0; y < (ssize_t) image->rows; y++)
8428
0
           {
8429
0
             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8430
8431
0
             if (r == (Quantum *) NULL)
8432
0
               break;
8433
8434
0
             for (x=0; x < (ssize_t) image->columns; x++)
8435
0
             {
8436
0
                LBR02PixelRGBA(r);
8437
0
                r+=(ptrdiff_t) GetPixelChannels(image);
8438
0
             }
8439
8440
0
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
8441
0
                break;
8442
0
           }
8443
8444
0
           if (image->storage_class == PseudoClass && image->colormap != NULL)
8445
0
           {
8446
0
             for (i=0; i < (ssize_t) image->colors; i++)
8447
0
             {
8448
0
               LBR02PacketRGBA(image->colormap[i]);
8449
0
             }
8450
0
           }
8451
0
         }
8452
0
       else
8453
0
         {
8454
           /* Scale to 1-bit */
8455
0
           LBR01PacketRGBA(image->background_color);
8456
8457
0
           for (y=0; y < (ssize_t) image->rows; y++)
8458
0
           {
8459
0
             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8460
8461
0
             if (r == (Quantum *) NULL)
8462
0
               break;
8463
8464
0
             for (x=0; x < (ssize_t) image->columns; x++)
8465
0
             {
8466
0
                LBR01PixelRGBA(r);
8467
0
                r+=(ptrdiff_t) GetPixelChannels(image);
8468
0
             }
8469
8470
0
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
8471
0
                break;
8472
0
           }
8473
8474
0
           if (image->storage_class == PseudoClass && image->colormap != NULL)
8475
0
           {
8476
0
             for (i=0; i < (ssize_t) image->colors; i++)
8477
0
             {
8478
0
               LBR01PacketRGBA(image->colormap[i]);
8479
0
             }
8480
0
           }
8481
0
         }
8482
0
    }
8483
8484
  /* To do: set to next higher multiple of 8 */
8485
2.27k
  if (image->depth < 8)
8486
0
     image->depth=8;
8487
8488
#if (MAGICKCORE_QUANTUM_DEPTH > 16)
8489
  /* PNG does not handle depths greater than 16 so reduce it even
8490
   * if lossy
8491
   */
8492
  if (image->depth > 8)
8493
      image->depth=16;
8494
#endif
8495
8496
2.27k
#if (MAGICKCORE_QUANTUM_DEPTH > 8)
8497
2.27k
  if (image->depth > 8)
8498
933
    {
8499
      /* To do: fill low byte properly */
8500
933
      image->depth=16;
8501
933
    }
8502
8503
2.27k
  if (image->depth == 16 && mng_info->depth != 16)
8504
395
    if (mng_info->write_png8 != MagickFalse ||
8505
395
        LosslessReduceDepthOK(image,exception) != MagickFalse)
8506
192
      image->depth = 8;
8507
2.27k
#endif
8508
8509
2.27k
  image_colors = (int) image->colors;
8510
2.27k
  number_opaque = (int) image->colors;
8511
2.27k
  number_transparent = 0;
8512
2.27k
  number_semitransparent = 0;
8513
2.27k
  if (IdentifyImageCoderGray(image,exception) != MagickFalse)
8514
1.22k
    ping_have_color=MagickFalse;
8515
8516
2.27k
  if (mng_info->colortype &&
8517
1.63k
     (mng_info->colortype > 4 || (mng_info->depth >= 8 &&
8518
927
     mng_info->colortype < 4 &&
8519
596
     image->alpha_trait == UndefinedPixelTrait)))
8520
1.05k
  {
8521
     /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8522
      * are not going to need the result.
8523
      */
8524
1.05k
     if (mng_info->colortype == 1 ||
8525
1.02k
        mng_info->colortype == 5)
8526
32
       ping_have_color=MagickFalse;
8527
8528
1.05k
     if (image->alpha_trait != UndefinedPixelTrait)
8529
154
       {
8530
154
         number_transparent = 2;
8531
154
         number_semitransparent = 1;
8532
154
       }
8533
1.05k
  }
8534
8535
2.27k
  if (mng_info->colortype < 7)
8536
1.72k
  {
8537
  /* BUILD_PALETTE
8538
   *
8539
   * Normally we run this just once, but in the case of writing PNG8
8540
   * we reduce the transparency to binary and run again, then if there
8541
   * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8542
   * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8543
   * palette.  Then (To do) we take care of a final reduction that is only
8544
   * needed if there are still 256 colors present and one of them has both
8545
   * transparent and opaque instances.
8546
   */
8547
8548
1.72k
  tried_332 = MagickFalse;
8549
1.72k
  tried_333 = MagickFalse;
8550
1.72k
  tried_444 = MagickFalse;
8551
8552
1.72k
  if (image->depth != GetImageDepth(image,exception))
8553
1.10k
    (void) SetImageDepth(image,image->depth,exception);
8554
1.74k
  for (j=0; j<6; j++)
8555
1.74k
  {
8556
    /*
8557
     * Sometimes we get DirectClass images that have 256 colors or fewer.
8558
     * This code will build a colormap.
8559
     *
8560
     * Also, sometimes we get PseudoClass images with an out-of-date
8561
     * colormap.  This code will replace the colormap with a new one.
8562
     * Sometimes we get PseudoClass images that have more than 256 colors.
8563
     * This code will delete the colormap and change the image to
8564
     * DirectClass.
8565
     *
8566
     * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8567
     * even though it sometimes contains left-over non-opaque values.
8568
     *
8569
     * Also we gather some information (number of opaque, transparent,
8570
     * and semitransparent pixels, and whether the image has any non-gray
8571
     * pixels or only black-and-white pixels) that we might need later.
8572
     *
8573
     * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8574
     * we need to check for bogus non-opaque values, at least.
8575
     */
8576
8577
1.74k
   int
8578
1.74k
     n;
8579
8580
1.74k
   PixelInfo
8581
1.74k
     opaque[260],
8582
1.74k
     semitransparent[260],
8583
1.74k
     transparent[260];
8584
8585
1.74k
   const Quantum
8586
1.74k
     *r;
8587
8588
1.74k
   Quantum
8589
1.74k
     *q;
8590
8591
1.74k
   size_t
8592
1.74k
     h;
8593
8594
1.74k
   unsigned short
8595
1.74k
     opaque_hash[PNGPaletteHashSize],
8596
1.74k
     semitransparent_hash[PNGPaletteHashSize],
8597
1.74k
     transparent_hash[PNGPaletteHashSize];
8598
8599
1.74k
   if (logging != MagickFalse)
8600
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8601
0
         "    Enter BUILD_PALETTE:");
8602
8603
1.74k
   if (logging != MagickFalse)
8604
0
     {
8605
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8606
0
             "      image->columns=%.17g",(double) image->columns);
8607
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8608
0
             "      image->rows=%.17g",(double) image->rows);
8609
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8610
0
             "      image->alpha_trait=%.17g",(double) image->alpha_trait);
8611
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8612
0
             "      image->depth=%.17g",(double) image->depth);
8613
8614
0
       if (image->storage_class == PseudoClass && image->colormap != NULL)
8615
0
       {
8616
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8617
0
             "      Original colormap:");
8618
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8619
0
             "        i    (red,green,blue,alpha)");
8620
8621
0
         for (i=0; i < (ssize_t) MagickMin(image->colors,256); i++)
8622
0
         {
8623
0
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8624
0
                   "        %d    (%d,%d,%d,%d)",
8625
0
                    (int) i,
8626
0
                    (int) image->colormap[i].red,
8627
0
                    (int) image->colormap[i].green,
8628
0
                    (int) image->colormap[i].blue,
8629
0
                    (int) image->colormap[i].alpha);
8630
0
         }
8631
8632
0
         for (i=(ssize_t) image->colors - 10; i < (ssize_t) image->colors; i++)
8633
0
         {
8634
0
           if (i > 255)
8635
0
             {
8636
0
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8637
0
                   "        %d    (%d,%d,%d,%d)",
8638
0
                    (int) i,
8639
0
                    (int) image->colormap[i].red,
8640
0
                    (int) image->colormap[i].green,
8641
0
                    (int) image->colormap[i].blue,
8642
0
                    (int) image->colormap[i].alpha);
8643
0
             }
8644
0
         }
8645
0
       }
8646
8647
0
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8648
0
           "      image->colors=%d",(int) image->colors);
8649
8650
0
       if (image->colors == 0)
8651
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8652
0
             "        (zero means unknown)");
8653
8654
0
       if (mng_info->preserve_colormap == MagickFalse)
8655
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8656
0
              "      Regenerate the colormap");
8657
0
     }
8658
8659
1.74k
     image_colors=0;
8660
1.74k
     number_opaque = 0;
8661
1.74k
     number_semitransparent = 0;
8662
1.74k
     number_transparent = 0;
8663
1.74k
     (void) memset(opaque_hash,0,sizeof(opaque_hash));
8664
1.74k
     (void) memset(semitransparent_hash,0,sizeof(semitransparent_hash));
8665
1.74k
     (void) memset(transparent_hash,0,sizeof(transparent_hash));
8666
8667
251k
     for (y=0; y < (ssize_t) image->rows; y++)
8668
250k
     {
8669
250k
       r=GetVirtualPixels(image,0,y,image->columns,1,exception);
8670
8671
250k
       if (r == (const Quantum *) NULL)
8672
0
         break;
8673
8674
275M
       for (x=0; x < (ssize_t) image->columns; x++)
8675
275M
       {
8676
275M
           if ((((image->alpha_trait & BlendPixelTrait) == 0) &&
8677
274M
                ((image->alpha_trait & UpdatePixelTrait) == 0)) ||
8678
1.16M
               (GetPixelAlpha(image,r) == OpaqueAlpha))
8679
275M
             {
8680
275M
               if (number_opaque < 259)
8681
274M
                 {
8682
274M
                   h=PNGPaletteHash(GetPixelRed(image,r),GetPixelGreen(image,r),
8683
274M
                     GetPixelBlue(image,r),(Quantum) 0);
8684
274M
                   if (number_opaque == 0)
8685
1.68k
                     {
8686
1.68k
                       GetPixelInfoPixel(image,r,opaque);
8687
1.68k
                       opaque[0].alpha=OpaqueAlpha;
8688
1.68k
                       number_opaque=1;
8689
1.68k
                       opaque_hash[h]=1;
8690
1.68k
                     }
8691
8692
275M
                   while ((opaque_hash[h] != 0) &&
8693
275M
                          (IsColorEqual(image,r,opaque+opaque_hash[h]-1) ==
8694
275M
                           MagickFalse))
8695
574k
                     h=(h+1) & (PNGPaletteHashSize-1);
8696
8697
274M
                   if (opaque_hash[h] == 0)
8698
82.4k
                     {
8699
82.4k
                       i=(ssize_t) number_opaque++;
8700
82.4k
                       GetPixelInfoPixel(image,r,opaque+i);
8701
82.4k
                       opaque[i].alpha=OpaqueAlpha;
8702
82.4k
                       opaque_hash[h]=(unsigned short) number_opaque;
8703
82.4k
                     }
8704
274M
                 }
8705
275M
             }
8706
592k
           else if (GetPixelAlpha(image,r) == TransparentAlpha)
8707
309k
             {
8708
309k
               if (number_transparent < 259)
8709
309k
                 {
8710
309k
                   h=PNGPaletteHash(GetPixelRed(image,r),GetPixelGreen(image,r),
8711
309k
                     GetPixelBlue(image,r),(Quantum) 0);
8712
309k
                   if (number_transparent == 0)
8713
186
                     {
8714
186
                       GetPixelInfoPixel(image,r,transparent);
8715
186
                       ping_trans_color.red=(unsigned short)
8716
186
                         GetPixelRed(image,r);
8717
186
                       ping_trans_color.green=(unsigned short)
8718
186
                         GetPixelGreen(image,r);
8719
186
                       ping_trans_color.blue=(unsigned short)
8720
186
                         GetPixelBlue(image,r);
8721
186
                       ping_trans_color.gray=(unsigned short)
8722
186
                         GetPixelGray(image,r);
8723
186
                       number_transparent = 1;
8724
186
                       transparent_hash[h]=1;
8725
186
                     }
8726
8727
310k
                   while ((transparent_hash[h] != 0) &&
8728
308k
                          (IsColorEqual(image,r,transparent+
8729
308k
                           transparent_hash[h]-1) == MagickFalse))
8730
48
                     h=(h+1) & (PNGPaletteHashSize-1);
8731
8732
309k
                   if (transparent_hash[h] == 0)
8733
1.11k
                     {
8734
1.11k
                       i=(ssize_t) number_transparent++;
8735
1.11k
                       GetPixelInfoPixel(image,r,transparent+i);
8736
1.11k
                       transparent_hash[h]=(unsigned short) number_transparent;
8737
1.11k
                     }
8738
309k
                 }
8739
309k
             }
8740
282k
           else
8741
282k
             {
8742
282k
               if (number_semitransparent < 259)
8743
116k
                 {
8744
116k
                   h=PNGPaletteHash(GetPixelRed(image,r),GetPixelGreen(image,r),
8745
116k
                     GetPixelBlue(image,r),GetPixelAlpha(image,r));
8746
116k
                   if (number_semitransparent == 0)
8747
96
                     {
8748
96
                       GetPixelInfoPixel(image,r,semitransparent);
8749
96
                       number_semitransparent = 1;
8750
96
                       semitransparent_hash[h]=1;
8751
96
                     }
8752
8753
142k
                   while (semitransparent_hash[h] != 0)
8754
132k
                     {
8755
132k
                       i=(ssize_t) semitransparent_hash[h]-1;
8756
132k
                       if (IsColorEqual(image,r,semitransparent+i)
8757
108k
                           && (double) GetPixelAlpha(image,r) ==
8758
108k
                           semitransparent[i].alpha)
8759
106k
                         break;
8760
25.8k
                       h=(h+1) & (PNGPaletteHashSize-1);
8761
25.8k
                     }
8762
8763
116k
                   if (semitransparent_hash[h] == 0)
8764
9.65k
                     {
8765
9.65k
                       i=(ssize_t) number_semitransparent++;
8766
9.65k
                       GetPixelInfoPixel(image,r,semitransparent+i);
8767
9.65k
                       semitransparent_hash[h]=(unsigned short)
8768
9.65k
                         number_semitransparent;
8769
9.65k
                     }
8770
116k
                 }
8771
282k
             }
8772
275M
           r+=(ptrdiff_t) GetPixelChannels(image);
8773
275M
        }
8774
250k
     }
8775
8776
1.74k
     image_colors=number_opaque+number_transparent+number_semitransparent;
8777
8778
1.74k
     if (mng_info->write_png8 == MagickFalse &&
8779
1.40k
         mng_info->exclude_bKGD == MagickFalse)
8780
1.09k
       {
8781
1.09k
          if (logging != MagickFalse)
8782
0
            {
8783
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8784
0
                  "      Check colormap for background (%d,%d,%d)",
8785
0
                  (int) image->background_color.red,
8786
0
                  (int) image->background_color.green,
8787
0
                  (int) image->background_color.blue);
8788
0
            }
8789
1.09k
       }
8790
8791
1.74k
     image_colors=number_opaque+number_transparent+number_semitransparent;
8792
8793
1.74k
     if (logging != MagickFalse)
8794
0
       {
8795
0
         if (image_colors > 256)
8796
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8797
0
                  "      image has more than 256 colors");
8798
8799
0
         else
8800
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8801
0
                  "      image has %d colors",image_colors);
8802
0
       }
8803
8804
1.74k
     if (mng_info->preserve_colormap != MagickFalse)
8805
0
       break;
8806
8807
1.74k
     if (mng_info->colortype != 7) /* We won't need this info */
8808
1.74k
       {
8809
1.74k
         ping_have_color=MagickFalse;
8810
1.74k
         ping_have_non_bw=MagickFalse;
8811
8812
1.74k
         if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8813
0
         {
8814
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8815
0
              "incompatible colorspace");
8816
0
           ping_have_color=MagickTrue;
8817
0
           ping_have_non_bw=MagickTrue;
8818
0
         }
8819
8820
1.74k
         if (image_colors > 256)
8821
137
           {
8822
1.84k
             for (y=0; y < (ssize_t) image->rows; y++)
8823
1.81k
             {
8824
1.81k
               q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8825
8826
1.81k
               if (q == (Quantum *) NULL)
8827
0
                 break;
8828
8829
1.81k
               r=q;
8830
194k
               for (x=0; x < (ssize_t) image->columns; x++)
8831
193k
               {
8832
193k
                 if (GetPixelRed(image,r) != GetPixelGreen(image,r) ||
8833
193k
                     GetPixelRed(image,r) != GetPixelBlue(image,r))
8834
100
                   {
8835
100
                      ping_have_color=MagickTrue;
8836
100
                      ping_have_non_bw=MagickTrue;
8837
100
                      break;
8838
100
                   }
8839
192k
                 r+=(ptrdiff_t) GetPixelChannels(image);
8840
192k
               }
8841
8842
1.81k
               if (ping_have_color != MagickFalse)
8843
100
                 break;
8844
8845
               /* Worst case is black-and-white; we are looking at every
8846
                * pixel twice.
8847
                */
8848
8849
1.71k
               if (ping_have_non_bw == MagickFalse)
8850
104
                 {
8851
104
                   r=q;
8852
4.53k
                   for (x=0; x < (ssize_t) image->columns; x++)
8853
4.47k
                   {
8854
4.47k
                     if (GetPixelRed(image,r) != 0 &&
8855
2.01k
                         GetPixelRed(image,r) != QuantumRange)
8856
44
                       {
8857
44
                         ping_have_non_bw=MagickTrue;
8858
44
                         break;
8859
44
                       }
8860
4.42k
                     r+=(ptrdiff_t) GetPixelChannels(image);
8861
4.42k
                   }
8862
104
               }
8863
1.71k
             }
8864
137
           }
8865
1.74k
       }
8866
8867
1.74k
     if (image_colors < 257)
8868
1.60k
       {
8869
1.60k
         MagickBooleanType
8870
1.60k
           ignore_alpha;
8871
8872
1.60k
         PixelInfo
8873
1.60k
           colormap[260];
8874
8875
1.60k
         unsigned short
8876
1.60k
           colormap_hash[PNGPaletteHashSize];
8877
8878
         /*
8879
          * Initialize image colormap.
8880
          */
8881
8882
1.60k
         if (logging != MagickFalse)
8883
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8884
0
                  "      Sort the new colormap");
8885
8886
        /* Sort palette, transparent first */;
8887
8888
1.60k
         n = 0;
8889
8890
1.82k
         for (i=0; i<number_transparent; i++)
8891
215
            colormap[n++] = transparent[i];
8892
8893
4.44k
         for (i=0; i<number_semitransparent; i++)
8894
2.84k
            colormap[n++] = semitransparent[i];
8895
8896
55.1k
         for (i=0; i<number_opaque; i++)
8897
53.5k
            colormap[n++] = opaque[i];
8898
8899
1.60k
         ping_background.index += (png_byte) (number_transparent +
8900
1.60k
           number_semitransparent);
8901
8902
         /* image_colors < 257; search the colormap instead of the pixels
8903
          * to get ping_have_color and ping_have_non_bw
8904
          */
8905
13.3k
         for (i=0; i<n; i++)
8906
12.4k
         {
8907
12.4k
           if (ping_have_color == MagickFalse)
8908
12.4k
             {
8909
12.4k
                if (colormap[i].red != colormap[i].green ||
8910
12.0k
                    colormap[i].red != colormap[i].blue)
8911
708
                  {
8912
708
                     ping_have_color=MagickTrue;
8913
708
                     ping_have_non_bw=MagickTrue;
8914
708
                     break;
8915
708
                  }
8916
12.4k
              }
8917
8918
11.7k
           if (ping_have_non_bw == MagickFalse)
8919
1.46k
             {
8920
1.46k
               if (colormap[i].red != 0 && colormap[i].red != (double) QuantumRange)
8921
318
                   ping_have_non_bw=MagickTrue;
8922
1.46k
             }
8923
11.7k
          }
8924
8925
1.60k
        if ((mng_info->exclude_tRNS == MagickFalse ||
8926
311
            (number_transparent == 0 && number_semitransparent == 0)) &&
8927
1.60k
            (((mng_info->colortype-1) == PNG_COLOR_TYPE_PALETTE) ||
8928
1.20k
            (mng_info->colortype == 0)))
8929
987
          {
8930
987
            if (logging != MagickFalse)
8931
0
              {
8932
0
                if (n !=  (ssize_t) image_colors)
8933
0
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8934
0
                   "   image_colors (%d) and n (%d)  don't match",
8935
0
                   image_colors, n);
8936
8937
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8938
0
                   "      AcquireImageColormap");
8939
0
              }
8940
8941
987
            image->colors = (size_t) image_colors;
8942
8943
987
            if (AcquireImageColormap(image,(size_t) image_colors,exception) == MagickFalse)
8944
0
              {
8945
0
                (void) ThrowMagickException(exception,GetMagickModule(),
8946
0
                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
8947
0
                  image->filename);
8948
0
                break;
8949
0
              }
8950
8951
38.1k
            for (i=0; i< (ssize_t) image_colors; i++)
8952
37.1k
               image->colormap[i] = colormap[i];
8953
8954
987
            if (logging != MagickFalse)
8955
0
              {
8956
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8957
0
                      "      image->colors=%d (%d)",
8958
0
                      (int) image->colors, image_colors);
8959
8960
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8961
0
                      "      Update the pixel indexes");
8962
0
              }
8963
8964
            /* Sync the pixel indices with the new colormap */
8965
8966
987
            ignore_alpha=(((image->alpha_trait & BlendPixelTrait) == 0) &&
8967
841
              ((image->alpha_trait & UpdatePixelTrait) == 0)) ? MagickTrue :
8968
987
              MagickFalse;
8969
987
            (void) memset(colormap_hash,0,sizeof(colormap_hash));
8970
38.1k
            for (i=0; i< (ssize_t) image_colors; i++)
8971
37.1k
            {
8972
37.1k
              h=PNGPaletteHash((Quantum) image->colormap[i].red,
8973
37.1k
                (Quantum) image->colormap[i].green,
8974
37.1k
                (Quantum) image->colormap[i].blue,ignore_alpha != MagickFalse ?
8975
31.4k
                (Quantum) 0 : (Quantum) image->colormap[i].alpha);
8976
45.1k
              while (colormap_hash[h] != 0)
8977
8.01k
                h=(h+1) & (PNGPaletteHashSize-1);
8978
37.1k
              colormap_hash[h]=(unsigned short) (i+1);
8979
37.1k
            }
8980
8981
224k
            for (y=0; y < (ssize_t) image->rows; y++)
8982
223k
            {
8983
223k
              q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8984
8985
223k
              if (q == (Quantum *) NULL)
8986
0
                break;
8987
8988
269M
              for (x=0; x < (ssize_t) image->columns; x++)
8989
269M
              {
8990
269M
                h=PNGPaletteHash(GetPixelRed(image,q),GetPixelGreen(image,q),
8991
269M
                  GetPixelBlue(image,q),ignore_alpha != MagickFalse ?
8992
268M
                  (Quantum) 0 : GetPixelAlpha(image,q));
8993
269M
                while (colormap_hash[h] != 0)
8994
269M
                {
8995
269M
                  i=(ssize_t) colormap_hash[h]-1;
8996
269M
                  if ((ignore_alpha != MagickFalse ||
8997
768k
                      image->colormap[i].alpha == (double) GetPixelAlpha(image,q)) &&
8998
269M
                      image->colormap[i].red == (double) GetPixelRed(image,q) &&
8999
269M
                      image->colormap[i].green == (double) GetPixelGreen(image,q) &&
9000
269M
                      image->colormap[i].blue == (double) GetPixelBlue(image,q))
9001
269M
                  {
9002
269M
                    SetPixelIndex(image,(Quantum) i,q);
9003
269M
                    break;
9004
269M
                  }
9005
512k
                  h=(h+1) & (PNGPaletteHashSize-1);
9006
512k
                }
9007
269M
                q+=(ptrdiff_t) GetPixelChannels(image);
9008
269M
              }
9009
9010
223k
              if (SyncAuthenticPixels(image,exception) == MagickFalse)
9011
0
                 break;
9012
223k
            }
9013
987
          }
9014
1.60k
       }
9015
9016
1.74k
     if (logging != MagickFalse)
9017
0
       {
9018
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9019
0
            "      image->colors=%d", (int) image->colors);
9020
9021
0
         if (image->colormap != NULL)
9022
0
           {
9023
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9024
0
                 "       i     (red,green,blue,alpha)");
9025
9026
0
             for (i=0; i < (ssize_t) image->colors; i++)
9027
0
             {
9028
0
               if (i < 300 || i >= (ssize_t) image->colors - 10)
9029
0
                 {
9030
0
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9031
0
                       "       %d     (%d,%d,%d,%d)",
9032
0
                        (int) i,
9033
0
                        (int) image->colormap[i].red,
9034
0
                        (int) image->colormap[i].green,
9035
0
                        (int) image->colormap[i].blue,
9036
0
                        (int) image->colormap[i].alpha);
9037
0
                 }
9038
0
             }
9039
0
           }
9040
9041
0
           if (number_transparent < 257)
9042
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9043
0
                   "      number_transparent     = %d",
9044
0
                   number_transparent);
9045
0
           else
9046
9047
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9048
0
                   "      number_transparent     > 256");
9049
9050
0
           if (number_opaque < 257)
9051
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9052
0
                   "      number_opaque          = %d",
9053
0
                   number_opaque);
9054
9055
0
           else
9056
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9057
0
                   "      number_opaque          > 256");
9058
9059
0
           if (number_semitransparent < 257)
9060
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9061
0
                   "      number_semitransparent = %d",
9062
0
                   number_semitransparent);
9063
9064
0
           else
9065
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9066
0
                   "      number_semitransparent > 256");
9067
9068
0
           if (ping_have_non_bw == MagickFalse)
9069
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9070
0
                    "      All pixels and the background are black or white");
9071
9072
0
           else if (ping_have_color == MagickFalse)
9073
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9074
0
                    "      All pixels and the background are gray");
9075
9076
0
           else
9077
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9078
0
                    "      At least one pixel or the background is non-gray");
9079
9080
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9081
0
               "    Exit BUILD_PALETTE:");
9082
0
       }
9083
9084
1.74k
   if (mng_info->write_png8 == MagickFalse)
9085
1.40k
      break;
9086
9087
   /* Make any reductions necessary for the PNG8 format */
9088
340
    if (image_colors <= 256 &&
9089
340
        image_colors != 0 && image->colormap != NULL &&
9090
340
        number_semitransparent == 0 &&
9091
321
        number_transparent <= 1)
9092
321
      break;
9093
9094
    /* PNG8 can't have semitransparent colors so we threshold the
9095
     * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
9096
     * transparent color so if more than one is transparent we merge
9097
     * them into image->background_color.
9098
     */
9099
19
    if (number_semitransparent != 0 || number_transparent > 1)
9100
19
      {
9101
19
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9102
19
            "    Thresholding the alpha channel to binary");
9103
9104
1.02k
        for (y=0; y < (ssize_t) image->rows; y++)
9105
1.00k
        {
9106
1.00k
          q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9107
9108
1.00k
          if (q == (Quantum *) NULL)
9109
0
            break;
9110
9111
166k
          for (x=0; x < (ssize_t) image->columns; x++)
9112
165k
          {
9113
165k
              if (GetPixelAlpha(image,q) < OpaqueAlpha/2)
9114
80.1k
                {
9115
80.1k
                  SetPixelViaPixelInfo(image,&image->background_color,q);
9116
80.1k
                  SetPixelAlpha(image,TransparentAlpha,q);
9117
80.1k
                }
9118
84.8k
              else
9119
84.8k
                  SetPixelAlpha(image,OpaqueAlpha,q);
9120
165k
              q+=(ptrdiff_t) GetPixelChannels(image);
9121
165k
          }
9122
9123
1.00k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
9124
0
             break;
9125
9126
1.00k
          if (image_colors != 0 && image_colors <= 256 &&
9127
1.00k
             image->colormap != NULL)
9128
90.4k
            for (i=0; i<image_colors; i++)
9129
89.4k
                image->colormap[i].alpha =
9130
89.4k
                    (image->colormap[i].alpha > (double) TransparentAlpha/2 ?
9131
44.7k
                    TransparentAlpha : OpaqueAlpha);
9132
1.00k
        }
9133
19
      continue;
9134
19
    }
9135
9136
    /* PNG8 can't have more than 256 colors so we quantize the pixels and
9137
     * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette.  If the
9138
     * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
9139
     * colors or less.
9140
     */
9141
0
    if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
9142
0
      {
9143
0
        if (logging != MagickFalse)
9144
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9145
0
               "    Quantizing the background color to 4-4-4");
9146
9147
0
        tried_444 = MagickTrue;
9148
9149
0
        LBR04PacketRGB(image->background_color);
9150
9151
0
        if (logging != MagickFalse)
9152
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9153
0
              "    Quantizing the pixel colors to 4-4-4");
9154
9155
0
        if (image->colormap == NULL)
9156
0
        {
9157
0
          for (y=0; y < (ssize_t) image->rows; y++)
9158
0
          {
9159
0
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9160
9161
0
            if (q == (Quantum *) NULL)
9162
0
              break;
9163
9164
0
            for (x=0; x < (ssize_t) image->columns; x++)
9165
0
            {
9166
0
              if (GetPixelAlpha(image,q) == OpaqueAlpha)
9167
0
                  LBR04PixelRGB(q);
9168
0
              q+=(ptrdiff_t) GetPixelChannels(image);
9169
0
            }
9170
9171
0
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
9172
0
               break;
9173
0
          }
9174
0
        }
9175
9176
0
        else /* Should not reach this; colormap already exists and
9177
                must be <= 256 */
9178
0
        {
9179
0
          if (logging != MagickFalse)
9180
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9181
0
              "    Quantizing the colormap to 4-4-4");
9182
9183
0
          for (i=0; i<image_colors; i++)
9184
0
          {
9185
0
            LBR04PacketRGB(image->colormap[i]);
9186
0
          }
9187
0
        }
9188
0
        continue;
9189
0
      }
9190
9191
0
    if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
9192
0
      {
9193
0
        if (logging != MagickFalse)
9194
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9195
0
               "    Quantizing the background color to 3-3-3");
9196
9197
0
        tried_333 = MagickTrue;
9198
9199
0
        LBR03PacketRGB(image->background_color);
9200
9201
0
        if (logging != MagickFalse)
9202
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9203
0
              "    Quantizing the pixel colors to 3-3-3-1");
9204
9205
0
        if (image->colormap == NULL)
9206
0
        {
9207
0
          for (y=0; y < (ssize_t) image->rows; y++)
9208
0
          {
9209
0
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9210
9211
0
            if (q == (Quantum *) NULL)
9212
0
              break;
9213
9214
0
            for (x=0; x < (ssize_t) image->columns; x++)
9215
0
            {
9216
0
              if (GetPixelAlpha(image,q) == OpaqueAlpha)
9217
0
                  LBR03RGB(q);
9218
0
              q+=(ptrdiff_t) GetPixelChannels(image);
9219
0
            }
9220
9221
0
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
9222
0
               break;
9223
0
          }
9224
0
        }
9225
9226
0
        else /* Should not reach this; colormap already exists and
9227
                must be <= 256 */
9228
0
        {
9229
0
          if (logging != MagickFalse)
9230
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9231
0
              "    Quantizing the colormap to 3-3-3-1");
9232
0
          for (i=0; i<image_colors; i++)
9233
0
          {
9234
0
              LBR03PacketRGB(image->colormap[i]);
9235
0
          }
9236
0
        }
9237
0
        continue;
9238
0
      }
9239
9240
0
    if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
9241
0
      {
9242
0
        if (logging != MagickFalse)
9243
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9244
0
               "    Quantizing the background color to 3-3-2");
9245
9246
0
        tried_332 = MagickTrue;
9247
9248
        /* Red and green were already done so we only quantize the blue
9249
         * channel
9250
         */
9251
9252
0
        LBR02PacketBlue(image->background_color);
9253
9254
0
        if (logging != MagickFalse)
9255
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9256
0
              "    Quantizing the pixel colors to 3-3-2-1");
9257
9258
0
        if (image->colormap == NULL)
9259
0
        {
9260
0
          for (y=0; y < (ssize_t) image->rows; y++)
9261
0
          {
9262
0
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9263
9264
0
            if (q == (Quantum *) NULL)
9265
0
              break;
9266
9267
0
            for (x=0; x < (ssize_t) image->columns; x++)
9268
0
            {
9269
0
              if (GetPixelAlpha(image,q) == OpaqueAlpha)
9270
0
                  LBR02PixelBlue(q);
9271
0
              q+=(ptrdiff_t) GetPixelChannels(image);
9272
0
            }
9273
9274
0
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
9275
0
               break;
9276
0
          }
9277
0
        }
9278
9279
0
        else /* Should not reach this; colormap already exists and
9280
                must be <= 256 */
9281
0
        {
9282
0
          if (logging != MagickFalse)
9283
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9284
0
              "    Quantizing the colormap to 3-3-2-1");
9285
0
          for (i=0; i<image_colors; i++)
9286
0
          {
9287
0
              LBR02PacketBlue(image->colormap[i]);
9288
0
          }
9289
0
      }
9290
0
      continue;
9291
0
    }
9292
9293
0
    if (image_colors == 0 || image_colors > 256)
9294
0
    {
9295
      /* Take care of special case with 256 opaque colors + 1 transparent
9296
       * color.  We don't need to quantize to 2-3-2-1; we only need to
9297
       * eliminate one color, so we'll merge the two darkest red
9298
       * colors (0x49, 0, 0) -> (0x24, 0, 0).
9299
       */
9300
0
      if (logging != MagickFalse)
9301
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9302
0
            "    Merging two dark red background colors to 3-3-2-1");
9303
9304
0
      if (ScaleQuantumToChar((Quantum) image->background_color.red) == 0x49 &&
9305
0
          ScaleQuantumToChar((Quantum) image->background_color.green) == 0x00 &&
9306
0
          ScaleQuantumToChar((Quantum) image->background_color.blue) == 0x00)
9307
0
      {
9308
0
         image->background_color.red=ScaleCharToQuantum(0x24);
9309
0
      }
9310
9311
0
      if (logging != MagickFalse)
9312
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9313
0
            "    Merging two dark red pixel colors to 3-3-2-1");
9314
9315
0
      if (image->colormap == NULL)
9316
0
      {
9317
0
        for (y=0; y < (ssize_t) image->rows; y++)
9318
0
        {
9319
0
          q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9320
9321
0
          if (q == (Quantum *) NULL)
9322
0
            break;
9323
9324
0
          for (x=0; x < (ssize_t) image->columns; x++)
9325
0
          {
9326
0
            if (ScaleQuantumToChar(GetPixelRed(image,q)) == 0x49 &&
9327
0
                ScaleQuantumToChar(GetPixelGreen(image,q)) == 0x00 &&
9328
0
                ScaleQuantumToChar(GetPixelBlue(image,q)) == 0x00 &&
9329
0
                GetPixelAlpha(image,q) == OpaqueAlpha)
9330
0
              {
9331
0
                SetPixelRed(image,ScaleCharToQuantum(0x24),q);
9332
0
              }
9333
0
            q+=(ptrdiff_t) GetPixelChannels(image);
9334
0
          }
9335
9336
0
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
9337
0
             break;
9338
9339
0
        }
9340
0
      }
9341
9342
0
      else
9343
0
      {
9344
0
         for (i=0; i<image_colors; i++)
9345
0
         {
9346
0
            if (ScaleQuantumToChar((Quantum) image->colormap[i].red) == 0x49 &&
9347
0
                ScaleQuantumToChar((Quantum) image->colormap[i].green) == 0x00 &&
9348
0
                ScaleQuantumToChar((Quantum) image->colormap[i].blue) == 0x00)
9349
0
            {
9350
0
               image->colormap[i].red=ScaleCharToQuantum(0x24);
9351
0
            }
9352
0
         }
9353
0
      }
9354
0
    }
9355
0
  }
9356
1.72k
  }
9357
  /* END OF BUILD_PALETTE */
9358
9359
  /* If we are excluding the tRNS chunk and there is transparency,
9360
   * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
9361
   * PNG.
9362
   */
9363
2.27k
  if (mng_info->exclude_tRNS != MagickFalse &&
9364
311
     (number_transparent != 0 || number_semitransparent != 0))
9365
0
    {
9366
0
      volatile unsigned int colortype = mng_info->colortype;
9367
9368
0
      if (ping_have_color == MagickFalse)
9369
0
        mng_info->colortype=5;
9370
9371
0
      else
9372
0
        mng_info->colortype=7;
9373
9374
0
      if (colortype != 0 &&
9375
0
         mng_info->colortype != colortype)
9376
0
        ping_need_colortype_warning=MagickTrue;
9377
9378
0
    }
9379
9380
  /* See if cheap transparency is possible.  It is only possible
9381
   * when there is a single transparent color, no semitransparent
9382
   * color, and no opaque color that has the same RGB components
9383
   * as the transparent color.  We only need this information if
9384
   * we are writing a PNG with colortype 0 or 2, and we have not
9385
   * excluded the tRNS chunk.
9386
   */
9387
2.27k
  if (number_transparent == 1 &&
9388
149
      mng_info->colortype < 4)
9389
101
    {
9390
101
       ping_have_cheap_transparency = MagickTrue;
9391
9392
101
       if (number_semitransparent != 0)
9393
26
         ping_have_cheap_transparency = MagickFalse;
9394
9395
75
       else if (image_colors == 0 || image_colors > 256 ||
9396
61
           image->colormap == NULL)
9397
42
         {
9398
42
           const Quantum
9399
42
             *q;
9400
9401
1.58k
           for (y=0; y < (ssize_t) image->rows; y++)
9402
1.54k
           {
9403
1.54k
             q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9404
9405
1.54k
             if (q == (Quantum *) NULL)
9406
0
               break;
9407
9408
205k
             for (x=0; x < (ssize_t) image->columns; x++)
9409
204k
             {
9410
204k
                 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9411
164k
                     (unsigned short) GetPixelRed(image,q) ==
9412
164k
                                     ping_trans_color.red &&
9413
5.12k
                     (unsigned short) GetPixelGreen(image,q) ==
9414
5.12k
                                     ping_trans_color.green &&
9415
4.61k
                     (unsigned short) GetPixelBlue(image,q) ==
9416
4.61k
                                     ping_trans_color.blue)
9417
3
                   {
9418
3
                     ping_have_cheap_transparency = MagickFalse;
9419
3
                     break;
9420
3
                   }
9421
9422
204k
                 q+=(ptrdiff_t) GetPixelChannels(image);
9423
204k
             }
9424
9425
1.54k
             if (ping_have_cheap_transparency == MagickFalse)
9426
3
                break;
9427
1.54k
           }
9428
42
         }
9429
33
       else
9430
33
         {
9431
            /* Assuming that image->colormap[0] is the one transparent color
9432
             * and that all others are opaque.
9433
             */
9434
33
            if (image_colors > 1)
9435
844
              for (i=1; i<image_colors; i++)
9436
828
                if (image->colormap[i].red == image->colormap[0].red &&
9437
4
                    image->colormap[i].green == image->colormap[0].green &&
9438
3
                    image->colormap[i].blue == image->colormap[0].blue)
9439
1
                  {
9440
1
                     ping_have_cheap_transparency = MagickFalse;
9441
1
                     break;
9442
1
                  }
9443
33
         }
9444
9445
101
       if (logging != MagickFalse)
9446
0
         {
9447
0
           if (ping_have_cheap_transparency == MagickFalse)
9448
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9449
0
                 "   Cheap transparency is not possible.");
9450
9451
0
           else
9452
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9453
0
                 "   Cheap transparency is possible.");
9454
0
         }
9455
101
     }
9456
2.17k
  else
9457
2.17k
    ping_have_cheap_transparency = MagickFalse;
9458
9459
2.27k
  image_depth=image->depth;
9460
9461
2.27k
  quantum_info = (QuantumInfo *) NULL;
9462
2.27k
  number_colors=0;
9463
2.27k
  image_matte=image->alpha_trait !=
9464
2.27k
        UndefinedPixelTrait ? MagickTrue : MagickFalse;
9465
9466
2.27k
  if (mng_info->colortype < 5)
9467
1.71k
    mng_info->is_palette=(image->storage_class == PseudoClass) &&
9468
1.08k
      (image_colors <= 256) && (image->colormap != NULL) ? MagickTrue :
9469
1.71k
      MagickFalse;
9470
558
  else
9471
558
    mng_info->is_palette=MagickFalse;
9472
9473
2.27k
  if (((mng_info->colortype == 4) || (mng_info->write_png8 != MagickFalse)) &&
9474
379
     ((image_colors == 0) || (image->colormap == NULL)))
9475
0
    {
9476
0
      image_info=DestroyImageInfo(image_info);
9477
0
      image=DestroyImage(image);
9478
0
      (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9479
0
          "Cannot write PNG8 or color-type 3; colormap is NULL",
9480
0
          "`%s'",IMimage->filename);
9481
0
      return(MagickFalse);
9482
0
    }
9483
9484
  /*
9485
    Allocate the PNG structures
9486
  */
9487
2.27k
#ifdef PNG_USER_MEM_SUPPORTED
9488
2.27k
 error_info.image=image;
9489
2.27k
 error_info.exception=exception;
9490
2.27k
  ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9491
2.27k
    MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9492
2.27k
    (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9493
9494
#else
9495
  ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9496
    MagickPNGErrorHandler,MagickPNGWarningHandler);
9497
9498
#endif
9499
2.27k
  if (ping == (png_struct *) NULL)
9500
0
    {
9501
0
      image_info=DestroyImageInfo(image_info);
9502
0
      image=DestroyImage(image);
9503
0
      (void) ThrowMagickException(exception,GetMagickModule(),
9504
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",IMimage->filename);
9505
0
      return(MagickFalse);
9506
0
    }
9507
9508
2.27k
  ping_info=png_create_info_struct(ping);
9509
9510
2.27k
  if (ping_info == (png_info *) NULL)
9511
0
    {
9512
0
      image_info=DestroyImageInfo(image_info);
9513
0
      image=DestroyImage(image);
9514
0
      png_destroy_write_struct(&ping,(png_info **) NULL);
9515
0
      (void) ThrowMagickException(exception,GetMagickModule(),
9516
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",IMimage->filename);
9517
0
      return(MagickFalse);
9518
0
    }
9519
9520
2.27k
  png_set_write_fn(ping,image,png_put_data,png_flush_data);
9521
2.27k
  pixel_info=(MemoryInfo *) NULL;
9522
9523
2.27k
  if (setjmp(png_jmpbuf(ping)))
9524
0
    {
9525
      /*
9526
        PNG write failed.
9527
      */
9528
0
      png_destroy_write_struct(&ping,&ping_info);
9529
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
9530
      UnlockSemaphoreInfo(ping_semaphore);
9531
#endif
9532
9533
0
      if (pixel_info != (MemoryInfo *) NULL)
9534
0
        pixel_info=RelinquishVirtualMemory(pixel_info);
9535
9536
0
      if (quantum_info != (QuantumInfo *) NULL)
9537
0
        quantum_info=DestroyQuantumInfo(quantum_info);
9538
9539
0
      image_info=DestroyImageInfo(image_info);
9540
0
      (void) CloseBlob(image);
9541
0
      image=DestroyImage(image);
9542
9543
0
      if (ping_have_blob != MagickFalse)
9544
0
        (void) CloseBlob(IMimage);
9545
9546
0
      return(MagickFalse);
9547
0
    }
9548
9549
  /* {  For navigation to end of SETJMP-protected block.  Within this
9550
   *    block, use png_error() instead of Throwing an Exception, to ensure
9551
   *    that libpng is able to clean up, and that the semaphore is unlocked.
9552
   */
9553
9554
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
9555
  LockSemaphoreInfo(ping_semaphore);
9556
#endif
9557
9558
2.27k
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
9559
  /* Allow benign errors */
9560
2.27k
  png_set_benign_errors(ping, 1);
9561
2.27k
#endif
9562
9563
2.27k
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
9564
  /* Reject images with too many rows or columns */
9565
2.27k
  png_set_user_limits(ping,
9566
2.27k
    (png_uint_32) MagickMin(0x7fffffffL,
9567
2.27k
        GetMagickResourceLimit(WidthResource)),
9568
2.27k
    (png_uint_32) MagickMin(0x7fffffffL,
9569
2.27k
        GetMagickResourceLimit(HeightResource)));
9570
2.27k
#endif /* PNG_SET_USER_LIMITS_SUPPORTED */
9571
9572
  /*
9573
    Prepare PNG for writing.
9574
  */
9575
9576
2.27k
  if (mng_info->write_mng != MagickFalse)
9577
311
  {
9578
311
     (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9579
311
# ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9580
     /* Disable new libpng-1.5.10 feature when writing a MNG because
9581
      * zero-length PLTE is OK
9582
      */
9583
311
     png_set_check_for_invalid_index (ping, 0);
9584
311
# endif
9585
311
  }
9586
9587
2.27k
  x=0;
9588
9589
2.27k
  ping_width=(png_uint_32) image->columns;
9590
2.27k
  ping_height=(png_uint_32) image->rows;
9591
9592
2.27k
  if ((mng_info->write_png8 != MagickFalse) ||
9593
1.95k
      (mng_info->write_png24 != MagickFalse) ||
9594
1.69k
      (mng_info->write_png32 != MagickFalse))
9595
834
     image_depth=8;
9596
9597
2.27k
  if ((mng_info->write_png48 != MagickFalse) ||
9598
2.04k
      (mng_info->write_png64 != MagickFalse))
9599
482
     image_depth=16;
9600
9601
2.27k
  if (mng_info->depth != 0)
9602
1.63k
     image_depth=mng_info->depth;
9603
9604
  /* Adjust requested depth to next higher valid depth if necessary */
9605
2.27k
  if (image_depth > 8)
9606
741
     image_depth=16;
9607
9608
2.27k
  if ((image_depth > 4) && (image_depth < 8))
9609
0
     image_depth=8;
9610
9611
2.27k
  if (image_depth == 3)
9612
0
     image_depth=4;
9613
9614
2.27k
  if (logging != MagickFalse)
9615
0
    {
9616
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9617
0
        "    width=%.17g",(double) ping_width);
9618
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9619
0
        "    height=%.17g",(double) ping_height);
9620
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9621
0
        "    image_matte=%.17g",(double) image->alpha_trait);
9622
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9623
0
        "    image->depth=%.17g",(double) image->depth);
9624
0
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9625
0
        "    Tentative ping_bit_depth=%.17g",(double) image_depth);
9626
0
    }
9627
9628
2.27k
  save_image_depth=image_depth;
9629
2.27k
  ping_bit_depth=(png_byte) save_image_depth;
9630
9631
9632
2.27k
#if defined(PNG_pHYs_SUPPORTED)
9633
2.27k
  if (mng_info->exclude_pHYs == MagickFalse)
9634
1.96k
  {
9635
1.96k
  if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9636
79
      (mng_info->write_mng == MagickFalse || mng_info->equal_physs == MagickFalse))
9637
79
    {
9638
79
      if (logging != MagickFalse)
9639
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9640
0
            "    Setting up pHYs chunk");
9641
9642
79
      if (image->units == PixelsPerInchResolution)
9643
0
        {
9644
0
          ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9645
0
          ping_pHYs_x_resolution=(png_uint_32) CastDoubleToSizeT((100.0*
9646
0
            image->resolution.x)/2.54);
9647
0
          ping_pHYs_y_resolution=(png_uint_32) CastDoubleToSizeT((100.0*
9648
0
            image->resolution.y+0.5)/2.54);
9649
0
        }
9650
9651
79
      else if (image->units == PixelsPerCentimeterResolution)
9652
43
        {
9653
43
          ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9654
43
          ping_pHYs_x_resolution=(png_uint_32) CastDoubleToSizeT(100.0*
9655
43
            image->resolution.x);
9656
43
          ping_pHYs_y_resolution=(png_uint_32) CastDoubleToSizeT(100.0*
9657
43
            image->resolution.y);
9658
43
        }
9659
9660
36
      else
9661
36
        {
9662
36
          ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9663
36
          ping_pHYs_x_resolution=(png_uint_32) CastDoubleToSizeT(
9664
36
            image->resolution.x);
9665
36
          ping_pHYs_y_resolution=(png_uint_32) CastDoubleToSizeT(
9666
36
            image->resolution.y);
9667
36
        }
9668
9669
79
      if (logging != MagickFalse)
9670
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9671
0
          "    Set up PNG pHYs chunk: xres: %.17g, yres: %.17g, units: %d.",
9672
0
          (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9673
0
          (int) ping_pHYs_unit_type);
9674
79
       ping_have_pHYs = MagickTrue;
9675
79
    }
9676
1.96k
  }
9677
2.27k
#endif
9678
9679
2.27k
  if (mng_info->exclude_bKGD == MagickFalse)
9680
1.96k
  {
9681
1.96k
  if ((mng_info->adjoin == MagickFalse || mng_info->equal_backgrounds == MagickFalse))
9682
1.96k
    {
9683
1.96k
       unsigned int
9684
1.96k
         mask;
9685
9686
1.96k
       mask=0xffff;
9687
1.96k
       if (ping_bit_depth == 8)
9688
1.19k
          mask=0x00ff;
9689
9690
1.96k
       if (ping_bit_depth == 4)
9691
24
          mask=0x000f;
9692
9693
1.96k
       if (ping_bit_depth == 2)
9694
24
          mask=0x0003;
9695
9696
1.96k
       if (ping_bit_depth == 1)
9697
103
          mask=0x0001;
9698
9699
1.96k
       ping_background.red=(png_uint_16)
9700
1.96k
         (ScaleQuantumToShort((Quantum) image->background_color.red) & mask);
9701
9702
1.96k
       ping_background.green=(png_uint_16)
9703
1.96k
         (ScaleQuantumToShort((Quantum) image->background_color.green) & mask);
9704
9705
1.96k
       ping_background.blue=(png_uint_16)
9706
1.96k
         (ScaleQuantumToShort((Quantum) image->background_color.blue) & mask);
9707
9708
1.96k
       ping_background.gray=(png_uint_16) ping_background.green;
9709
1.96k
    }
9710
9711
1.96k
  if (logging != MagickFalse)
9712
0
    {
9713
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9714
0
          "    Setting up bKGD chunk (1)");
9715
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9716
0
          "      background_color index is %d",
9717
0
          (int) ping_background.index);
9718
9719
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9720
0
          "    ping_bit_depth=%d",ping_bit_depth);
9721
0
    }
9722
9723
1.96k
  ping_have_bKGD = MagickTrue;
9724
1.96k
  }
9725
9726
  /*
9727
    Select the color type.
9728
  */
9729
2.27k
  matte=image_matte;
9730
2.27k
  old_bit_depth=0;
9731
9732
2.27k
  if ((mng_info->is_palette != MagickFalse) &&
9733
1.08k
      (mng_info->write_png8 != MagickFalse))
9734
321
    {
9735
      /* To do: make this a function cause it's used twice, except
9736
         for reducing the sample depth from 8. */
9737
9738
321
      number_colors=image_colors;
9739
9740
321
      ping_have_tRNS=MagickFalse;
9741
9742
      /*
9743
        Set image palette.
9744
      */
9745
321
      ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9746
9747
321
      if (logging != MagickFalse)
9748
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9749
0
            "  Setting up PLTE chunk with %d colors (%d)",
9750
0
            number_colors, image_colors);
9751
9752
22.9k
      for (i=0; i < (ssize_t) number_colors; i++)
9753
22.6k
      {
9754
22.6k
        palette[i].red=ScaleQuantumToChar((Quantum) image->colormap[i].red);
9755
22.6k
        palette[i].green=ScaleQuantumToChar((Quantum) image->colormap[i].green);
9756
22.6k
        palette[i].blue=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
9757
22.6k
        if (logging != MagickFalse)
9758
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9759
#if MAGICKCORE_QUANTUM_DEPTH == 8
9760
            "    %3ld (%3d,%3d,%3d)",
9761
#else
9762
0
            "    %5ld (%5d,%5d,%5d)",
9763
0
#endif
9764
0
            (long) i,palette[i].red,palette[i].green,palette[i].blue);
9765
9766
22.6k
      }
9767
9768
321
      ping_have_PLTE=MagickTrue;
9769
321
      image_depth=(size_t) ping_bit_depth;
9770
321
      ping_num_trans=0;
9771
9772
321
      if (matte != MagickFalse)
9773
56
      {
9774
          /*
9775
            Identify which colormap entry is transparent.
9776
          */
9777
56
          assert(number_colors <= 256);
9778
56
          assert(image->colormap != NULL);
9779
9780
98
          for (i=0; i < (ssize_t) number_transparent; i++)
9781
42
             ping_trans_alpha[i]=0;
9782
9783
9784
56
          ping_num_trans=(unsigned short) (number_transparent +
9785
56
             number_semitransparent);
9786
9787
56
          if (ping_num_trans == 0)
9788
14
             ping_have_tRNS=MagickFalse;
9789
9790
42
          else
9791
42
             ping_have_tRNS=MagickTrue;
9792
56
      }
9793
9794
321
      if (mng_info->exclude_bKGD == MagickFalse)
9795
321
      {
9796
       /*
9797
        * Identify which colormap entry is the background color.
9798
        */
9799
9800
22.7k
        for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9801
22.4k
          if (IsPNGColorEqual(ping_background,image->colormap[i]))
9802
1
            break;
9803
9804
321
        ping_background.index=(png_byte) i;
9805
9806
321
        if (logging != MagickFalse)
9807
0
          {
9808
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9809
0
                 "      background_color index is %d",
9810
0
                 (int) ping_background.index);
9811
0
          }
9812
321
      }
9813
321
    } /* end of write_png8 */
9814
9815
1.95k
  else if (mng_info->colortype == 1)
9816
133
    {
9817
133
      image_matte=MagickFalse;
9818
133
      ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9819
133
    }
9820
9821
1.82k
  else if ((mng_info->write_png24 != MagickFalse) ||
9822
1.56k
           (mng_info->write_png48 != MagickFalse) ||
9823
1.33k
           (mng_info->colortype == 3))
9824
566
    {
9825
566
      image_matte=MagickFalse;
9826
566
      ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9827
566
    }
9828
9829
1.25k
  else if ((mng_info->write_png32 != MagickFalse) ||
9830
997
           (mng_info->write_png64 != MagickFalse) ||
9831
743
           (mng_info->colortype == 7))
9832
551
    {
9833
551
      image_matte=MagickTrue;
9834
551
      ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9835
551
    }
9836
9837
704
  else /* mng_info->write_pngNN not specified */
9838
704
    {
9839
704
      image_depth=(size_t) ping_bit_depth;
9840
9841
704
      if (mng_info->colortype != 0)
9842
65
        {
9843
65
          ping_color_type=(png_byte) mng_info->colortype-1;
9844
9845
65
          if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9846
58
              ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9847
7
            image_matte=MagickTrue;
9848
9849
58
          else
9850
58
            image_matte=MagickFalse;
9851
9852
65
          if (logging != MagickFalse)
9853
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9854
0
             "   PNG colortype %d was specified:",(int) ping_color_type);
9855
65
        }
9856
9857
639
      else /* write_png_colortype not specified */
9858
639
        {
9859
639
          if (logging != MagickFalse)
9860
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9861
0
             "  Selecting PNG colortype:");
9862
9863
639
          if (image_info->type == TrueColorType)
9864
0
            {
9865
0
              ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9866
0
              image_matte=MagickFalse;
9867
0
            }
9868
639
          else if (image_info->type == TrueColorAlphaType)
9869
0
            {
9870
0
              ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9871
0
              image_matte=MagickTrue;
9872
0
            }
9873
639
          else if (image_info->type == PaletteType ||
9874
639
                   image_info->type == PaletteAlphaType)
9875
0
            ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9876
639
          else
9877
639
            {
9878
639
              if (ping_have_color == MagickFalse)
9879
351
                {
9880
351
                  if (image_matte == MagickFalse)
9881
310
                    {
9882
310
                      ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9883
310
                      image_matte=MagickFalse;
9884
310
                    }
9885
9886
41
                  else
9887
41
                    {
9888
41
                      ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9889
41
                      image_matte=MagickTrue;
9890
41
                    }
9891
351
                }
9892
288
              else
9893
288
                {
9894
288
                  if (image_matte == MagickFalse)
9895
255
                    {
9896
255
                      ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9897
255
                      image_matte=MagickFalse;
9898
255
                    }
9899
9900
33
                  else
9901
33
                    {
9902
33
                      ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9903
33
                      image_matte=MagickTrue;
9904
33
                    }
9905
288
                 }
9906
639
            }
9907
9908
639
        }
9909
9910
704
      if (logging != MagickFalse)
9911
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9912
0
         "    Selected PNG colortype=%d",ping_color_type);
9913
9914
704
      if (ping_bit_depth < 8)
9915
48
        {
9916
48
          if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9917
48
              ping_color_type == PNG_COLOR_TYPE_RGB ||
9918
48
              ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9919
0
            ping_bit_depth=8;
9920
48
        }
9921
9922
704
      old_bit_depth=(size_t) ping_bit_depth;
9923
9924
704
      if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9925
310
        {
9926
310
          if (((image->alpha_trait & BlendPixelTrait) == 0) &&
9927
310
              ((image->alpha_trait & UpdatePixelTrait) == 0) &&
9928
310
               (ping_have_non_bw == MagickFalse))
9929
227
             ping_bit_depth=1;
9930
310
        }
9931
9932
704
      if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9933
58
        {
9934
58
           size_t one = 1;
9935
58
           ping_bit_depth=1;
9936
9937
58
           if (image_colors == 0)
9938
0
           {
9939
              /* DO SOMETHING */
9940
0
                png_error(ping,"image has 0 colors");
9941
0
           }
9942
9943
113
           while ((ping_bit_depth < 64) && (int) (one << ping_bit_depth) < (ssize_t) image_colors)
9944
55
             ping_bit_depth <<= 1;
9945
58
        }
9946
9947
704
      if (logging != MagickFalse)
9948
0
         {
9949
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9950
0
            "    Number of colors: %.17g",(double) image_colors);
9951
9952
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9953
0
            "    Tentative PNG bit depth: %d",ping_bit_depth);
9954
0
         }
9955
9956
704
      if (ping_bit_depth < (int) mng_info->depth)
9957
10
         ping_bit_depth = (int) mng_info->depth;
9958
704
    }
9959
2.27k
  (void) old_bit_depth;
9960
2.27k
  image_depth=(size_t) ping_bit_depth;
9961
9962
2.27k
  if (logging != MagickFalse)
9963
0
    {
9964
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9965
0
        "    Tentative PNG color type: %s (%.17g)",
9966
0
        PngColorTypeToString((unsigned int) ping_color_type),
9967
0
        (double) ping_color_type);
9968
9969
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9970
0
        "    image_info->type: %.17g",(double) image_info->type);
9971
9972
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9973
0
        "    image_depth: %.17g",(double) image_depth);
9974
9975
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9976
9977
0
        "    image->depth: %.17g",(double) image->depth);
9978
9979
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9980
0
        "    ping_bit_depth: %.17g",(double) ping_bit_depth);
9981
0
    }
9982
9983
2.27k
  if (matte != MagickFalse)
9984
404
    {
9985
404
      if (mng_info->is_palette != MagickFalse)
9986
136
        {
9987
136
          if (mng_info->colortype == 0)
9988
60
            {
9989
60
              ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9990
9991
60
              if (ping_have_color != MagickFalse)
9992
28
                 ping_color_type=PNG_COLOR_TYPE_RGBA;
9993
60
            }
9994
9995
          /*
9996
           * Determine if there is any transparent color.
9997
          */
9998
136
          if (number_transparent + number_semitransparent == 0)
9999
31
            {
10000
              /*
10001
                No transparent pixels are present.  Change 4 or 6 to 0 or 2.
10002
              */
10003
10004
31
              image_matte=MagickFalse;
10005
10006
31
              if (mng_info->colortype == 0)
10007
13
                ping_color_type&=0x03;
10008
31
            }
10009
10010
105
          else
10011
105
            {
10012
105
              unsigned int
10013
105
                mask;
10014
10015
105
              mask=0xffff;
10016
10017
105
              if (ping_bit_depth == 8)
10018
86
                 mask=0x00ff;
10019
10020
105
              if (ping_bit_depth == 4)
10021
5
                 mask=0x000f;
10022
10023
105
              if (ping_bit_depth == 2)
10024
3
                 mask=0x0003;
10025
10026
105
              if (ping_bit_depth == 1)
10027
6
                 mask=0x0001;
10028
10029
105
              ping_trans_color.red=(png_uint_16)
10030
105
                (ScaleQuantumToShort((Quantum) image->colormap[0].red) & mask);
10031
10032
105
              ping_trans_color.green=(png_uint_16)
10033
105
                (ScaleQuantumToShort((Quantum) image->colormap[0].green) & mask);
10034
10035
105
              ping_trans_color.blue=(png_uint_16)
10036
105
                (ScaleQuantumToShort((Quantum) image->colormap[0].blue) & mask);
10037
10038
105
              ping_trans_color.gray=(png_uint_16)
10039
105
                (ScaleQuantumToShort((Quantum) GetPixelInfoIntensity(image,
10040
105
                   image->colormap)) & mask);
10041
10042
105
              ping_trans_color.index=(png_byte) 0;
10043
10044
105
              ping_have_tRNS=MagickTrue;
10045
105
            }
10046
10047
136
          if (ping_have_tRNS != MagickFalse)
10048
105
            {
10049
              /*
10050
               * Determine if there is one and only one transparent color
10051
               * and if so if it is fully transparent.
10052
               */
10053
105
              if (ping_have_cheap_transparency == MagickFalse)
10054
73
                ping_have_tRNS=MagickFalse;
10055
105
            }
10056
10057
136
          if (ping_have_tRNS != MagickFalse)
10058
32
            {
10059
32
              if (mng_info->colortype == 0)
10060
26
                ping_color_type &= 0x03;  /* changes 4 or 6 to 0 or 2 */
10061
10062
32
              if (image_depth == 8)
10063
26
                {
10064
26
                  ping_trans_color.red&=0xff;
10065
26
                  ping_trans_color.green&=0xff;
10066
26
                  ping_trans_color.blue&=0xff;
10067
26
                  ping_trans_color.gray&=0xff;
10068
26
                }
10069
32
            }
10070
136
        }
10071
268
      else
10072
268
        {
10073
268
          if (image_depth == 8)
10074
160
            {
10075
160
              ping_trans_color.red&=0xff;
10076
160
              ping_trans_color.green&=0xff;
10077
160
              ping_trans_color.blue&=0xff;
10078
160
              ping_trans_color.gray&=0xff;
10079
160
            }
10080
268
        }
10081
404
    }
10082
10083
2.27k
    matte=image_matte;
10084
10085
2.27k
    if (ping_have_tRNS != MagickFalse)
10086
32
      image_matte=MagickFalse;
10087
10088
2.27k
    if ((mng_info->is_palette != MagickFalse) &&
10089
1.08k
        mng_info->colortype-1 != PNG_COLOR_TYPE_PALETTE &&
10090
710
        ping_have_color == MagickFalse &&
10091
460
        (image_matte == MagickFalse || image_depth >= 8))
10092
460
      {
10093
460
        size_t one=1;
10094
10095
460
        if (image_matte != MagickFalse)
10096
5
          ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
10097
10098
455
        else if (mng_info->colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
10099
455
          {
10100
455
            ping_color_type=PNG_COLOR_TYPE_GRAY;
10101
10102
455
            if (save_image_depth == 16 && image_depth == 8)
10103
0
              {
10104
0
                if (logging != MagickFalse)
10105
0
                  {
10106
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10107
0
                        "  Scaling ping_trans_color (0)");
10108
0
                  }
10109
0
                    ping_trans_color.gray*=0x0101;
10110
0
              }
10111
455
          }
10112
10113
460
        if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
10114
0
          image_depth=MAGICKCORE_QUANTUM_DEPTH;
10115
10116
460
        if ((image_colors == 0) ||
10117
460
             ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
10118
0
          image_colors=(int) (one << image_depth);
10119
10120
460
        if (image_depth > 8)
10121
16
          ping_bit_depth=16;
10122
10123
444
        else
10124
444
          {
10125
444
            ping_bit_depth=8;
10126
444
            if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
10127
0
              {
10128
0
                if(!mng_info->depth)
10129
0
                  {
10130
0
                    ping_bit_depth=1;
10131
10132
0
                    while ((int) (one << ping_bit_depth)
10133
0
                        < (ssize_t) image_colors)
10134
0
                      ping_bit_depth <<= 1;
10135
0
                  }
10136
0
              }
10137
10138
444
            else if (ping_color_type ==
10139
444
                PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
10140
426
                mng_info->is_palette != MagickFalse)
10141
426
              {
10142
              /* Check if grayscale is reducible */
10143
10144
426
                int
10145
426
                  depth_4_ok=MagickTrue,
10146
426
                  depth_2_ok=MagickTrue,
10147
426
                  depth_1_ok=MagickTrue;
10148
10149
1.25k
                for (i=0; i < (ssize_t) image_colors; i++)
10150
824
                {
10151
824
                   unsigned char
10152
824
                     intensity;
10153
10154
824
                   intensity=ScaleQuantumToChar((Quantum) image->colormap[i].red);
10155
10156
824
                   if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
10157
47
                     depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
10158
777
                   else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
10159
231
                     depth_2_ok=depth_1_ok=MagickFalse;
10160
546
                   else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
10161
68
                     depth_1_ok=MagickFalse;
10162
824
                }
10163
10164
426
                if (depth_1_ok && mng_info->depth <= 1)
10165
326
                  ping_bit_depth=1;
10166
10167
100
                else if (depth_2_ok && mng_info->depth <= 2)
10168
29
                  ping_bit_depth=2;
10169
10170
71
                else if (depth_4_ok && mng_info->depth <= 4)
10171
40
                  ping_bit_depth=4;
10172
426
              }
10173
444
          }
10174
10175
460
          image_depth=(size_t) ping_bit_depth;
10176
460
      }
10177
10178
1.81k
    else
10179
10180
1.81k
      if (mng_info->is_palette != MagickFalse)
10181
629
      {
10182
629
        number_colors=image_colors;
10183
10184
629
        if (image_depth <= 8)
10185
478
          {
10186
            /*
10187
              Set image palette.
10188
            */
10189
478
            ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
10190
10191
478
            if (!(mng_info->have_global_plte != MagickFalse && matte == MagickFalse))
10192
478
              {
10193
28.5k
                for (i=0; i < (ssize_t) number_colors; i++)
10194
28.1k
                {
10195
28.1k
                  palette[i].red=ScaleQuantumToChar((Quantum) image->colormap[i].red);
10196
28.1k
                  palette[i].green=ScaleQuantumToChar((Quantum) image->colormap[i].green);
10197
28.1k
                  palette[i].blue=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
10198
28.1k
                }
10199
10200
478
                if (logging != MagickFalse)
10201
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10202
0
                    "  Setting up PLTE chunk with %d colors",
10203
0
                    number_colors);
10204
10205
478
                ping_have_PLTE=MagickTrue;
10206
478
              }
10207
10208
            /* color_type is PNG_COLOR_TYPE_PALETTE */
10209
478
            if (mng_info->depth == 0)
10210
99
              {
10211
99
                size_t
10212
99
                  one;
10213
10214
99
                ping_bit_depth=1;
10215
99
                one=1;
10216
10217
234
                while ((one << ping_bit_depth) < (size_t) number_colors)
10218
135
                  ping_bit_depth <<= 1;
10219
99
              }
10220
10221
478
            ping_num_trans=0;
10222
10223
478
            if (matte != MagickFalse)
10224
62
              {
10225
                /*
10226
                 * Set up trans_colors array.
10227
                 */
10228
62
                assert(number_colors <= 256);
10229
10230
62
                ping_num_trans=(unsigned short) (number_transparent +
10231
62
                  number_semitransparent);
10232
10233
62
                if (ping_num_trans == 0)
10234
0
                  ping_have_tRNS=MagickFalse;
10235
10236
62
                else
10237
62
                  {
10238
62
                    if (logging != MagickFalse)
10239
0
                      {
10240
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10241
0
                          "  Scaling ping_trans_color (1)");
10242
0
                      }
10243
62
                    ping_have_tRNS=MagickTrue;
10244
10245
644
                    for (i=0; i < ping_num_trans; i++)
10246
582
                    {
10247
582
                       ping_trans_alpha[i]= (png_byte)
10248
582
                         ScaleQuantumToChar((Quantum) image->colormap[i].alpha);
10249
582
                    }
10250
62
                  }
10251
62
              }
10252
478
          }
10253
629
      }
10254
10255
1.18k
    else
10256
1.18k
      {
10257
10258
1.18k
        if (image_depth < 8)
10259
0
          image_depth=8;
10260
10261
1.18k
        if ((save_image_depth == 16) && (image_depth == 8))
10262
0
          {
10263
0
            if (logging != MagickFalse)
10264
0
              {
10265
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10266
0
                  "    Scaling ping_trans_color from (%d,%d,%d)",
10267
0
                  (int) ping_trans_color.red,
10268
0
                  (int) ping_trans_color.green,
10269
0
                  (int) ping_trans_color.blue);
10270
0
              }
10271
10272
0
            ping_trans_color.red*=0x0101;
10273
0
            ping_trans_color.green*=0x0101;
10274
0
            ping_trans_color.blue*=0x0101;
10275
0
            ping_trans_color.gray*=0x0101;
10276
10277
0
            if (logging != MagickFalse)
10278
0
              {
10279
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10280
0
                  "    to (%d,%d,%d)",
10281
0
                  (int) ping_trans_color.red,
10282
0
                  (int) ping_trans_color.green,
10283
0
                  (int) ping_trans_color.blue);
10284
0
              }
10285
0
          }
10286
1.18k
      }
10287
10288
2.27k
    if (ping_bit_depth <  (int) mng_info->depth)
10289
0
         ping_bit_depth =  (int) mng_info->depth;
10290
10291
    /*
10292
      Adjust background and transparency samples in sub-8-bit grayscale files.
10293
    */
10294
2.27k
    if (ping_bit_depth < 8 && ping_color_type ==
10295
515
        PNG_COLOR_TYPE_GRAY)
10296
395
      {
10297
395
         png_uint_16
10298
395
           maxval;
10299
10300
395
         size_t
10301
395
           one=1;
10302
10303
395
         maxval=(png_uint_16) ((one << ping_bit_depth)-1);
10304
10305
395
         if (mng_info->exclude_bKGD == MagickFalse)
10306
222
         {
10307
10308
222
         ping_background.gray=(png_uint_16) ((maxval/65535.)*
10309
222
           (ScaleQuantumToShort((Quantum) (((GetPixelInfoIntensity(image,
10310
222
           &image->background_color))) +.5))));
10311
10312
222
         if (logging != MagickFalse)
10313
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10314
0
             "  Setting up bKGD chunk (2)");
10315
222
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10316
222
             "      background_color index is %d",
10317
222
             (int) ping_background.index);
10318
10319
222
         ping_have_bKGD = MagickTrue;
10320
222
         }
10321
10322
395
         if (logging != MagickFalse)
10323
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10324
0
             "  Scaling ping_trans_color.gray from %d",
10325
0
             (int)ping_trans_color.gray);
10326
10327
395
         ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
10328
395
           ping_trans_color.gray)+.5);
10329
10330
395
         if (logging != MagickFalse)
10331
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10332
0
             "      to %d", (int)ping_trans_color.gray);
10333
395
      }
10334
10335
2.27k
  if (mng_info->exclude_bKGD == MagickFalse)
10336
1.96k
  {
10337
1.96k
    if (mng_info->is_palette != MagickFalse &&
10338
778
        (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
10339
467
      {
10340
        /*
10341
           Identify which colormap entry is the background color.
10342
        */
10343
10344
467
        number_colors=image_colors;
10345
10346
24.8k
        for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
10347
24.5k
          if (IsPNGColorEqual(image->background_color,image->colormap[i]))
10348
159
            break;
10349
10350
467
        ping_background.index=(png_byte) i;
10351
10352
467
        if (logging != MagickFalse)
10353
0
          {
10354
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10355
0
              "  Setting up bKGD chunk with index=%d",(int) i);
10356
0
          }
10357
10358
467
        if (i < (ssize_t) number_colors)
10359
159
          {
10360
159
            ping_have_bKGD = MagickTrue;
10361
10362
159
            if (logging != MagickFalse)
10363
0
              {
10364
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10365
0
                  "     background   =(%d,%d,%d)",
10366
0
                        (int) ping_background.red,
10367
0
                        (int) ping_background.green,
10368
0
                        (int) ping_background.blue);
10369
0
              }
10370
159
          }
10371
10372
308
        else  /* Can't happen */
10373
308
          {
10374
308
            if (logging != MagickFalse)
10375
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10376
0
                  "      No room in PLTE to add bKGD color");
10377
308
            ping_have_bKGD = MagickFalse;
10378
308
          }
10379
467
      }
10380
1.96k
  }
10381
10382
2.27k
  if (logging != MagickFalse)
10383
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10384
0
      "    PNG color type: %s (%.17g)", PngColorTypeToString((unsigned int)
10385
0
      ping_color_type), (double) ping_color_type);
10386
  /*
10387
    Initialize compression level and filtering.
10388
  */
10389
2.27k
  if (logging != MagickFalse)
10390
0
    {
10391
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10392
0
        "  Setting up deflate compression");
10393
10394
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10395
0
        "    Compression buffer size: 32768");
10396
0
    }
10397
10398
2.27k
  png_set_compression_buffer_size(ping,32768L);
10399
10400
2.27k
  if (logging != MagickFalse)
10401
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10402
0
      "    Compression mem level: 9");
10403
10404
2.27k
  png_set_compression_mem_level(ping, 9);
10405
10406
  /* Untangle the "-quality" setting:
10407
10408
     Undefined is 0; the default is used.
10409
     Default is 75
10410
10411
     10's digit:
10412
10413
        0 or omitted: Use Z_HUFFMAN_ONLY strategy with the
10414
           zlib default compression level
10415
10416
        1-9: the zlib compression level
10417
10418
     1's digit:
10419
10420
        0-4: the PNG filter method
10421
10422
        5:   libpng adaptive filtering if compression level > 5
10423
             libpng filter type "none" if compression level <= 5
10424
                or if image is grayscale or palette
10425
10426
        6:   libpng adaptive filtering
10427
10428
        7:   "LOCO" filtering (intrapixel differing) if writing
10429
             a MNG, otherwise "none".  Did not work in IM-6.7.0-9
10430
             and earlier because of a missing "else".
10431
10432
        8:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive
10433
             filtering. Unused prior to IM-6.7.0-10, was same as 6
10434
10435
        9:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters
10436
             Unused prior to IM-6.7.0-10, was same as 6
10437
10438
    Note that using the -quality option, not all combinations of
10439
    PNG filter type, zlib compression level, and zlib compression
10440
    strategy are possible.  This will be addressed soon in a
10441
    release that accommodates "-define png:compression-strategy", etc.
10442
10443
   */
10444
10445
2.27k
  quality=image_info->quality == UndefinedCompressionQuality ? 75UL :
10446
2.27k
     image_info->quality;
10447
10448
2.27k
  if (quality <= 9)
10449
0
    {
10450
0
      if (mng_info->compression_strategy == 0)
10451
0
        mng_info->compression_strategy = Z_HUFFMAN_ONLY+1;
10452
0
    }
10453
10454
2.27k
  else if (mng_info->compression_level == 0)
10455
2.27k
    {
10456
2.27k
      int
10457
2.27k
        level;
10458
10459
2.27k
      level=(int) MagickMin((ssize_t) quality/10,9);
10460
10461
2.27k
      mng_info->compression_level = (size_t) level+1;
10462
2.27k
    }
10463
10464
2.27k
  if (mng_info->compression_strategy == 0)
10465
2.27k
    {
10466
2.27k
        if ((quality %10) == 8 || (quality %10) == 9)
10467
0
#ifdef Z_RLE  /* Z_RLE was added to zlib-1.2.0 */
10468
0
          mng_info->compression_strategy=Z_RLE+1;
10469
#else
10470
          mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10471
#endif
10472
2.27k
    }
10473
10474
2.27k
  if (mng_info->compression_filter == 0)
10475
2.27k
        mng_info->compression_filter=((size_t) quality % 10) + 1;
10476
10477
2.27k
  if (logging != MagickFalse)
10478
0
    {
10479
0
        if (mng_info->compression_level)
10480
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10481
0
            "    Compression level:    %d",
10482
0
            (int) mng_info->compression_level-1);
10483
10484
0
        if (mng_info->compression_strategy)
10485
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10486
0
            "    Compression strategy: %d",
10487
0
            (int) mng_info->compression_strategy-1);
10488
10489
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10490
0
          "  Setting up filtering");
10491
10492
0
        if (mng_info->compression_filter == 6)
10493
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10494
0
            "    Base filter method: ADAPTIVE");
10495
0
        else if (mng_info->compression_filter == 0 ||
10496
0
                 mng_info->compression_filter == 1)
10497
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10498
0
            "    Base filter method: NONE");
10499
0
        else
10500
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10501
0
            "    Base filter method: %d",
10502
0
            (int) mng_info->compression_filter-1);
10503
0
    }
10504
10505
2.27k
  if (mng_info->compression_level != 0)
10506
2.27k
    png_set_compression_level(ping,(int) mng_info->compression_level-1);
10507
10508
2.27k
  if (mng_info->compression_filter == 6)
10509
2.27k
    {
10510
2.27k
      if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10511
1.80k
         ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10512
1.32k
         (quality < 50))
10513
948
        png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10514
1.32k
      else
10515
1.32k
        png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10516
2.27k
     }
10517
0
  else if (mng_info->compression_filter == 7 ||
10518
0
      mng_info->compression_filter == 10)
10519
0
    png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10520
10521
0
  else if (mng_info->compression_filter == 8)
10522
0
    {
10523
0
#if defined(PNG_INTRAPIXEL_DIFFERENCING)
10524
0
      if (mng_info->write_mng != MagickFalse)
10525
0
      {
10526
0
         if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10527
0
             ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10528
0
        ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10529
0
      }
10530
0
#endif
10531
0
      png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10532
0
    }
10533
10534
0
  else if (mng_info->compression_filter == 9)
10535
0
    png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10536
10537
0
  else if (mng_info->compression_filter != 0)
10538
0
    png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10539
0
       (int) mng_info->compression_filter-1);
10540
10541
2.27k
  if (mng_info->compression_strategy != 0)
10542
0
    png_set_compression_strategy(ping,
10543
0
       (int) mng_info->compression_strategy-1);
10544
10545
2.27k
  ping_interlace_method=image_info->interlace != NoInterlace;
10546
10547
2.27k
  if (mng_info->write_mng != MagickFalse)
10548
311
    png_set_sig_bytes(ping,8);
10549
10550
  /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10551
10552
2.27k
  if (mng_info->colortype != 0)
10553
1.63k
    {
10554
1.63k
     if (mng_info->colortype-1 == PNG_COLOR_TYPE_GRAY)
10555
133
       if (ping_have_color != MagickFalse)
10556
0
         {
10557
0
           ping_color_type = PNG_COLOR_TYPE_RGB;
10558
10559
0
           if (ping_bit_depth < 8)
10560
0
             ping_bit_depth=8;
10561
0
         }
10562
10563
1.63k
     if (mng_info->colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10564
7
       if (ping_have_color != MagickFalse)
10565
0
         ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10566
1.63k
    }
10567
10568
2.27k
  if (ping_need_colortype_warning != MagickFalse ||
10569
2.27k
     ((mng_info->depth &&
10570
1.63k
     (int) mng_info->depth != ping_bit_depth) ||
10571
2.27k
     (mng_info->colortype &&
10572
1.63k
     ((int) mng_info->colortype-1 != ping_color_type &&
10573
0
      mng_info->colortype != 7 &&
10574
0
      !(mng_info->colortype == 5 && ping_color_type == 0)))))
10575
0
    {
10576
0
      if (logging != MagickFalse)
10577
0
        {
10578
0
          if (ping_need_colortype_warning != MagickFalse)
10579
0
            {
10580
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10581
0
                 "  Image has transparency but tRNS chunk was excluded");
10582
0
            }
10583
10584
0
          if (mng_info->depth)
10585
0
            {
10586
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10587
0
                  "  Defined png:bit-depth=%u, Computed depth=%u",
10588
0
                  mng_info->depth,
10589
0
                  ping_bit_depth);
10590
0
            }
10591
10592
0
          if (mng_info->colortype)
10593
0
            {
10594
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10595
0
                  "  Defined png:color-type=%u, Computed color type=%u",
10596
0
                  mng_info->colortype-1,
10597
0
                  ping_color_type);
10598
0
            }
10599
0
        }
10600
10601
0
      png_warning(ping,
10602
0
        "Cannot write image with defined png:bit-depth or png:color-type.");
10603
0
    }
10604
10605
2.27k
  if ((image_matte != MagickFalse) &&
10606
635
      ((image->alpha_trait & BlendPixelTrait) == 0) &&
10607
404
      ((image->alpha_trait & UpdatePixelTrait) == 0))
10608
404
    {
10609
      /* Add an opaque matte channel */
10610
404
      image->alpha_trait = BlendPixelTrait;
10611
404
      (void) SetImageAlpha(image,OpaqueAlpha,exception);
10612
10613
404
      if (logging != MagickFalse)
10614
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10615
0
          "  Added an opaque matte channel");
10616
404
    }
10617
10618
2.27k
  if (number_transparent != 0 || number_semitransparent != 0)
10619
349
    {
10620
349
      if (ping_color_type < 4)
10621
175
        {
10622
175
           ping_have_tRNS=MagickTrue;
10623
175
           if (logging != MagickFalse)
10624
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10625
0
               "  Setting ping_have_tRNS=MagickTrue.");
10626
175
        }
10627
349
    }
10628
10629
2.27k
  if (logging != MagickFalse)
10630
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10631
0
      "  Writing PNG header chunks");
10632
10633
2.27k
  png_set_IHDR(ping,ping_info,ping_width,ping_height,
10634
2.27k
               ping_bit_depth,ping_color_type,
10635
2.27k
               ping_interlace_method,ping_compression_method,
10636
2.27k
               ping_filter_method);
10637
10638
2.27k
  if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10639
478
    {
10640
478
      png_set_PLTE(ping,ping_info,palette,number_colors);
10641
10642
478
      if (logging != MagickFalse)
10643
0
        {
10644
0
          for (i=0; i< (ssize_t) number_colors; i++)
10645
0
          {
10646
0
            if (i < ping_num_trans)
10647
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10648
0
                "     PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10649
0
                      (int) i,
10650
0
                      (int) palette[i].red,
10651
0
                      (int) palette[i].green,
10652
0
                      (int) palette[i].blue,
10653
0
                      (int) i,
10654
0
                      (int) ping_trans_alpha[i]);
10655
0
             else
10656
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10657
0
                "     PLTE[%d] = (%d,%d,%d)",
10658
0
                      (int) i,
10659
0
                      (int) palette[i].red,
10660
0
                      (int) palette[i].green,
10661
0
                      (int) palette[i].blue);
10662
0
           }
10663
0
         }
10664
478
    }
10665
10666
  /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10667
2.27k
  if (mng_info->exclude_sRGB != MagickFalse ||
10668
1.96k
     (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10669
2.27k
  {
10670
2.27k
    if ((mng_info->exclude_tEXt == MagickFalse ||
10671
311
         mng_info->exclude_zTXt == MagickFalse) &&
10672
1.96k
       (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10673
1.96k
    {
10674
1.96k
      ResetImageProfileIterator(image);
10675
2.08k
      for (name=GetNextImageProfile(image); name != (char *) NULL; )
10676
123
      {
10677
123
        profile=GetImageProfile(image,name);
10678
10679
123
        if (profile != (StringInfo *) NULL)
10680
123
          {
10681
123
#ifdef PNG_WRITE_iCCP_SUPPORTED
10682
123
            if ((LocaleCompare(name,"ICC") == 0) ||
10683
105
                (LocaleCompare(name,"ICM") == 0))
10684
18
              {
10685
18
                ping_have_iCCP = MagickTrue;
10686
18
                if (ping_exclude_iCCP == MagickFalse)
10687
18
                  {
10688
18
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10689
18
                        "  Setting up iCCP chunk");
10690
10691
18
                    png_set_iCCP(ping,ping_info,(png_charp) name,0,
10692
#if (PNG_LIBPNG_VER < 10500)
10693
                    (png_charp) GetStringInfoDatum(profile),
10694
#else
10695
18
                    (const png_byte *) GetStringInfoDatum(profile),
10696
18
#endif
10697
18
                    (png_uint_32) GetStringInfoLength(profile));
10698
18
                  }
10699
0
                else
10700
0
                  {
10701
                    /* Do not write hex-encoded ICC chunk */
10702
0
                       name=GetNextImageProfile(image);
10703
0
                       continue;
10704
0
                  }
10705
18
              }
10706
123
#endif /* WRITE_iCCP */
10707
10708
123
            if (LocaleCompare(name,"exif") == 0)
10709
105
              {
10710
                   /* Do not write hex-encoded ICC chunk; we will
10711
                      write it later as an eXIf chunk */
10712
105
                   name=GetNextImageProfile(image);
10713
105
                   continue;
10714
105
              }
10715
10716
18
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10717
18
                 "  Setting up zTXt chunk with uuencoded %s profile",
10718
18
                 name);
10719
18
              Magick_png_write_raw_profile(image_info,ping,ping_info,
10720
18
                (unsigned char *) name,(unsigned char *) name,
10721
18
                GetStringInfoDatum(profile),(png_uint_32)
10722
18
                GetStringInfoLength(profile),exception);
10723
18
          }
10724
18
        name=GetNextImageProfile(image);
10725
18
      }
10726
1.96k
    }
10727
2.27k
  }
10728
10729
2.27k
#if defined(PNG_WRITE_sRGB_SUPPORTED)
10730
2.27k
  if ((mng_info->have_global_srgb == MagickFalse) &&
10731
2.27k
      ping_have_iCCP != MagickTrue &&
10732
2.25k
      (ping_have_sRGB != MagickFalse ||
10733
2.25k
      png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10734
0
    {
10735
0
      if (mng_info->exclude_sRGB == MagickFalse)
10736
0
        {
10737
          /*
10738
            Note image rendering intent.
10739
          */
10740
0
          if (logging != MagickFalse)
10741
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10742
0
                "  Setting up sRGB chunk");
10743
10744
0
          (void) png_set_sRGB(ping,ping_info,(
10745
0
            Magick_RenderingIntent_to_PNG_RenderingIntent(
10746
0
              image->rendering_intent)));
10747
10748
0
          ping_have_sRGB = MagickTrue;
10749
0
        }
10750
0
    }
10751
10752
2.27k
  if ((mng_info->write_mng == MagickFalse) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10753
2.27k
#endif
10754
2.27k
    {
10755
2.27k
      if (mng_info->exclude_gAMA == MagickFalse &&
10756
1.96k
          ping_have_iCCP == MagickFalse &&
10757
1.94k
          ((ping_have_sRGB != MagickFalse &&
10758
0
            mng_info->exclude_sRGB == MagickFalse) ||
10759
1.94k
           (ping_have_sRGB == MagickFalse &&
10760
1.94k
            (image->gamma < 0.45 || image->gamma > 0.46))))
10761
302
      {
10762
302
      if ((mng_info->have_global_gama == MagickFalse) && (image->gamma != 0.0))
10763
302
        {
10764
          /*
10765
            Note image gamma.
10766
          */
10767
302
          if (logging != MagickFalse)
10768
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10769
0
              "  Setting up gAMA chunk (%.17g)",image->gamma);
10770
10771
302
          png_set_gAMA(ping,ping_info,image->gamma);
10772
302
        }
10773
302
      }
10774
10775
2.27k
      if (mng_info->exclude_cHRM == MagickFalse && ping_have_sRGB == MagickFalse)
10776
1.96k
        {
10777
1.96k
          if ((mng_info->have_global_chrm == MagickFalse) &&
10778
1.96k
              (image->chromaticity.red_primary.x != 0.0))
10779
784
            {
10780
              /*
10781
                Note image chromaticity.
10782
              */
10783
784
               PrimaryInfo
10784
784
                 bp,
10785
784
                 gp,
10786
784
                 rp,
10787
784
                 wp;
10788
10789
784
               wp=image->chromaticity.white_point;
10790
784
               rp=image->chromaticity.red_primary;
10791
784
               gp=image->chromaticity.green_primary;
10792
784
               bp=image->chromaticity.blue_primary;
10793
10794
784
               if (logging != MagickFalse)
10795
0
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10796
0
                   "  Setting up cHRM chunk");
10797
10798
784
               png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10799
784
                   bp.x,bp.y);
10800
784
           }
10801
1.96k
        }
10802
2.27k
    }
10803
10804
2.27k
  if (mng_info->exclude_bKGD == MagickFalse)
10805
1.96k
    {
10806
1.96k
      if (ping_have_bKGD != MagickFalse)
10807
1.65k
        {
10808
1.65k
          png_set_bKGD(ping,ping_info,&ping_background);
10809
1.65k
          if (logging != MagickFalse)
10810
0
            {
10811
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10812
0
                   "    Setting up bKGD chunk");
10813
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10814
0
                   "      background color = (%d,%d,%d)",
10815
0
                        (int) ping_background.red,
10816
0
                        (int) ping_background.green,
10817
0
                        (int) ping_background.blue);
10818
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10819
0
                   "      index = %d, gray=%d",
10820
0
                        (int) ping_background.index,
10821
0
                        (int) ping_background.gray);
10822
0
            }
10823
1.65k
         }
10824
1.96k
    }
10825
10826
2.27k
  if (mng_info->exclude_pHYs == MagickFalse)
10827
1.96k
    {
10828
1.96k
      if (ping_have_pHYs != MagickFalse)
10829
79
        {
10830
79
          png_set_pHYs(ping,ping_info,
10831
79
             ping_pHYs_x_resolution,
10832
79
             ping_pHYs_y_resolution,
10833
79
             ping_pHYs_unit_type);
10834
10835
79
          if (logging != MagickFalse)
10836
0
            {
10837
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10838
0
                   "    Setting up pHYs chunk");
10839
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10840
0
                   "      x_resolution=%g",(double) ping_pHYs_x_resolution);
10841
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10842
0
                   "      y_resolution=%g",(double) ping_pHYs_y_resolution);
10843
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10844
0
                   "      unit_type=%g",(double) ping_pHYs_unit_type);
10845
0
            }
10846
79
        }
10847
1.96k
    }
10848
10849
2.27k
#if defined(PNG_tIME_SUPPORTED)
10850
2.27k
  if (mng_info->exclude_tIME == MagickFalse)
10851
2.27k
    {
10852
2.27k
      const char
10853
2.27k
        *timestamp;
10854
10855
2.27k
      if (image->taint == MagickFalse)
10856
620
        {
10857
620
          timestamp=GetImageOption(image_info,"png:tIME");
10858
10859
620
          if (timestamp == (const char *) NULL)
10860
620
            timestamp=GetImageProperty(image,"png:tIME",exception);
10861
620
        }
10862
10863
1.65k
      else
10864
1.65k
        {
10865
1.65k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10866
1.65k
             "  Reset tIME in tainted image");
10867
10868
1.65k
          timestamp=GetImageProperty(image,"date:modify",exception);
10869
1.65k
        }
10870
10871
2.27k
      if (timestamp != (const char *) NULL)
10872
1.68k
          write_tIME_chunk(image,ping,ping_info,timestamp,exception);
10873
2.27k
    }
10874
2.27k
#endif
10875
10876
2.27k
  if (mng_info->need_blob != MagickFalse)
10877
1.96k
  {
10878
1.96k
    if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10879
1.96k
       MagickFalse)
10880
0
       png_error(ping,"WriteBlob Failed");
10881
10882
1.96k
     ping_have_blob=MagickTrue;
10883
1.96k
  }
10884
10885
2.27k
  png_write_info_before_PLTE(ping, ping_info);
10886
10887
2.27k
  if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10888
175
    {
10889
175
      if (logging != MagickFalse)
10890
0
        {
10891
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10892
0
              "  Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10893
0
        }
10894
10895
175
      if (ping_color_type == 3)
10896
72
         (void) png_set_tRNS(ping, ping_info,
10897
72
                ping_trans_alpha,
10898
72
                ping_num_trans,
10899
72
                NULL);
10900
10901
103
      else
10902
103
        {
10903
103
           (void) png_set_tRNS(ping, ping_info,
10904
103
                  NULL,
10905
103
                  0,
10906
103
                  &ping_trans_color);
10907
10908
103
           if (logging != MagickFalse)
10909
0
             {
10910
0
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10911
0
                 "     tRNS color   =(%d,%d,%d)",
10912
0
                       (int) ping_trans_color.red,
10913
0
                       (int) ping_trans_color.green,
10914
0
                       (int) ping_trans_color.blue);
10915
0
             }
10916
103
         }
10917
175
    }
10918
10919
  /*
10920
    Generate text chunks.
10921
  */
10922
2.27k
  if (mng_info->exclude_tEXt == MagickFalse || mng_info->exclude_zTXt == MagickFalse)
10923
1.96k
  {
10924
1.96k
    ResetImagePropertyIterator(image);
10925
21.9k
    while ((property=GetNextImageProperty(image)) != (const char *) NULL)
10926
20.0k
    {
10927
      /* Don't write any "png:" or "jpeg:" properties; those are just for
10928
       * "identify" or for passing through to another JPEG
10929
       */
10930
20.0k
      if ((LocaleNCompare(property,"png:",4) == 0 ||
10931
6.58k
           LocaleNCompare(property,"jpeg:",5) == 0))
10932
13.4k
        continue;
10933
      /* Suppress density and units if we wrote a pHYs chunk */
10934
6.58k
      if ((mng_info->exclude_pHYs == MagickFalse) && (
10935
6.58k
          ((LocaleCompare(property,"exif:ResolutionUnit") == 0) ||
10936
6.57k
           (LocaleCompare(property,"exif:XResolution") == 0) ||
10937
6.57k
           (LocaleCompare(property,"exif:YResolution") == 0) ||
10938
6.56k
           (LocaleCompare(property,"tiff:ResolutionUnit") == 0) ||
10939
6.56k
           (LocaleCompare(property,"tiff:XResolution") == 0) ||
10940
6.56k
           (LocaleCompare(property,"tiff:YResolution") == 0) ||
10941
6.56k
           (LocaleCompare(property,"density") == 0) ||
10942
6.56k
           (LocaleCompare(property,"units") == 0))))
10943
27
        continue;
10944
      /* Suppress the IM-generated date:create and date:modify */
10945
6.56k
      if ((mng_info->exclude_date != MagickFalse) &&
10946
0
          (LocaleNCompare(property, "date:",5) == 0))
10947
0
        continue;
10948
6.56k
      value=GetImageProperty(image,property,exception);
10949
6.56k
      if (value == (const char *) NULL)
10950
0
        continue;
10951
6.56k
      Magick_png_set_text(ping,ping_info,mng_info,image_info,property,value);
10952
6.56k
    }
10953
1.96k
  }
10954
10955
  /* write eXIf profile */
10956
2.27k
  if (ping_have_eXIf != MagickFalse && mng_info->exclude_eXIf == MagickFalse)
10957
2.27k
    {
10958
2.27k
      ResetImageProfileIterator(image);
10959
10960
2.29k
      for (name=GetNextImageProfile(image); name != (char *) NULL; )
10961
123
      {
10962
123
        if (LocaleCompare(name,"exif") == 0)
10963
105
          {
10964
105
            profile=GetImageProfile(image,name);
10965
10966
105
            if (profile != (StringInfo *) NULL)
10967
105
              {
10968
105
                png_uint_32
10969
105
                  length;
10970
10971
105
                unsigned char
10972
105
                  chunk[4],
10973
105
                  *data;
10974
10975
105
                StringInfo
10976
105
                  *ping_profile;
10977
10978
105
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10979
105
                    "  Have eXIf profile");
10980
10981
105
                ping_profile=CloneStringInfo(profile);
10982
105
                data=GetStringInfoDatum(ping_profile),
10983
105
                length=(png_uint_32) GetStringInfoLength(ping_profile);
10984
10985
105
                PNGType(chunk,mng_eXIf);
10986
105
                if (length < 7)
10987
0
                  {
10988
0
                    ping_profile=DestroyStringInfo(ping_profile);
10989
0
                    break;  /* otherwise crashes */
10990
0
                  }
10991
10992
105
                if (*data == 'E' && *(data+1) == 'x' && *(data+2) == 'i' &&
10993
105
                    *(data+3) == 'f' && *(data+4) == '\0' && *(data+5) == '\0')
10994
105
                  {
10995
                    /* skip the "Exif\0\0" JFIF Exif Header ID */
10996
105
                    length -= 6;
10997
105
                    data += 6;
10998
105
                  }
10999
11000
105
                LogPNGChunk(logging,chunk,length);
11001
105
                (void) WriteBlobMSBULong(image,length);
11002
105
                (void) WriteBlob(image,4,chunk);
11003
105
                (void) WriteBlob(image,length,data);
11004
105
                (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4), data,
11005
105
                  (uInt) length));
11006
105
                ping_profile=DestroyStringInfo(ping_profile);
11007
105
                break;
11008
105
             }
11009
105
         }
11010
18
       name=GetNextImageProfile(image);
11011
18
     }
11012
2.27k
  }
11013
11014
2.27k
  png_write_info(ping,ping_info);
11015
11016
  /* write orNT if image->orientation is defined */
11017
2.27k
  if (image->orientation != UndefinedOrientation)
11018
4
    {
11019
4
      unsigned char
11020
4
        chunk[6];
11021
4
      (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
11022
4
      PNGType(chunk,mng_orNT);
11023
4
      LogPNGChunk(logging,mng_orNT,1L);
11024
      /* PNG uses Exif orientation values */
11025
4
      chunk[4]=(unsigned char) Magick_Orientation_to_Exif_Orientation(image->orientation);
11026
4
      (void) WriteBlob(image,5,chunk);
11027
4
      (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11028
4
    }
11029
11030
2.27k
  ping_wrote_caNv = MagickFalse;
11031
11032
  /* write caNv chunk */
11033
2.27k
  if (mng_info->exclude_caNv == MagickFalse)
11034
1.96k
    {
11035
1.96k
      if ((image->page.width != 0 && image->page.width != image->columns) ||
11036
1.94k
          (image->page.height != 0 && image->page.height != image->rows) ||
11037
1.93k
          image->page.x != 0 || image->page.y != 0)
11038
38
        {
11039
38
          unsigned char
11040
38
            chunk[20];
11041
11042
38
          (void) WriteBlobMSBULong(image,16L);  /* data length=8 */
11043
38
          PNGType(chunk,mng_caNv);
11044
38
          LogPNGChunk(logging,mng_caNv,16L);
11045
38
          PNGLong(chunk+4,(png_uint_32) image->page.width);
11046
38
          PNGLong(chunk+8,(png_uint_32) image->page.height);
11047
38
          PNGsLong(chunk+12,(png_int_32) image->page.x);
11048
38
          PNGsLong(chunk+16,(png_int_32) image->page.y);
11049
38
          (void) WriteBlob(image,20,chunk);
11050
38
          (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11051
38
          ping_wrote_caNv = MagickTrue;
11052
38
        }
11053
1.96k
    }
11054
11055
2.27k
#if defined(PNG_oFFs_SUPPORTED)
11056
2.27k
  if (mng_info->exclude_oFFs == MagickFalse && ping_wrote_caNv == MagickFalse)
11057
1.92k
    {
11058
1.92k
      if (image->page.x || image->page.y)
11059
0
        {
11060
0
           png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
11061
0
              (png_int_32) image->page.y, 0);
11062
11063
0
           if (logging != MagickFalse)
11064
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11065
0
                 "    Setting up oFFs chunk with x=%d, y=%d, units=0",
11066
0
                 (int) image->page.x, (int) image->page.y);
11067
0
        }
11068
1.92k
    }
11069
2.27k
#endif
11070
11071
#if (PNG_LIBPNG_VER == 10206)
11072
    /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
11073
#define PNG_HAVE_IDAT               0x04
11074
    ping->mode |= PNG_HAVE_IDAT;
11075
#undef PNG_HAVE_IDAT
11076
#endif
11077
11078
2.27k
  png_set_packing(ping);
11079
  /*
11080
    Allocate memory.
11081
  */
11082
2.27k
  rowbytes=image->columns;
11083
2.27k
  if (image_depth > 8)
11084
741
    rowbytes*=2;
11085
2.27k
  switch (ping_color_type)
11086
2.27k
    {
11087
748
      case PNG_COLOR_TYPE_RGB:
11088
748
        rowbytes*=3;
11089
748
        break;
11090
11091
21
      case PNG_COLOR_TYPE_GRAY_ALPHA:
11092
21
        rowbytes*=2;
11093
21
        break;
11094
11095
558
      case PNG_COLOR_TYPE_RGBA:
11096
558
        rowbytes*=4;
11097
558
        break;
11098
11099
948
      default:
11100
948
        break;
11101
2.27k
    }
11102
11103
2.27k
  if (logging != MagickFalse)
11104
0
    {
11105
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11106
0
        "  Writing PNG image data");
11107
11108
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11109
0
        "    Allocating %.17g bytes of memory for pixels",(double) rowbytes);
11110
0
    }
11111
2.27k
  pixel_info=AcquireVirtualMemory(rowbytes,GetPixelChannels(image)*
11112
2.27k
    sizeof(*ping_pixels));
11113
2.27k
  if (pixel_info == (MemoryInfo *) NULL)
11114
0
    png_error(ping,"Allocation of memory for pixels failed");
11115
2.27k
  ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
11116
2.27k
  (void) memset(ping_pixels,0,rowbytes*GetPixelChannels(image)*
11117
2.27k
    sizeof(*ping_pixels));
11118
  /*
11119
    Initialize image scanlines.
11120
  */
11121
2.27k
  quantum_info=AcquireQuantumInfo(image_info,image);
11122
2.27k
  if (quantum_info == (QuantumInfo *) NULL)
11123
0
    png_error(ping,"Memory allocation for quantum_info failed");
11124
2.27k
  (void) SetQuantumFormat(image,quantum_info,UndefinedQuantumFormat);
11125
2.27k
  (void) SetQuantumDepth(image,quantum_info,image_depth);
11126
2.27k
  (void) SetQuantumEndian(image,quantum_info,MSBEndian);
11127
2.27k
  num_passes=png_set_interlace_handling(ping);
11128
11129
2.27k
  if ((mng_info->colortype-1 == PNG_COLOR_TYPE_PALETTE) ||
11130
1.89k
      ((mng_info->write_png8 == MagickFalse) &&
11131
1.89k
       (mng_info->write_png24 == MagickFalse) &&
11132
1.64k
       (mng_info->write_png48 == MagickFalse) &&
11133
1.41k
       (mng_info->write_png64 == MagickFalse) &&
11134
1.15k
       (mng_info->write_png32 == MagickFalse) &&
11135
901
       (image_matte == MagickFalse) &&
11136
820
       (ping_have_non_bw == MagickFalse) &&
11137
340
       ((mng_info->is_palette != MagickFalse) ||
11138
7
        (image_info->type == BilevelType))))
11139
712
     {
11140
      /* Palette, Bilevel, or Opaque Monochrome */
11141
712
      QuantumType
11142
712
        quantum_type;
11143
11144
712
      const Quantum
11145
712
        *p;
11146
11147
712
      quantum_type=RedQuantum;
11148
712
      if (mng_info->is_palette != MagickFalse)
11149
712
        {
11150
712
          quantum_type=GrayQuantum;
11151
712
          if (mng_info->colortype-1 == PNG_COLOR_TYPE_PALETTE)
11152
379
            quantum_type=IndexQuantum;
11153
712
        }
11154
712
      (void) SetQuantumDepth(image,quantum_info,8);
11155
1.42k
      for (pass=0; pass < num_passes; pass++)
11156
712
      {
11157
        /*
11158
          Convert PseudoClass image to a PNG monochrome image.
11159
        */
11160
126k
        for (y=0; y < (ssize_t) image->rows; y++)
11161
126k
        {
11162
126k
          if (logging != MagickFalse && y == 0)
11163
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11164
0
                 "    Writing row of pixels (0)");
11165
11166
126k
          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
11167
11168
126k
          if (p == (const Quantum *) NULL)
11169
0
            break;
11170
11171
126k
          (void) ExportQuantumPixels(image,(CacheView *) NULL,
11172
126k
            quantum_info,quantum_type,ping_pixels,exception);
11173
126k
          if (mng_info->colortype-1 != PNG_COLOR_TYPE_PALETTE)
11174
130M
            for (i=0; i < (ssize_t) image->columns; i++)
11175
130M
               *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
11176
128M
                      255 : 0);
11177
11178
126k
          if (logging != MagickFalse && y == 0)
11179
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11180
0
                "    Writing row of pixels (1)");
11181
11182
126k
          png_write_row(ping,ping_pixels);
11183
11184
126k
          status=SetImageProgress(image,SaveImageTag,
11185
126k
              (MagickOffsetType) (pass * (ssize_t) image->rows + y),
11186
126k
              (MagickSizeType) num_passes * image->rows);
11187
11188
126k
          if (status == MagickFalse)
11189
0
            break;
11190
126k
        }
11191
712
      }
11192
712
    }
11193
11194
1.56k
  else   /* Not Palette, Bilevel, or Opaque Monochrome */
11195
1.56k
    {
11196
1.56k
      if (((mng_info->write_png8 == MagickFalse) &&
11197
1.56k
           (mng_info->write_png24 == MagickFalse) &&
11198
1.30k
           (mng_info->write_png48 == MagickFalse) &&
11199
1.08k
           (mng_info->write_png64 == MagickFalse) &&
11200
826
           (mng_info->write_png32 == MagickFalse)) &&
11201
568
          ((image_matte != MagickFalse) || ((ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH))) &&
11202
325
          ((mng_info->is_palette != MagickFalse)) && (ping_have_color == MagickFalse))
11203
18
        {
11204
18
          const Quantum
11205
18
            *p;
11206
11207
36
          for (pass=0; pass < num_passes; pass++)
11208
18
          {
11209
11210
1.15k
          for (y=0; y < (ssize_t) image->rows; y++)
11211
1.13k
          {
11212
1.13k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
11213
11214
1.13k
            if (p == (const Quantum *) NULL)
11215
0
              break;
11216
11217
1.13k
            if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11218
959
              {
11219
959
                if (mng_info->is_palette != MagickFalse)
11220
959
                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
11221
959
                    quantum_info,GrayQuantum,ping_pixels,exception);
11222
11223
0
                else
11224
0
                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
11225
0
                    quantum_info,RedQuantum,ping_pixels,exception);
11226
11227
959
                if (logging != MagickFalse && y == 0)
11228
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11229
0
                       "    Writing GRAY PNG pixels (2)");
11230
959
              }
11231
11232
176
            else /* PNG_COLOR_TYPE_GRAY_ALPHA */
11233
176
              {
11234
176
                if (logging != MagickFalse && y == 0)
11235
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11236
0
                         "    Writing GRAY_ALPHA PNG pixels (2)");
11237
11238
176
                (void) ExportQuantumPixels(image,(CacheView *) NULL,
11239
176
                  quantum_info,GrayAlphaQuantum,ping_pixels,exception);
11240
176
              }
11241
11242
1.13k
            if (logging != MagickFalse && y == 0)
11243
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11244
0
                  "    Writing row of pixels (2)");
11245
11246
1.13k
            png_write_row(ping,ping_pixels);
11247
11248
1.13k
            status=SetImageProgress(image,SaveImageTag,
11249
1.13k
              (MagickOffsetType) (pass * (ssize_t) image->rows + y),
11250
1.13k
              (MagickSizeType) num_passes * image->rows);
11251
11252
1.13k
            if (status == MagickFalse)
11253
0
              break;
11254
1.13k
            }
11255
18
          }
11256
18
        }
11257
11258
1.54k
      else
11259
1.54k
        {
11260
1.54k
          const Quantum
11261
1.54k
            *p;
11262
11263
3.09k
          for (pass=0; pass < num_passes; pass++)
11264
1.54k
          {
11265
1.54k
            if ((image_depth > 8) ||
11266
820
                (mng_info->write_png24 != MagickFalse) ||
11267
565
                (mng_info->write_png32 != MagickFalse) ||
11268
307
                (mng_info->write_png48 != MagickFalse) ||
11269
307
                (mng_info->write_png64 != MagickFalse) ||
11270
307
                ((mng_info->write_png8 == MagickFalse) &&
11271
307
                 (mng_info->is_palette == MagickFalse)))
11272
1.33k
            {
11273
129k
              for (y=0; y < (ssize_t) image->rows; y++)
11274
127k
              {
11275
127k
                p=GetVirtualPixels(image,0,y,image->columns,1, exception);
11276
11277
127k
                if (p == (const Quantum *) NULL)
11278
0
                  break;
11279
11280
127k
                if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11281
495
                  {
11282
495
                    if (image->storage_class == DirectClass)
11283
495
                      (void) ExportQuantumPixels(image,(CacheView *) NULL,
11284
495
                        quantum_info,RedQuantum,ping_pixels,exception);
11285
11286
0
                    else
11287
0
                      (void) ExportQuantumPixels(image,(CacheView *) NULL,
11288
0
                        quantum_info,GrayQuantum,ping_pixels,exception);
11289
495
                  }
11290
11291
127k
                else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11292
946
                  {
11293
946
                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
11294
946
                      quantum_info,GrayAlphaQuantum,ping_pixels,exception);
11295
11296
946
                    if (logging != MagickFalse && y == 0)
11297
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11298
0
                           "    Writing GRAY_ALPHA PNG pixels (3)");
11299
946
                  }
11300
11301
126k
                else if (image_matte != MagickFalse)
11302
19.9k
                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
11303
19.9k
                    quantum_info,RGBAQuantum,ping_pixels,exception);
11304
11305
106k
                else
11306
106k
                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
11307
106k
                    quantum_info,RGBQuantum,ping_pixels,exception);
11308
11309
127k
                if (logging != MagickFalse && y == 0)
11310
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11311
0
                      "    Writing row of pixels (3)");
11312
11313
127k
                png_write_row(ping,ping_pixels);
11314
11315
127k
                status=SetImageProgress(image,SaveImageTag,
11316
127k
                  (MagickOffsetType) (pass * (ssize_t) image->rows + y),
11317
127k
                  (MagickSizeType) num_passes * image->rows);
11318
11319
127k
                if (status == MagickFalse)
11320
0
                  break;
11321
127k
              }
11322
1.33k
            }
11323
11324
208
          else
11325
            /* not ((image_depth > 8) ||
11326
                mng_info->write_png24 || mng_info->write_png32 ||
11327
                mng_info->write_png48 || mng_info->write_png64 ||
11328
                (!mng_info->write_png8 && !mng_info->IsPalette))
11329
             */
11330
208
            {
11331
208
              if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
11332
99
                  (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
11333
99
                {
11334
99
                  if (logging != MagickFalse)
11335
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11336
0
                      "  pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
11337
11338
99
                  (void) SetQuantumDepth(image,quantum_info,8);
11339
99
                  image_depth=8;
11340
99
                }
11341
11342
13.5k
              for (y=0; y < (ssize_t) image->rows; y++)
11343
13.3k
              {
11344
13.3k
                if (logging != MagickFalse && y == 0)
11345
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11346
0
                    "  pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",
11347
0
                    pass);
11348
11349
13.3k
                p=GetVirtualPixels(image,0,y,image->columns,1, exception);
11350
11351
13.3k
                if (p == (const Quantum *) NULL)
11352
0
                  break;
11353
11354
13.3k
                if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11355
5.31k
                  {
11356
5.31k
                    (void) SetQuantumDepth(image,quantum_info,image->depth);
11357
11358
5.31k
                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
11359
5.31k
                       quantum_info,GrayQuantum,ping_pixels,exception);
11360
5.31k
                  }
11361
11362
7.99k
                else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11363
0
                  {
11364
0
                    if (logging != MagickFalse && y == 0)
11365
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11366
0
                           "  Writing GRAY_ALPHA PNG pixels (4)");
11367
11368
0
                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
11369
0
                         quantum_info,GrayAlphaQuantum,ping_pixels,
11370
0
                         exception);
11371
0
                  }
11372
11373
7.99k
                else
11374
7.99k
                  {
11375
7.99k
                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
11376
7.99k
                      quantum_info,IndexQuantum,ping_pixels,exception);
11377
11378
7.99k
                    if (logging != MagickFalse && y <= 2)
11379
0
                    {
11380
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11381
0
                          "  Writing row of non-gray pixels (4)");
11382
11383
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11384
0
                          "  ping_pixels[0]=%d,ping_pixels[1]=%d",
11385
0
                          (int)ping_pixels[0],(int)ping_pixels[1]);
11386
0
                    }
11387
7.99k
                  }
11388
13.3k
                png_write_row(ping,ping_pixels);
11389
11390
13.3k
                status=SetImageProgress(image,SaveImageTag,
11391
13.3k
                  (MagickOffsetType) pass * (ssize_t) image->rows + y,
11392
13.3k
                  (MagickSizeType) num_passes * image->rows);
11393
11394
13.3k
                if (status == MagickFalse)
11395
0
                  break;
11396
13.3k
              }
11397
208
            }
11398
1.54k
          }
11399
1.54k
        }
11400
1.56k
    }
11401
11402
2.27k
  if (quantum_info != (QuantumInfo *) NULL)
11403
2.27k
    quantum_info=DestroyQuantumInfo(quantum_info);
11404
11405
2.27k
  if (logging != MagickFalse)
11406
0
    {
11407
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11408
0
        "  Wrote PNG image data");
11409
11410
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11411
0
        "    Width: %.17g",(double) ping_width);
11412
11413
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11414
0
        "    Height: %.17g",(double) ping_height);
11415
11416
0
      if (mng_info->depth)
11417
0
        {
11418
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11419
0
            "    Defined png:bit-depth: %d",mng_info->depth);
11420
0
        }
11421
11422
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11423
0
        "    PNG bit-depth written: %d",ping_bit_depth);
11424
11425
0
      if (mng_info->colortype)
11426
0
        {
11427
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11428
0
            "    Defined png:color-type: %d",mng_info->colortype-1);
11429
0
        }
11430
11431
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11432
0
        "    PNG color-type written: %d",ping_color_type);
11433
11434
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11435
0
        "    PNG Interlace method: %d",ping_interlace_method);
11436
0
    }
11437
11438
2.27k
  if (logging != MagickFalse)
11439
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11440
0
      "  Writing PNG end info");
11441
11442
2.27k
  png_write_end(ping,ping_info);
11443
11444
2.27k
  if (mng_info->need_fram != MagickFalse &&
11445
31
      (int) image->dispose == BackgroundDispose)
11446
31
    {
11447
31
      if (mng_info->need_defi == MagickFalse &&
11448
31
          (mng_info->page.x || mng_info->page.y ||
11449
31
          (ping_width != mng_info->page.width) ||
11450
31
          (ping_height != mng_info->page.height)))
11451
0
        {
11452
0
          unsigned char
11453
0
            chunk[32];
11454
11455
          /*
11456
            Write FRAM 4 with clipping boundaries followed by FRAM 1.
11457
          */
11458
0
          (void) WriteBlobMSBULong(image,27L);  /* data length=27 */
11459
0
          PNGType(chunk,mng_FRAM);
11460
0
          LogPNGChunk(logging,mng_FRAM,27L);
11461
0
          chunk[4]=4;
11462
0
          chunk[5]=0;  /* frame name separator (no name) */
11463
0
          chunk[6]=1;  /* flag for changing delay, for next frame only */
11464
0
          chunk[7]=0;  /* flag for changing frame timeout */
11465
0
          chunk[8]=1;  /* flag for changing frame clipping for next frame */
11466
0
          chunk[9]=0;  /* flag for changing frame sync_id */
11467
0
          PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
11468
0
          chunk[14]=0; /* clipping boundaries delta type */
11469
0
          PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
11470
0
          PNGLong(chunk+19,
11471
0
             (png_uint_32) (mng_info->page.x + ping_width));
11472
0
          PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
11473
0
          PNGLong(chunk+27,
11474
0
             (png_uint_32) (mng_info->page.y + ping_height));
11475
0
          (void) WriteBlob(image,31,chunk);
11476
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
11477
0
          mng_info->old_framing_mode=4;
11478
0
          mng_info->framing_mode=1;
11479
0
        }
11480
11481
31
      else
11482
31
        mng_info->framing_mode=3;
11483
31
    }
11484
2.27k
  if ((mng_info->write_mng != MagickFalse) &&
11485
311
      (mng_info->need_fram == MagickFalse) && ((int) image->dispose == 3))
11486
0
     png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11487
11488
  /*
11489
    Free PNG resources.
11490
  */
11491
11492
2.27k
  png_destroy_write_struct(&ping,&ping_info);
11493
11494
2.27k
  pixel_info=RelinquishVirtualMemory(pixel_info);
11495
11496
2.27k
  image_info=DestroyImageInfo(image_info);
11497
2.27k
  image=DestroyImage(image);
11498
11499
2.27k
  if (ping_have_blob != MagickFalse)
11500
1.96k
    (void) CloseBlob(IMimage);
11501
11502
  /* Store bit depth actually written */
11503
2.27k
  s[0]=(char) ping_bit_depth;
11504
2.27k
  s[1]='\0';
11505
11506
2.27k
  (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11507
11508
2.27k
  if (logging != MagickFalse)
11509
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11510
0
      "  exit WriteOnePNGImage()");
11511
11512
#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
11513
  UnlockSemaphoreInfo(ping_semaphore);
11514
#endif
11515
11516
   /* }  for navigation to beginning of SETJMP-protected block. Revert to
11517
    *    Throwing an Exception when an error occurs.
11518
    */
11519
11520
2.27k
  return(MagickTrue);
11521
/*  End write one PNG image */
11522
11523
2.27k
}
11524
11525
/*
11526
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11527
%                                                                             %
11528
%                                                                             %
11529
%                                                                             %
11530
%   W r i t e P N G I m a g e                                                 %
11531
%                                                                             %
11532
%                                                                             %
11533
%                                                                             %
11534
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11535
%
11536
%  WritePNGImage() writes a Portable Network Graphics (PNG) or
11537
%  Multiple-image Network Graphics (MNG) image file.
11538
%
11539
%  MNG support written by Glenn Randers-Pehrson, glennrp@image...
11540
%
11541
%  The format of the WritePNGImage method is:
11542
%
11543
%      MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11544
%        Image *image,ExceptionInfo *exception)
11545
%
11546
%  A description of each parameter follows:
11547
%
11548
%    o image_info: the image info.
11549
%
11550
%    o image:  The image.
11551
%
11552
%    o exception: return any errors or warnings in this structure.
11553
%
11554
%  Returns MagickTrue on success, MagickFalse on failure.
11555
%
11556
%  Communicating with the PNG encoder:
11557
%
11558
%  While the datastream written is always in PNG format and normally would
11559
%  be given the "png" file extension, this method also writes the following
11560
%  pseudo-formats which are subsets of png:
11561
%
11562
%    o PNG8:    An 8-bit indexed PNG datastream is written.  If the image has
11563
%               a depth greater than 8, the depth is reduced. If transparency
11564
%               is present, the tRNS chunk must only have values 0 and 255
11565
%               (i.e., transparency is binary: fully opaque or fully
11566
%               transparent).  If other values are present they will be
11567
%               50%-thresholded to binary transparency.  If more than 256
11568
%               colors are present, they will be quantized to the 4-4-4-1,
11569
%               3-3-3-1, or 3-3-2-1 palette.  The underlying RGB color
11570
%               of any resulting fully-transparent pixels is changed to
11571
%               the image's background color.
11572
%
11573
%               If you want better quantization or dithering of the colors
11574
%               or alpha than that, you need to do it before calling the
11575
%               PNG encoder. The pixels contain 8-bit indices even if
11576
%               they could be represented with 1, 2, or 4 bits.  Grayscale
11577
%               images will be written as indexed PNG files even though the
11578
%               PNG grayscale type might be slightly more efficient.  Please
11579
%               note that writing to the PNG8 format may result in loss
11580
%               of color and alpha data.
11581
%
11582
%    o PNG24:   An 8-bit per sample RGB PNG datastream is written.  The tRNS
11583
%               chunk can be present to convey binary transparency by naming
11584
%               one of the colors as transparent.  The only loss incurred
11585
%               is reduction of sample depth to 8.  If the image has more
11586
%               than one transparent color, has semitransparent pixels, or
11587
%               has an opaque pixel with the same RGB components as the
11588
%               transparent color, an image is not written.
11589
%
11590
%    o PNG32:   An 8-bit per sample RGBA PNG is written.  Partial
11591
%               transparency is permitted, i.e., the alpha sample for
11592
%               each pixel can have any value from 0 to 255. The alpha
11593
%               channel is present even if the image is fully opaque.
11594
%               The only loss in data is the reduction of the sample depth
11595
%               to 8.
11596
%
11597
%    o PNG48:   A 16-bit per sample RGB PNG datastream is written.  The tRNS
11598
%               chunk can be present to convey binary transparency by naming
11599
%               one of the colors as transparent.  If the image has more
11600
%               than one transparent color, has semitransparent pixels, or
11601
%               has an opaque pixel with the same RGB components as the
11602
%               transparent color, an image is not written.
11603
%
11604
%    o PNG64:   A 16-bit per sample RGBA PNG is written.  Partial
11605
%               transparency is permitted, i.e., the alpha sample for
11606
%               each pixel can have any value from 0 to 65535. The alpha
11607
%               channel is present even if the image is fully opaque.
11608
%
11609
%    o PNG00:   A PNG that inherits its colortype and bit-depth from the input
11610
%               image, if the input was a PNG, is written.  If these values
11611
%               cannot be found, or if the pixels have been changed in a way
11612
%               that makes this impossible, then "PNG00" falls back to the
11613
%               regular "PNG" format.
11614
%
11615
%    o -define: For more precise control of the PNG output, you can use the
11616
%               Image options "png:bit-depth" and "png:color-type".  These
11617
%               can be set from the commandline with "-define" and also
11618
%               from the application programming interfaces.  The options
11619
%               are case-independent and are converted to lowercase before
11620
%               being passed to this encoder.
11621
%
11622
%               png:color-type can be 0, 2, 3, 4, or 6.
11623
%
11624
%               When png:color-type is 0 (Grayscale), png:bit-depth can
11625
%               be 1, 2, 4, 8, or 16.
11626
%
11627
%               When png:color-type is 2 (RGB), png:bit-depth can
11628
%               be 8 or 16.
11629
%
11630
%               When png:color-type is 3 (Indexed), png:bit-depth can
11631
%               be 1, 2, 4, or 8.  This refers to the number of bits
11632
%               used to store the index.  The color samples always have
11633
%               bit-depth 8 in indexed PNG files.
11634
%
11635
%               When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11636
%               png:bit-depth can be 8 or 16.
11637
%
11638
%               If the image cannot be written without loss with the
11639
%               requested bit-depth and color-type, a PNG file will not
11640
%               be written, a warning will be issued, and the encoder will
11641
%               return MagickFalse.
11642
%
11643
%  Since image encoders should not be responsible for the "heavy lifting",
11644
%  the user should make sure that ImageMagick has already reduced the
11645
%  image depth and number of colors and limit transparency to binary
11646
%  transparency prior to attempting to write the image with depth, color,
11647
%  or transparency limitations.
11648
%
11649
%  Note that another definition, "png:bit-depth-written" exists, but it
11650
%  is not intended for external use.  It is only used internally by the
11651
%  PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11652
%
11653
%  As of version 6.6.6 the following optimizations are always done:
11654
%
11655
%   o  32-bit depth is reduced to 16.
11656
%   o  16-bit depth is reduced to 8 if all pixels contain samples whose
11657
%      high byte and low byte are identical.
11658
%   o  Palette is sorted to remove unused entries and to put a
11659
%      transparent color first, if BUILD_PNG_PALETTE is defined.
11660
%   o  Opaque matte channel is removed when writing an indexed PNG.
11661
%   o  Grayscale images are reduced to 1, 2, or 4 bit depth if
11662
%      this can be done without loss and a larger bit depth N was not
11663
%      requested via the "-define png:bit-depth=N" option.
11664
%   o  If matte channel is present but only one transparent color is
11665
%      present, RGB+tRNS is written instead of RGBA
11666
%   o  Opaque matte channel is removed (or added, if color-type 4 or 6
11667
%      was requested when converting an opaque image).
11668
%
11669
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11670
*/
11671
static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11672
  Image *image,ExceptionInfo *exception)
11673
1.96k
{
11674
1.96k
  MagickBooleanType
11675
1.96k
    excluding,
11676
1.96k
    logging = MagickFalse,
11677
1.96k
    status;
11678
11679
1.96k
  MngWriteInfo
11680
1.96k
    *mng_info;
11681
11682
1.96k
  const char
11683
1.96k
    *value;
11684
11685
1.96k
  int
11686
1.96k
    source;
11687
11688
  /*
11689
    Open image file.
11690
  */
11691
1.96k
  assert(image_info != (const ImageInfo *) NULL);
11692
1.96k
  assert(image_info->signature == MagickCoreSignature);
11693
1.96k
  assert(image != (Image *) NULL);
11694
1.96k
  assert(image->signature == MagickCoreSignature);
11695
1.96k
  if (IsEventLogging() != MagickFalse)
11696
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11697
1.96k
  if (image->debug != MagickFalse)
11698
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11699
0
      "Enter WritePNGImage()");
11700
1.96k
  mng_info=(MngWriteInfo *) AcquireMagickMemory(sizeof(*mng_info));
11701
1.96k
  if (mng_info == (MngWriteInfo *) NULL)
11702
1.96k
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11703
1.96k
  (void) memset(mng_info,0,sizeof(*mng_info));
11704
1.96k
  mng_info->image=image;
11705
1.96k
  mng_info->equal_backgrounds=MagickTrue;
11706
11707
  /* See if user has requested a specific PNG subformat */
11708
11709
1.96k
  mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0 ?
11710
1.64k
    MagickTrue : MagickFalse;
11711
1.96k
  mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0 ?
11712
1.70k
    MagickTrue : MagickFalse;
11713
1.96k
  mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0 ?
11714
1.70k
    MagickTrue : MagickFalse;
11715
1.96k
  mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0 ?
11716
1.73k
    MagickTrue : MagickFalse;
11717
1.96k
  mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0 ?
11718
1.71k
    MagickTrue : MagickFalse;
11719
11720
1.96k
  value=GetImageOption(image_info,"png:format");
11721
11722
1.96k
  if (value != (char *) NULL || LocaleCompare(image_info->magick,"PNG00") == 0)
11723
320
    {
11724
320
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11725
320
         "  Format=%s",value);
11726
11727
320
      mng_info->write_png8 = MagickFalse;
11728
320
      mng_info->write_png24 = MagickFalse;
11729
320
      mng_info->write_png32 = MagickFalse;
11730
320
      mng_info->write_png48 = MagickFalse;
11731
320
      mng_info->write_png64 = MagickFalse;
11732
11733
320
      if (LocaleCompare(value,"png8") == 0)
11734
0
        mng_info->write_png8 = MagickTrue;
11735
11736
320
      else if (LocaleCompare(value,"png24") == 0)
11737
0
        mng_info->write_png24 = MagickTrue;
11738
11739
320
      else if (LocaleCompare(value,"png32") == 0)
11740
0
        mng_info->write_png32 = MagickTrue;
11741
11742
320
      else if (LocaleCompare(value,"png48") == 0)
11743
0
        mng_info->write_png48 = MagickTrue;
11744
11745
320
      else if (LocaleCompare(value,"png64") == 0)
11746
0
        mng_info->write_png64 = MagickTrue;
11747
11748
320
      else if ((LocaleCompare(value,"png00") == 0) ||
11749
320
         LocaleCompare(image_info->magick,"PNG00") == 0)
11750
320
        {
11751
          /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig. */
11752
320
          value=GetImageProperty(image,"png:IHDR.bit-depth-orig",exception);
11753
11754
320
          if (value != (char *) NULL)
11755
320
            {
11756
320
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11757
320
                 "  png00 inherited bit depth=%s",value);
11758
11759
320
              if (LocaleCompare(value,"1") == 0)
11760
103
                mng_info->depth = 1;
11761
11762
217
              else if (LocaleCompare(value,"2") == 0)
11763
24
                mng_info->depth = 2;
11764
11765
193
              else if (LocaleCompare(value,"4") == 0)
11766
24
                mng_info->depth = 4;
11767
11768
169
              else if (LocaleCompare(value,"8") == 0)
11769
113
                mng_info->depth = 8;
11770
11771
56
              else if (LocaleCompare(value,"16") == 0)
11772
56
                mng_info->depth = 16;
11773
320
            }
11774
11775
320
          value=GetImageProperty(image,"png:IHDR.color-type-orig",exception);
11776
11777
320
          if (value != (char *) NULL)
11778
320
            {
11779
320
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11780
320
                 "  png00 inherited color type=%s",value);
11781
11782
320
              if (LocaleCompare(value,"0") == 0)
11783
133
                mng_info->colortype=1;
11784
187
              else if (LocaleCompare(value,"2") == 0)
11785
83
                mng_info->colortype=3;
11786
104
              else if (LocaleCompare(value,"3") == 0)
11787
58
                mng_info->colortype=4;
11788
46
              else if (LocaleCompare(value,"4") == 0)
11789
7
                mng_info->colortype=5;
11790
39
              else if (LocaleCompare(value,"6") == 0)
11791
39
                mng_info->colortype=7;
11792
320
            }
11793
320
        }
11794
320
    }
11795
11796
1.96k
  if (mng_info->write_png8 != MagickFalse)
11797
321
    {
11798
321
      mng_info->colortype=4; /* 3 */
11799
321
      mng_info->depth = 8;
11800
321
      image->depth = 8;
11801
321
      if (image->alpha_trait != UndefinedPixelTrait)
11802
56
        (void) SetImageType(image,PaletteAlphaType,exception);
11803
265
      else
11804
265
        (void) SetImageType(image,PaletteType,exception);
11805
321
    }
11806
11807
1.96k
  if (mng_info->write_png24 != MagickFalse)
11808
255
    {
11809
255
      mng_info->colortype=3; /* 2 */
11810
255
      mng_info->depth = 8;
11811
255
      image->depth = 8;
11812
11813
255
      if (image->alpha_trait != UndefinedPixelTrait)
11814
51
        (void) SetImageType(image,TrueColorAlphaType,exception);
11815
204
      else
11816
204
        (void) SetImageType(image,TrueColorType,exception);
11817
11818
255
      (void) SyncImage(image,exception);
11819
255
    }
11820
11821
1.96k
  if (mng_info->write_png32 != MagickFalse)
11822
258
    {
11823
258
      mng_info->colortype = /* 6 */  7;
11824
258
      mng_info->depth = 8;
11825
258
      image->depth = 8;
11826
258
      if (image->alpha_trait != UndefinedPixelTrait)
11827
58
        (void) SetImageType(image,TrueColorAlphaType,exception);
11828
200
      else
11829
200
        (void) SetImageType(image,TrueColorType,exception);
11830
258
      (void) SyncImage(image,exception);
11831
258
    }
11832
11833
1.96k
  if (mng_info->write_png48 != MagickFalse)
11834
228
    {
11835
228
      mng_info->colortype = /* 2 */ 3;
11836
228
      mng_info->depth = 16;
11837
228
      image->depth = 16;
11838
228
      if (image->alpha_trait != UndefinedPixelTrait)
11839
44
        (void) SetImageType(image,TrueColorAlphaType,exception);
11840
184
      else
11841
184
        (void) SetImageType(image,TrueColorType,exception);
11842
228
      (void) SyncImage(image,exception);
11843
228
    }
11844
11845
1.96k
  if (mng_info->write_png64 != MagickFalse)
11846
254
    {
11847
254
      mng_info->colortype = /* 6 */  7;
11848
254
      mng_info->depth = 16;
11849
254
      image->depth = 16;
11850
254
      if (image->alpha_trait != UndefinedPixelTrait)
11851
50
        (void) SetImageType(image,TrueColorAlphaType,exception);
11852
204
      else
11853
204
        (void) SetImageType(image,TrueColorType,exception);
11854
254
      (void) SyncImage(image,exception);
11855
254
    }
11856
11857
1.96k
  value=GetImageOption(image_info,"png:bit-depth");
11858
11859
1.96k
  if (value != (char *) NULL)
11860
0
    {
11861
0
      if (LocaleCompare(value,"1") == 0)
11862
0
        mng_info->depth = 1;
11863
11864
0
      else if (LocaleCompare(value,"2") == 0)
11865
0
        mng_info->depth = 2;
11866
11867
0
      else if (LocaleCompare(value,"4") == 0)
11868
0
        mng_info->depth = 4;
11869
11870
0
      else if (LocaleCompare(value,"8") == 0)
11871
0
        mng_info->depth = 8;
11872
11873
0
      else if (LocaleCompare(value,"16") == 0)
11874
0
        mng_info->depth = 16;
11875
11876
0
      else
11877
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
11878
0
          "ignoring invalid defined png:bit-depth","=%s",value);
11879
11880
0
      if (logging != MagickFalse)
11881
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11882
0
          "  png:bit-depth=%d was defined.\n",mng_info->depth);
11883
0
    }
11884
11885
1.96k
  value=GetImageOption(image_info,"png:color-type");
11886
11887
1.96k
  if (value != (char *) NULL)
11888
0
    {
11889
      /* We must store colortype+1 because 0 is a valid colortype */
11890
0
      if (LocaleCompare(value,"0") == 0)
11891
0
        mng_info->colortype = 1;
11892
11893
0
      else if (LocaleCompare(value,"1") == 0)
11894
0
        mng_info->colortype = 2;
11895
11896
0
      else if (LocaleCompare(value,"2") == 0)
11897
0
        mng_info->colortype = 3;
11898
11899
0
      else if (LocaleCompare(value,"3") == 0)
11900
0
        mng_info->colortype = 4;
11901
11902
0
      else if (LocaleCompare(value,"4") == 0)
11903
0
        mng_info->colortype = 5;
11904
11905
0
      else if (LocaleCompare(value,"6") == 0)
11906
0
        mng_info->colortype = 7;
11907
11908
0
      else
11909
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
11910
0
          "ignoring invalid defined png:color-type","=%s",value);
11911
11912
0
      if (logging != MagickFalse)
11913
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11914
0
          "  png:color-type=%d was defined.\n",
11915
0
          mng_info->colortype-1);
11916
0
    }
11917
11918
  /* Check for chunks to be excluded:
11919
   *
11920
   * The default is to not exclude any known chunks except for any
11921
   * listed in the "unused_chunks" array, above.
11922
   *
11923
   * Chunks can be listed for exclusion via a "png:exclude-chunk"
11924
   * define (in the image properties or in the image artifacts)
11925
   * or via a mng_info member.  For convenience, in addition
11926
   * to or instead of a comma-separated list of chunks, the
11927
   * "exclude-chunk" string can be simply "all" or "none".
11928
   *
11929
   * Note that the "-strip" option provides a convenient way of
11930
   * doing the equivalent of
11931
   *
11932
   *    -define png:exclude-chunk="bKGD,caNv,cHRM,eXIf,gAMA,iCCP,
11933
   *            iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date"
11934
   *
11935
   * The exclude-chunk define takes priority over the mng_info.
11936
   *
11937
   * A "png:include-chunk" define takes  priority over both the
11938
   * mng_info and the "png:exclude-chunk" define.  Like the
11939
   * "exclude-chunk" string, it can define "all" or "none" as
11940
   * well as a comma-separated list.  Chunks that are unknown to
11941
   * ImageMagick are always excluded, regardless of their "copy-safe"
11942
   * status according to the PNG specification, and even if they
11943
   * appear in the "include-chunk" list. Such defines appearing among
11944
   * the image options take priority over those found among the image
11945
   * artifacts.
11946
   *
11947
   * Finally, all chunks listed in the "unused_chunks" array are
11948
   * automatically excluded, regardless of the other instructions
11949
   * or lack thereof.
11950
   *
11951
   * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11952
   * will not be written and the gAMA chunk will only be written if it
11953
   * is not between .45 and .46, or approximately (1.0/2.2).
11954
   *
11955
   * If you exclude tRNS and the image has transparency, the colortype
11956
   * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11957
   *
11958
   * The -strip option causes StripImage() to set the png:include-chunk
11959
   * artifact to "none,trns,gama".
11960
   */
11961
11962
1.96k
  mng_info->exclude_bKGD=MagickFalse;
11963
1.96k
  mng_info->exclude_caNv=MagickFalse;
11964
1.96k
  mng_info->exclude_cHRM=MagickFalse;
11965
1.96k
  mng_info->exclude_date=MagickFalse;
11966
1.96k
  mng_info->exclude_eXIf=MagickFalse;
11967
1.96k
  mng_info->exclude_EXIF=MagickFalse;
11968
1.96k
  mng_info->exclude_gAMA=MagickFalse;
11969
1.96k
  mng_info->exclude_iCCP=MagickFalse;
11970
1.96k
  mng_info->exclude_oFFs=MagickFalse;
11971
1.96k
  mng_info->exclude_pHYs=MagickFalse;
11972
1.96k
  mng_info->exclude_sRGB=MagickFalse;
11973
1.96k
  mng_info->exclude_tEXt=MagickFalse;
11974
1.96k
  mng_info->exclude_tIME=MagickFalse;
11975
1.96k
  mng_info->exclude_tRNS=MagickFalse;
11976
1.96k
  mng_info->exclude_zCCP=MagickFalse;
11977
1.96k
  mng_info->exclude_zTXt=MagickFalse;
11978
11979
1.96k
  mng_info->preserve_colormap=MagickFalse;
11980
11981
1.96k
  value=GetImageOption(image_info,"png:preserve-colormap");
11982
1.96k
  if (value == NULL)
11983
1.96k
     value=GetImageArtifact(image,"png:preserve-colormap");
11984
1.96k
  if (value != NULL)
11985
0
     mng_info->preserve_colormap=MagickTrue;
11986
11987
1.96k
  mng_info->preserve_iCCP=MagickFalse;
11988
11989
1.96k
  value=GetImageOption(image_info,"png:preserve-iCCP");
11990
1.96k
  if (value == NULL)
11991
1.96k
     value=GetImageArtifact(image,"png:preserve-iCCP");
11992
1.96k
  if (value != NULL)
11993
0
     mng_info->preserve_iCCP=MagickTrue;
11994
11995
  /* These compression-level, compression-strategy, and compression-filter
11996
   * defines take precedence over values from the -quality option.
11997
   */
11998
1.96k
  value=GetImageOption(image_info,"png:compression-level");
11999
1.96k
  if (value == NULL)
12000
1.96k
     value=GetImageArtifact(image,"png:compression-level");
12001
1.96k
  if (value != NULL)
12002
0
  {
12003
      /* We have to add 1 to everything because 0 is a valid input,
12004
       * and we want to use 0 (the default) to mean undefined.
12005
       */
12006
0
      if (LocaleCompare(value,"0") == 0)
12007
0
        mng_info->compression_level = 1;
12008
12009
0
      else if (LocaleCompare(value,"1") == 0)
12010
0
        mng_info->compression_level = 2;
12011
12012
0
      else if (LocaleCompare(value,"2") == 0)
12013
0
        mng_info->compression_level = 3;
12014
12015
0
      else if (LocaleCompare(value,"3") == 0)
12016
0
        mng_info->compression_level = 4;
12017
12018
0
      else if (LocaleCompare(value,"4") == 0)
12019
0
        mng_info->compression_level = 5;
12020
12021
0
      else if (LocaleCompare(value,"5") == 0)
12022
0
        mng_info->compression_level = 6;
12023
12024
0
      else if (LocaleCompare(value,"6") == 0)
12025
0
        mng_info->compression_level = 7;
12026
12027
0
      else if (LocaleCompare(value,"7") == 0)
12028
0
        mng_info->compression_level = 8;
12029
12030
0
      else if (LocaleCompare(value,"8") == 0)
12031
0
        mng_info->compression_level = 9;
12032
12033
0
      else if (LocaleCompare(value,"9") == 0)
12034
0
        mng_info->compression_level = 10;
12035
12036
0
      else
12037
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
12038
0
          "ignoring invalid defined png:compression-level","=%s",value);
12039
0
    }
12040
12041
1.96k
  value=GetImageOption(image_info,"png:compression-strategy");
12042
1.96k
  if (value == NULL)
12043
1.96k
     value=GetImageArtifact(image,"png:compression-strategy");
12044
1.96k
  if (value != NULL)
12045
0
  {
12046
0
      if (LocaleCompare(value,"0") == 0)
12047
0
        mng_info->compression_strategy = Z_DEFAULT_STRATEGY+1;
12048
12049
0
      else if (LocaleCompare(value,"1") == 0)
12050
0
        mng_info->compression_strategy = Z_FILTERED+1;
12051
12052
0
      else if (LocaleCompare(value,"2") == 0)
12053
0
        mng_info->compression_strategy = Z_HUFFMAN_ONLY+1;
12054
12055
0
      else if (LocaleCompare(value,"3") == 0)
12056
0
#ifdef Z_RLE  /* Z_RLE was added to zlib-1.2.0 */
12057
0
        mng_info->compression_strategy = Z_RLE+1;
12058
#else
12059
        mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
12060
#endif
12061
12062
0
      else if (LocaleCompare(value,"4") == 0)
12063
0
#ifdef Z_FIXED  /* Z_FIXED was added to zlib-1.2.2.2 */
12064
0
        mng_info->compression_strategy = Z_FIXED+1;
12065
#else
12066
        mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
12067
#endif
12068
12069
0
      else
12070
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
12071
0
          "ignoring invalid defined png:compression-strategy","=%s",value);
12072
0
    }
12073
12074
1.96k
  value=GetImageOption(image_info,"png:compression-filter");
12075
1.96k
  if (value == NULL)
12076
1.96k
     value=GetImageArtifact(image,"png:compression-filter");
12077
1.96k
  if (value != NULL)
12078
0
  {
12079
      /* To do: combinations of filters allowed by libpng
12080
       * masks 0x08 through 0xf8
12081
       *
12082
       * Implement this as a comma-separated list of 0,1,2,3,4,5
12083
       * where 5 is a special case meaning PNG_ALL_FILTERS.
12084
       */
12085
12086
0
      mng_info->compression_filter = StringToUnsignedLong(value)+1;
12087
0
      if (mng_info->compression_filter > 6)
12088
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
12089
0
          "ignoring invalid defined png:compression-filter","=%s",value);
12090
0
  }
12091
12092
17.6k
  for (source=0; source<8; source++)
12093
15.7k
  {
12094
15.7k
    value = (const char *) NULL;
12095
12096
15.7k
    switch(source)
12097
15.7k
    {
12098
1.96k
      case 0:
12099
1.96k
        value=GetImageOption(image_info,"png:exclude-chunks");
12100
1.96k
        break;
12101
1.96k
      case 1:
12102
1.96k
        value=GetImageArtifact(image,"png:exclude-chunks");
12103
1.96k
        break;
12104
1.96k
      case 2:
12105
1.96k
        value=GetImageOption(image_info,"png:exclude-chunk");
12106
1.96k
        break;
12107
1.96k
      case 3:
12108
1.96k
        value=GetImageArtifact(image,"png:exclude-chunk");
12109
1.96k
        break;
12110
1.96k
      case 4:
12111
1.96k
        value=GetImageOption(image_info,"png:include-chunks");
12112
1.96k
        break;
12113
1.96k
      case 5:
12114
1.96k
        value=GetImageArtifact(image,"png:include-chunks");
12115
1.96k
        break;
12116
1.96k
      case 6:
12117
1.96k
        value=GetImageOption(image_info,"png:include-chunk");
12118
1.96k
        break;
12119
1.96k
      case 7:
12120
1.96k
        value=GetImageArtifact(image,"png:include-chunk");
12121
1.96k
        break;
12122
15.7k
    }
12123
12124
15.7k
    if (value == NULL)
12125
15.7k
       continue;
12126
12127
0
    if (source < 4)
12128
0
      excluding = MagickTrue;
12129
0
    else
12130
0
      excluding = MagickFalse;
12131
12132
0
    if (logging != MagickFalse)
12133
0
      {
12134
0
        if (source == 0 || source == 2)
12135
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12136
0
              "  png:exclude-chunk=%s found in image options.\n", value);
12137
0
        else if (source == 1 || source == 3)
12138
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12139
0
              "  png:exclude-chunk=%s found in image artifacts.\n", value);
12140
0
        else if (source == 4 || source == 6)
12141
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12142
0
              "  png:include-chunk=%s found in image options.\n", value);
12143
0
        else /* if (source == 5 || source == 7) */
12144
0
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12145
0
              "  png:include-chunk=%s found in image artifacts.\n", value);
12146
0
      }
12147
12148
0
    if (IsOptionMember("all",value) != MagickFalse)
12149
0
      {
12150
0
        mng_info->exclude_bKGD=excluding;
12151
0
        mng_info->exclude_caNv=excluding;
12152
0
        mng_info->exclude_cHRM=excluding;
12153
0
        mng_info->exclude_date=excluding;
12154
0
        mng_info->exclude_EXIF=excluding;
12155
0
        mng_info->exclude_eXIf=excluding;
12156
0
        mng_info->exclude_gAMA=excluding;
12157
0
        mng_info->exclude_iCCP=excluding;
12158
0
        mng_info->exclude_oFFs=excluding;
12159
0
        mng_info->exclude_pHYs=excluding;
12160
0
        mng_info->exclude_sRGB=excluding;
12161
0
        mng_info->exclude_tEXt=excluding;
12162
0
        mng_info->exclude_tIME=excluding;
12163
0
        mng_info->exclude_tRNS=excluding;
12164
0
        mng_info->exclude_zCCP=excluding;
12165
0
        mng_info->exclude_zTXt=excluding;
12166
0
      }
12167
12168
0
    if (IsOptionMember("none",value) != MagickFalse)
12169
0
      {
12170
0
        mng_info->exclude_bKGD=excluding != MagickFalse ? MagickFalse :
12171
0
          MagickTrue;
12172
0
        mng_info->exclude_caNv=excluding != MagickFalse ? MagickFalse :
12173
0
          MagickTrue;
12174
0
        mng_info->exclude_cHRM=excluding != MagickFalse ? MagickFalse :
12175
0
          MagickTrue;
12176
0
        mng_info->exclude_date=excluding != MagickFalse ? MagickFalse :
12177
0
          MagickTrue;
12178
0
        mng_info->exclude_eXIf=excluding != MagickFalse ? MagickFalse :
12179
0
          MagickTrue;
12180
0
        mng_info->exclude_EXIF=excluding != MagickFalse ? MagickFalse :
12181
0
          MagickTrue;
12182
0
        mng_info->exclude_gAMA=excluding != MagickFalse ? MagickFalse :
12183
0
          MagickTrue;
12184
0
        mng_info->exclude_iCCP=excluding != MagickFalse ? MagickFalse :
12185
0
          MagickTrue;
12186
0
        mng_info->exclude_oFFs=excluding != MagickFalse ? MagickFalse :
12187
0
          MagickTrue;
12188
0
        mng_info->exclude_pHYs=excluding != MagickFalse ? MagickFalse :
12189
0
          MagickTrue;
12190
0
        mng_info->exclude_sRGB=excluding != MagickFalse ? MagickFalse :
12191
0
          MagickTrue;
12192
0
        mng_info->exclude_tEXt=excluding != MagickFalse ? MagickFalse :
12193
0
          MagickTrue;
12194
0
        mng_info->exclude_tIME=excluding != MagickFalse ? MagickFalse :
12195
0
          MagickTrue;
12196
0
        mng_info->exclude_tRNS=excluding != MagickFalse ? MagickFalse :
12197
0
          MagickTrue;
12198
0
        mng_info->exclude_zCCP=excluding != MagickFalse ? MagickFalse :
12199
0
          MagickTrue;
12200
0
        mng_info->exclude_zTXt=excluding != MagickFalse ? MagickFalse :
12201
0
          MagickTrue;
12202
0
      }
12203
12204
0
    if (IsOptionMember("bkgd",value) != MagickFalse)
12205
0
      mng_info->exclude_bKGD=excluding;
12206
12207
0
    if (IsOptionMember("caNv",value) != MagickFalse)
12208
0
      mng_info->exclude_caNv=excluding;
12209
12210
0
    if (IsOptionMember("chrm",value) != MagickFalse)
12211
0
      mng_info->exclude_cHRM=excluding;
12212
12213
0
    if (IsOptionMember("date",value) != MagickFalse)
12214
0
      mng_info->exclude_date=excluding;
12215
12216
0
    if (IsOptionMember("exif",value) != MagickFalse)
12217
0
      {
12218
0
        mng_info->exclude_EXIF=excluding;
12219
0
        mng_info->exclude_eXIf=excluding;
12220
0
      }
12221
12222
0
    if (IsOptionMember("gama",value) != MagickFalse)
12223
0
      mng_info->exclude_gAMA=excluding;
12224
12225
0
    if (IsOptionMember("iccp",value) != MagickFalse)
12226
0
      mng_info->exclude_iCCP=excluding;
12227
12228
0
    if (IsOptionMember("offs",value) != MagickFalse)
12229
0
      mng_info->exclude_oFFs=excluding;
12230
12231
0
    if (IsOptionMember("phys",value) != MagickFalse)
12232
0
      mng_info->exclude_pHYs=excluding;
12233
12234
0
    if (IsOptionMember("srgb",value) != MagickFalse)
12235
0
      mng_info->exclude_sRGB=excluding;
12236
12237
0
    if (IsOptionMember("text",value) != MagickFalse)
12238
0
      mng_info->exclude_tEXt=excluding;
12239
12240
0
    if (IsOptionMember("time",value) != MagickFalse)
12241
0
      mng_info->exclude_tIME=excluding;
12242
12243
0
    if (IsOptionMember("trns",value) != MagickFalse)
12244
0
      mng_info->exclude_tRNS=excluding;
12245
12246
0
    if (IsOptionMember("zccp",value) != MagickFalse)
12247
0
      mng_info->exclude_zCCP=excluding;
12248
12249
0
    if (IsOptionMember("ztxt",value) != MagickFalse)
12250
0
      mng_info->exclude_zTXt=excluding;
12251
0
  }
12252
12253
1.96k
  if (logging != MagickFalse)
12254
0
  {
12255
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12256
0
      "  Chunks to be excluded from the output png:");
12257
0
    if (mng_info->exclude_bKGD != MagickFalse)
12258
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12259
0
          "    bKGD");
12260
0
    if (mng_info->exclude_caNv != MagickFalse)
12261
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12262
0
          "    caNv");
12263
0
    if (mng_info->exclude_cHRM != MagickFalse)
12264
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12265
0
          "    cHRM");
12266
0
    if (mng_info->exclude_date != MagickFalse)
12267
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12268
0
          "    date");
12269
0
    if (mng_info->exclude_EXIF != MagickFalse)
12270
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12271
0
          "    EXIF");
12272
0
    if (mng_info->exclude_eXIf != MagickFalse)
12273
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12274
0
          "    eXIf");
12275
0
    if (mng_info->exclude_gAMA != MagickFalse)
12276
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12277
0
          "    gAMA");
12278
0
    if (mng_info->exclude_iCCP != MagickFalse)
12279
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12280
0
          "    iCCP");
12281
0
    if (mng_info->exclude_oFFs != MagickFalse)
12282
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12283
0
          "    oFFs");
12284
0
    if (mng_info->exclude_pHYs != MagickFalse)
12285
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12286
0
          "    pHYs");
12287
0
    if (mng_info->exclude_sRGB != MagickFalse)
12288
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12289
0
          "    sRGB");
12290
0
    if (mng_info->exclude_tEXt != MagickFalse)
12291
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12292
0
          "    tEXt");
12293
0
    if (mng_info->exclude_tIME != MagickFalse)
12294
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12295
0
          "    tIME");
12296
0
    if (mng_info->exclude_tRNS != MagickFalse)
12297
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12298
0
          "    tRNS");
12299
0
    if (mng_info->exclude_zCCP != MagickFalse)
12300
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12301
0
          "    zCCP");
12302
0
    if (mng_info->exclude_zTXt != MagickFalse)
12303
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12304
0
          "    zTXt");
12305
0
  }
12306
12307
1.96k
  mng_info->need_blob = MagickTrue;
12308
12309
1.96k
  status=WriteOnePNGImage(mng_info,image_info,image,exception);
12310
12311
1.96k
  mng_info=(MngWriteInfo *) RelinquishMagickMemory(mng_info);
12312
12313
1.96k
  if (logging != MagickFalse)
12314
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
12315
12316
1.96k
  return(status);
12317
1.96k
}
12318
12319
#if defined(JNG_SUPPORTED)
12320
12321
/* Write one JNG image */
12322
static MagickBooleanType WriteOneJNGImage(MngWriteInfo *mng_info,
12323
   const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12324
0
{
12325
0
  Image
12326
0
    *jpeg_image;
12327
12328
0
  ImageInfo
12329
0
    *jpeg_image_info;
12330
12331
0
  MagickBooleanType
12332
0
    logging = MagickFalse,
12333
0
    status;
12334
12335
0
  size_t
12336
0
    length;
12337
12338
0
  unsigned char
12339
0
    *blob,
12340
0
    chunk[80],
12341
0
    *p;
12342
12343
0
  unsigned int
12344
0
    jng_alpha_compression_method,
12345
0
    jng_alpha_sample_depth,
12346
0
    jng_color_type,
12347
0
    transparent;
12348
12349
0
  size_t
12350
0
    jng_alpha_quality,
12351
0
    jng_quality;
12352
12353
0
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12354
0
    "  Enter WriteOneJNGImage()");
12355
12356
0
  if ((image->columns > 65500U) || (image->rows > 65500U))
12357
0
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
12358
12359
0
  blob=(unsigned char *) NULL;
12360
0
  jpeg_image=(Image *) NULL;
12361
0
  jpeg_image_info=(ImageInfo *) NULL;
12362
0
  length=0;
12363
12364
0
  status=MagickTrue;
12365
0
  transparent=image_info->type==GrayscaleAlphaType ||
12366
0
     image_info->type==TrueColorAlphaType ||
12367
0
     image->alpha_trait != UndefinedPixelTrait;
12368
12369
0
  jng_alpha_sample_depth = 0;
12370
12371
0
  jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12372
12373
0
  jng_alpha_compression_method=(image->compression==JPEGCompression ||
12374
0
    image_info->compression==JPEGCompression) ? 8 : 0;
12375
12376
0
  jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12377
0
      image_info->quality;
12378
12379
0
  if (jng_alpha_quality >= 1000)
12380
0
    jng_alpha_quality /= 1000;
12381
12382
0
  length=0;
12383
12384
0
  if (transparent != 0)
12385
0
    {
12386
0
      jng_color_type=14;
12387
12388
      /* Create JPEG blob, image, and image_info */
12389
0
      if (logging != MagickFalse)
12390
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12391
0
          "  Creating jpeg_image_info for alpha.");
12392
12393
0
      jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12394
12395
0
      if (jpeg_image_info == (ImageInfo *) NULL)
12396
0
        {
12397
0
          jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12398
0
          ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12399
0
        }
12400
12401
0
      if (logging != MagickFalse)
12402
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12403
0
          "  Creating jpeg_image.");
12404
12405
0
      jpeg_image=SeparateImage(image,AlphaChannel,exception);
12406
0
      if (jpeg_image == (Image *) NULL)
12407
0
        {
12408
0
          jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12409
0
          ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12410
0
        }
12411
0
      (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
12412
0
      jpeg_image->alpha_trait=UndefinedPixelTrait;
12413
0
      jpeg_image->quality=jng_alpha_quality;
12414
0
      jpeg_image_info->type=GrayscaleType;
12415
0
      (void) SetImageType(jpeg_image,GrayscaleType,exception);
12416
0
      (void) AcquireUniqueFilename(jpeg_image->filename);
12417
0
      (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,
12418
0
        "%s",jpeg_image->filename);
12419
0
    }
12420
0
  else
12421
0
    {
12422
0
      jng_alpha_compression_method=0;
12423
0
      jng_color_type=10;
12424
0
      jng_alpha_sample_depth=0;
12425
0
    }
12426
12427
  /* To do: check bit depth of PNG alpha channel */
12428
12429
  /* Check if image is grayscale. */
12430
0
  if ((image_info->type != TrueColorAlphaType) &&
12431
0
      (image_info->type != TrueColorType))
12432
0
    {
12433
0
      if (IdentifyImageCoderGray(image,exception) != MagickFalse)
12434
0
        jng_color_type-=2;
12435
0
    }
12436
12437
0
  if (logging != MagickFalse)
12438
0
    {
12439
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12440
0
          "    JNG Quality           = %d",(int) jng_quality);
12441
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12442
0
          "    JNG Color Type        = %d",jng_color_type);
12443
0
        if (transparent != 0)
12444
0
          {
12445
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12446
0
              "    JNG Alpha Compression = %d",jng_alpha_compression_method);
12447
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12448
0
              "    JNG Alpha Depth       = %d",jng_alpha_sample_depth);
12449
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12450
0
              "    JNG Alpha Quality     = %d",(int) jng_alpha_quality);
12451
0
          }
12452
0
    }
12453
12454
0
  if (transparent != 0)
12455
0
    {
12456
0
      if (jng_alpha_compression_method==0)
12457
0
        {
12458
0
          const char
12459
0
            *value;
12460
          /* Encode alpha as a grayscale PNG blob */
12461
0
          status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12462
0
            exception);
12463
0
          if (status == MagickFalse)
12464
0
            {
12465
0
              jpeg_image=DestroyImage(jpeg_image);
12466
0
              jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12467
0
              ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12468
0
            }
12469
12470
0
          if (logging != MagickFalse)
12471
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12472
0
              "  Creating PNG blob.");
12473
12474
0
          (void) CopyMagickString(jpeg_image_info->magick,"PNG",
12475
0
             MagickPathExtent);
12476
0
          (void) CopyMagickString(jpeg_image->magick,"PNG",MagickPathExtent);
12477
0
          jpeg_image_info->interlace=NoInterlace;
12478
12479
          /* Exclude all ancillary chunks */
12480
0
          (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12481
12482
0
          blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,
12483
0
            &length,exception);
12484
12485
0
          if (blob == (unsigned char *) NULL)
12486
0
            {
12487
0
              jpeg_image=DestroyImage(jpeg_image);
12488
0
              jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12489
0
              return(MagickFalse);
12490
0
            }
12491
12492
          /* Retrieve sample depth used */
12493
0
          value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12494
0
          if (value != (char *) NULL)
12495
0
            jng_alpha_sample_depth= (unsigned int) value[0];
12496
0
        }
12497
0
      else
12498
0
        {
12499
          /* Encode alpha as a grayscale JPEG blob */
12500
12501
0
          status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12502
0
            exception);
12503
0
          if (status == MagickFalse)
12504
0
            {
12505
0
              jpeg_image=DestroyImage(jpeg_image);
12506
0
              jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12507
0
              ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12508
0
            }
12509
12510
0
          (void) CopyMagickString(jpeg_image_info->magick,"JPEG",
12511
0
            MagickPathExtent);
12512
0
          (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
12513
0
          jpeg_image_info->interlace=NoInterlace;
12514
0
          if (logging != MagickFalse)
12515
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12516
0
              "  Creating blob.");
12517
0
          blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,
12518
0
            &length,exception);
12519
0
          if (blob == (unsigned char *) NULL)
12520
0
            {
12521
0
              jpeg_image=DestroyImage(jpeg_image);
12522
0
              jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12523
0
              return(MagickFalse);
12524
0
            }
12525
0
          jng_alpha_sample_depth=8;
12526
12527
0
          if (logging != MagickFalse)
12528
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12529
0
              "  Successfully read jpeg_image into a blob, length=%.17g.",
12530
0
              (double) length);
12531
12532
0
        }
12533
      /* Destroy JPEG image and image_info */
12534
0
      jpeg_image=DestroyImage(jpeg_image);
12535
0
      (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12536
0
      jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12537
0
    }
12538
12539
  /* Write JHDR chunk */
12540
0
  (void) WriteBlobMSBULong(image,16L);  /* chunk data length=16 */
12541
0
  PNGType(chunk,mng_JHDR);
12542
0
  LogPNGChunk(logging,mng_JHDR,16L);
12543
0
  PNGLong(chunk+4,(png_uint_32) image->columns);
12544
0
  PNGLong(chunk+8,(png_uint_32) image->rows);
12545
0
  chunk[12]=(unsigned char) jng_color_type;
12546
0
  chunk[13]=8;  /* sample depth */
12547
0
  chunk[14]=8; /*jng_image_compression_method */
12548
0
  chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12549
0
  chunk[16]=(unsigned char) jng_alpha_sample_depth;
12550
0
  chunk[17]=(unsigned char) jng_alpha_compression_method;
12551
0
  chunk[18]=0; /*jng_alpha_filter_method */
12552
0
  chunk[19]=0; /*jng_alpha_interlace_method */
12553
0
  (void) WriteBlob(image,20,chunk);
12554
0
  (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12555
0
  if (logging != MagickFalse)
12556
0
    {
12557
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12558
0
        "    JNG width:%15lu",(unsigned long) image->columns);
12559
12560
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12561
0
        "    JNG height:%14lu",(unsigned long) image->rows);
12562
12563
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12564
0
        "    JNG color type:%10d",jng_color_type);
12565
12566
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12567
0
        "    JNG sample depth:%8d",8);
12568
12569
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12570
0
        "    JNG compression:%9d",8);
12571
12572
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12573
0
        "    JNG interlace:%11d",0);
12574
12575
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12576
0
        "    JNG alpha depth:%9d",jng_alpha_sample_depth);
12577
12578
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12579
0
        "    JNG alpha compression:%3d",jng_alpha_compression_method);
12580
12581
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12582
0
        "    JNG alpha filter:%8d",0);
12583
12584
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12585
0
        "    JNG alpha interlace:%5d",0);
12586
0
    }
12587
12588
  /*
12589
     Write leading ancillary chunks
12590
  */
12591
12592
0
  if (transparent != 0)
12593
0
  {
12594
    /*
12595
      Write JNG bKGD chunk
12596
    */
12597
12598
0
    unsigned char
12599
0
      blue,
12600
0
      green,
12601
0
      red;
12602
12603
0
    ssize_t
12604
0
      num_bytes;
12605
12606
0
    if (jng_color_type == 8 || jng_color_type == 12)
12607
0
      num_bytes=6L;
12608
0
    else
12609
0
      num_bytes=10L;
12610
0
    (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12611
0
    PNGType(chunk,mng_bKGD);
12612
0
    LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12613
0
    red=ScaleQuantumToChar((Quantum) image->background_color.red);
12614
0
    green=ScaleQuantumToChar((Quantum) image->background_color.green);
12615
0
    blue=ScaleQuantumToChar((Quantum) image->background_color.blue);
12616
0
    *(chunk+4)=0;
12617
0
    *(chunk+5)=red;
12618
0
    *(chunk+6)=0;
12619
0
    *(chunk+7)=green;
12620
0
    *(chunk+8)=0;
12621
0
    *(chunk+9)=blue;
12622
0
    (void) WriteBlob(image,(size_t) num_bytes,chunk);
12623
0
    (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12624
0
  }
12625
12626
0
  if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12627
0
    {
12628
      /*
12629
        Write JNG sRGB chunk
12630
      */
12631
0
      (void) WriteBlobMSBULong(image,1L);
12632
0
      PNGType(chunk,mng_sRGB);
12633
0
      LogPNGChunk(logging,mng_sRGB,1L);
12634
12635
0
      if (image->rendering_intent != UndefinedIntent)
12636
0
        chunk[4]=(unsigned char)
12637
0
          Magick_RenderingIntent_to_PNG_RenderingIntent(
12638
0
          (image->rendering_intent));
12639
12640
0
      else
12641
0
        chunk[4]=(unsigned char)
12642
0
          Magick_RenderingIntent_to_PNG_RenderingIntent(
12643
0
          (PerceptualIntent));
12644
12645
0
      (void) WriteBlob(image,5,chunk);
12646
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12647
0
    }
12648
0
  else
12649
0
    {
12650
0
      if (image->gamma != 0.0)
12651
0
        {
12652
          /*
12653
             Write JNG gAMA chunk
12654
          */
12655
0
          (void) WriteBlobMSBULong(image,4L);
12656
0
          PNGType(chunk,mng_gAMA);
12657
0
          LogPNGChunk(logging,mng_gAMA,4L);
12658
0
          PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12659
0
          (void) WriteBlob(image,8,chunk);
12660
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12661
0
        }
12662
12663
0
      if ((mng_info->equal_chrms == MagickFalse) &&
12664
0
          (image->chromaticity.red_primary.x != 0.0))
12665
0
        {
12666
0
          PrimaryInfo
12667
0
            primary;
12668
12669
          /*
12670
             Write JNG cHRM chunk
12671
          */
12672
0
          (void) WriteBlobMSBULong(image,32L);
12673
0
          PNGType(chunk,mng_cHRM);
12674
0
          LogPNGChunk(logging,mng_cHRM,32L);
12675
0
          primary=image->chromaticity.white_point;
12676
0
          PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12677
0
          PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12678
0
          primary=image->chromaticity.red_primary;
12679
0
          PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12680
0
          PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12681
0
          primary=image->chromaticity.green_primary;
12682
0
          PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12683
0
          PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12684
0
          primary=image->chromaticity.blue_primary;
12685
0
          PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12686
0
          PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12687
0
          (void) WriteBlob(image,36,chunk);
12688
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12689
0
        }
12690
0
    }
12691
12692
0
  if (image->resolution.x && image->resolution.y &&
12693
0
      mng_info->equal_physs == MagickFalse)
12694
0
    {
12695
      /*
12696
         Write JNG pHYs chunk
12697
      */
12698
0
      (void) WriteBlobMSBULong(image,9L);
12699
0
      PNGType(chunk,mng_pHYs);
12700
0
      LogPNGChunk(logging,mng_pHYs,9L);
12701
0
      if (image->units == PixelsPerInchResolution)
12702
0
        {
12703
0
          PNGLong(chunk+4,(png_uint_32)
12704
0
            (image->resolution.x*100.0/2.54+0.5));
12705
12706
0
          PNGLong(chunk+8,(png_uint_32)
12707
0
            (image->resolution.y*100.0/2.54+0.5));
12708
12709
0
          chunk[12]=1;
12710
0
        }
12711
12712
0
      else
12713
0
        {
12714
0
          if (image->units == PixelsPerCentimeterResolution)
12715
0
            {
12716
0
              PNGLong(chunk+4,(png_uint_32)
12717
0
                (image->resolution.x*100.0+0.5));
12718
12719
0
              PNGLong(chunk+8,(png_uint_32)
12720
0
                (image->resolution.y*100.0+0.5));
12721
12722
0
              chunk[12]=1;
12723
0
            }
12724
12725
0
          else
12726
0
            {
12727
0
              PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12728
0
              PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12729
0
              chunk[12]=0;
12730
0
            }
12731
0
        }
12732
0
      (void) WriteBlob(image,13,chunk);
12733
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12734
0
    }
12735
12736
0
  if ((mng_info->write_mng == MagickFalse) && (image->page.x || image->page.y))
12737
0
    {
12738
      /*
12739
         Write JNG oFFs chunk
12740
      */
12741
0
      (void) WriteBlobMSBULong(image,9L);
12742
0
      PNGType(chunk,mng_oFFs);
12743
0
      LogPNGChunk(logging,mng_oFFs,9L);
12744
0
      PNGsLong(chunk+4,(png_int_32) (image->page.x));
12745
0
      PNGsLong(chunk+8,(png_int_32) (image->page.y));
12746
0
      chunk[12]=0;
12747
0
      (void) WriteBlob(image,13,chunk);
12748
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12749
0
    }
12750
12751
0
  if (transparent != 0)
12752
0
    {
12753
0
      if (jng_alpha_compression_method==0)
12754
0
        {
12755
0
          ssize_t
12756
0
            i;
12757
12758
0
          size_t
12759
0
            len;
12760
12761
          /* Write IDAT chunk header */
12762
0
          if (logging != MagickFalse)
12763
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12764
0
              "  Write IDAT chunks from blob, length=%.17g.",(double)
12765
0
              length);
12766
12767
          /* Copy IDAT chunks */
12768
0
          len=0;
12769
0
          p=blob+8;
12770
0
          for (i=8; i<(ssize_t) length; i+=(ssize_t) len+12)
12771
0
          {
12772
0
            len=(((unsigned int) *(p    ) & 0xff) << 24) +
12773
0
                (((unsigned int) *(p + 1) & 0xff) << 16) +
12774
0
                (((unsigned int) *(p + 2) & 0xff) <<  8) +
12775
0
                (((unsigned int) *(p + 3) & 0xff)      ) ;
12776
0
            p+=(ptrdiff_t) 4;
12777
12778
0
            if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12779
0
              {
12780
                /* Found an IDAT chunk. */
12781
0
                (void) WriteBlobMSBULong(image,len);
12782
0
                LogPNGChunk(logging,mng_IDAT,len);
12783
0
                (void) WriteBlob(image,len+4,p);
12784
0
                (void) WriteBlobMSBULong(image, crc32(0,p,(uInt) len+4));
12785
0
              }
12786
12787
0
            else
12788
0
              {
12789
0
                if (logging != MagickFalse)
12790
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12791
0
                    "    Skipping %c%c%c%c chunk, length=%.17g.",
12792
0
                    *(p),*(p+1),*(p+2),*(p+3),(double) len);
12793
0
              }
12794
0
            p+=(ptrdiff_t) (8+len);
12795
0
          }
12796
0
        }
12797
0
      else if (length != 0)
12798
0
        {
12799
          /* Write JDAA chunk header */
12800
0
          if (logging != MagickFalse)
12801
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12802
0
              "  Write JDAA chunk, length=%.17g.",(double) length);
12803
0
          (void) WriteBlobMSBULong(image,(size_t) length);
12804
0
          PNGType(chunk,mng_JDAA);
12805
0
          LogPNGChunk(logging,mng_JDAA,length);
12806
          /* Write JDAT chunk(s) data */
12807
0
          (void) WriteBlob(image,4,chunk);
12808
0
          (void) WriteBlob(image,length,blob);
12809
0
          (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12810
0
             (uInt) length));
12811
0
        }
12812
0
      blob=(unsigned char *) RelinquishMagickMemory(blob);
12813
0
    }
12814
12815
  /* Encode image as a JPEG blob */
12816
0
  if (logging != MagickFalse)
12817
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12818
0
      "  Creating jpeg_image_info.");
12819
0
  jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12820
0
  if (jpeg_image_info == (ImageInfo *) NULL)
12821
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12822
12823
0
  if (logging != MagickFalse)
12824
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12825
0
      "  Creating jpeg_image.");
12826
12827
0
  jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12828
0
  if (jpeg_image == (Image *) NULL)
12829
0
    {
12830
0
      jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12831
0
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12832
0
    }
12833
0
  (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
12834
12835
0
  (void) AcquireUniqueFilename(jpeg_image->filename);
12836
0
  (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,"%s",
12837
0
    jpeg_image->filename);
12838
12839
0
  status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12840
0
    exception);
12841
12842
0
  if (logging != MagickFalse)
12843
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12844
0
      "  Created jpeg_image, %.17g x %.17g.",(double) jpeg_image->columns,
12845
0
      (double) jpeg_image->rows);
12846
12847
0
  if (status == MagickFalse)
12848
0
    {
12849
0
      jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12850
0
      jpeg_image=DestroyImage(jpeg_image);
12851
0
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12852
0
    }
12853
12854
0
  if (jng_color_type == 8 || jng_color_type == 12)
12855
0
    jpeg_image_info->type=GrayscaleType;
12856
12857
0
  jpeg_image_info->quality=jng_quality;
12858
0
  jpeg_image->quality=jng_quality;
12859
0
  (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent);
12860
0
  (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
12861
12862
0
  if (logging != MagickFalse)
12863
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12864
0
      "  Creating blob.");
12865
12866
0
  blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
12867
0
    exception);
12868
12869
0
  if (blob == (unsigned char *) NULL)
12870
0
    {
12871
0
      jpeg_image=DestroyImage(jpeg_image);
12872
0
      jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12873
0
      return(MagickFalse);
12874
0
    }
12875
12876
0
  if (logging != MagickFalse)
12877
0
    {
12878
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12879
0
        "  Successfully read jpeg_image into a blob, length=%.17g.",
12880
0
        (double) length);
12881
12882
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12883
0
        "  Write JDAT chunk, length=%.17g.",(double) length);
12884
0
    }
12885
12886
  /* Write JDAT chunk(s) */
12887
0
  (void) WriteBlobMSBULong(image,(size_t) length);
12888
0
  PNGType(chunk,mng_JDAT);
12889
0
  LogPNGChunk(logging,mng_JDAT,length);
12890
0
  (void) WriteBlob(image,4,chunk);
12891
0
  (void) WriteBlob(image,length,blob);
12892
0
  (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12893
12894
0
  jpeg_image=DestroyImage(jpeg_image);
12895
0
  (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12896
0
  jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12897
0
  blob=(unsigned char *) RelinquishMagickMemory(blob);
12898
12899
  /* Write IEND chunk */
12900
0
  (void) WriteBlobMSBULong(image,0L);
12901
0
  PNGType(chunk,mng_IEND);
12902
0
  LogPNGChunk(logging,mng_IEND,0);
12903
0
  (void) WriteBlob(image,4,chunk);
12904
0
  (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12905
12906
0
  if (logging != MagickFalse)
12907
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12908
0
      "  exit WriteOneJNGImage()");
12909
12910
0
  return(status);
12911
0
}
12912
12913
/*
12914
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12915
%                                                                             %
12916
%                                                                             %
12917
%                                                                             %
12918
%   W r i t e J N G I m a g e                                                 %
12919
%                                                                             %
12920
%                                                                             %
12921
%                                                                             %
12922
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12923
%
12924
%  WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12925
%
12926
%  JNG support written by Glenn Randers-Pehrson, glennrp@image...
12927
%
12928
%  The format of the WriteJNGImage method is:
12929
%
12930
%      MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12931
%        Image *image,ExceptionInfo *exception)
12932
%
12933
%  A description of each parameter follows:
12934
%
12935
%    o image_info: the image info.
12936
%
12937
%    o image:  The image.
12938
%
12939
%    o exception: return any errors or warnings in this structure.
12940
%
12941
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12942
*/
12943
static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12944
  ExceptionInfo *exception)
12945
0
{
12946
0
  MagickBooleanType
12947
0
    logging = MagickFalse,
12948
0
    status;
12949
12950
0
  MngWriteInfo
12951
0
    *mng_info;
12952
12953
  /*
12954
    Open image file.
12955
  */
12956
0
  assert(image_info != (const ImageInfo *) NULL);
12957
0
  assert(image_info->signature == MagickCoreSignature);
12958
0
  assert(image != (Image *) NULL);
12959
0
  assert(image->signature == MagickCoreSignature);
12960
0
  if (IsEventLogging() != MagickFalse)
12961
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12962
0
  if (image->debug != MagickFalse)
12963
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12964
0
      "Enter WriteJNGImage()");
12965
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12966
0
  if (status == MagickFalse)
12967
0
    return(status);
12968
0
  if ((image->columns > 65535UL) || (image->rows > 65535UL))
12969
0
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
12970
0
  mng_info=(MngWriteInfo *) AcquireMagickMemory(sizeof(*mng_info));
12971
0
  if (mng_info == (MngWriteInfo *) NULL)
12972
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12973
0
  (void) memset(mng_info,0,sizeof(*mng_info));
12974
0
  mng_info->image=image;
12975
12976
0
  (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12977
12978
0
  status=WriteOneJNGImage(mng_info,image_info,image,exception);
12979
12980
0
  mng_info=(MngWriteInfo *) RelinquishMagickMemory(mng_info);
12981
12982
0
  (void) CloseBlob(image);
12983
12984
0
  (void) CatchImageException(image);
12985
0
  if (logging != MagickFalse)
12986
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12987
0
  return(status);
12988
0
}
12989
#endif
12990
12991
static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12992
311
{
12993
311
  Image
12994
311
    *next_image;
12995
12996
311
  MagickBooleanType
12997
311
    status,
12998
311
    write_jng,
12999
311
    write_mng;
13000
13001
311
  volatile MagickBooleanType
13002
311
    logging = MagickFalse;
13003
13004
311
  MngWriteInfo
13005
311
    *mng_info;
13006
13007
311
  int
13008
311
    image_count,
13009
311
    need_iterations,
13010
311
    need_matte;
13011
13012
311
  volatile int
13013
311
    need_local_plte,
13014
311
    all_images_are_gray,
13015
311
    use_global_plte;
13016
13017
311
  unsigned char
13018
311
    chunk[800];
13019
13020
311
  volatile size_t
13021
311
    scene;
13022
13023
311
  size_t
13024
311
    final_delay=0,
13025
311
    number_scenes,
13026
311
    initial_delay;
13027
13028
  /*
13029
    Open image file.
13030
  */
13031
311
  assert(image_info != (const ImageInfo *) NULL);
13032
311
  assert(image_info->signature == MagickCoreSignature);
13033
311
  assert(image != (Image *) NULL);
13034
311
  assert(image->signature == MagickCoreSignature);
13035
311
  if (IsEventLogging() != MagickFalse)
13036
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13037
311
  if (image->debug != MagickFalse)
13038
0
    logging=LogMagickEvent(CoderEvent,GetMagickModule(),
13039
0
      "Enter WriteMNGImage()");
13040
311
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
13041
311
  if (status == MagickFalse)
13042
0
    return(status);
13043
311
  mng_info=(MngWriteInfo *) AcquireMagickMemory(sizeof(*mng_info));
13044
311
  if (mng_info == (MngWriteInfo *) NULL)
13045
311
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
13046
311
  (void) memset(mng_info,0,sizeof(*mng_info));
13047
311
  mng_info->image=image;
13048
311
  write_mng=LocaleCompare(image_info->magick,"MNG") == 0 ?
13049
311
    MagickTrue : MagickFalse;
13050
  /*
13051
   * See if user has requested a specific PNG subformat to be used
13052
   * for all of the PNGs in the MNG being written, e.g.,
13053
   *
13054
   *    convert *.png png8:animation.mng
13055
   *
13056
   * To do: check -define png:bit_depth and png:color_type as well,
13057
   * or perhaps use mng:bit_depth and mng:color_type instead for
13058
   * global settings.
13059
   */
13060
13061
311
  mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0 ?
13062
311
    MagickTrue : MagickFalse;
13063
311
  mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0 ?
13064
311
    MagickTrue : MagickFalse;
13065
311
  mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0 ?
13066
311
    MagickTrue : MagickFalse;
13067
13068
311
  write_jng=MagickFalse;
13069
311
  if (image_info->compression == JPEGCompression)
13070
0
    write_jng=MagickTrue;
13071
13072
311
  mng_info->adjoin=(image_info->adjoin != MagickFalse) &&
13073
311
    (write_mng != MagickFalse) &&
13074
311
    (GetNextImageInList(image) != (Image *) NULL) ?
13075
311
    MagickTrue : MagickFalse;
13076
13077
311
  if (logging != MagickFalse)
13078
0
    {
13079
      /* Log some info about the input */
13080
0
      Image
13081
0
        *p;
13082
13083
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13084
0
        "  Checking input image(s)\n"
13085
0
        "    Image_info depth: %.17g,    Type: %d",
13086
0
        (double) image_info->depth, image_info->type);
13087
13088
0
      scene=0;
13089
0
      for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
13090
0
      {
13091
13092
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13093
0
           "    Scene: %.17g\n,   Image depth: %.17g",
13094
0
           (double) scene, (double) p->depth);
13095
0
        scene+=1;
13096
13097
0
        if (p->alpha_trait != UndefinedPixelTrait)
13098
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13099
0
            "      Matte: True");
13100
13101
0
        else
13102
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13103
0
            "      Matte: False");
13104
13105
0
        if (p->storage_class == PseudoClass)
13106
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13107
0
            "      Storage class: PseudoClass");
13108
13109
0
        else
13110
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13111
0
            "      Storage class: DirectClass");
13112
13113
0
        if (p->colors)
13114
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13115
0
            "      Number of colors: %.17g",(double) p->colors);
13116
13117
0
        else
13118
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13119
0
            "      Number of colors: unspecified");
13120
13121
0
        if (mng_info->adjoin == MagickFalse)
13122
0
          break;
13123
0
      }
13124
0
    }
13125
13126
311
  use_global_plte=MagickFalse;
13127
311
  all_images_are_gray=MagickFalse;
13128
311
  need_local_plte=MagickTrue;
13129
311
  mng_info->need_defi=MagickFalse;
13130
311
  need_matte=MagickFalse;
13131
311
  mng_info->framing_mode=1;
13132
311
  mng_info->old_framing_mode=1;
13133
13134
311
  if (write_mng != MagickFalse)
13135
311
    {
13136
311
      unsigned int
13137
311
        need_geom;
13138
13139
311
      unsigned short
13140
311
        red,
13141
311
        green,
13142
311
        blue;
13143
13144
311
      const char *
13145
311
        option;
13146
13147
311
      if (image_info->page != (char *) NULL)
13148
0
        {
13149
          /*
13150
            Determine image bounding box.
13151
          */
13152
0
          SetGeometry(image,&mng_info->page);
13153
0
          (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
13154
0
            &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
13155
0
        }
13156
311
      mng_info->page=image->page;
13157
311
      need_geom=MagickTrue;
13158
311
      if (mng_info->page.width || mng_info->page.height)
13159
311
         need_geom=MagickFalse;
13160
      /*
13161
        Check all the scenes.
13162
      */
13163
311
      initial_delay=image->delay;
13164
311
      need_iterations=MagickFalse;
13165
311
      mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0 ?
13166
311
        MagickTrue : MagickFalse;
13167
311
      mng_info->equal_physs=MagickTrue,
13168
311
      mng_info->equal_gammas=MagickTrue;
13169
311
      mng_info->equal_srgbs=MagickTrue;
13170
311
      mng_info->equal_backgrounds=MagickTrue;
13171
311
      image_count=0;
13172
311
      all_images_are_gray=MagickTrue;
13173
311
      mng_info->equal_palettes=MagickFalse;
13174
311
      need_local_plte=MagickTrue;
13175
622
      for (next_image=image; next_image != (Image *) NULL; )
13176
311
      {
13177
311
        if (need_geom)
13178
0
          {
13179
0
            if ((next_image->columns+(size_t) next_image->page.x) > mng_info->page.width)
13180
0
              mng_info->page.width=next_image->columns+(size_t) next_image->page.x;
13181
13182
0
            if ((next_image->rows+(size_t) next_image->page.y) > mng_info->page.height)
13183
0
              mng_info->page.height=next_image->rows+(size_t) next_image->page.y;
13184
0
          }
13185
13186
311
        if (next_image->page.x || next_image->page.y)
13187
0
          mng_info->need_defi=MagickTrue;
13188
13189
311
        if (next_image->alpha_trait != UndefinedPixelTrait)
13190
0
          need_matte=MagickTrue;
13191
13192
311
        if ((int) next_image->dispose >= BackgroundDispose)
13193
311
          if ((next_image->alpha_trait != UndefinedPixelTrait) ||
13194
311
               next_image->page.x || next_image->page.y ||
13195
311
              ((next_image->columns < mng_info->page.width) &&
13196
0
               (next_image->rows < mng_info->page.height)))
13197
0
            mng_info->need_fram=MagickTrue;
13198
13199
311
        if (next_image->iterations)
13200
309
          need_iterations=MagickTrue;
13201
13202
311
        final_delay=next_image->delay;
13203
13204
311
        if (final_delay != initial_delay || (ssize_t) final_delay > 
13205
311
           next_image->ticks_per_second)
13206
31
          mng_info->need_fram=MagickTrue;
13207
13208
        /*
13209
          check for global palette possibility.
13210
        */
13211
311
        if (image->alpha_trait != UndefinedPixelTrait)
13212
0
           need_local_plte=MagickTrue;
13213
13214
311
        if (need_local_plte == 0)
13215
0
          {
13216
0
            if (IdentifyImageCoderGray(image,exception) == MagickFalse)
13217
0
              all_images_are_gray=MagickFalse;
13218
0
            mng_info->equal_palettes=PalettesAreEqual(image,next_image);
13219
0
            if (use_global_plte == 0)
13220
0
              use_global_plte=(int) mng_info->equal_palettes;
13221
0
            need_local_plte=!mng_info->equal_palettes;
13222
0
          }
13223
311
        if (GetNextImageInList(next_image) != (Image *) NULL)
13224
0
          {
13225
0
            if (next_image->background_color.red !=
13226
0
                next_image->next->background_color.red ||
13227
0
                next_image->background_color.green !=
13228
0
                next_image->next->background_color.green ||
13229
0
                next_image->background_color.blue !=
13230
0
                next_image->next->background_color.blue)
13231
0
              mng_info->equal_backgrounds=MagickFalse;
13232
13233
0
            if (next_image->gamma != next_image->next->gamma)
13234
0
              mng_info->equal_gammas=MagickFalse;
13235
13236
0
            if (next_image->rendering_intent !=
13237
0
                next_image->next->rendering_intent)
13238
0
              mng_info->equal_srgbs=MagickFalse;
13239
13240
0
            if ((next_image->units != next_image->next->units) ||
13241
0
                (next_image->resolution.x != next_image->next->resolution.x) ||
13242
0
                (next_image->resolution.y != next_image->next->resolution.y))
13243
0
              mng_info->equal_physs=MagickFalse;
13244
13245
0
            if (mng_info->equal_chrms != MagickFalse)
13246
0
              {
13247
0
                if (next_image->chromaticity.red_primary.x !=
13248
0
                    next_image->next->chromaticity.red_primary.x ||
13249
0
                    next_image->chromaticity.red_primary.y !=
13250
0
                    next_image->next->chromaticity.red_primary.y ||
13251
0
                    next_image->chromaticity.green_primary.x !=
13252
0
                    next_image->next->chromaticity.green_primary.x ||
13253
0
                    next_image->chromaticity.green_primary.y !=
13254
0
                    next_image->next->chromaticity.green_primary.y ||
13255
0
                    next_image->chromaticity.blue_primary.x !=
13256
0
                    next_image->next->chromaticity.blue_primary.x ||
13257
0
                    next_image->chromaticity.blue_primary.y !=
13258
0
                    next_image->next->chromaticity.blue_primary.y ||
13259
0
                    next_image->chromaticity.white_point.x !=
13260
0
                    next_image->next->chromaticity.white_point.x ||
13261
0
                    next_image->chromaticity.white_point.y !=
13262
0
                    next_image->next->chromaticity.white_point.y)
13263
0
                  mng_info->equal_chrms=MagickFalse;
13264
0
              }
13265
0
          }
13266
311
        image_count++;
13267
311
        next_image=GetNextImageInList(next_image);
13268
311
      }
13269
311
      if (image_count < 2)
13270
311
        {
13271
311
          mng_info->equal_backgrounds=MagickFalse;
13272
311
          mng_info->equal_chrms=MagickFalse;
13273
311
          mng_info->equal_gammas=MagickFalse;
13274
311
          mng_info->equal_srgbs=MagickFalse;
13275
311
          mng_info->equal_physs=MagickFalse;
13276
311
          use_global_plte=MagickFalse;
13277
311
          need_local_plte=MagickTrue;
13278
311
          need_iterations=MagickFalse;
13279
311
        }
13280
13281
311
     if (mng_info->need_fram == MagickFalse)
13282
280
       {
13283
         /*
13284
           Only certain framing rates 100/n are exactly representable without
13285
           the FRAM chunk but we'll allow some slop in VLC files
13286
         */
13287
280
         if (final_delay == 0)
13288
239
           {
13289
239
             if (need_iterations != MagickFalse)
13290
0
               {
13291
                 /*
13292
                   It's probably a GIF with loop; don't run it *too* fast.
13293
                 */
13294
0
                 if (mng_info->adjoin != MagickFalse)
13295
0
                   {
13296
0
                     final_delay=10;
13297
0
                     (void) ThrowMagickException(exception,GetMagickModule(),
13298
0
                       CoderWarning,
13299
0
                       "input has zero delay between all frames; assuming",
13300
0
                       " 10 cs `%s'","");
13301
0
                   }
13302
0
               }
13303
239
             else
13304
239
               mng_info->ticks_per_second=0;
13305
239
           }
13306
280
         if (final_delay != 0)
13307
41
           mng_info->ticks_per_second=(png_uint_32)
13308
41
              image->ticks_per_second/(png_uint_32) final_delay;
13309
280
         if (final_delay > 50)
13310
13
           mng_info->ticks_per_second=2;
13311
13312
280
         if (final_delay > 75)
13313
11
           mng_info->ticks_per_second=1;
13314
13315
280
         if (final_delay > 125)
13316
0
           mng_info->need_fram=MagickTrue;
13317
13318
280
         if (mng_info->need_defi && final_delay > 2 && (final_delay != 4) &&
13319
0
            (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
13320
0
            (final_delay != 25) && (final_delay != 50) &&
13321
0
            (final_delay != (size_t) image->ticks_per_second))
13322
0
           mng_info->need_fram=MagickTrue;  /* make it exact; cannot be VLC */
13323
280
       }
13324
13325
311
     if (mng_info->need_fram != MagickFalse)
13326
31
        mng_info->ticks_per_second=(unsigned long) image->ticks_per_second;
13327
     /*
13328
        If pseudocolor, we should also check to see if all the
13329
        palettes are identical and write a global PLTE if they are.
13330
        ../glennrp Feb 99.
13331
     */
13332
     /*
13333
        Write the MNG version 1.0 signature and MHDR chunk.
13334
     */
13335
311
     (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
13336
311
     (void) WriteBlobMSBULong(image,28L);  /* chunk data length=28 */
13337
311
     PNGType(chunk,mng_MHDR);
13338
311
     LogPNGChunk(logging,mng_MHDR,28L);
13339
311
     PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
13340
311
     PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
13341
311
     PNGLong(chunk+12,mng_info->ticks_per_second);
13342
311
     PNGLong(chunk+16,0L);  /* layer count=unknown */
13343
311
     PNGLong(chunk+20,0L);  /* frame count=unknown */
13344
311
     PNGLong(chunk+24,0L);  /* play time=unknown   */
13345
311
     if (write_jng != MagickFalse)
13346
0
       {
13347
0
         if (need_matte)
13348
0
           {
13349
0
             if (mng_info->need_defi || mng_info->need_fram != MagickFalse || use_global_plte)
13350
0
               PNGLong(chunk+28,27L);    /* simplicity=LC+JNG */
13351
13352
0
             else
13353
0
               PNGLong(chunk+28,25L);    /* simplicity=VLC+JNG */
13354
0
           }
13355
13356
0
         else
13357
0
           {
13358
0
             if (mng_info->need_defi || mng_info->need_fram != MagickFalse || use_global_plte)
13359
0
               PNGLong(chunk+28,19L);  /* simplicity=LC+JNG, no transparency */
13360
13361
0
             else
13362
0
               PNGLong(chunk+28,17L);  /* simplicity=VLC+JNG, no transparency */
13363
0
           }
13364
0
       }
13365
13366
311
     else
13367
311
       {
13368
311
         if (need_matte)
13369
0
           {
13370
0
             if (mng_info->need_defi || mng_info->need_fram != MagickFalse || use_global_plte)
13371
0
               PNGLong(chunk+28,11L);    /* simplicity=LC */
13372
13373
0
             else
13374
0
               PNGLong(chunk+28,9L);    /* simplicity=VLC */
13375
0
           }
13376
13377
311
         else
13378
311
           {
13379
311
             if (mng_info->need_defi || mng_info->need_fram != MagickFalse || use_global_plte)
13380
31
               PNGLong(chunk+28,3L);    /* simplicity=LC, no transparency */
13381
13382
280
             else
13383
280
               PNGLong(chunk+28,1L);    /* simplicity=VLC, no transparency */
13384
311
           }
13385
311
       }
13386
311
     (void) WriteBlob(image,32,chunk);
13387
311
     (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13388
311
     option=GetImageOption(image_info,"mng:need-cacheoff");
13389
311
     if (option != (const char *) NULL)
13390
0
       {
13391
0
         size_t
13392
0
           length;
13393
         /*
13394
           Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13395
         */
13396
0
         PNGType(chunk,mng_nEED);
13397
0
         length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13398
0
         (void) WriteBlobMSBULong(image,(size_t) length);
13399
0
         LogPNGChunk(logging,mng_nEED,(size_t) length);
13400
0
         length+=4;
13401
0
         (void) WriteBlob(image,length,chunk);
13402
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13403
0
       }
13404
311
     if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13405
311
         (GetNextImageInList(image) != (Image *) NULL) &&
13406
0
         (image->iterations != 1))
13407
0
       {
13408
         /*
13409
           Write MNG TERM chunk
13410
         */
13411
0
         (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
13412
0
         PNGType(chunk,mng_TERM);
13413
0
         LogPNGChunk(logging,mng_TERM,10L);
13414
0
         chunk[4]=3;  /* repeat animation */
13415
0
         chunk[5]=0;  /* show last frame when done */
13416
0
         PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13417
0
            final_delay/(size_t) MagickMax(image->ticks_per_second,1)));
13418
13419
0
         if (image->iterations == 0)
13420
0
           PNGLong(chunk+10,PNG_UINT_31_MAX);
13421
13422
0
         else
13423
0
           PNGLong(chunk+10,(png_uint_32) image->iterations);
13424
13425
0
         if (logging != MagickFalse)
13426
0
           {
13427
0
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13428
0
               "     TERM delay: %.17g",(double) (mng_info->ticks_per_second*
13429
0
              final_delay/(size_t) MagickMax(image->ticks_per_second,1)));
13430
13431
0
             if (image->iterations == 0)
13432
0
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13433
0
                 "     TERM iterations: %.17g",(double) PNG_UINT_31_MAX);
13434
13435
0
             else
13436
0
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13437
0
                 "     Image iterations: %.17g",(double) image->iterations);
13438
0
           }
13439
0
         (void) WriteBlob(image,14,chunk);
13440
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13441
0
       }
13442
     /*
13443
       To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13444
     */
13445
311
     if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13446
311
          mng_info->equal_srgbs != MagickFalse)
13447
0
       {
13448
         /*
13449
           Write MNG sRGB chunk
13450
         */
13451
0
         (void) WriteBlobMSBULong(image,1L);
13452
0
         PNGType(chunk,mng_sRGB);
13453
0
         LogPNGChunk(logging,mng_sRGB,1L);
13454
13455
0
         if (image->rendering_intent != UndefinedIntent)
13456
0
           chunk[4]=(unsigned char)
13457
0
             Magick_RenderingIntent_to_PNG_RenderingIntent(
13458
0
             (image->rendering_intent));
13459
13460
0
         else
13461
0
           chunk[4]=(unsigned char)
13462
0
             Magick_RenderingIntent_to_PNG_RenderingIntent(
13463
0
               (PerceptualIntent));
13464
13465
0
         (void) WriteBlob(image,5,chunk);
13466
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13467
0
         mng_info->have_global_srgb=MagickTrue;
13468
0
       }
13469
13470
311
     else
13471
311
       {
13472
311
         if (image->gamma && mng_info->equal_gammas != MagickFalse)
13473
0
           {
13474
             /*
13475
                Write MNG gAMA chunk
13476
             */
13477
0
             (void) WriteBlobMSBULong(image,4L);
13478
0
             PNGType(chunk,mng_gAMA);
13479
0
             LogPNGChunk(logging,mng_gAMA,4L);
13480
0
             PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13481
0
             (void) WriteBlob(image,8,chunk);
13482
0
             (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13483
0
             mng_info->have_global_gama=MagickTrue;
13484
0
           }
13485
311
         if (mng_info->equal_chrms != MagickFalse)
13486
0
           {
13487
0
             PrimaryInfo
13488
0
               primary;
13489
13490
             /*
13491
                Write MNG cHRM chunk
13492
             */
13493
0
             (void) WriteBlobMSBULong(image,32L);
13494
0
             PNGType(chunk,mng_cHRM);
13495
0
             LogPNGChunk(logging,mng_cHRM,32L);
13496
0
             primary=image->chromaticity.white_point;
13497
0
             PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13498
0
             PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13499
0
             primary=image->chromaticity.red_primary;
13500
0
             PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13501
0
             PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13502
0
             primary=image->chromaticity.green_primary;
13503
0
             PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13504
0
             PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13505
0
             primary=image->chromaticity.blue_primary;
13506
0
             PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13507
0
             PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13508
0
             (void) WriteBlob(image,36,chunk);
13509
0
             (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13510
0
             mng_info->have_global_chrm=MagickTrue;
13511
0
           }
13512
311
       }
13513
311
     if (image->resolution.x && image->resolution.y &&
13514
0
         mng_info->equal_physs == MagickFalse)
13515
0
       {
13516
         /*
13517
            Write MNG pHYs chunk
13518
         */
13519
0
         (void) WriteBlobMSBULong(image,9L);
13520
0
         PNGType(chunk,mng_pHYs);
13521
0
         LogPNGChunk(logging,mng_pHYs,9L);
13522
13523
0
         if (image->units == PixelsPerInchResolution)
13524
0
           {
13525
0
             PNGLong(chunk+4,(png_uint_32)
13526
0
               (image->resolution.x*100.0/2.54+0.5));
13527
13528
0
             PNGLong(chunk+8,(png_uint_32)
13529
0
               (image->resolution.y*100.0/2.54+0.5));
13530
13531
0
             chunk[12]=1;
13532
0
           }
13533
13534
0
         else
13535
0
           {
13536
0
             if (image->units == PixelsPerCentimeterResolution)
13537
0
               {
13538
0
                 PNGLong(chunk+4,(png_uint_32)
13539
0
                   (image->resolution.x*100.0+0.5));
13540
13541
0
                 PNGLong(chunk+8,(png_uint_32)
13542
0
                   (image->resolution.y*100.0+0.5));
13543
13544
0
                 chunk[12]=1;
13545
0
               }
13546
13547
0
             else
13548
0
               {
13549
0
                 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13550
0
                 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13551
0
                 chunk[12]=0;
13552
0
               }
13553
0
           }
13554
0
         (void) WriteBlob(image,13,chunk);
13555
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13556
0
       }
13557
     /*
13558
       Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13559
       or does not cover the entire frame.
13560
     */
13561
311
     if ((write_mng != MagickFalse) && ((image->alpha_trait != UndefinedPixelTrait) ||
13562
311
         image->page.x > 0 || image->page.y > 0 || (image->page.width &&
13563
311
         ((ssize_t) image->page.width+image->page.x < (ssize_t) mng_info->page.width))
13564
311
         || (image->page.height && ((ssize_t) image->page.height+image->page.y
13565
311
         < (ssize_t) mng_info->page.height))))
13566
0
       {
13567
0
         (void) WriteBlobMSBULong(image,6L);
13568
0
         PNGType(chunk,mng_BACK);
13569
0
         LogPNGChunk(logging,mng_BACK,6L);
13570
0
         red=ScaleQuantumToShort((Quantum) image->background_color.red);
13571
0
         green=ScaleQuantumToShort((Quantum) image->background_color.green);
13572
0
         blue=ScaleQuantumToShort((Quantum) image->background_color.blue);
13573
0
         PNGShort(chunk+4,red);
13574
0
         PNGShort(chunk+6,green);
13575
0
         PNGShort(chunk+8,blue);
13576
0
         (void) WriteBlob(image,10,chunk);
13577
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13578
0
         if (mng_info->equal_backgrounds != MagickFalse)
13579
0
           {
13580
0
             (void) WriteBlobMSBULong(image,6L);
13581
0
             PNGType(chunk,mng_bKGD);
13582
0
             LogPNGChunk(logging,mng_bKGD,6L);
13583
0
             (void) WriteBlob(image,10,chunk);
13584
0
             (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13585
0
           }
13586
0
       }
13587
13588
311
     if ((need_local_plte == MagickFalse) &&
13589
0
         (image->storage_class == PseudoClass) &&
13590
0
         (all_images_are_gray == MagickFalse) && (image->colors <= 256))
13591
0
       {
13592
0
         size_t
13593
0
           data_length;
13594
13595
0
         ssize_t
13596
0
           i;
13597
13598
         /*
13599
           Write MNG PLTE chunk
13600
         */
13601
0
         data_length=3*image->colors;
13602
0
         (void) WriteBlobMSBULong(image,data_length);
13603
0
         PNGType(chunk,mng_PLTE);
13604
0
         LogPNGChunk(logging,mng_PLTE,data_length);
13605
13606
0
         for (i=0; i < (ssize_t) image->colors; i++)
13607
0
         {
13608
0
           chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13609
0
             (Quantum) image->colormap[i].red) & 0xff);
13610
0
           chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13611
0
             (Quantum) image->colormap[i].green) & 0xff);
13612
0
           chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13613
0
             (Quantum) image->colormap[i].blue) & 0xff);
13614
0
         }
13615
13616
0
         (void) WriteBlob(image,data_length+4,chunk);
13617
0
         (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13618
0
         mng_info->have_global_plte=MagickTrue;
13619
0
       }
13620
311
    }
13621
311
  scene=0;
13622
311
  mng_info->delay=0;
13623
311
  mng_info->equal_palettes=MagickFalse;
13624
311
  number_scenes=GetImageListLength(image);
13625
311
  do
13626
311
  {
13627
311
    if (mng_info->adjoin != MagickFalse)
13628
0
    {
13629
    /*
13630
      If we aren't using a global palette for the entire MNG, check to
13631
      see if we can use one for two or more consecutive images.
13632
    */
13633
0
    if (need_local_plte && use_global_plte && !all_images_are_gray)
13634
0
      {
13635
0
        if (mng_info->is_palette != MagickFalse)
13636
0
          {
13637
            /*
13638
              When equal_palettes is true, this image has the same palette
13639
              as the previous PseudoClass image
13640
            */
13641
0
            mng_info->have_global_plte=mng_info->equal_palettes;
13642
0
            mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13643
0
            if ((mng_info->equal_palettes && !mng_info->have_global_plte) &&
13644
0
                (image->colors <= 256))
13645
0
              {
13646
                /*
13647
                  Write MNG PLTE chunk
13648
                */
13649
0
                size_t
13650
0
                  data_length;
13651
13652
0
                ssize_t
13653
0
                  i;
13654
13655
0
                data_length=3*image->colors;
13656
0
                (void) WriteBlobMSBULong(image,data_length);
13657
0
                PNGType(chunk,mng_PLTE);
13658
0
                LogPNGChunk(logging,mng_PLTE,data_length);
13659
13660
0
                for (i=0; i < (ssize_t) image->colors; i++)
13661
0
                {
13662
0
                  chunk[4+i*3]=ScaleQuantumToChar((Quantum) image->colormap[i].red);
13663
0
                  chunk[5+i*3]=ScaleQuantumToChar((Quantum) image->colormap[i].green);
13664
0
                  chunk[6+i*3]=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
13665
0
                }
13666
13667
0
                (void) WriteBlob(image,data_length+4,chunk);
13668
0
                (void) WriteBlobMSBULong(image,crc32(0,chunk,
13669
0
                   (uInt) (data_length+4)));
13670
0
                mng_info->have_global_plte=MagickTrue;
13671
0
              }
13672
0
          }
13673
0
        else
13674
0
          mng_info->have_global_plte=MagickFalse;
13675
0
      }
13676
0
    if (mng_info->need_defi)
13677
0
      {
13678
0
        ssize_t
13679
0
          previous_x,
13680
0
          previous_y;
13681
13682
0
        if (scene != 0)
13683
0
          {
13684
0
            previous_x=mng_info->page.x;
13685
0
            previous_y=mng_info->page.y;
13686
0
          }
13687
0
        else
13688
0
          {
13689
0
            previous_x=0;
13690
0
            previous_y=0;
13691
0
          }
13692
0
        mng_info->page=image->page;
13693
0
        if ((mng_info->page.x !=  previous_x) ||
13694
0
            (mng_info->page.y != previous_y))
13695
0
          {
13696
0
             (void) WriteBlobMSBULong(image,12L);  /* data length=12 */
13697
0
             PNGType(chunk,mng_DEFI);
13698
0
             LogPNGChunk(logging,mng_DEFI,12L);
13699
0
             chunk[4]=0; /* object 0 MSB */
13700
0
             chunk[5]=0; /* object 0 LSB */
13701
0
             chunk[6]=0; /* visible  */
13702
0
             chunk[7]=0; /* abstract */
13703
0
             PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13704
0
             PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13705
0
             (void) WriteBlob(image,16,chunk);
13706
0
             (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13707
0
          }
13708
0
      }
13709
0
    }
13710
13711
311
   mng_info->write_mng=write_mng;
13712
13713
311
   if ((int) image->dispose >= BackgroundDispose)
13714
311
     mng_info->framing_mode=3;
13715
13716
311
   if (mng_info->need_fram != MagickFalse && mng_info->adjoin != MagickFalse &&
13717
0
       ((image->delay != mng_info->delay) ||
13718
0
        (mng_info->framing_mode != mng_info->old_framing_mode)))
13719
0
     {
13720
0
       if (image->delay == mng_info->delay)
13721
0
         {
13722
           /*
13723
             Write a MNG FRAM chunk with the new framing mode.
13724
           */
13725
0
           (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
13726
0
           PNGType(chunk,mng_FRAM);
13727
0
           LogPNGChunk(logging,mng_FRAM,1L);
13728
0
           chunk[4]=(unsigned char) mng_info->framing_mode;
13729
0
           (void) WriteBlob(image,5,chunk);
13730
0
           (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13731
0
         }
13732
0
       else
13733
0
         {
13734
           /*
13735
             Write a MNG FRAM chunk with the delay.
13736
           */
13737
0
           (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
13738
0
           PNGType(chunk,mng_FRAM);
13739
0
           LogPNGChunk(logging,mng_FRAM,10L);
13740
0
           chunk[4]=(unsigned char) mng_info->framing_mode;
13741
0
           chunk[5]=0;  /* frame name separator (no name) */
13742
0
           chunk[6]=2;  /* flag for changing default delay */
13743
0
           chunk[7]=0;  /* flag for changing frame timeout */
13744
0
           chunk[8]=0;  /* flag for changing frame clipping */
13745
0
           chunk[9]=0;  /* flag for changing frame sync_id */
13746
0
           PNGLong(chunk+10,(png_uint_32) ((mng_info->ticks_per_second*
13747
0
             image->delay)/(size_t) MagickMax(image->ticks_per_second,1)));
13748
0
           (void) WriteBlob(image,14,chunk);
13749
0
           (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13750
0
           mng_info->delay=(png_uint_32) image->delay;
13751
0
         }
13752
0
       mng_info->old_framing_mode=mng_info->framing_mode;
13753
0
     }
13754
13755
311
#if defined(JNG_SUPPORTED)
13756
311
   if (image_info->compression == JPEGCompression)
13757
0
     {
13758
0
       ImageInfo
13759
0
         *write_info;
13760
13761
0
       if (logging != MagickFalse)
13762
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13763
0
           "  Writing JNG object.");
13764
       /* To do: specify the desired alpha compression method. */
13765
0
       write_info=CloneImageInfo(image_info);
13766
0
       write_info->compression=UndefinedCompression;
13767
0
       status=WriteOneJNGImage(mng_info,write_info,image,exception);
13768
0
       write_info=DestroyImageInfo(write_info);
13769
0
     }
13770
311
   else
13771
311
#endif
13772
311
     {
13773
311
       if (logging != MagickFalse)
13774
0
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13775
0
           "  Writing PNG object.");
13776
13777
311
       mng_info->need_blob = MagickFalse;
13778
311
       mng_info->preserve_colormap = MagickFalse;
13779
13780
       /* We don't want any ancillary chunks written */
13781
311
       mng_info->exclude_bKGD=MagickTrue;
13782
311
       mng_info->exclude_caNv=MagickTrue;
13783
311
       mng_info->exclude_cHRM=MagickTrue;
13784
311
       mng_info->exclude_date=MagickTrue;
13785
311
       mng_info->exclude_EXIF=MagickTrue;
13786
311
       mng_info->exclude_gAMA=MagickTrue;
13787
311
       mng_info->exclude_iCCP=MagickTrue;
13788
311
       mng_info->exclude_oFFs=MagickTrue;
13789
311
       mng_info->exclude_pHYs=MagickTrue;
13790
311
       mng_info->exclude_sRGB=MagickTrue;
13791
311
       mng_info->exclude_tEXt=MagickTrue;
13792
311
       mng_info->exclude_tRNS=MagickTrue;
13793
311
       mng_info->exclude_zCCP=MagickTrue;
13794
311
       mng_info->exclude_zTXt=MagickTrue;
13795
13796
311
       status=WriteOnePNGImage(mng_info,image_info,image,exception);
13797
311
     }
13798
13799
311
    if (status == MagickFalse)
13800
0
      {
13801
0
        (void) CloseBlob(image);
13802
0
        mng_info=(MngWriteInfo *) RelinquishMagickMemory(mng_info);
13803
0
        return(MagickFalse);
13804
0
      }
13805
311
    (void) CatchImageException(image);
13806
311
    if (GetNextImageInList(image) == (Image *) NULL)
13807
311
      break;
13808
0
    image=SyncNextImageInList(image);
13809
0
    status=SetImageProgress(image,SaveImagesTag,(MagickOffsetType) scene,
13810
0
      number_scenes);
13811
0
    scene+=1;
13812
13813
0
    if (status == MagickFalse)
13814
0
      break;
13815
13816
0
  } while (mng_info->adjoin != MagickFalse);
13817
13818
311
  if (write_mng != MagickFalse)
13819
311
    {
13820
      /*
13821
        Write the MEND chunk.
13822
      */
13823
311
      (void) WriteBlobMSBULong(mng_info->image,0x00000000L);
13824
311
      PNGType(chunk,mng_MEND);
13825
311
      LogPNGChunk(logging,mng_MEND,0L);
13826
311
      (void) WriteBlob(mng_info->image,4,chunk);
13827
311
      (void) WriteBlobMSBULong(mng_info->image,crc32(0,chunk,4));
13828
311
    }
13829
  /*
13830
    Relinquish resources.
13831
  */
13832
311
  (void) CloseBlob(mng_info->image);
13833
311
  mng_info=(MngWriteInfo *) RelinquishMagickMemory(mng_info);
13834
13835
311
  if (logging != MagickFalse)
13836
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13837
13838
311
  return(MagickTrue);
13839
311
}
13840
#endif