Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/png.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            PPPP   N   N   GGGG                              %
15
%                            P   P  NN  N  G                                  %
16
%                            PPPP   N N N  G  GG                              %
17
%                            P      N  NN  G   G                              %
18
%                            P      N   N   GGG                               %
19
%                                                                             %
20
%                                                                             %
21
%             Read/Write Portable Network Graphics Image Format.              %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                           Glenn Randers-Pehrson                             %
27
%                               November 1997                                 %
28
%                                                                             %
29
%                                                                             %
30
%                                                                             %
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32
%
33
%
34
*/
35

36
/* GraphicsMagick differences */
37
38
#if !defined(RGBColorMatchExact)
39
/* Similar to ColorMatch() but with value argument rather than pointer */
40
#define RGBColorMatchExact(color,target) \
41
57.4k
   (((color).red == (target).red) && \
42
57.4k
    ((color).green == (target).green) && \
43
57.4k
    ((color).blue == (target).blue))
44
#endif /* if !defined(RGBColorMatchExact) */
45
46
/*
47
  Include declarations.
48
*/
49
#include "magick/studio.h"
50
#include "magick/analyze.h"
51
#include "magick/attribute.h"
52
#include "magick/blob.h"
53
#include "magick/channel.h"
54
#include "magick/color.h"
55
#include "magick/colormap.h"
56
#include "magick/constitute.h"
57
#include "magick/enhance.h"
58
#include "magick/log.h"
59
#include "magick/magick.h"
60
#include "magick/monitor.h"
61
#include "magick/pixel_cache.h"
62
#include "magick/profile.h"
63
#include "magick/quantize.h"
64
#include "magick/resource.h"
65
#include "magick/semaphore.h"
66
#include "magick/static.h"
67
#include "magick/tempfile.h"
68
#include "magick/transform.h"
69
#include "magick/utility.h"
70
#include "magick/version.h"
71
#include "magick/static.h"
72
#if defined(HasPNG)
73
74
/* Suppress libpng pedantic warnings */
75
#define PNG_DEPRECATED  /* Use of this function is deprecated */
76
#define PNG_USE_RESULT  /* The result of this function must be checked */
77
#define PNG_NORETURN    /* This function does not return */
78
/* #define PNG_ALLOCATED */ /* The result of the function is new memory */
79
#define PNG_DEPSTRUCT   /* access to this struct member is deprecated */
80
81
#include "png.h"
82
#include "zlib.h"
83
#if defined(HasLCMS)
84
#  if defined(HAVE_LCMS2_LCMS2_H)
85
#    include <lcms2/lcms2.h>
86
#  elif defined(HAVE_LCMS2_H)
87
#    include <lcms2.h>
88
#  else
89
#    error "LCMS 2 header missing!"
90
#  endif
91
#endif
92

93
94
#if PNG_LIBPNG_VER > 10011
95
/*
96
  Optional declarations. Define or undefine them as you like.
97
*/
98
99
/* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
100
101
/*
102
  Features under construction.  Define these to work on them.
103
*/
104
#undef MNG_OBJECT_BUFFERS
105
#undef MNG_BASI_SUPPORTED
106
#define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
107
#define MNG_INSERT_LAYERS   /* Troublesome, but seem to work as of 5.4.4 */
108
#define GMPNG_BUILD_PALETTE   /* This works as of 5.4.3. */
109
#if defined(HasJPEG)
110
#  define JNG_SUPPORTED /* Not finished as of 5.5.2.  See "To do" comments. */
111
#endif
112
113
/*
114
  Establish thread safety.
115
  setjmp/longjmp is claimed to be safe on these platforms:
116
  setjmp/longjmp is alleged to be unsafe on these platforms:
117
*/
118
#ifdef PNG_SETJMP_SUPPORTED
119
# ifndef SETJMP_IS_THREAD_SAFE
120
#   define GMPNG_SETJMP_NOT_THREAD_SAFE
121
# endif
122
123
# if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
124
static SemaphoreInfo
125
  *png_semaphore = (SemaphoreInfo *) NULL;
126
# endif
127
#endif
128
129
/*
130
  This is temporary until I set up malloc'ed object attributes array.
131
  Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
132
  waste more memory.
133
*/
134
395M
#define MNG_MAX_OBJECTS 256
135
136
/*
137
  If this is not defined, spec is interpreted strictly.  If it is
138
  defined, an attempt will be made to recover from some errors,
139
  including
140
      o global PLTE too short
141
*/
142
#undef MNG_LOOSE
143
144
/*
145
  Don't try to define PNG_MNG_FEATURES_SUPPORTED here.  Make sure
146
  it's defined in libpng/pngconf.h, version 1.0.9 or later.  It won't work
147
  with earlier versions of libpng.  From libpng-1.0.3a to libpng-1.0.8,
148
  PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
149
  libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
150
  PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
151
  will be enabled by default in libpng-1.2.0.
152
*/
153
#ifdef PNG_MNG_FEATURES_SUPPORTED
154
#  ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
155
#    define PNG_READ_EMPTY_PLTE_SUPPORTED
156
#  endif
157
#  ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
158
#    define PNG_WRITE_EMPTY_PLTE_SUPPORTED
159
#  endif
160
#endif
161
162
/*
163
  Maximum valid unsigned long in PNG/MNG chunks is (2^31)-1
164
  This macro is only defined in libpng-1.0.3a and later.
165
*/
166
#ifndef PNG_MAX_UINT
167
136M
#define PNG_MAX_UINT (png_uint_32) 0x7fffffffL
168
#endif
169
170
/*
171
  Constant strings for known chunk types.  If you need to add a chunk,
172
  add a string holding the name here.   To make the code more
173
  portable, we use ASCII numbers like this, not characters.
174
*/
175
176
static png_byte const mng_MHDR[5]={ 77,  72,  68,  82, '\0'};
177
static png_byte const mng_BACK[5]={ 66,  65,  67,  75, '\0'};
178
static png_byte const mng_BASI[5]={ 66,  65,  83,  73, '\0'};
179
static png_byte const mng_CLIP[5]={ 67,  76,  73,  80, '\0'};
180
static png_byte const mng_CLON[5]={ 67,  76,  79,  78, '\0'};
181
static png_byte const mng_DEFI[5]={ 68,  69,  70,  73, '\0'};
182
static png_byte const mng_DHDR[5]={ 68,  72,  68,  82, '\0'};
183
static png_byte const mng_DISC[5]={ 68,  73,  83,  67, '\0'};
184
static png_byte const mng_ENDL[5]={ 69,  78,  68,  76, '\0'};
185
static png_byte const mng_FRAM[5]={ 70,  82,  65,  77, '\0'};
186
static png_byte const mng_IEND[5]={ 73,  69,  78,  68, '\0'};
187
static png_byte const mng_IHDR[5]={ 73,  72,  68,  82, '\0'};
188
static png_byte const mng_JHDR[5]={ 74,  72,  68,  82, '\0'};
189
static png_byte const mng_LOOP[5]={ 76,  79,  79,  80, '\0'};
190
static png_byte const mng_MAGN[5]={ 77,  65,  71,  78, '\0'};
191
static png_byte const mng_MEND[5]={ 77,  69,  78,  68, '\0'};
192
static png_byte const mng_MOVE[5]={ 77,  79,  86,  69, '\0'};
193
static png_byte const mng_PAST[5]={ 80,  65,  83,  84, '\0'};
194
static png_byte const mng_PLTE[5]={ 80,  76,  84,  69, '\0'};
195
static png_byte const mng_SAVE[5]={ 83,  65,  86,  69, '\0'};
196
static png_byte const mng_SEEK[5]={ 83,  69,  69,  75, '\0'};
197
static png_byte const mng_SHOW[5]={ 83,  72,  79,  87, '\0'};
198
static png_byte const mng_TERM[5]={ 84,  69,  82,  77, '\0'};
199
static png_byte const mng_bKGD[5]={ 98,  75,  71,  68, '\0'};
200
static png_byte const mng_caNv[5]={ 99,  97,  78, 118, '\0'};
201
static png_byte const mng_cHRM[5]={ 99,  72,  82,  77, '\0'};
202
static png_byte const mng_eXIf[5]={101,  88,  73, 102, '\0'};
203
static png_byte const mng_gAMA[5]={103,  65,  77,  65, '\0'};
204
static png_byte const mng_iCCP[5]={105,  67,  67,  80, '\0'};
205
static png_byte const mng_nEED[5]={110,  69,  69,  68, '\0'};
206
static png_byte const mng_orNT[5]={111, 114,  78,  84, '\0'};
207
static png_byte const mng_pHYg[5]={112,  72,  89, 103, '\0'};
208
static png_byte const mng_pHYs[5]={112,  72,  89, 115, '\0'};
209
static png_byte const mng_sBIT[5]={115,  66,  73,  84, '\0'};
210
static png_byte const mng_sRGB[5]={115,  82,  71,  66, '\0'};
211
static png_byte const mng_tRNS[5]={116,  82,  78,  83, '\0'};
212
213
#if defined(JNG_SUPPORTED)
214
static png_byte const mng_IDAT[5]={ 73,  68,  65,  84, '\0'};
215
static png_byte const mng_JDAT[5]={ 74,  68,  65,  84, '\0'};
216
static png_byte const mng_JDAA[5]={ 74,  68,  65,  65, '\0'};
217
static png_byte const mng_JdAA[5]={ 74, 100,  65,  65, '\0'};
218
static png_byte const mng_JSEP[5]={ 74,  83,  69,  80, '\0'};
219
static png_byte const mng_oFFs[5]={111,  70,  70, 115, '\0'};
220
#endif
221
222
/*
223
static png_byte const mng_hIST[5]={104,  73,  83,  84, '\0'};
224
static png_byte const mng_iCCP[5]={105,  67,  67,  80, '\0'};
225
static png_byte const mng_iTXt[5]={105,  84,  88, 116, '\0'};
226
static png_byte const mng_sPLT[5]={115,  80,  76,  84, '\0'};
227
static png_byte const mng_tEXt[5]={116,  69,  88, 116, '\0'};
228
static png_byte const mng_tIME[5]={116,  73,  77,  69, '\0'};
229
static png_byte const mng_zTXt[5]={122,  84,  88, 116, '\0'};
230
*/
231
232
typedef struct _UShortPixelPacket
233
{
234
  unsigned short
235
    red,
236
    green,
237
    blue,
238
    opacity,
239
    index;
240
} UShortPixelPacket;
241
242
typedef struct _MngBox
243
{
244
  long
245
    left,
246
    right,
247
    top,
248
    bottom;
249
} MngBox;
250
251
typedef struct _MngPair
252
{
253
  volatile long
254
    a,
255
    b;
256
} MngPair;
257
258
#ifdef MNG_OBJECT_BUFFERS
259
typedef struct _MngBuffer
260
{
261
262
  unsigned long
263
    height,
264
    width;
265
266
  Image
267
    *image;
268
269
  png_color
270
    plte[256];
271
272
  int
273
    reference_count;
274
275
  unsigned char
276
    alpha_sample_depth,
277
    compression_method,
278
    color_type,
279
    concrete,
280
    filter_method,
281
    frozen,
282
    image_type,
283
    interlace_method,
284
    pixel_sample_depth,
285
    plte_length,
286
    sample_depth,
287
    viewable;
288
} MngBuffer;
289
#endif
290
291
typedef struct _MngInfo
292
{
293
294
#ifdef MNG_OBJECT_BUFFERS
295
  MngBuffer
296
    *ob[MNG_MAX_OBJECTS];
297
#endif
298
299
  Image *
300
    image;
301
302
  RectangleInfo
303
    page;
304
305
  int
306
    adjoin,
307
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
308
    bytes_in_read_buffer,
309
    found_empty_plte,
310
#endif
311
    equal_backgrounds,
312
    equal_chrms,
313
    equal_gammas,
314
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
315
    defined(PNG_MNG_FEATURES_SUPPORTED)
316
    equal_palettes,
317
#endif
318
    equal_physs,
319
    equal_srgbs,
320
    framing_mode,
321
    have_global_bkgd,
322
    have_global_chrm,
323
    have_global_gama,
324
    have_global_phys,
325
    have_global_sbit,
326
    have_global_srgb,
327
    have_saved_bkgd_index,
328
    have_write_global_chrm,
329
    have_write_global_gama,
330
    have_write_global_plte,
331
    have_write_global_srgb,
332
    need_fram,
333
    object_id,
334
    old_framing_mode,
335
    saved_bkgd_index;
336
337
  int
338
    new_number_colors;
339
340
  long
341
    image_found,
342
    loop_count[256],
343
    loop_iteration[256],
344
    scenes_found,
345
    x_off[MNG_MAX_OBJECTS],
346
    y_off[MNG_MAX_OBJECTS];
347
348
  MngBox
349
    clip,
350
    frame,
351
    image_box,
352
    object_clip[MNG_MAX_OBJECTS];
353
354
  unsigned char
355
    /* These flags could be combined into one byte */
356
    exists[MNG_MAX_OBJECTS],
357
    frozen[MNG_MAX_OBJECTS],
358
    loop_active[256],
359
    invisible[MNG_MAX_OBJECTS],
360
    viewable[MNG_MAX_OBJECTS];
361
362
  ExtendedSignedIntegralType
363
    loop_jump[256];
364
365
  png_colorp
366
    global_plte;
367
368
  png_color_8
369
    global_sbit;
370
371
  png_byte
372
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
373
    read_buffer[8],
374
#endif
375
    global_trns[256];
376
377
  float
378
    global_gamma;
379
380
  ChromaticityInfo
381
    global_chrm;
382
383
  RenderingIntent
384
    global_srgb_intent;
385
386
  unsigned long
387
    delay,
388
    global_plte_length,
389
    global_trns_length,
390
    global_x_pixels_per_unit,
391
    global_y_pixels_per_unit,
392
    mng_width,
393
    mng_height,
394
    ticks_per_second;
395
396
  unsigned int
397
    IsPalette,
398
    global_phys_unit_type,
399
    basi_warning,
400
    clon_warning,
401
    dhdr_warning,
402
    jhdr_warning,
403
    magn_warning,
404
    past_warning,
405
    phyg_warning,
406
    phys_warning,
407
    sbit_warning,
408
    show_warning,
409
    mng_type,
410
    write_mng,
411
    write_png_colortype,
412
    write_png_depth,
413
    write_png8,
414
    write_png24,
415
    write_png32,
416
    write_png48,
417
    write_png64;
418
419
#ifdef MNG_BASI_SUPPORTED
420
  unsigned long
421
    basi_width,
422
    basi_height;
423
424
  unsigned int
425
    basi_depth,
426
    basi_color_type,
427
    basi_compression_method,
428
    basi_filter_type,
429
    basi_interlace_method,
430
    basi_red,
431
    basi_green,
432
    basi_blue,
433
    basi_alpha,
434
    basi_viewable;
435
#endif
436
437
  png_uint_16
438
    magn_first,
439
    magn_last,
440
    magn_mb,
441
    magn_ml,
442
    magn_mr,
443
    magn_mt,
444
    magn_mx,
445
    magn_my,
446
    magn_methx,
447
    magn_methy;
448
449
  PixelPacket
450
    mng_global_bkgd;
451
452
  unsigned char
453
    *png_pixels;
454
455
  Quantum
456
    *quantum_scanline;
457
458
} MngInfo;
459
#endif /* VER */
460

461
/*
462
  Forward declarations.
463
*/
464
static unsigned int
465
  WritePNGImage(const ImageInfo *,Image *);
466
static unsigned int
467
  WriteMNGImage(const ImageInfo *,Image *);
468
#if defined(JNG_SUPPORTED)
469
static unsigned int
470
  WriteJNGImage(const ImageInfo *,Image *);
471
#endif
472
static const char* PngColorTypeToString(const unsigned int color_type)
473
0
{
474
0
  const char
475
0
    *result = "Unknown";
476
477
0
  switch (color_type)
478
0
    {
479
0
    case PNG_COLOR_TYPE_GRAY:
480
0
      result = "Gray";
481
0
      break;
482
0
    case PNG_COLOR_TYPE_GRAY_ALPHA:
483
0
      result = "Gray+Alpha";
484
0
      break;
485
0
    case PNG_COLOR_TYPE_PALETTE:
486
0
      result = "Palette";
487
0
      break;
488
0
    case PNG_COLOR_TYPE_RGB:
489
0
      result = "RGB";
490
0
      break;
491
0
    case PNG_COLOR_TYPE_RGB_ALPHA:
492
0
      result = "RGB+Alpha";
493
0
      break;
494
0
    }
495
496
0
  return result;
497
0
}
498
#endif /* HasPNG */
499

500
/*
501
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502
%                                                                             %
503
%                                                                             %
504
%                                                                             %
505
%   I s M N G                                                                 %
506
%                                                                             %
507
%                                                                             %
508
%                                                                             %
509
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510
%
511
%  Method IsMNG returns True if the image format type, identified by the
512
%  magick string, is MNG.
513
%
514
%  The format of the IsMNG method is:
515
%
516
%      unsigned int IsMNG(const unsigned char *magick,const size_t length)
517
%
518
%  A description of each parameter follows:
519
%
520
%    o status:  Method IsMNG returns True if the image format type is MNG.
521
%
522
%    o magick: This string is generally the first few bytes of an image file
523
%      or blob.
524
%
525
%    o length: Specifies the length of the magick string.
526
%
527
%
528
*/
529
static MagickPassFail IsMNG(const unsigned char *magick,const size_t length)
530
0
{
531
0
  if (length < 8)
532
0
    return(MagickFail);
533
0
  if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
534
0
    return(MagickPass);
535
0
  return(MagickFail);
536
0
}
537

538
/*
539
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540
%                                                                             %
541
%                                                                             %
542
%                                                                             %
543
%   I s J N G                                                                 %
544
%                                                                             %
545
%                                                                             %
546
%                                                                             %
547
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548
%
549
%  Method IsJNG returns True if the image format type, identified by the
550
%  magick string, is JNG.
551
%
552
%  The format of the IsJNG method is:
553
%
554
%      unsigned int IsJNG(const unsigned char *magick,const size_t length)
555
%
556
%  A description of each parameter follows:
557
%
558
%    o status:  Method IsJNG returns True if the image format type is JNG.
559
%
560
%    o magick: This string is generally the first few bytes of an image file
561
%      or blob.
562
%
563
%    o length: Specifies the length of the magick string.
564
%
565
%
566
*/
567
static MagickPassFail IsJNG(const unsigned char *magick,const size_t length)
568
0
{
569
0
  if (length < 8)
570
0
    return(MagickFail);
571
0
  if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
572
0
    return(MagickPass);
573
0
  return(MagickFail);
574
0
}
575

576
/*
577
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578
%                                                                             %
579
%                                                                             %
580
%                                                                             %
581
%   I s P N G                                                                 %
582
%                                                                             %
583
%                                                                             %
584
%                                                                             %
585
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586
%
587
%  Method IsPNG returns True if the image format type, identified by the
588
%  magick string, is PNG.
589
%
590
%  The format of the IsPNG method is:
591
%
592
%      unsigned int IsPNG(const unsigned char *magick,const size_t length)
593
%
594
%  A description of each parameter follows:
595
%
596
%    o status:  Method IsPNG returns True if the image format type is PNG.
597
%
598
%    o magick: This string is generally the first few bytes of an image file
599
%      or blob.
600
%
601
%    o length: Specifies the length of the magick string.
602
%
603
%
604
*/
605
static MagickPassFail IsPNG(const unsigned char *magick,const size_t length)
606
0
{
607
0
  if (length < 8)
608
0
    return(MagickFail);
609
0
  if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
610
0
    return(MagickPass);
611
0
  return(MagickFail);
612
0
}
613

614
#if defined(HasPNG)
615
#if defined(__cplusplus) || defined(c_plusplus)
616
extern "C" {
617
#endif
618
619
#if (PNG_LIBPNG_VER > 10011)
620
static size_t WriteBlobMSBULong(Image *image,const unsigned long value)
621
123k
{
622
123k
  unsigned char
623
123k
    buffer[4];
624
625
123k
  assert(image != (Image *) NULL);
626
123k
  assert(image->signature == MagickSignature);
627
123k
  buffer[0]=(unsigned char) (value >> 24);
628
123k
  buffer[1]=(unsigned char) (value >> 16);
629
123k
  buffer[2]=(unsigned char) (value >> 8);
630
123k
  buffer[3]=(unsigned char) value;
631
123k
  return(WriteBlob(image,4,buffer));
632
123k
}
633
634
static void PNGLong(png_bytep p,png_uint_32 value)
635
24.2k
{
636
24.2k
  *p++=(png_byte) ((value >> 24) & 0xff);
637
24.2k
  *p++=(png_byte) ((value >> 16) & 0xff);
638
24.2k
  *p++=(png_byte) ((value >> 8) & 0xff);
639
24.2k
  *p++=(png_byte) (value & 0xff);
640
24.2k
}
641
642
static void PNGsLong(png_bytep p,png_int_32 value)
643
2.95k
{
644
2.95k
  *p++=(png_byte) ((value >> 24) & 0xff);
645
2.95k
  *p++=(png_byte) ((value >> 16) & 0xff);
646
2.95k
  *p++=(png_byte) ((value >> 8) & 0xff);
647
2.95k
  *p++=(png_byte) (value & 0xff);
648
2.95k
}
649
650
static void PNGShort(png_bytep p,png_uint_16 value)
651
0
{
652
0
  *p++=(png_byte) ((value >> 8) & 0xff);
653
0
  *p++=(png_byte) (value & 0xff);
654
0
}
655
656
static void PNGType(png_bytep p,png_byte const * type)
657
61.7k
{
658
61.7k
  (void) memcpy(p,type,4*sizeof(png_byte));
659
61.7k
}
660
661
static void LogPNGChunk(int logging, png_byte const * type, size_t length)
662
61.7k
{
663
61.7k
  if (logging)
664
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
665
0
        "  Writing %c%c%c%c chunk, length: %" MAGICK_SIZE_T_F "u",
666
0
        type[0],type[1],type[2],type[3],(MAGICK_SIZE_T) length);
667
61.7k
}
668
#endif /* PNG_LIBPNG_VER > 10011 */
669
670
#if defined(__cplusplus) || defined(c_plusplus)
671
}
672
#endif
673
674
/*
675
  Use a macro to report exceptions (rather than calling libpng's
676
  png_error()) for exceptions thrown from this module.
677
678
  This provides useful file/line information as well as allowing code
679
  analyzers to have a more accurate idea of what is going on.
680
*/
681
#undef png_error
682
#define png_error(png_ptr,error_message)                              \
683
14.7k
  do                                                                  \
684
14.7k
    {                                                                 \
685
14.7k
      Image *                                                         \
686
14.7k
        _image;                                                       \
687
14.7k
                                                                      \
688
14.7k
      _image=(Image *) png_get_error_ptr(png_ptr);                    \
689
14.7k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),             \
690
14.7k
                            "  error: %.1024s", error_message);       \
691
14.7k
      (void) ThrowException2(&_image->exception,CoderError,           \
692
14.7k
                             error_message,_image->filename);         \
693
14.7k
      longjmp(png_jmpbuf(png_ptr),1);                                 \
694
14.7k
    } while(0)
695
696
#if PNG_LIBPNG_VER > 10011
697
/*
698
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699
%                                                                             %
700
%                                                                             %
701
%                                                                             %
702
%   R e a d P N G I m a g e                                                   %
703
%                                                                             %
704
%                                                                             %
705
%                                                                             %
706
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707
%
708
%  Method ReadPNGImage reads a Portable Network Graphics (PNG) or
709
%  Multiple-image Network Graphics (MNG) image file and returns it.  It
710
%  allocates the memory necessary for the new Image structure and returns a
711
%  pointer to the new image or set of images.
712
%
713
%  MNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu.
714
%
715
%  The format of the ReadPNGImage method is:
716
%
717
%      Image *ReadPNGImage(const ImageInfo *image_info,
718
%                          ExceptionInfo *exception)
719
%
720
%  A description of each parameter follows:
721
%
722
%    o image:  Method ReadPNGImage returns a pointer to the image after
723
%      reading.  A null image is returned if there is a memory shortage or
724
%      if the image cannot be read.
725
%
726
%    o image_info: Specifies a pointer to a ImageInfo structure.
727
%
728
%    o exception: return any errors or warnings in this structure.
729
%
730
%  To do, more or less in chronological order (as of version 5.5.2,
731
%   November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
732
%
733
%    Get 16-bit cheap transparency working.
734
%
735
%    (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
736
%
737
%    Preserve all unknown and not-yet-handled known chunks found in input
738
%    PNG file and copy them into output PNG files according to the PNG
739
%    copying rules.
740
%
741
%    (At this point, PNG encoding should be in full MNG compliance)
742
%
743
%    Provide options for choice of background to use when the MNG BACK
744
%    chunk is not present or is not mandatory (i.e., leave transparent,
745
%    user specified, MNG BACK, PNG bKGD)
746
%
747
%    Implement LOOP/ENDL [done, but could do discretionary loops more
748
%    efficiently by linking in the duplicate frames.].
749
%
750
%    Decode and act on the MHDR simplicity profile (offer option to reject
751
%    files or attempt to process them anyway when the profile isn't LC or VLC).
752
%
753
%    Upgrade to full MNG without Delta-PNG.
754
%
755
%        o  BACK [done a while ago except for background image ID]
756
%        o  MOVE [done 15 May 1999]
757
%        o  CLIP [done 15 May 1999]
758
%        o  DISC [done 19 May 1999]
759
%        o  SAVE [partially done 19 May 1999 (marks objects frozen)]
760
%        o  SEEK [partially done 19 May 1999 (discard function only)]
761
%        o  SHOW
762
%        o  PAST
763
%        o  BASI
764
%        o  MNG-level tEXt/iTXt/zTXt
765
%        o  pHYg
766
%        o  pHYs
767
%        o  sBIT
768
%        o  bKGD
769
%        o  iTXt (wait for libpng implementation).
770
%
771
%    Use the scene signature to discover when an identical scene is
772
%    being reused, and just point to the original image->pixels instead
773
%    of storing another set of pixels.  This is not specific to MNG
774
%    but could be applied generally.
775
%
776
%    Upgrade to full MNG with Delta-PNG.
777
%
778
%    JNG tEXt/iTXt/zTXt
779
%
780
%    We will not attempt to read files containing the CgBI chunk.
781
%    They are really Xcode files meant for display on the iPhone.
782
%    These are not valid PNG files and it is impossible to recover
783
%    the original PNG from files that have been converted to Xcode-PNG,
784
%    since irretrievable loss of color data has occurred due to the
785
%    use of premultiplied alpha.
786
*/
787
788
#if defined(__cplusplus) || defined(c_plusplus)
789
extern "C" {
790
#endif
791
792
/*
793
  Compute a distance vector between two colors (0-3.0)
794
*/
795
static double DistanceVector(const PixelPacket *a, const PixelPacket *b)
796
852k
{
797
852k
  double
798
852k
    difference,
799
852k
    distance,
800
852k
    distance_squared;
801
802
852k
  difference=(a->red-(double) b->red)/MaxRGBDouble;
803
852k
  distance_squared=(difference*difference);
804
805
852k
  difference=(a->green-(double) b->green)/MaxRGBDouble;
806
852k
  distance_squared+=(difference*difference);
807
808
852k
  difference=(a->blue-(double) b->blue)/MaxRGBDouble;
809
852k
  distance_squared+=(difference*difference);
810
852k
  distance=sqrt(distance_squared);
811
852k
  return distance;
812
852k
}
813
814
/*
815
  This is the function that does the actual reading of data.  It is
816
  the same as the one supplied in libpng, except that it receives the
817
  datastream from the ReadBlob() function instead of standard input.
818
*/
819
static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
820
6.31M
{
821
6.31M
  Image
822
6.31M
    *image;
823
824
6.31M
  image=(Image *) png_get_io_ptr(png_ptr);
825
6.31M
  if (length > 0)
826
6.31M
    {
827
6.31M
      size_t
828
6.31M
        check;
829
830
6.31M
      if (length > 0x7fffffff)
831
0
        png_warning(png_ptr, "chunk length > 2G");
832
6.31M
      check=ReadBlob(image, length,(char *) data);
833
6.31M
      if (check != length)
834
56.0k
        {
835
56.0k
          char
836
56.0k
            msg[MaxTextExtent];
837
838
56.0k
          (void) snprintf(msg,sizeof(msg),"Expected %" MAGICK_SIZE_T_F "u bytes;"
839
56.0k
                         " found %" MAGICK_SIZE_T_F "u bytes",
840
56.0k
                         (MAGICK_SIZE_T) length,(MAGICK_SIZE_T) check);
841
56.0k
          png_warning(png_ptr,msg);
842
56.0k
          png_error(png_ptr,"Read Exception");
843
56.0k
        }
844
6.31M
    }
845
6.31M
}
846
847
#if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
848
    !defined(PNG_MNG_FEATURES_SUPPORTED)
849
/* We use mng_get_data() instead of png_get_data() if we have a libpng
850
 * older than libpng-1.0.3a, which was the first to allow the empty
851
 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
852
 * ifdef'ed out.  Earlier versions would crash if the bKGD chunk was
853
 * encountered after an empty PLTE, so we have to look ahead for bKGD
854
 * chunks and remove them from the datastream that is passed to libpng,
855
 * and store their contents for later use.
856
 */
857
static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
858
{
859
  MngInfo
860
    *mng_info;
861
862
  Image
863
    *image;
864
865
  png_size_t
866
    check;
867
868
  register long
869
    i;
870
871
  i=0;
872
  mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
873
  image=(Image *) mng_info->image;
874
  while (mng_info->bytes_in_read_buffer && length)
875
    {
876
      data[i]=mng_info->read_buffer[i];
877
      mng_info->bytes_in_read_buffer--;
878
      length--;
879
      i++;
880
    }
881
  if (length)
882
    {
883
      check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
884
      if (check != length)
885
        png_error(png_ptr,"Read Exception");
886
      if (length == 4)
887
        {
888
          if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
889
              (data[3] == 0))
890
            {
891
              check=(png_size_t) ReadBlob(image,(size_t) length,
892
                                          (char *) mng_info->read_buffer);
893
              if (check != length)
894
                png_error(png_ptr,"Read Exception");
895
              mng_info->read_buffer[4]=0;
896
              mng_info->bytes_in_read_buffer=4;
897
              if (!memcmp(mng_info->read_buffer,mng_PLTE,4))
898
                mng_info->found_empty_plte=MagickTrue;
899
              if (!memcmp(mng_info->read_buffer,mng_IEND,4))
900
                {
901
                  mng_info->found_empty_plte=MagickFalse;
902
                  mng_info->have_saved_bkgd_index=MagickFalse;
903
                }
904
            }
905
          if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
906
              (data[3] == 1))
907
            {
908
              check=(png_size_t) ReadBlob(image,(size_t) length,
909
                                          (char *) mng_info->read_buffer);
910
              if (check != length)
911
                png_error(png_ptr,"Read Exception");
912
              mng_info->read_buffer[4]=0;
913
              mng_info->bytes_in_read_buffer=4;
914
              if (!memcmp(mng_info->read_buffer,mng_bKGD,4))
915
                if (mng_info->found_empty_plte)
916
                  {
917
                    /*
918
                      Skip the bKGD data byte and CRC.
919
                    */
920
                    check=(png_size_t)
921
                      ReadBlob(image,5,(char *) mng_info->read_buffer);
922
                    if (check != 5)
923
                      png_error(png_ptr,"Read Exception");
924
                    check=(png_size_t) ReadBlob(image,(size_t) length,
925
                                                (char *)
926
                                                mng_info->read_buffer);
927
                    if (check != length)
928
                      png_error(png_ptr,"Read Exception");
929
                    mng_info->saved_bkgd_index=mng_info->read_buffer[0];
930
                    mng_info->have_saved_bkgd_index=MagickTrue;
931
                    mng_info->bytes_in_read_buffer=0;
932
                  }
933
            }
934
        }
935
    }
936
}
937
#endif
938
939
static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
940
663k
{
941
663k
  Image
942
663k
    *image;
943
944
663k
  image=(Image *) png_get_io_ptr(png_ptr);
945
663k
  if (length)
946
646k
    {
947
646k
      png_size_t
948
646k
        check;
949
950
646k
      check=(png_size_t) WriteBlob(image,(unsigned long) length,(char *) data);
951
646k
      if (check != length)
952
1
        png_error(png_ptr,"WriteBlob Failed");
953
646k
    }
954
663k
}
955
956
static void png_flush_data(png_structp png_ptr)
957
0
{
958
0
  ARG_NOT_USED(png_ptr);
959
960
  /* There is currently no safe API to "flush" a blob. */
961
#if 0
962
  Image
963
    *image;
964
965
  image=(Image *) png_get_io_ptr(png_ptr);
966
  (void) SyncBlob(image);
967
#endif
968
0
}
969
970
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
971
static int PalettesAreEqual(Image *a,Image *b)
972
6.28k
{
973
6.28k
  long
974
6.28k
    i;
975
976
6.28k
  if ((a == (Image *) NULL) || (b == (Image *) NULL))
977
82
    return(MagickFail);
978
6.20k
  if (a->storage_class!=PseudoClass || b->storage_class!=PseudoClass)
979
0
    return(MagickFail);
980
6.20k
  if (a->colors != b->colors)
981
0
    return(MagickFail);
982
11.7k
  for (i=0; i < (long) a->colors; i++)
983
6.20k
    {
984
6.20k
      if ((a->colormap[i].red != b->colormap[i].red) ||
985
5.96k
          (a->colormap[i].green != b->colormap[i].green) ||
986
5.85k
          (a->colormap[i].blue != b->colormap[i].blue))
987
669
        return(MagickFail);
988
6.20k
    }
989
5.53k
  return((int) MagickTrue);
990
6.20k
}
991
#endif
992
993
static void MngInfoDiscardObject(MngInfo *mng_info,int i)
994
138M
{
995
138M
  if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
996
138M
      mng_info->exists[i] && !mng_info->frozen[i])
997
26.6k
    {
998
#ifdef MNG_OBJECT_BUFFERS
999
      if (mng_info->ob[i] != (MngBuffer *) NULL)
1000
        {
1001
          if (mng_info->ob[i]->reference_count > 0)
1002
            mng_info->ob[i]->reference_count--;
1003
          if (mng_info->ob[i]->reference_count == 0)
1004
            {
1005
              if (mng_info->ob[i]->image != (Image *) NULL)
1006
                {
1007
                  DestroyImage(mng_info->ob[i]->image);
1008
                  mng_info->ob[i]->image=(Image *) NULL;
1009
                }
1010
              MagickFreeMemory(mng_info->ob[i]);
1011
            }
1012
        }
1013
      mng_info->ob[i]=(MngBuffer *) NULL;
1014
#endif
1015
26.6k
      mng_info->exists[i]=MagickFalse;
1016
26.6k
      mng_info->invisible[i]=MagickFalse;
1017
26.6k
      mng_info->viewable[i]=MagickFalse;
1018
26.6k
      mng_info->frozen[i]=MagickFalse;
1019
26.6k
      mng_info->x_off[i]=0;
1020
26.6k
      mng_info->y_off[i]=0;
1021
26.6k
      mng_info->object_clip[i].left=0;
1022
26.6k
      mng_info->object_clip[i].right=PNG_MAX_UINT;
1023
26.6k
      mng_info->object_clip[i].top=0;
1024
26.6k
      mng_info->object_clip[i].bottom=PNG_MAX_UINT;
1025
26.6k
    }
1026
138M
}
1027
1028
static void MngInfoFreeStruct(MngInfo *mng_info,int *have_mng_structure)
1029
531k
{
1030
531k
  if (*have_mng_structure && (mng_info != (MngInfo *) NULL))
1031
531k
    {
1032
531k
      register long
1033
531k
        i;
1034
1035
135M
      for (i=1; i < MNG_MAX_OBJECTS; i++)
1036
135M
        MngInfoDiscardObject(mng_info,i);
1037
531k
      mng_info->image=(Image *)NULL;
1038
531k
      MagickFreeMemory(mng_info->global_plte);
1039
531k
      MagickFreeMemory(mng_info);
1040
531k
      *have_mng_structure=MagickFalse;
1041
531k
    }
1042
531k
}
1043
1044
static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1045
159k
{
1046
159k
  MngBox
1047
159k
    box;
1048
1049
159k
  box=box1;
1050
159k
  if (box.left < box2.left)
1051
1.11k
    box.left=box2.left;
1052
159k
  if (box.top < box2.top)
1053
8.77k
    box.top=box2.top;
1054
159k
  if (box.right > box2.right)
1055
65.9k
    box.right=box2.right;
1056
159k
  if (box.bottom > box2.bottom)
1057
65.2k
    box.bottom=box2.bottom;
1058
159k
  return box;
1059
159k
}
1060
1061
static long mng_get_long(unsigned char *p)
1062
1.07M
{
1063
1.07M
  return ((long) (((magick_uint32_t) p[0] << 24) |
1064
1.07M
                  ((magick_uint32_t) p[1] << 16) |
1065
1.07M
                  ((magick_uint32_t) p[2] <<  8) |
1066
1.07M
                  (magick_uint32_t)  p[3]));
1067
1.07M
}
1068
1069
static MngBox mng_read_box(MngBox previous_box,char delta_type,
1070
                           unsigned char *p)
1071
104k
{
1072
104k
  MngBox
1073
104k
    box;
1074
1075
  /*
1076
    Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1077
  */
1078
104k
  box.left  = mng_get_long(p);
1079
104k
  box.right = mng_get_long(&p[4]);
1080
104k
  box.top   = mng_get_long(&p[8]);
1081
104k
  box.bottom= mng_get_long(&p[12]);
1082
104k
  if (delta_type != 0)
1083
50.1k
    {
1084
50.1k
      box.left+=previous_box.left;
1085
50.1k
      box.right+=previous_box.right;
1086
50.1k
      box.top+=previous_box.top;
1087
50.1k
      box.bottom+=previous_box.bottom;
1088
50.1k
    }
1089
104k
  return(box);
1090
104k
}
1091
1092
static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1093
  unsigned char *p)
1094
787
{
1095
787
  MngPair
1096
787
    pair;
1097
  /*
1098
    Read two longs from CLON, MOVE or PAST chunk
1099
  */
1100
787
  pair.a= mng_get_long(p);
1101
787
  pair.b= mng_get_long(&p[4]);
1102
1103
787
  if (delta_type != 0)
1104
324
    {
1105
324
      pair.a+=previous_pair.a;
1106
324
      pair.b+=previous_pair.b;
1107
324
    }
1108
787
  return(pair);
1109
787
}
1110
1111
static void PNGErrorHandler(png_struct *ping,png_const_charp message) MAGICK_FUNC_NORETURN;
1112
1113
static void PNGErrorHandler(png_struct *ping,png_const_charp message)
1114
165k
{
1115
165k
  Image
1116
165k
    *image;
1117
1118
165k
  image=(Image *) png_get_error_ptr(ping);
1119
165k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1120
165k
                        "  libpng-%.1024s error: %.1024s",
1121
165k
                        PNG_LIBPNG_VER_STRING, message);
1122
165k
  (void) ThrowException2(&image->exception,CoderError,message,image->filename);
1123
#if (PNG_LIBPNG_VER < 10500)
1124
  longjmp(ping->jmpbuf,1);
1125
#else
1126
165k
  png_longjmp(ping,1);
1127
165k
#endif
1128
165k
  SignalHandlerExit(EXIT_FAILURE); /* Avoid GCC warning about non-exit function which does exit */
1129
165k
}
1130
1131
static void PNGWarningHandler(png_struct *ping,png_const_charp message)
1132
2.09M
{
1133
2.09M
  Image
1134
2.09M
    *image;
1135
1136
2.09M
  if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1137
0
    png_error(ping, message);
1138
2.09M
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1139
2.09M
                        "  libpng-%.1024s warning: %.1024s",
1140
2.09M
                        PNG_LIBPNG_VER_STRING, message);
1141
2.09M
  image=(Image *) png_get_error_ptr(ping);
1142
2.09M
  errno=0;
1143
2.09M
  (void) ThrowException2(&image->exception,CoderWarning,message,
1144
2.09M
                         image->filename);
1145
2.09M
}
1146
1147
#ifdef PNG_USER_MEM_SUPPORTED
1148
#if PNG_LIBPNG_VER >= 14000
1149
static png_voidp png_IM_malloc(png_structp png_ptr,png_alloc_size_t size)
1150
#else
1151
static png_voidp png_IM_malloc(png_structp png_ptr,png_size_t size)
1152
#endif
1153
4.29M
{
1154
4.29M
  (void) png_ptr;
1155
4.29M
  return MagickAllocateMemory(png_voidp,(size_t) size);
1156
4.29M
}
1157
1158
/*
1159
  Free a pointer.  It is removed from the list at the same time.
1160
*/
1161
static void png_IM_free(png_structp png_ptr,png_voidp ptr)
1162
4.29M
{
1163
4.29M
  (void) png_ptr;
1164
4.29M
  MagickFreeMemory(ptr);
1165
4.29M
  return;
1166
4.29M
}
1167
#endif
1168
1169
#if defined(__cplusplus) || defined(c_plusplus)
1170
}
1171
#endif
1172
1173
static MagickPassFail
1174
png_read_raw_profile(Image *image, const ImageInfo *image_info,
1175
                     png_textp text,long ii,ExceptionInfo *exception)
1176
29.7k
{
1177
29.7k
  char
1178
29.7k
    profile_description[MaxTextExtent],
1179
29.7k
    profile_name[MaxTextExtent];
1180
1181
29.7k
  unsigned char
1182
29.7k
    *info;
1183
1184
29.7k
  register size_t
1185
29.7k
    i;
1186
1187
29.7k
  size_t
1188
29.7k
    length,
1189
29.7k
    nibbles;
1190
1191
29.7k
  long
1192
29.7k
    length_s;
1193
1194
29.7k
  register unsigned char
1195
29.7k
    *dp;
1196
1197
29.7k
  register png_charp
1198
29.7k
    sp;
1199
1200
29.7k
  png_charp
1201
29.7k
    ep;
1202
1203
29.7k
  static const unsigned char
1204
29.7k
    unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1205
29.7k
                0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1206
29.7k
                0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1207
29.7k
                0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1208
29.7k
                0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1209
29.7k
                13,14,15};
1210
1211
29.7k
  if (image->logging)
1212
29.7k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1213
29.7k
                          "    Read raw profile[%ld]",ii);
1214
1215
29.7k
  sp=text[ii].text+1;
1216
29.7k
  ep=text[ii].text+text[ii].text_length;
1217
29.7k
  if (ep <= sp)
1218
38
    {
1219
38
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1220
38
      return MagickFail;
1221
38
    }
1222
  /* look for newline */
1223
230k
  while ((sp < ep) && (*sp != '\n'))
1224
200k
    sp++;
1225
29.7k
  if (sp == ep)
1226
3.02k
    {
1227
3.02k
      if (image->logging)
1228
3.02k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1229
3.02k
                              "    Failed to find new-line in raw profile");
1230
3.02k
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1231
3.02k
      return MagickFail;
1232
3.02k
    }
1233
  /* look for length */
1234
74.7k
  while ((sp < ep) && (*sp == '\0' || *sp == ' ' || *sp == '\n'))
1235
48.0k
    sp++;
1236
26.7k
  if (sp == ep)
1237
71
    {
1238
71
      if (image->logging)
1239
71
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1240
71
                              "    Failed to find raw profile length!");
1241
71
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1242
71
      return MagickFail;
1243
71
    }
1244
26.6k
  length_s = MagickAtoL(sp);
1245
26.6k
  if ((length_s <= 0) || (length_s >= (ep-sp)))
1246
5.88k
    {
1247
5.88k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1248
5.88k
                            "invalid profile length %ld", length_s);
1249
5.88k
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1250
5.88k
      return (MagickFail);
1251
5.88k
    }
1252
20.7k
  length=(size_t) length_s;
1253
223k
  while ((sp < ep) && (*sp != ' ' && *sp != '\n'))
1254
202k
    sp++;
1255
20.7k
  if (sp == ep)
1256
5.97k
    {
1257
5.97k
      if (image->logging)
1258
5.97k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1259
5.97k
                              "    End of text while looking for start of hex-encoded profile");
1260
5.97k
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1261
5.97k
      return MagickFail;
1262
5.97k
    }
1263
  /* allocate space */
1264
14.7k
  if ((length == 0) || ((magick_uintptr_t) (ep-sp) <= length*2))
1265
50
    {
1266
50
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1267
50
                            "invalid profile length %" MAGICK_SIZE_T_F "u", (MAGICK_SIZE_T) length);
1268
50
      ThrowException(exception,CorruptImageWarning,UnableToParseEmbeddedProfile,image->filename);
1269
50
      return (MagickFail);
1270
50
    }
1271
14.7k
  info=MagickAllocateMemory(unsigned char *,length);
1272
14.7k
  if (info == (unsigned char *) NULL)
1273
0
    {
1274
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1275
0
          "Unable to copy profile");
1276
0
      return (MagickFail);
1277
0
    }
1278
  /* copy profile, skipping white space and column 1 "=" signs */
1279
14.7k
  dp=info;
1280
14.7k
  nibbles=length*2;
1281
225k
  for (i=0; i < nibbles; i++)
1282
212k
    {
1283
422k
      while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1284
211k
        {
1285
211k
          if (*sp == '\0')
1286
1.24k
            {
1287
1.24k
              MagickFreeMemory(info);
1288
1.24k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1289
1.24k
                  "ran out of profile data");
1290
1.24k
              return (MagickFail);
1291
1.24k
            }
1292
210k
          sp++;
1293
210k
        }
1294
211k
      if (i%2 == 0)
1295
105k
        *dp=16*unhex[(int) *sp++];
1296
105k
      else
1297
105k
        (*dp++)+=unhex[(int) *sp++];
1298
211k
    }
1299
1300
  /* We have already read "Raw profile type " */
1301
13.5k
  if(!memcmp(&text[ii].key[17], "iptc\0",5))
1302
659
    {
1303
659
      strlcpy(profile_name,"IPTC",sizeof(profile_name));
1304
659
      strlcpy(profile_description,"IPTC profile.",sizeof(profile_description));
1305
659
    }
1306
12.8k
  else if (!memcmp(&text[ii].key[17], "icm\0",4))
1307
910
    {
1308
910
      strlcpy(profile_name,"ICM",sizeof(profile_name));
1309
910
      strlcpy(profile_description,"ICM (ICCP) profile.",
1310
910
              sizeof(profile_description));
1311
910
    }
1312
11.9k
  else
1313
11.9k
    {
1314
11.9k
      strlcpy(profile_name,&text[ii].key[17],sizeof(profile_name));
1315
11.9k
      LocaleUpper(profile_name);
1316
11.9k
      strlcpy(profile_description,"generic profile, type ",
1317
11.9k
              sizeof(profile_description));
1318
11.9k
      strlcat(profile_description,&text[ii].key[17],
1319
11.9k
              sizeof(profile_description));
1320
11.9k
    }
1321
13.5k
  if (image_info->verbose)
1322
0
    (void) printf(" Found a %.1024s\n",profile_description);
1323
13.5k
  if(SetImageProfile(image,profile_name,info,length) == MagickFail)
1324
0
    {
1325
0
      MagickFreeMemory(info);
1326
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1327
0
           "unable to copy profile");
1328
0
      return MagickFail;
1329
0
    }
1330
13.5k
  MagickFreeMemory(info);
1331
13.5k
  return MagickTrue;
1332
13.5k
}
1333
1334
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1335
1336
static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1337
429k
{
1338
429k
  Image
1339
429k
    *image;
1340
1341
1342
  /* The unknown chunk structure contains the chunk data:
1343
     png_byte name[5];
1344
     png_byte *data;
1345
     png_size_t size;
1346
1347
     Note that libpng has already taken care of the CRC handling.
1348
1349
     Returns one of the following:
1350
         return(-n);  An error occurred; png_chunk_error will be called.
1351
         return(0);   The chunk was not handled, the chunk will be discarded
1352
                      unless png_set_keep_unknown_chunks has been used to set
1353
                      a 'keep' behavior for this particular chunk, in which
1354
                      case that will be used.  A critical chunk will cause an
1355
                      error at this point unless it is to be saved.
1356
         return(n);  The chunk was handled, libpng will ignore/discard it.
1357
  */
1358
1359
429k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1360
429k
     "    read_user_chunk: found %c%c%c%c chunk with size"
1361
429k
                        " %" MAGICK_SIZE_T_F "u",
1362
429k
                        chunk->name[0],chunk->name[1],
1363
429k
                        chunk->name[2],chunk->name[3],
1364
429k
                        (MAGICK_SIZE_T) chunk->size);
1365
1366
429k
  if (chunk->name[0]  == 101 &&
1367
120k
      (chunk->name[1] ==  88 || chunk->name[1] == 120 ) &&
1368
106k
      chunk->name[2]  ==  73 &&
1369
101k
      chunk->name[3]  == 102)
1370
66.2k
    {
1371
      /* process eXIf or exIf chunk */
1372
1373
66.2k
      unsigned char
1374
66.2k
        *profile;
1375
1376
66.2k
      unsigned char
1377
66.2k
        *p;
1378
1379
66.2k
      png_byte
1380
66.2k
        *s;
1381
1382
66.2k
      size_t
1383
66.2k
        i;
1384
1385
66.2k
      const size_t app1_hdr_size = MAGICK_JPEG_APP1_EXIF_HEADER_SIZE;
1386
1387
66.2k
      image=(Image *) png_get_user_chunk_ptr(ping);
1388
1389
66.2k
      if (image->logging)
1390
66.2k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1391
66.2k
                              "    recognized eXIf chunk");
1392
1393
66.2k
      profile=MagickAllocateMemory(unsigned char *,chunk->size+app1_hdr_size);
1394
1395
66.2k
      if (profile == (unsigned char *) NULL)
1396
0
        {
1397
0
          ThrowException(&image->exception,ResourceLimitError,
1398
0
                         MemoryAllocationFailed,image->filename);
1399
0
          return -1;
1400
0
        }
1401
1402
66.2k
      p=profile;
1403
1404
      /* Stored profile should start with JPEG APP1 "Exif\0\0" header */
1405
66.2k
      (void) memcpy(p,MAGICK_JPEG_APP1_EXIF_HEADER,app1_hdr_size);
1406
66.2k
      p += app1_hdr_size;
1407
1408
66.2k
      i=0;
1409
66.2k
      s=chunk->data;
1410
1411
66.2k
      if (chunk->size > app1_hdr_size &&
1412
17.5k
          (memcmp((const void *) s,(const void *) MAGICK_JPEG_APP1_EXIF_HEADER,
1413
17.5k
                  app1_hdr_size) == 0))
1414
1.97k
        {
1415
          /*
1416
            Skip over "Exif\0\0" if already present
1417
          */
1418
1.97k
          i=app1_hdr_size;
1419
1.97k
          s += app1_hdr_size;
1420
1.97k
        }
1421
1422
      /* copy chunk->data to profile */
1423
      /* It is documented that the first four bytes of eXIf profile
1424
         should be '73 73 42 0' or '77 77 0 42' */
1425
9.76M
      for (; i<chunk->size; i++)
1426
9.69M
        *p++ = *s++;
1427
1428
66.2k
      (void) SetImageProfile(image,"exif",
1429
66.2k
         (const unsigned char *)profile, p-profile);
1430
66.2k
      MagickFreeMemory(profile)
1431
1432
66.2k
      return(1);
1433
66.2k
    }
1434
1435
  /* orNT */
1436
363k
  if (chunk->name[0] == 111 &&
1437
96.2k
      chunk->name[1] == 114 &&
1438
85.4k
      chunk->name[2] ==  78 &&
1439
73.7k
      chunk->name[3] ==  84)
1440
69.9k
    {
1441
     /* recognized orNT */
1442
69.9k
     if (chunk->size != 1)
1443
219
       return(-1); /* Error return */
1444
1445
69.7k
     image=(Image *) png_get_user_chunk_ptr(ping);
1446
69.7k
     if (chunk->data[0] < 9)
1447
64.9k
       image->orientation = (OrientationType) chunk->data[0];
1448
4.85k
     else
1449
4.85k
       image->orientation = UndefinedOrientation;
1450
69.7k
     return(1);
1451
69.9k
    }
1452
1453
  /* caNv */
1454
293k
  if (chunk->name[0] ==  99 &&
1455
76.6k
      chunk->name[1] ==  97 &&
1456
38.3k
      chunk->name[2] ==  78 &&
1457
25.2k
      chunk->name[3] == 118)
1458
3.47k
    {
1459
     /* recognized caNv */
1460
1461
3.47k
     if (chunk->size != 16)
1462
360
       return(-1); /* Error return */
1463
1464
3.11k
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1465
3.11k
             "    recognized caNv chunk");
1466
1467
3.11k
     image=(Image *) png_get_user_chunk_ptr(ping);
1468
1469
3.11k
     image->page.width=(size_t) mng_get_long(chunk->data);
1470
3.11k
     image->page.height=(size_t) mng_get_long(&chunk->data[4]);
1471
3.11k
     image->page.x=(size_t) mng_get_long(&chunk->data[8]);
1472
3.11k
     image->page.y=(size_t) mng_get_long(&chunk->data[12]);
1473
1474
3.11k
     return(1);
1475
3.47k
    }
1476
1477
289k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1478
289k
         "    unrecognized user chunk: %s", chunk->name);
1479
1480
289k
  return(0); /* Did not recognize */
1481
293k
}
1482
#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */
1483
1484
/*
1485
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486
%                                                                             %
1487
%                                                                             %
1488
%                                                                             %
1489
%   R e a d O n e P N G I m a g e                                             %
1490
%                                                                             %
1491
%                                                                             %
1492
%                                                                             %
1493
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494
%
1495
%  Method ReadOnePNGImage reads a Portable Network Graphics (PNG) image file
1496
%  (minus the 8-byte signature)  and returns it.  It allocates the memory
1497
%  necessary for the new Image structure and returns a pointer to the new
1498
%  image.
1499
%
1500
%  The format of the ReadOnePNGImage method is:
1501
%
1502
%      Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1503
%         ExceptionInfo *exception)
1504
%
1505
%  A description of each parameter follows:
1506
%
1507
%    o image:  Method ReadOnePNGImage returns a pointer to the image after
1508
%      reading.  A null image is returned if there is a memory shortage or
1509
%      if the image cannot be read.
1510
%
1511
%    o mng_info: Specifies a pointer to a MngInfo structure.
1512
%
1513
%    o image_info: Specifies a pointer to a ImageInfo structure.
1514
%
1515
%    o exception: return any errors or warnings in this structure.
1516
%
1517
*/
1518
static Image *ReadOnePNGImage(MngInfo *mng_info,
1519
                              const ImageInfo *image_info,
1520
                              ExceptionInfo *exception)
1521
332k
{
1522
  /* Read one PNG image */
1523
1524
332k
  Image
1525
332k
    *image;
1526
1527
332k
  png_info
1528
332k
    *end_info,
1529
332k
    *ping_info;
1530
1531
332k
  png_struct
1532
332k
    *ping;
1533
1534
332k
  png_textp
1535
332k
    text;
1536
1537
332k
  png_bytep
1538
332k
     ping_trans_alpha = (png_bytep) NULL;
1539
1540
332k
  size_t
1541
332k
    length,
1542
332k
    ping_rowbytes,
1543
332k
    row_offset;
1544
1545
332k
  unsigned int
1546
332k
    ping_file_depth;
1547
1548
332k
  int
1549
332k
    logging,
1550
332k
    num_text,
1551
332k
    num_passes,
1552
332k
    pass,
1553
332k
    ping_bit_depth,
1554
332k
    ping_colortype,
1555
332k
    ping_interlace_method,
1556
332k
    ping_compression_method,
1557
332k
    ping_filter_method,
1558
332k
    ping_num_trans=0;
1559
1560
332k
  LongPixelPacket
1561
332k
    transparent_color;
1562
1563
332k
  png_color_16p
1564
332k
     ping_background = (png_color_16p) NULL,
1565
332k
     ping_trans_color = (png_color_16p) NULL;
1566
1567
332k
  png_uint_32
1568
332k
    ping_width,
1569
332k
    ping_height;
1570
1571
332k
  long
1572
332k
    y;
1573
1574
332k
  register IndexPacket
1575
332k
    *indexes;
1576
1577
332k
  register long
1578
332k
    i,
1579
332k
    x;
1580
1581
332k
  register PixelPacket
1582
332k
    *q;
1583
1584
332k
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1585
332k
  static const png_byte unused_chunks[]=
1586
332k
    {
1587
332k
      104,  73,  83,  84, '\0',   /* hIST */
1588
332k
      105,  84,  88, 116, '\0',   /* iTXt */
1589
332k
      112,  67,  65,  76, '\0',   /* pCAL */
1590
332k
      115,  67,  65,  76, '\0',   /* sCAL */
1591
332k
      115,  80,  76,  84, '\0',   /* sPLT */
1592
332k
      116,  73,  77,  69, '\0',   /* tIME */
1593
332k
#ifdef PNG_READ_eXIf_SUPPORTED /* Enforce custom eXIf processing to override default one. */
1594
332k
      101,  88,  73, 102, '\0',   /* eXIf*/
1595
332k
#endif
1596
332k
#ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
1597
                          /* ignore the APNG chunks */
1598
332k
       97,  99,  84,  76, '\0',   /* acTL */
1599
332k
      102,  99,  84,  76, '\0',   /* fcTL */
1600
332k
      102, 100,  65,  84, '\0',   /* fdAT */
1601
332k
#endif
1602
332k
    };
1603
332k
#endif
1604
1605
332k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1606
332k
                         "  enter ReadOnePNGImage()");
1607
1608
  /* Set to an out-of-range color unless tRNS chunk is present */
1609
332k
  transparent_color.red=65537;
1610
332k
  transparent_color.green=65537;
1611
332k
  transparent_color.blue=65537;
1612
332k
  transparent_color.opacity=65537;
1613
1614
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
1615
  LockSemaphoreInfo(png_semaphore);
1616
#endif
1617
1618
#if (PNG_LIBPNG_VER < 10012)
1619
  if (image_info->verbose)
1620
    printf("Your PNG library (libpng-%s) is rather old.\n",
1621
           PNG_LIBPNG_VER_STRING);
1622
#endif
1623
1624
332k
  image=mng_info->image;
1625
1626
  /*
1627
    Allocate the PNG structures
1628
  */
1629
332k
#ifdef PNG_USER_MEM_SUPPORTED
1630
332k
  ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1631
332k
                                PNGErrorHandler,PNGWarningHandler, NULL,
1632
332k
                                (png_malloc_ptr) png_IM_malloc,
1633
332k
                                (png_free_ptr) png_IM_free);
1634
#else
1635
  ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1636
                              PNGErrorHandler,PNGWarningHandler);
1637
#endif
1638
332k
  if (ping == (png_struct *) NULL)
1639
0
    {
1640
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
1641
      UnlockSemaphoreInfo(png_semaphore);
1642
#endif
1643
0
      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1644
0
    }
1645
1646
332k
  png_set_crc_action(ping, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
1647
1648
332k
  mng_info->png_pixels=(unsigned char *) NULL;
1649
332k
  mng_info->quantum_scanline=(Quantum *) NULL;
1650
1651
332k
  if (setjmp(png_jmpbuf(ping)))
1652
221k
    {
1653
      /*
1654
        PNG image is corrupt.
1655
      */
1656
221k
      png_destroy_read_struct(&ping,&ping_info,&end_info);
1657
221k
      MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline);
1658
221k
      MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels);
1659
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
1660
      UnlockSemaphoreInfo(png_semaphore);
1661
#endif
1662
221k
      if (logging)
1663
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1664
0
                              "  exit ReadOnePNGImage() with error.");
1665
221k
      if (image != (Image *) NULL)
1666
221k
        {
1667
221k
          if (image->exception.severity > exception->severity)
1668
63.1k
            CopyException(exception,&image->exception);
1669
221k
          image->columns=0;
1670
221k
        }
1671
221k
      if (image)
1672
221k
        {
1673
          /* Image is part of mng_info->image list (see above) */
1674
221k
          DestroyImageList(image);
1675
221k
          image=(Image *) NULL;
1676
221k
          mng_info->image=(Image *) NULL;
1677
221k
        }
1678
      /* We are not aware that the following case ever happens */
1679
221k
      if (mng_info->image)
1680
0
        {
1681
0
          DestroyImageList(mng_info->image);
1682
0
          mng_info->image=(Image *) NULL;
1683
0
        }
1684
221k
      return(image);
1685
221k
    }
1686
1687
/* { From here through end of ReadOnePNGImage(), use png_error(), not Throw() */
1688
1689
111k
  ping_info=png_create_info_struct(ping);
1690
111k
  if (ping_info == (png_info *) NULL)
1691
0
    {
1692
0
      png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1693
0
      png_error(ping,"Could not allocate PNG info struct");
1694
0
    }
1695
1696
111k
  end_info=png_create_info_struct(ping);
1697
111k
  if (end_info == (png_info *) NULL)
1698
0
    {
1699
0
      png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1700
0
      png_error(ping,"Could not allocate PNG end_info struct");
1701
0
    }
1702
1703
111k
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
1704
  /* Allow benign errors */
1705
111k
  png_set_benign_errors(ping, 1);
1706
111k
#endif
1707
1708
  /* Default to using libpng's limit (PNG_USER_CHUNK_MALLOC_MAX ==
1709
     8000000) on chunk size */
1710
111k
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1711
  /* Reject images with too many rows or columns */
1712
111k
  png_set_user_limits(ping,
1713
111k
    (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)),
1714
111k
    (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(HeightResource)));
1715
  /* Allow specifying a different chunk size limit than the
1716
     PNG_USER_CHUNK_MALLOC_MAX baked into libpng */
1717
111k
# if PNG_LIBPNG_VER >= 10401 /* png_set_chunk_malloc_max was added in 1.4.1 */
1718
111k
  {
1719
111k
    const char *chunk_malloc_max_str;
1720
111k
    if ((chunk_malloc_max_str=AccessDefinition(image_info,"png","chunk-malloc-max")))
1721
0
      {
1722
0
        unsigned long chunk_malloc_max;
1723
0
        if (MagickAtoULChk(chunk_malloc_max_str, &chunk_malloc_max) == MagickPass)
1724
0
          {
1725
0
            png_set_chunk_malloc_max(ping, chunk_malloc_max);
1726
0
            if (logging)
1727
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1728
0
                                    "Set PNG chunk-malloc-max to %lu bytes",
1729
0
                                    chunk_malloc_max);
1730
0
          }
1731
0
        else
1732
0
          {
1733
0
            if (logging)
1734
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1735
0
                                    "Failed to parse chunk-malloc-max value \"%s\"",
1736
0
                                    chunk_malloc_max_str);
1737
0
          }
1738
0
      }
1739
111k
  }
1740
111k
# endif
1741
111k
#endif /* PNG_SET_USER_LIMITS_SUPPORTED */
1742
1743
111k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1744
111k
                            "    PNG width limit: %lu, height limit: %lu",
1745
111k
    (unsigned long) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)),
1746
111k
    (unsigned long) Min(0x7fffffffL, GetMagickResourceLimit(HeightResource)));
1747
111k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1748
111k
                            "    PNG pixels limit: %lu",
1749
111k
    (unsigned long) GetMagickResourceLimit(PixelsResource));
1750
1751
  /*
1752
    Prepare PNG for reading.
1753
  */
1754
111k
  mng_info->image_found++;
1755
111k
  png_set_sig_bytes(ping,8);
1756
111k
  if (LocaleCompare(image_info->magick,"MNG") == 0)
1757
117k
    {
1758
117k
#if defined(PNG_MNG_FEATURES_SUPPORTED)
1759
117k
      (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1760
117k
      png_set_read_fn(ping,image,png_get_data);
1761
#else
1762
# if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1763
      png_permit_empty_plte(ping,MagickTrue);
1764
      png_set_read_fn(ping,image,png_get_data);
1765
# else
1766
      mng_info->image=image;
1767
      mng_info->bytes_in_read_buffer=0;
1768
      mng_info->found_empty_plte=MagickFalse;
1769
      mng_info->have_saved_bkgd_index=MagickFalse;
1770
      png_set_read_fn(ping,mng_info,mng_get_data);
1771
# endif
1772
#endif
1773
117k
    }
1774
18.4E
  else
1775
18.4E
    png_set_read_fn(ping,image,png_get_data);
1776
1777
111k
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1778
  /* Ignore unknown chunks */
1779
# if PNG_LIBPNG_VER < 10700 /* Avoid a libpng16 warning */
1780
  png_set_keep_unknown_chunks(ping, 2, NULL, 0);
1781
# else
1782
111k
  png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1783
111k
# endif
1784
  /* Ignore unused chunks and all unknown chunks except for caNv */
1785
111k
  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_caNv, 1);
1786
111k
  png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1787
111k
                              (int)sizeof(unused_chunks)/5);
1788
  /* Callback for other unknown chunks */
1789
111k
  png_set_read_user_chunk_fn(ping, image, read_user_chunk_callback);
1790
111k
#endif
1791
1792
111k
#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
1793
    /* Disable new libpng-1.5.10 feature while reading */
1794
111k
    png_set_check_for_invalid_index (ping, 0);
1795
111k
#endif
1796
1797
#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED)  \
1798
  && (PNG_LIBPNG_VER >= 10200)
1799
  /* Disable thread-unsafe features of pnggccrd */
1800
  if (png_access_version_number() >= 10200)
1801
    {
1802
      png_uint_32 mmx_disable_mask=0;
1803
      png_uint_32 asm_flags;
1804
1805
      mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
1806
                            | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
1807
                            | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
1808
                            | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1809
      asm_flags=png_get_asm_flags(ping);
1810
      png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1811
    }
1812
#endif
1813
1814
111k
  png_read_info(ping,ping_info);
1815
1816
111k
  (void) png_get_IHDR(ping,ping_info,
1817
111k
                      &ping_width,
1818
111k
                      &ping_height,
1819
111k
                      &ping_bit_depth,
1820
111k
                      &ping_colortype,
1821
111k
                      &ping_interlace_method,
1822
111k
                      &ping_compression_method,
1823
1824
111k
                      &ping_filter_method);
1825
1826
#if (defined(__clang_analyzer__) || defined(__COVERITY__))
1827
  /*
1828
    png_get_IHDR() should already have thrown an exception but
1829
    Coverity and Clang Analyzer can not see that since it is library
1830
    code.
1831
  */
1832
  if (ping_bit_depth != 1 &&
1833
      ping_bit_depth != 2 &&
1834
      ping_bit_depth != 4 &&
1835
      ping_bit_depth != 8 &&
1836
      ping_bit_depth != 16)
1837
    {
1838
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1839
                            "  libpng-%.1024s error: %.1024s",
1840
                            PNG_LIBPNG_VER_STRING, "Bit depth is not valid");
1841
      longjmp(png_jmpbuf(ping),1);
1842
    }
1843
#endif /* #if (defined(__clang_analyzer__)  || defined(__COVERITY__)) */
1844
1845
#if (QuantumDepth == 8)
1846
  if (ping_bit_depth > 8)
1847
  {
1848
#  if defined(PNG_READ_STRIP_16_TO_8_SUPPORTED) || \
1849
      defined(PNG_READ_16_TO_8_SUPPORTED)
1850
    png_set_strip_16(ping);
1851
#  else
1852
#    ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
1853
    png_set_scale_16(ping);
1854
#    endif
1855
#  endif
1856
    ping_bit_depth=8;
1857
    image->depth=8;
1858
  }
1859
#else /* QuantumDepth > 8 */
1860
111k
  if (ping_bit_depth > 8)
1861
28.5k
    image->depth=16;
1862
82.5k
  else
1863
82.5k
    image->depth=8;
1864
111k
#endif
1865
1866
111k
  ping_file_depth = (unsigned int) ping_bit_depth;
1867
1868
  /* Save bit-depth and color-type in case we later want to write a PNG00 */
1869
111k
  {
1870
111k
      char
1871
111k
        msg[MaxTextExtent];
1872
1873
111k
      (void) MagickFormatString(msg,sizeof(msg),"%d",(int) ping_colortype);
1874
111k
      (void) SetImageAttribute(image,"png:IHDR.color-type-orig",msg);
1875
1876
111k
      (void) MagickFormatString(msg,sizeof(msg),"%d",(int) ping_bit_depth);
1877
111k
      (void) SetImageAttribute(image,"png:IHDR.bit-depth-orig",msg);
1878
111k
  }
1879
1880
111k
  (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1881
111k
                      &ping_trans_color);
1882
1883
111k
  (void) png_get_bKGD(ping, ping_info, &ping_background);
1884
1885
111k
  if (logging)
1886
0
    {
1887
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1888
0
                            "    PNG width: %lu, height: %lu",
1889
0
                            (unsigned long)ping_width,
1890
0
                            (unsigned long)ping_height);
1891
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1892
0
                            "    PNG color_type: %d, bit_depth: %d",
1893
0
                            ping_colortype, ping_bit_depth);
1894
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1895
0
                            "    PNG compression_method: %d",
1896
0
                            ping_compression_method);
1897
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1898
0
                            "    PNG interlace_method: %d, filter_method: %d",
1899
0
                            ping_interlace_method,
1900
0
                            ping_filter_method);
1901
0
    }
1902
1903
  /* Too big? */
1904
111k
  if (ping_width >
1905
111k
    (magick_uint64_t) GetMagickResourceLimit(PixelsResource)/ping_height)
1906
0
  {
1907
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1908
0
      "Number of pixels exceeds resource limit");
1909
0
    png_error(ping, "Number of pixels exceeds resource limit");
1910
0
  }
1911
1912
111k
  if (ping_bit_depth < 8)
1913
36.8k
    {
1914
36.8k
       png_set_packing(ping);
1915
36.8k
       ping_bit_depth=8;
1916
36.8k
       image->depth=8;
1917
36.8k
    }
1918
1919
111k
#if defined(PNG_READ_iCCP_SUPPORTED)
1920
111k
    if (png_get_valid(ping, ping_info, PNG_INFO_iCCP))
1921
250
    {
1922
250
      int
1923
250
        compression;
1924
1925
#if (PNG_LIBPNG_VER < 10500)
1926
      png_charp
1927
        info;
1928
#else
1929
250
      png_bytep
1930
250
        info;
1931
250
#endif
1932
1933
250
      png_charp
1934
250
        name;
1935
1936
250
      png_uint_32
1937
250
        profile_length;
1938
1939
250
      (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1940
250
                          &profile_length);
1941
250
      if (profile_length)
1942
250
        {
1943
250
          if (logging)
1944
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1945
0
                                  "    Reading PNG iCCP chunk.");
1946
          /* libpng will destroy name and info */
1947
250
          if (SetImageProfile(image,"ICM",(const unsigned char *) info,
1948
250
                              (size_t) profile_length) == MagickFail)
1949
0
            {
1950
0
              MagickError3(ResourceLimitError,MemoryAllocationFailed,
1951
0
                           UnableToAllocateICCProfile);
1952
0
            }
1953
250
        }
1954
250
    }
1955
111k
#endif /* #if defined(PNG_READ_iCCP_SUPPORTED) */
1956
111k
#if defined(PNG_READ_sRGB_SUPPORTED)
1957
111k
  {
1958
111k
    int
1959
111k
      intent;
1960
1961
111k
    if (!png_get_sRGB(ping,ping_info,&intent))
1962
151k
      {
1963
151k
        if (mng_info->have_global_srgb)
1964
4.22k
          {
1965
4.22k
            png_set_sRGB(ping,ping_info,(mng_info->global_srgb_intent+1));
1966
4.22k
          }
1967
151k
      }
1968
111k
    if (png_get_sRGB(ping,ping_info,&intent))
1969
5.45k
      {
1970
5.45k
        image->rendering_intent=(RenderingIntent) (intent+1);
1971
5.45k
        if (logging)
1972
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1973
0
                                "    Reading PNG sRGB chunk:"
1974
0
                                " rendering_intent: %d",
1975
0
                                intent+1);
1976
5.45k
      }
1977
111k
  }
1978
111k
#endif /* if defined(PNG_READ_sRGB_SUPPORTED) */
1979
111k
  {
1980
111k
    double
1981
111k
      file_gamma;
1982
1983
111k
    if (!png_get_gAMA(ping,ping_info,&file_gamma))
1984
151k
      {
1985
151k
        if (mng_info->have_global_gama)
1986
805
          png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1987
151k
      }
1988
111k
    if (png_get_gAMA(ping,ping_info,&file_gamma))
1989
2.07k
      {
1990
2.07k
        image->gamma=(float) file_gamma;
1991
2.07k
        if (logging)
1992
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1993
0
                                "    Reading PNG gAMA chunk: gamma: %f",
1994
0
                                file_gamma);
1995
2.07k
      }
1996
111k
  }
1997
111k
  if (!png_get_valid(ping, ping_info, PNG_INFO_cHRM))
1998
152k
    {
1999
152k
      if (mng_info->have_global_chrm)
2000
5.15k
        (void) png_set_cHRM(ping,ping_info,
2001
5.15k
                     mng_info->global_chrm.white_point.x,
2002
5.15k
                     mng_info->global_chrm.white_point.y,
2003
5.15k
                     mng_info->global_chrm.red_primary.x,
2004
5.15k
                     mng_info->global_chrm.red_primary.y,
2005
5.15k
                     mng_info->global_chrm.green_primary.x,
2006
5.15k
                     mng_info->global_chrm.green_primary.y,
2007
5.15k
                     mng_info->global_chrm.blue_primary.x,
2008
5.15k
                     mng_info->global_chrm.blue_primary.y);
2009
152k
    }
2010
111k
  if (png_get_valid(ping, ping_info, PNG_INFO_cHRM))
2011
5.23k
    {
2012
5.23k
      (void) png_get_cHRM(ping,ping_info,
2013
5.23k
                          &image->chromaticity.white_point.x,
2014
5.23k
                          &image->chromaticity.white_point.y,
2015
5.23k
                          &image->chromaticity.red_primary.x,
2016
5.23k
                          &image->chromaticity.red_primary.y,
2017
5.23k
                          &image->chromaticity.green_primary.x,
2018
5.23k
                          &image->chromaticity.green_primary.y,
2019
5.23k
                          &image->chromaticity.blue_primary.x,
2020
5.23k
                          &image->chromaticity.blue_primary.y);
2021
5.23k
      if (logging)
2022
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2023
0
                              "    Reading PNG cHRM chunk.");
2024
5.23k
    }
2025
111k
  if (image->rendering_intent)
2026
5.45k
    {
2027
5.45k
      image->gamma=0.45455f;
2028
5.45k
      image->chromaticity.red_primary.x=0.6400f;
2029
5.45k
      image->chromaticity.red_primary.y=0.3300f;
2030
5.45k
      image->chromaticity.green_primary.x=0.3000f;
2031
5.45k
      image->chromaticity.green_primary.y=0.6000f;
2032
5.45k
      image->chromaticity.blue_primary.x=0.1500f;
2033
5.45k
      image->chromaticity.blue_primary.y=0.0600f;
2034
5.45k
      image->chromaticity.white_point.x=0.3127f;
2035
5.45k
      image->chromaticity.white_point.y=0.3290f;
2036
5.45k
    }
2037
111k
#if defined(PNG_oFFs_SUPPORTED)
2038
136k
  if (mng_info->mng_type == 0 && (png_get_valid(ping, ping_info,
2039
136k
                                                PNG_INFO_oFFs)))
2040
1.06k
    {
2041
1.06k
      image->page.x=png_get_x_offset_pixels(ping, ping_info);
2042
1.06k
      image->page.y=png_get_y_offset_pixels(ping, ping_info);
2043
1.06k
      if (logging)
2044
0
        if (image->page.x || image->page.y)
2045
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2046
0
                                "    Reading PNG oFFs chunk: x: %ld, y: %ld.",
2047
0
                                image->page.x,
2048
0
                                image->page.y);
2049
1.06k
    }
2050
111k
#endif
2051
111k
#if defined(PNG_pHYs_SUPPORTED)
2052
111k
  if (!png_get_valid(ping, ping_info, PNG_INFO_pHYs))
2053
148k
    {
2054
148k
      if (mng_info->have_global_phys)
2055
4.88k
        {
2056
4.88k
          png_set_pHYs(ping,ping_info,
2057
4.88k
                       mng_info->global_x_pixels_per_unit,
2058
4.88k
                       mng_info->global_y_pixels_per_unit,
2059
4.88k
                       mng_info->global_phys_unit_type);
2060
4.88k
        }
2061
148k
    }
2062
111k
  if (png_get_valid(ping, ping_info, PNG_INFO_pHYs))
2063
9.11k
    {
2064
9.11k
      int
2065
9.11k
        unit_type;
2066
2067
9.11k
      png_uint_32
2068
9.11k
        x_resolution,
2069
9.11k
        y_resolution;
2070
2071
      /*
2072
        Set image resolution.
2073
      */
2074
9.11k
      (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2075
9.11k
                          &unit_type);
2076
9.11k
      image->x_resolution=(float) x_resolution;
2077
9.11k
      image->y_resolution=(float) y_resolution;
2078
9.11k
      if (unit_type == PNG_RESOLUTION_METER)
2079
556
        {
2080
556
          image->units=PixelsPerCentimeterResolution;
2081
556
          image->x_resolution=(double) x_resolution/100.0;
2082
556
          image->y_resolution=(double) y_resolution/100.0;
2083
556
        }
2084
9.11k
      if (logging)
2085
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2086
0
                              "    Reading PNG pHYs chunk:"
2087
0
                              " xres: %lu, yres: %lu, units: %d.",
2088
0
                              (unsigned long)x_resolution,
2089
0
                              (unsigned long)y_resolution,
2090
0
                              unit_type);
2091
9.11k
    }
2092
111k
#endif
2093
111k
  if (png_get_valid(ping, ping_info, PNG_INFO_PLTE))
2094
11.2k
    {
2095
11.2k
      int
2096
11.2k
        number_colors;
2097
2098
11.2k
      png_colorp
2099
11.2k
        palette;
2100
2101
11.2k
      (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2102
11.2k
      if (number_colors == 0 && ping_colortype ==
2103
1.45k
          PNG_COLOR_TYPE_PALETTE)
2104
1.20k
        {
2105
1.20k
          if (mng_info->global_plte_length)
2106
1.20k
            {
2107
1.20k
              png_set_PLTE(ping,ping_info,mng_info->global_plte,
2108
1.20k
                           (int) mng_info->global_plte_length);
2109
1.20k
              if (!(png_get_valid(ping, ping_info, PNG_INFO_tRNS)))
2110
1.20k
                if (mng_info->global_trns_length)
2111
621
                  {
2112
621
                    if (mng_info->global_trns_length >
2113
621
                        mng_info->global_plte_length)
2114
2
                       png_error(ping, "global tRNS has more entries"
2115
621
                                 " than global PLTE");
2116
619
                    png_set_tRNS(ping,ping_info,mng_info->global_trns,
2117
619
                                 (int) mng_info->global_trns_length,NULL);
2118
619
                  }
2119
1.20k
#if defined(PNG_READ_bKGD_SUPPORTED)
2120
1.20k
              if (
2121
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2122
                  mng_info->have_saved_bkgd_index ||
2123
#endif
2124
1.20k
                  png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2125
45
                {
2126
45
                  png_color_16
2127
45
                    background;
2128
2129
45
                  background.index=0;
2130
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2131
                  if (mng_info->have_saved_bkgd_index)
2132
                    background.index=mng_info->saved_bkgd_index;
2133
#endif
2134
45
                  if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2135
45
                    background.index=ping_background->index;
2136
45
                  background.red=(png_uint_16)
2137
45
                    mng_info->global_plte[background.index].red;
2138
45
                  background.green=(png_uint_16)
2139
45
                    mng_info->global_plte[background.index].green;
2140
45
                  background.blue=(png_uint_16)
2141
45
                    mng_info->global_plte[background.index].blue;
2142
45
                  png_set_bKGD(ping,ping_info,&background);
2143
45
                }
2144
1.20k
#endif
2145
1.20k
            }
2146
3
          else
2147
3
            png_error (ping, "No global PLTE in file");
2148
1.20k
        }
2149
11.2k
    }
2150
2151
111k
#if defined(PNG_READ_bKGD_SUPPORTED)
2152
111k
  if (mng_info->have_global_bkgd &&
2153
719
              !(png_get_valid(ping,ping_info, PNG_INFO_bKGD)))
2154
425
    image->background_color=mng_info->mng_global_bkgd;
2155
111k
  if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2156
5.58k
    {
2157
      /*
2158
        Set image background color.
2159
      */
2160
2161
5.58k
      if (logging)
2162
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2163
0
                              "    Reading PNG bKGD chunk.");
2164
2165
5.58k
      if (ping_bit_depth == QuantumDepth)
2166
456
        {
2167
456
          image->background_color.red  = ping_background->red;
2168
456
          image->background_color.green= ping_background->green;
2169
456
          image->background_color.blue = ping_background->blue;
2170
456
        }
2171
5.12k
      else /* Scale background components to 16-bit */
2172
5.12k
        {
2173
5.12k
          unsigned int
2174
5.12k
            bkgd_scale;
2175
2176
5.12k
          if (logging != MagickFalse)
2177
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178
0
              "    raw ping_background=(%d,%d,%d).",ping_background->red,
2179
0
              ping_background->green,ping_background->blue);
2180
2181
5.12k
          bkgd_scale = 1;
2182
5.12k
          if (ping_file_depth == 1)
2183
4.34k
             bkgd_scale = 255;
2184
787
          else if (ping_file_depth == 2)
2185
45
             bkgd_scale = 85;
2186
742
          else if (ping_file_depth == 4)
2187
61
             bkgd_scale = 17;
2188
5.12k
          if (ping_file_depth <= 8)
2189
5.12k
             bkgd_scale *= 257;
2190
2191
5.12k
          ping_background->red *= bkgd_scale;
2192
5.12k
          ping_background->green *= bkgd_scale;
2193
5.12k
          ping_background->blue *= bkgd_scale;
2194
2195
5.12k
          if (logging != MagickFalse)
2196
0
            {
2197
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2198
0
              "    bkgd_scale=%d.",bkgd_scale);
2199
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2200
0
              "    ping_background=(%d,%d,%d).",ping_background->red,
2201
0
              ping_background->green,ping_background->blue);
2202
0
            }
2203
2204
5.12k
          image->background_color.red=
2205
5.12k
            ScaleShortToQuantum(ping_background->red);
2206
5.12k
          image->background_color.green=
2207
5.12k
            ScaleShortToQuantum(ping_background->green);
2208
5.12k
          image->background_color.blue=
2209
5.12k
            ScaleShortToQuantum(ping_background->blue);
2210
5.12k
          image->background_color.opacity=OpaqueOpacity;
2211
2212
5.12k
          if (logging != MagickFalse)
2213
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2214
0
              "    image->background_color=(%d,%d,%d).",
2215
0
              image->background_color.red,
2216
0
              image->background_color.green,image->background_color.blue);
2217
5.12k
        }
2218
5.58k
    }
2219
111k
#endif
2220
2221
111k
  if (png_get_valid(ping, ping_info, PNG_INFO_tRNS) &&
2222
27.5k
      (ping_trans_color != (png_color_16p) NULL) &&
2223
27.5k
      (((unsigned int) ping_file_depth) <= MaxColormapSize))
2224
27.5k
    {
2225
27.5k
      unsigned int
2226
27.5k
        bit_mask;
2227
2228
27.5k
      if (logging != MagickFalse)
2229
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2230
0
          "    Reading PNG tRNS chunk.");
2231
2232
27.5k
      bit_mask = MaxValueGivenBits(ping_file_depth);
2233
2234
      /*
2235
        Image has a transparent background.
2236
      */
2237
2238
27.5k
      transparent_color.red=
2239
27.5k
        (unsigned long)(ping_trans_color->red & bit_mask);
2240
27.5k
      transparent_color.green=
2241
27.5k
        (unsigned long) (ping_trans_color->green & bit_mask);
2242
27.5k
      transparent_color.blue=
2243
27.5k
        (unsigned long) (ping_trans_color->blue & bit_mask);
2244
27.5k
      transparent_color.opacity=
2245
27.5k
        (unsigned long) (ping_trans_color->gray & bit_mask);
2246
2247
27.5k
      if (ping_colortype == PNG_COLOR_TYPE_GRAY)
2248
3.32k
        {
2249
#if (QuantumDepth == 8)
2250
          if (ping_file_depth < QuantumDepth)
2251
#endif
2252
3.32k
            transparent_color.opacity=(unsigned long) (
2253
3.32k
                ping_trans_color->gray *
2254
3.32k
                (65535L/MaxValueGivenBits(ping_file_depth))); /* Coverity 381876 Division or modulo by zero (DIVIDE_BY_ZERO) */
2255
2256
#if (QuantumDepth == 8)
2257
          else
2258
            transparent_color.opacity=(unsigned long) (
2259
                (ping_trans_color->gray * 65535UL)/
2260
                MaxValueGivenBits(ping_file_depth));
2261
#endif
2262
3.32k
          if (logging != MagickFalse)
2263
0
            {
2264
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2265
0
                   "    Raw tRNS graylevel is %d.",ping_trans_color->gray);
2266
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2267
0
                   "    scaled graylevel is %d.",
2268
0
                   (int) transparent_color.opacity);
2269
0
            }
2270
3.32k
          transparent_color.red=transparent_color.opacity;
2271
3.32k
          transparent_color.green=transparent_color.opacity;
2272
3.32k
          transparent_color.blue=transparent_color.opacity;
2273
3.32k
        }
2274
27.5k
    }
2275
111k
#if defined(PNG_READ_sBIT_SUPPORTED)
2276
111k
  if (!png_get_valid(ping, ping_info, PNG_INFO_sBIT))
2277
152k
    if (mng_info->have_global_sbit)
2278
648
        png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2279
111k
#endif
2280
111k
  num_passes=png_set_interlace_handling(ping);
2281
2282
111k
  png_read_update_info(ping,ping_info);
2283
2284
111k
  ping_rowbytes=(size_t) png_get_rowbytes(ping,ping_info);
2285
2286
  /*
2287
    Initialize image structure.
2288
  */
2289
111k
  mng_info->image_box.left=0;
2290
111k
  mng_info->image_box.right=(long) ping_width;
2291
111k
  mng_info->image_box.top=0;
2292
111k
  mng_info->image_box.bottom=(long) ping_height;
2293
111k
  if (mng_info->mng_type == 0)
2294
136k
    {
2295
136k
      mng_info->mng_width=ping_width;
2296
136k
      mng_info->mng_height=ping_height;
2297
136k
      mng_info->frame=mng_info->image_box;
2298
136k
      mng_info->clip=mng_info->image_box;
2299
136k
    }
2300
18.4E
  else
2301
18.4E
    {
2302
18.4E
      image->page.y=mng_info->y_off[mng_info->object_id];
2303
18.4E
    }
2304
111k
  image->compression=ZipCompression;
2305
111k
  image->columns=ping_width;
2306
111k
  image->rows=ping_height;
2307
111k
  if (((unsigned int) ping_file_depth <= MaxColormapSize) &&
2308
152k
      ((ping_colortype == PNG_COLOR_TYPE_PALETTE) ||
2309
141k
       (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2310
128k
       (ping_colortype == PNG_COLOR_TYPE_GRAY)))
2311
62.8k
    {
2312
62.8k
      image->storage_class=PseudoClass;
2313
62.8k
      image->colors=1U << ping_file_depth; /* Coverity (#1-3 of 3): Bad bit shift operation (BAD_SHIFT) */
2314
#if (QuantumDepth == 8)
2315
      if (image->colors > 256)
2316
        image->colors=256;
2317
#else
2318
62.8k
      if (image->colors > 65536L)
2319
0
        image->colors=65536L;
2320
62.8k
#endif
2321
62.8k
      if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
2322
11.0k
        {
2323
11.0k
          int
2324
11.0k
            number_colors;
2325
2326
11.0k
          png_colorp
2327
11.0k
            palette;
2328
2329
11.0k
          (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2330
11.0k
          image->colors=number_colors; /* FIXME: bug 596 */
2331
11.0k
          if (logging)
2332
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2333
0
                                  "    Reading PNG PLTE chunk:"
2334
0
                                  " number_colors: %d.",number_colors);
2335
11.0k
        }
2336
62.8k
    }
2337
2338
111k
  if (image->storage_class == PseudoClass)
2339
62.8k
    {
2340
      /*
2341
        Initialize image colormap.
2342
      */
2343
62.8k
      if (!AllocateImageColormap(image,image->colors))
2344
0
        png_error(ping, "Could not allocate image colormap");
2345
62.8k
      if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
2346
11.0k
        {
2347
11.0k
          int
2348
11.0k
            number_colors;
2349
2350
11.0k
          png_colorp
2351
11.0k
            palette;
2352
2353
11.0k
          (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2354
223k
          for (i=0; i < (long) image->colors; i++)
2355
212k
            {
2356
212k
              image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2357
212k
              image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2358
212k
              image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2359
212k
            }
2360
11.0k
        }
2361
51.8k
      else
2362
51.8k
        {
2363
51.8k
          unsigned long
2364
51.8k
            scale;
2365
2366
51.8k
          scale=(MaxRGB/MaxValueGivenBits(ping_file_depth));
2367
51.8k
          if (scale < 1)
2368
0
            scale=1;
2369
192M
          for (i=0; i < (long) image->colors; i++)
2370
192M
            {
2371
192M
              image->colormap[i].red=(Quantum) (i*scale);
2372
192M
              image->colormap[i].green=(Quantum) (i*scale);
2373
192M
              image->colormap[i].blue=(Quantum) (i*scale);
2374
192M
            }
2375
51.8k
        }
2376
62.8k
    }
2377
111k
  if (image->delay != 0)
2378
146
    mng_info->scenes_found++;
2379
111k
  if (image_info->ping && ((mng_info->mng_type == 0) ||
2380
0
     ((image_info->subrange != 0) &&
2381
0
      mng_info->scenes_found > (long) (image_info->subimage+
2382
0
                                       image_info->subrange))))
2383
0
    {
2384
0
      image->matte=((ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) ||
2385
0
                      (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2386
0
                      (png_get_valid(ping, ping_info, PNG_INFO_tRNS)));
2387
2388
      /* This happens later in non-ping decodes */
2389
0
      if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2390
0
        image->storage_class=DirectClass;
2391
2392
0
      if (logging)
2393
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2394
0
                              "    Skipping PNG image data for scene %ld",
2395
0
                              mng_info->scenes_found-1);
2396
0
      png_destroy_read_struct(&ping,&ping_info,&end_info);
2397
0
      MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline);
2398
0
      MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels);
2399
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
2400
      UnlockSemaphoreInfo(png_semaphore);
2401
#endif
2402
0
      if (logging)
2403
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2404
0
                              "  exit ReadOnePNGImage().");
2405
0
      return (image);
2406
0
    }
2407
2408
  /*
2409
    Read image scanlines.
2410
  */
2411
111k
  if (logging)
2412
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2413
0
                          "    Reading PNG IDAT chunk(s)");
2414
111k
  if (num_passes > 1)
2415
68.1k
  {
2416
68.1k
    if (ping_rowbytes < (size_t) GetMagickResourceLimit(MemoryResource)/image->rows)
2417
68.1k
      mng_info->png_pixels=MagickAllocateResourceLimitedArray(unsigned char *,
2418
68.1k
                                                              ping_rowbytes,image->rows);
2419
0
    else
2420
0
      png_error(ping, "png_pixels array exceeds MemoryResource");
2421
68.1k
  }
2422
42.9k
  else
2423
42.9k
  {
2424
42.9k
    if (ping_rowbytes < (size_t) GetMagickResourceLimit(MemoryResource))
2425
84.2k
      mng_info->png_pixels=MagickAllocateResourceLimitedMemory(unsigned char *, ping_rowbytes);
2426
18.4E
    else
2427
18.4E
      png_error(ping, "png_rowbytes array exceeds MemoryResource");
2428
42.9k
  }
2429
152k
  if (mng_info->png_pixels == (unsigned char *) NULL)
2430
0
  {
2431
0
    png_error(ping, "Could not allocate png_pixels array");
2432
0
  }
2433
2434
152k
  if (logging)
2435
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2436
0
                          "    Converting PNG pixels to pixel packets");
2437
  /*
2438
    Convert PNG pixels to pixel packets.
2439
  */
2440
152k
  if (image->storage_class == DirectClass)
2441
405k
    for (pass=0; pass < num_passes; pass++)
2442
316k
      {
2443
        /*
2444
          Convert image to DirectClass pixel packets.
2445
        */
2446
#if (QuantumDepth == 8)
2447
        int
2448
          depth;
2449
2450
        depth=(long) ping_bit_depth;
2451
#endif
2452
316k
        image->matte=((ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA) ||
2453
132k
                      (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2454
132k
                      (png_get_valid(ping, ping_info, PNG_INFO_tRNS)));
2455
2456
1.58M
        for (y=0; y < (long) image->rows; y++)
2457
1.31M
          {
2458
1.31M
            if (num_passes > 1)
2459
1.10M
              row_offset=ping_rowbytes*y;
2460
2461
204k
            else
2462
204k
              row_offset=0;
2463
2464
1.31M
            png_read_row(ping,mng_info->png_pixels+row_offset,NULL);
2465
2466
1.31M
            if (!SetImagePixels(image,0,y,image->columns,1))
2467
44.0k
              break;
2468
2469
1.26M
            if (pass < num_passes-1)
2470
999k
              continue;
2471
2472
#if (QuantumDepth == 8)
2473
            if (depth == 16)
2474
              {
2475
                register Quantum
2476
                  *p,
2477
                  *r;
2478
2479
                r=mng_info->png_pixels+row_offset;
2480
                p=r;
2481
                if (ping_colortype == PNG_COLOR_TYPE_GRAY)
2482
                  {
2483
                    for (x=(long) image->columns; x > 0; x--)
2484
                      {
2485
                        *r++=*p++;
2486
                        p++;
2487
                        if ((png_get_valid(ping, ping_info, PNG_INFO_tRNS)) &&
2488
                            ((unsigned long) (((magick_uint32_t) *(p-2) << 8)|
2489
                                              (magick_uint32_t) *(p-1))
2490
                            == transparent_color.opacity))
2491
                          {
2492
                            /* Cheap transparency */
2493
                            *r++=TransparentOpacity;
2494
                          }
2495
                        else
2496
                          *r++=OpaqueOpacity;
2497
                      }
2498
                  }
2499
                else if (ping_colortype == PNG_COLOR_TYPE_RGB)
2500
                  {
2501
                    if (png_get_valid(ping, ping_info, PNG_INFO_tRNS))
2502
                      for (x=(long) image->columns; x > 0; x--)
2503
                        {
2504
                          *r++=*p++;
2505
                          p++;
2506
                          *r++=*p++;
2507
                          p++;
2508
                          *r++=*p++;
2509
                          p++;
2510
                          if (((unsigned long) (((magick_uint32_t) *(p-6) << 8)|*(p-5)) ==
2511
                              transparent_color.red) &&
2512
                              ((unsigned long) (((magick_uint32_t) *(p-4) << 8)|*(p-3)) ==
2513
                              transparent_color.green) &&
2514
                              ((unsigned long) (((magick_uint32_t) *(p-2) << 8)|*(p-1)) ==
2515
                              transparent_color.blue))
2516
                            {
2517
                              /* Cheap transparency */
2518
                              *r++=TransparentOpacity;
2519
                            }
2520
                          else
2521
                            *r++=OpaqueOpacity;
2522
                        }
2523
                    else
2524
                      for (x=(long) image->columns; x > 0; x--)
2525
                        {
2526
                          *r++=*p++;
2527
                          p++;
2528
                          *r++=*p++;
2529
                          p++;
2530
                          *r++=*p++;
2531
                          p++;
2532
                          *r++=OpaqueOpacity;
2533
                        }
2534
                  }
2535
                else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA)
2536
                  for (x=(long) (4*image->columns); x > 0; x--)
2537
                    {
2538
                      *r++=*p++;
2539
                      p++;
2540
                    }
2541
                else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
2542
                  for (x=(long) (2*image->columns); x > 0; x--)
2543
                    {
2544
                      *r++=*p++;
2545
                      p++;
2546
                    }
2547
              }
2548
            if (depth == 8 && ping_colortype == PNG_COLOR_TYPE_GRAY)
2549
              (void) ImportImagePixelArea(image,(QuantumType) GrayQuantum,
2550
                                          image->depth,mng_info->png_pixels+
2551
                                          row_offset,0,0);
2552
            else if (ping_colortype == PNG_COLOR_TYPE_GRAY)
2553
              {
2554
                image->depth=8;
2555
                (void) ImportImagePixelArea(image,
2556
                                           (QuantumType) GrayQuantum,
2557
                                            image->depth,mng_info->png_pixels+
2558
                                            row_offset,0,0);
2559
                image->depth=depth;
2560
              }
2561
            else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
2562
              {
2563
                image->depth=8;
2564
                (void) ImportImagePixelArea(image,
2565
                                           (QuantumType) GrayAlphaQuantum,
2566
                                            image->depth,mng_info->png_pixels+
2567
                                            row_offset,0,0);
2568
                image->depth=depth;
2569
              }
2570
            else if (depth == 8 && ping_colortype == PNG_COLOR_TYPE_RGB)
2571
              (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum,
2572
                                          image->depth,mng_info->png_pixels+
2573
                                          row_offset,0,0);
2574
            else if (ping_colortype == PNG_COLOR_TYPE_RGB)
2575
              {
2576
                image->depth=8;
2577
                (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum,
2578
                                            image->depth,mng_info->png_pixels+
2579
                                            row_offset,0,0);
2580
                image->depth=depth;
2581
              }
2582
            else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA)
2583
              {
2584
                image->depth=8;
2585
                (void) ImportImagePixelArea(image,(QuantumType) RGBAQuantum,
2586
                                            image->depth,mng_info->png_pixels+
2587
                                            row_offset,0,0);
2588
                image->depth=depth;
2589
              }
2590
            else if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
2591
              (void) ImportImagePixelArea(image,(QuantumType) IndexQuantum,
2592
                                          ping_bit_depth,mng_info->png_pixels+
2593
                                          row_offset,0,0);
2594
                                          /* FIXME, sample size ??? */
2595
#else /* (QuantumDepth != 8) */
2596
2597
268k
            if (ping_colortype == PNG_COLOR_TYPE_GRAY)
2598
0
              (void) ImportImagePixelArea(image,(QuantumType) GrayQuantum,
2599
0
                                          image->depth,mng_info->png_pixels+
2600
0
                                          row_offset,0,0);
2601
268k
            else if (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
2602
0
              (void) ImportImagePixelArea(image,(QuantumType) GrayAlphaQuantum,
2603
0
                                          image->depth,mng_info->png_pixels+
2604
0
                                          row_offset,0,0);
2605
268k
            else if (ping_colortype == PNG_COLOR_TYPE_RGB_ALPHA)
2606
68.8k
              (void) ImportImagePixelArea(image,(QuantumType) RGBAQuantum,
2607
68.8k
                                          image->depth,mng_info->png_pixels+
2608
68.8k
                                          row_offset,0,0);
2609
199k
            else if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
2610
0
              (void) ImportImagePixelArea(image,(QuantumType) IndexQuantum,
2611
0
                                          ping_bit_depth,mng_info->png_pixels+
2612
0
                                          row_offset,0,0);
2613
                                          /* FIXME, sample size ??? */
2614
199k
            else
2615
199k
              (void) ImportImagePixelArea(image,(QuantumType) RGBQuantum,
2616
199k
                                          image->depth,mng_info->png_pixels+
2617
199k
                                          row_offset,0,0);
2618
268k
#endif
2619
268k
            if (!SyncImagePixels(image))
2620
0
              break;
2621
268k
          }
2622
2623
316k
        if (image->previous == (Image *) NULL)
2624
97.8k
          if (QuantumTick(pass, num_passes))
2625
97.8k
            if (!MagickMonitorFormatted(pass,num_passes,exception,
2626
97.8k
                                        LoadImageText,image->filename,
2627
97.8k
                                        image->columns,image->rows))
2628
0
               break;
2629
316k
      }
2630
2631
62.8k
  else /* image->storage_class != DirectClass */
2632
62.8k
    {
2633
62.8k
      image->matte=ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA;
2634
62.8k
      mng_info->quantum_scanline=
2635
62.8k
        MagickAllocateResourceLimitedMemory(Quantum *,
2636
62.8k
                                            (image->matte ?  2 : 1) *
2637
62.8k
                                            (size_t) image->columns*sizeof(Quantum));
2638
62.8k
      if (mng_info->quantum_scanline == (Quantum *) NULL)
2639
0
        png_error(ping, "Could not allocate quantum_scanline");
2640
62.8k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2641
62.8k
                            "      Allocated quantum_scanline");
2642
2643
172k
      for (pass=0; pass < num_passes; pass++)
2644
137k
        {
2645
137k
          register Quantum
2646
137k
            *r;
2647
2648
          /*
2649
            Convert grayscale image to PseudoClass pixel packets.
2650
          */
2651
3.09M
          for (y=0; y < (long) image->rows; y++)
2652
2.98M
            {
2653
2.98M
              register unsigned char
2654
2.98M
                *p;
2655
2656
2.98M
              if (num_passes > 1)
2657
2.58M
                row_offset=ping_rowbytes*y;
2658
2659
403k
              else
2660
403k
                row_offset=0;
2661
2662
2.98M
              png_read_row(ping,mng_info->png_pixels+row_offset,NULL);
2663
2.98M
              q=SetImagePixels(image,0,y,image->columns,1);
2664
2.98M
              if (q == (PixelPacket *) NULL)
2665
6.74k
                break;
2666
2667
2.97M
              if (pass < num_passes-1)
2668
2.33M
                continue;
2669
2670
638k
              indexes=AccessMutableIndexes(image);
2671
638k
              p=mng_info->png_pixels+row_offset;
2672
638k
              r=mng_info->quantum_scanline;
2673
638k
              switch (ping_bit_depth)
2674
638k
                {
2675
543k
                case 8:
2676
543k
                  {
2677
543k
                    if (ping_colortype == 4)
2678
1.17M
                      for (x=(long) image->columns; x > 0; x--)
2679
1.15M
                        {
2680
1.15M
                          *r++=*p++;
2681
                          /* In image.h, OpaqueOpacity is 0
2682
                           * TransparentOpacity is MaxRGB
2683
                           * In a PNG datastream, Opaque is MaxRGB
2684
                           * and Transparent is 0.
2685
                           */
2686
1.15M
                          q->opacity=ScaleCharToQuantum(255-(*p++));
2687
1.15M
                          q++;
2688
1.15M
                        }
2689
522k
                    else
2690
95.0M
                      for (x=(long) image->columns; x > 0; x--)
2691
94.4M
                        *r++=*p++;
2692
543k
                    break;
2693
0
                  }
2694
73.4k
                case 16:
2695
73.4k
                  {
2696
6.81M
                    for (x=(long) image->columns; x > 0; x--)
2697
6.73M
                      {
2698
6.73M
#if (QuantumDepth == 16)
2699
6.73M
                        if (image->colors > 256)
2700
6.73M
                          *r=(((magick_uint32_t) *p++) << 8);
2701
0
                        else
2702
0
                          *r=0;
2703
6.73M
                        *r|=(*p++);
2704
6.73M
                        r++;
2705
6.73M
                        if (ping_colortype == 4)
2706
2.34M
                          {
2707
2.34M
                            q->opacity=(((magick_uint32_t) *p++) << 8);
2708
2.34M
                            q->opacity|=((magick_uint32_t) *p++);
2709
2.34M
                            q->opacity=(Quantum) (MaxRGB-q->opacity);
2710
2.34M
                            q++;
2711
2.34M
                          }
2712
#else
2713
#if (QuantumDepth == 32)
2714
                        if (image->colors > 256)
2715
                          *r=(((magick_uint32_t) *p++) << 8);
2716
                        else
2717
                          *r=0;
2718
                        *r|=(*p++);
2719
                        r++;
2720
                        if (ping_colortype == 4)
2721
                          {
2722
                            q->opacity=(((magick_uint32_t) *p++) << 8);
2723
                            q->opacity|=((magick_uint32_t) *p++);
2724
                            q->opacity*=65537U;
2725
                            q->opacity=(Quantum) (MaxRGB-q->opacity);
2726
                            q++;
2727
                          }
2728
#else /* QuantumDepth == 8 */
2729
                        *r++=(*p++);
2730
                        p++; /* strip low byte */
2731
                        if (ping_colortype == 4)
2732
                          {
2733
                            q->opacity=(Quantum) (MaxRGB-(*p++));
2734
                            p++;
2735
                            q++;
2736
                          }
2737
#endif
2738
#endif
2739
6.73M
                      }
2740
73.4k
                    break;
2741
0
                  }
2742
0
                default:
2743
0
                  break;
2744
638k
                }
2745
              /*
2746
                Transfer image scanline.
2747
              */
2748
617k
              r=mng_info->quantum_scanline;
2749
2750
103M
              for (x=0; x < (long) image->columns; x++)
2751
102M
                indexes[x]=(*r++);
2752
2753
617k
              if (!SyncImagePixels(image))
2754
0
                break;
2755
617k
            }
2756
2757
          /* Quit 'passes' loop if we encountered an error */
2758
116k
          if (y < (long) image->rows)
2759
6.74k
            break;
2760
2761
109k
          if (image->previous == (Image *) NULL)
2762
60.2k
            if (QuantumTick(pass, num_passes))
2763
60.2k
              if (!MagickMonitorFormatted(pass,num_passes,exception,LoadImageText,
2764
60.2k
                                          image->filename,
2765
60.2k
                                          image->columns,image->rows))
2766
0
              break;
2767
109k
      }
2768
2769
41.4k
      MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline);
2770
41.4k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2771
41.4k
                            "      Free'ed quantum_scanline after last pass");
2772
41.4k
    }
2773
2774
130k
  if (image->storage_class == PseudoClass)
2775
41.4k
    (void) SyncImage(image);
2776
130k
  png_read_end(ping,ping_info);
2777
2778
130k
  if (image_info->subrange != 0 && mng_info->scenes_found-1 <
2779
111k
      (long) image_info->subimage && image->delay != 0.)
2780
0
    {
2781
0
      png_destroy_read_struct(&ping,&ping_info,&end_info);
2782
0
      MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline);
2783
0
      MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels);
2784
0
      if (ReallocateImageColormap(image,2) == MagickFail)
2785
0
        {
2786
0
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
2787
0
                               image);
2788
0
        }
2789
0
      (void) SetImage(image,TransparentOpacity);
2790
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
2791
      UnlockSemaphoreInfo(png_semaphore);
2792
#endif
2793
0
      if (logging)
2794
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2795
0
                              "  exit ReadOnePNGImage().");
2796
0
      return (image);
2797
0
    }
2798
130k
  if (png_get_valid(ping, ping_info, PNG_INFO_tRNS))
2799
27.0k
    {
2800
27.0k
      ClassType
2801
27.0k
        storage_class;
2802
2803
      /*
2804
        Image has a transparent background.
2805
      */
2806
27.0k
      storage_class=image->storage_class;
2807
27.0k
      image->matte=MagickTrue;
2808
174k
      for (y=0; y < (long) image->rows; y++)
2809
154k
        {
2810
154k
          q=SetImagePixels(image,0,y,image->columns,1);
2811
154k
          if (q == (PixelPacket *) NULL)
2812
6.38k
            break;
2813
147k
          indexes=AccessMutableIndexes(image);
2814
2815
147k
          if (storage_class == PseudoClass)
2816
127k
            {
2817
127k
              IndexPacket
2818
127k
                index;
2819
2820
127k
              if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
2821
37.1M
                for (x=0; x < (long) image->columns; x++)
2822
37.0M
                  {
2823
37.0M
                    index=indexes[x];
2824
37.0M
                    if ((index < (unsigned int) ping_num_trans) &&
2825
35.4M
                        (ping_trans_alpha != (png_bytep) NULL))
2826
35.4M
                      q->opacity=
2827
35.4M
                        ScaleCharToQuantum(255-ping_trans_alpha[index]);
2828
1.66M
                    else
2829
1.66M
                      q->opacity=OpaqueOpacity;
2830
37.0M
                    q++;
2831
37.0M
                  }
2832
11.7k
              else if (ping_colortype == PNG_COLOR_TYPE_GRAY)
2833
84.0k
                for (x=0; x < (long) image->columns; x++)
2834
72.2k
                  {
2835
72.2k
                    index=indexes[x];
2836
72.2k
                    q->red=image->colormap[index].red;
2837
72.2k
                    q->green=image->colormap[index].green;
2838
72.2k
                    q->blue=image->colormap[index].blue;
2839
72.2k
                    if ((unsigned long) ScaleQuantumToShort(q->red) ==
2840
72.2k
                        transparent_color.opacity)
2841
5.83k
                      q->opacity=TransparentOpacity;
2842
66.4k
                    else
2843
66.4k
                      q->opacity=OpaqueOpacity;
2844
72.2k
                    q++;
2845
72.2k
                  }
2846
127k
            }
2847
20.2k
          else
2848
226k
            for (x=(long) image->columns; x > 0; x--)
2849
206k
              {
2850
206k
                if ((unsigned long) ScaleQuantumToShort(q->red) ==
2851
206k
                    transparent_color.red &&
2852
27.1k
                    (unsigned long) ScaleQuantumToShort(q->green) ==
2853
27.1k
                    transparent_color.green &&
2854
18.5k
                    (unsigned long) ScaleQuantumToShort(q->blue) ==
2855
18.5k
                    transparent_color.blue)
2856
10.2k
                  q->opacity=TransparentOpacity;
2857
195k
                else
2858
195k
                  q->opacity=OpaqueOpacity;
2859
206k
                q++;
2860
206k
              }
2861
147k
          if (!SyncImagePixels(image))
2862
0
            break;
2863
147k
        }
2864
27.0k
      image->storage_class=DirectClass;
2865
27.0k
    }
2866
#if (QuantumDepth == 8)
2867
  if (image->depth > 8)
2868
    image->depth=8;
2869
#endif
2870
130k
  if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2871
27.7k
    {
2872
27.7k
      if (logging)
2873
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2874
0
                              "    Text chunks: %u", num_text);
2875
160k
      for (i=0; i < (long) num_text; i++)
2876
148k
        {
2877
          /* Check for a profile */
2878
2879
148k
          if (logging)
2880
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2881
0
                                  "    Reading PNG text chunk[%ld] key=\"%.16s\","
2882
0
                                  " length=%" MAGICK_SSIZE_T_F "u",i,text[i].key,
2883
0
                                  (MAGICK_SSIZE_T) text[i].text_length);
2884
148k
          if (strlen(text[i].key) > 16 &&
2885
98.1k
              !memcmp(text[i].key, "Raw profile type ",17))
2886
31.0k
            {
2887
31.0k
              if (text[i].text_length == 0)
2888
1.22k
                {
2889
1.22k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2890
1.22k
                                        "    Skipping empty raw profile...");
2891
1.22k
                }
2892
29.7k
              else
2893
29.7k
                {
2894
29.7k
                  if (png_read_raw_profile(image,image_info,text,i,exception) ==
2895
29.7k
                      MagickFail)
2896
16.2k
                    break;
2897
29.7k
                }
2898
31.0k
            }
2899
117k
          else
2900
117k
            {
2901
117k
              char
2902
117k
                *value;
2903
2904
117k
              length=(unsigned long) text[i].text_length;
2905
117k
              value=MagickAllocateMemory(char *,length+1);
2906
117k
              if (value == (char *) NULL)
2907
0
                {
2908
0
                  png_warning(ping, "Could not allocate memory for text chunk");
2909
0
                  break;
2910
0
                }
2911
117k
              *value='\0';
2912
117k
              (void) strlcat(value,text[i].text,length+1);
2913
117k
              (void) SetImageAttribute(image,text[i].key,value);
2914
117k
              if (logging)
2915
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2916
0
                                      "      Keyword: %s",text[i].key);
2917
117k
              MagickFreeMemory(value);
2918
117k
            }
2919
148k
        }
2920
27.7k
    }
2921
#ifdef MNG_OBJECT_BUFFERS
2922
  /*
2923
    Store the object if necessary.
2924
  */
2925
  if (object_id && object_id < MNG_MAX_OBJECTS && !mng_info->frozen[object_id])
2926
    {
2927
      if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2928
        {
2929
          /*
2930
            create a new object buffer.
2931
          */
2932
          mng_info->ob[object_id]=MagickAllocateMemory(MngBuffer *,
2933
                                                       sizeof(MngBuffer));
2934
          if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2935
            {
2936
              mng_info->ob[object_id]->image=(Image *) NULL;
2937
              mng_info->ob[object_id]->reference_count=1;
2938
            }
2939
        }
2940
      if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2941
          mng_info->ob[object_id]->frozen)
2942
        {
2943
          if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2944
            png_error(ping, "Could not allocate MNG object");
2945
          if (mng_info->ob[object_id]->frozen)
2946
            png_error(ping, "Could not overwrite MNG frozen object buffer");
2947
        }
2948
      else
2949
        {
2950
          png_uint_32
2951
            width,
2952
            height;
2953
2954
          int
2955
            bit_depth,
2956
            color_type,
2957
            interlace_method,
2958
            compression_method,
2959
            filter_method;
2960
2961
          if (mng_info->ob[object_id]->image != (Image *) NULL)
2962
            {
2963
              DestroyImage(mng_info->ob[object_id]->image);
2964
              mng_info->ob[object_id]->image=(Image *) NULL;
2965
            }
2966
          mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
2967
                                                    &image->exception);
2968
          if (mng_info->ob[object_id]->image != (Image *) NULL)
2969
            mng_info->ob[object_id]->image->file=(FILE *) NULL;
2970
          else
2971
            png_error(ping, "Cloning image for object buffer failed");
2972
          png_get_IHDR(ping,ping_info,&width,&height,&bit_depth,&color_type,
2973
                       &interlace_method,&compression_method,&filter_method);
2974
          if (width > 250000L || height > 250000L)
2975
            png_error(ping,"PNG Image dimensions are too large.");
2976
          mng_info->ob[object_id]->width=width;
2977
          mng_info->ob[object_id]->height=height;
2978
          mng_info->ob[object_id]->color_type=color_type;
2979
          mng_info->ob[object_id]->sample_depth=bit_depth;
2980
          mng_info->ob[object_id]->interlace_method=interlace_method;
2981
          mng_info->ob[object_id]->compression_method=compression_method;
2982
          mng_info->ob[object_id]->filter_method=filter_method;
2983
          if (png_get_valid(ping, ping_info, PNG_INFO_PLTE))
2984
            {
2985
              int
2986
                number_colors;
2987
2988
              png_colorp
2989
                plte;
2990
2991
              /*
2992
                Copy the PLTE to the object buffer.
2993
              */
2994
              png_get_PLTE(ping,ping_info,&plte,&number_colors);
2995
              mng_info->ob[object_id]->plte_length=number_colors;
2996
              for (i=0; i < number_colors; i++)
2997
                {
2998
                  mng_info->ob[object_id]->plte[i]=plte[i];
2999
                }
3000
            }
3001
          else
3002
            mng_info->ob[object_id]->plte_length=0;
3003
        }
3004
    }
3005
#endif
3006
  /*
3007
    Free memory.
3008
  */
3009
130k
  png_destroy_read_struct(&ping,&ping_info,&end_info);
3010
130k
  MagickFreeResourceLimitedMemory(Quantum *,mng_info->quantum_scanline);
3011
130k
  MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels);
3012
3013
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
3014
  UnlockSemaphoreInfo(png_semaphore);
3015
#endif
3016
3017
  /*
3018
    Retrieve image orientation from EXIF (if present) and store in
3019
    image.
3020
  */
3021
130k
  {
3022
130k
    const ImageAttribute
3023
130k
      *attribute;
3024
3025
130k
    attribute = GetImageAttribute(image,"EXIF:Orientation");
3026
130k
    if ((attribute != (const ImageAttribute *) NULL) &&
3027
2.62k
        (attribute->value != (char *) NULL))
3028
2.62k
      {
3029
2.62k
        int
3030
2.62k
          orientation;
3031
3032
2.62k
        orientation = MagickAtoI(attribute->value);
3033
2.62k
        if ((orientation > UndefinedOrientation) &&
3034
446
            (orientation <= LeftBottomOrientation))
3035
27
          image->orientation=(OrientationType) orientation;
3036
2.62k
      }
3037
130k
  }
3038
3039
130k
  if (logging)
3040
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3041
0
                          "  exit ReadOnePNGImage()");
3042
130k
  return (image);
3043
3044
  /* End of setjmp-controlled block } */
3045
3046
  /* end of reading one PNG image */
3047
130k
}
3048
3049
static Image *ReadPNGImage(const ImageInfo *image_info,
3050
                           ExceptionInfo *exception)
3051
223k
{
3052
223k
  Image
3053
223k
    *image;
3054
3055
223k
  MngInfo
3056
223k
    *mng_info;
3057
3058
223k
  char
3059
223k
    magic_number[MaxTextExtent];
3060
3061
223k
  int
3062
223k
    have_mng_structure,
3063
223k
    logging;
3064
3065
223k
  unsigned int
3066
223k
    status;
3067
3068
  /*
3069
    Open image file.
3070
  */
3071
223k
  assert(image_info != (const ImageInfo *) NULL);
3072
223k
  assert(image_info->signature == MagickSignature);
3073
223k
  assert(exception != (ExceptionInfo *) NULL);
3074
223k
  assert(exception->signature == MagickSignature);
3075
223k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3076
223k
  image=AllocateImage(image_info);
3077
223k
  mng_info=(MngInfo *) NULL;
3078
223k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3079
223k
  if (status == MagickFalse)
3080
223k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
3081
  /*
3082
    Verify PNG signature.
3083
  */
3084
223k
  if ((ReadBlob(image,8,magic_number) != 8) ||
3085
223k
      (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0))
3086
1.49k
  {
3087
1.49k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
3088
0
  }
3089
3090
  /*
3091
     Verify that file size large enough to contain a PNG datastream
3092
     if using a seekable blob
3093
  */
3094
221k
  if (BlobIsSeekable(image) && GetBlobSize(image) < 61)
3095
6.98k
  {
3096
6.98k
    ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
3097
0
  }
3098
3099
  /*
3100
    Allocate a MngInfo structure.
3101
  */
3102
214k
  have_mng_structure=MagickFalse;
3103
214k
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
3104
214k
  if (mng_info == (MngInfo *) NULL)
3105
0
  {
3106
0
    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
3107
0
  }
3108
  /*
3109
    Initialize members of the MngInfo structure.
3110
  */
3111
214k
  (void) memset(mng_info,0,sizeof(MngInfo));
3112
214k
  mng_info->image=image;
3113
214k
  have_mng_structure=MagickTrue;
3114
3115
214k
  image=ReadOnePNGImage(mng_info,image_info,exception);
3116
214k
  MngInfoFreeStruct(mng_info,&have_mng_structure);
3117
214k
  if (image == (Image *) NULL)
3118
197k
    {
3119
197k
      if (logging)
3120
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3121
0
                              "exit ReadPNGImage() with error");
3122
197k
      return((Image *) NULL);
3123
197k
    }
3124
17.6k
  status &= CloseBlob(image);
3125
17.6k
  if (image->columns == 0 || image->rows == 0)
3126
0
    {
3127
0
      if (image->exception.severity > exception->severity)
3128
0
        CopyException(exception,&image->exception);
3129
0
      DestroyImageList(image);
3130
0
      image=(Image *) NULL;
3131
0
      if (logging)
3132
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3133
0
                              "exit ReadPNGImage() with error.");
3134
0
      return((Image *) NULL);
3135
0
    }
3136
#if 0
3137
  /*
3138
    Post-processing to convert the image type in the reader based on a
3139
    specified magick prefix string is now disabled.  This can (and
3140
    should) be done after the image has been returned.
3141
  */
3142
  if (LocaleCompare(image_info->magick,"PNG8") == 0)
3143
    {
3144
      (void) SetImageType(image,PaletteType);
3145
      if (image->matte)
3146
        {
3147
          /* To do: Reduce to binary transparency */
3148
        }
3149
    }
3150
  if (LocaleCompare(image_info->magick,"PNG24") == 0)
3151
    {
3152
      (void) SetImageType(image,TrueColorType);
3153
      image->matte=MagickFalse;
3154
    }
3155
  if (LocaleCompare(image_info->magick,"PNG32") == 0)
3156
    (void) SetImageType(image,TrueColorMatteType);
3157
#endif
3158
17.6k
  if (logging)
3159
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3160
17.6k
  return (image);
3161
17.6k
}
3162
3163
3164
3165
#if defined(JNG_SUPPORTED)
3166
3167
static void
3168
DestroyJNG(unsigned char *chunk,Image **color_image,
3169
   ImageInfo **color_image_info,
3170
   Image **alpha_image,ImageInfo **alpha_image_info)
3171
73.3k
{
3172
73.3k
  MagickFreeMemory(chunk);
3173
73.3k
  if (*color_image_info)
3174
27.2k
  {
3175
27.2k
    DestroyImageInfo(*color_image_info);
3176
27.2k
    *color_image_info = (ImageInfo *)NULL;
3177
27.2k
  }
3178
73.3k
  if (*alpha_image_info)
3179
8.24k
  {
3180
8.24k
    DestroyImageInfo(*alpha_image_info);
3181
8.24k
    *alpha_image_info = (ImageInfo *)NULL;
3182
8.24k
  }
3183
73.3k
  if (*color_image)
3184
27.2k
  {
3185
27.2k
    DestroyImageList(*color_image);
3186
27.2k
    *color_image = (Image *)NULL;
3187
27.2k
  }
3188
73.3k
  if (*alpha_image)
3189
8.24k
  {
3190
8.24k
    (void) LiberateTemporaryFile((*alpha_image)->filename);
3191
8.24k
    DestroyImageList(*alpha_image);
3192
8.24k
    *alpha_image = (Image *)NULL;
3193
8.24k
  }
3194
73.3k
}
3195
/*
3196
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3197
%                                                                             %
3198
%                                                                             %
3199
%                                                                             %
3200
%   R e a d O n e J N G I m a g e                                             %
3201
%                                                                             %
3202
%                                                                             %
3203
%                                                                             %
3204
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3205
%
3206
%  Method ReadOneJNGImage reads a JPEG Network Graphics (JNG) image file
3207
%  (minus the 8-byte signature)  and returns it.  It allocates the memory
3208
%  necessary for the new Image structure and returns a pointer to the new
3209
%  image.
3210
%
3211
%  JNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu.
3212
%
3213
%  The format of the ReadOneJNGImage method is:
3214
%
3215
%      Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3216
%         ExceptionInfo *exception)
3217
%
3218
%  A description of each parameter follows:
3219
%
3220
%    o image:  Method ReadOneJNGImage returns a pointer to the image after
3221
%      reading.  A null image is returned if there is a memory shortage or
3222
%      if the image cannot be read.
3223
%
3224
%    o mng_info: Specifies a pointer to a MngInfo structure.
3225
%
3226
%    o image_info: Specifies a pointer to a ImageInfo structure.
3227
%
3228
%    o exception: return any errors or warnings in this structure.
3229
%
3230
*/
3231
static Image *ReadOneJNGImage(MngInfo *mng_info,
3232
                              const ImageInfo *image_info,
3233
                              ExceptionInfo *exception)
3234
70.8k
{
3235
70.8k
  Image
3236
70.8k
    *alpha_image,
3237
70.8k
    *color_image,
3238
70.8k
    *image,
3239
70.8k
    *jng_image;
3240
3241
70.8k
  ImageInfo
3242
70.8k
    *alpha_image_info,
3243
70.8k
    *color_image_info;
3244
3245
70.8k
  long
3246
70.8k
    y;
3247
3248
70.8k
  magick_int64_t
3249
70.8k
    height_resource,
3250
70.8k
    width_resource;
3251
3252
70.8k
  unsigned long
3253
70.8k
    jng_height,
3254
70.8k
    jng_width;
3255
3256
70.8k
  png_byte
3257
70.8k
    jng_color_type,
3258
70.8k
    jng_image_sample_depth,
3259
70.8k
    jng_image_compression_method,
3260
70.8k
    jng_image_interlace_method,
3261
70.8k
    jng_alpha_sample_depth,
3262
70.8k
    jng_alpha_compression_method,
3263
70.8k
    jng_alpha_filter_method,
3264
70.8k
    jng_alpha_interlace_method;
3265
3266
70.8k
  register const PixelPacket
3267
70.8k
    *s;
3268
3269
70.8k
  register long
3270
70.8k
    x;
3271
3272
70.8k
  register PixelPacket
3273
70.8k
    *q;
3274
3275
70.8k
  register unsigned char
3276
70.8k
    *p;
3277
3278
70.8k
  unsigned int
3279
70.8k
    logging,
3280
70.8k
    read_JSEP,
3281
70.8k
    reading_idat,
3282
70.8k
    status;
3283
3284
70.8k
  size_t
3285
70.8k
    length;
3286
3287
70.8k
  magick_off_t
3288
70.8k
    blob_size;
3289
3290
70.8k
  jng_alpha_compression_method=0;
3291
70.8k
  jng_alpha_sample_depth=8;
3292
70.8k
  jng_color_type=0;
3293
70.8k
  jng_height=0;
3294
70.8k
  jng_width=0;
3295
70.8k
  alpha_image=(Image *) NULL;
3296
70.8k
  color_image=(Image *) NULL;
3297
70.8k
  alpha_image_info=(ImageInfo *) NULL;
3298
70.8k
  color_image_info=(ImageInfo *) NULL;
3299
3300
70.8k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3301
70.8k
                         "  enter ReadOneJNGImage()");
3302
3303
70.8k
  image=mng_info->image;
3304
70.8k
  blob_size=GetBlobSize(image);
3305
70.8k
  if (AccessMutablePixels(image) != (PixelPacket *) NULL)
3306
0
    {
3307
      /*
3308
        Allocate next image structure.
3309
      */
3310
0
      if (logging)
3311
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3312
0
                              "  AllocateNextImage()");
3313
0
      AllocateNextImage(image_info,image);
3314
0
      if (image->next == (Image *) NULL)
3315
0
        return((Image *) NULL);
3316
0
      image=SyncNextImageInList(image);
3317
0
    }
3318
70.8k
  mng_info->image=image;
3319
3320
  /*
3321
    Signature bytes have already been read.
3322
  */
3323
3324
70.8k
  read_JSEP=MagickFalse;
3325
70.8k
  reading_idat=MagickFalse;
3326
3327
70.8k
  width_resource = GetMagickResourceLimit(WidthResource);
3328
70.8k
  height_resource = GetMagickResourceLimit(HeightResource);
3329
3330
70.8k
  for (;;)
3331
1.65M
    {
3332
1.65M
      char
3333
1.65M
        type[MaxTextExtent];
3334
3335
1.65M
      unsigned char
3336
1.65M
        *chunk = (unsigned char *) NULL;
3337
3338
1.65M
      unsigned int
3339
1.65M
        count;
3340
3341
      /*
3342
        Read a new JNG chunk.
3343
      */
3344
3345
1.65M
      if (QuantumTick(TellBlob(image),2*blob_size))
3346
97.6k
        if (!MagickMonitorFormatted(TellBlob(image),2*blob_size,
3347
97.6k
                                    exception,LoadImagesText,image->filename))
3348
0
          break;
3349
3350
1.65M
      type[0]='\0';
3351
1.65M
      (void) strlcat(type,"errr",sizeof(type));
3352
1.65M
      length=(size_t) ReadBlobMSBLong(image);
3353
1.65M
      count=(unsigned int) ReadBlob(image,4,type);
3354
1.65M
      if (count != 4)
3355
9.20k
        {
3356
9.20k
          DestroyJNG(NULL,&color_image,&color_image_info,
3357
9.20k
                     &alpha_image,&alpha_image_info);
3358
9.20k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3359
9.20k
                                "chunk count is zero");
3360
9.20k
          ThrowException(exception,CorruptImageError,
3361
9.20k
                         UnexpectedEndOfFile,image->filename);
3362
9.20k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3363
9.20k
          return ((Image*)NULL);
3364
9.20k
        }
3365
1.65M
      if (logging)
3366
0
        {
3367
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3368
0
                                " Reading JNG chunk type %c%c%c%c, "
3369
0
                                "length: %" MAGICK_SIZE_T_F "u",
3370
0
                                type[0],type[1],type[2],type[3],
3371
0
                                (MAGICK_SIZE_T) length);
3372
3373
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3374
0
                                "   count=%u",count);
3375
0
        }
3376
3377
1.65M
      if (length > PNG_MAX_UINT)
3378
4.33k
        {
3379
4.33k
          DestroyJNG(NULL,&color_image,&color_image_info,
3380
4.33k
                     &alpha_image,&alpha_image_info);
3381
4.33k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3382
4.33k
                                "chunk length (%" MAGICK_SIZE_T_F "u) > PNG_MAX_UINT",
3383
4.33k
                                (MAGICK_SIZE_T) length);
3384
4.33k
          ThrowException(exception,CorruptImageError,
3385
4.33k
                         ImproperImageHeader,image->filename);
3386
4.33k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3387
4.33k
          return ((Image*)NULL);
3388
4.33k
        }
3389
1.64M
      if (length > (size_t) blob_size)
3390
29.2k
        {
3391
29.2k
          DestroyJNG(NULL,&color_image,&color_image_info,
3392
29.2k
                     &alpha_image,&alpha_image_info);
3393
29.2k
          if (image->logging)
3394
29.2k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3395
29.2k
                                  "chunk length (%" MAGICK_SIZE_T_F "u)"
3396
29.2k
                                  " is greater than input size"
3397
29.2k
                                  " (%" MAGICK_OFF_F "d)",
3398
29.2k
                                  (MAGICK_SIZE_T) length,
3399
29.2k
                                  blob_size);
3400
29.2k
          ThrowException(exception,CorruptImageError,
3401
29.2k
                         ImproperImageHeader,image->filename);
3402
29.2k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3403
29.2k
          return ((Image*)NULL);
3404
29.2k
        }
3405
3406
1.61M
      p=NULL;
3407
1.61M
      if (length)
3408
296k
        {
3409
296k
          chunk=MagickAllocateMemory(unsigned char *,length);
3410
296k
          if (chunk == (unsigned char *) NULL)
3411
0
            {
3412
0
              DestroyJNG(chunk,&color_image,&color_image_info,
3413
0
                         &alpha_image,&alpha_image_info);
3414
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415
0
                                    "    Could not allocate chunk memory");
3416
0
              ThrowException(exception,ResourceLimitError,
3417
0
                             MemoryAllocationFailed,image->filename);
3418
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3419
0
              return ((Image*)NULL);
3420
0
            }
3421
296k
          if (ReadBlob(image,length,chunk) != length)
3422
7.63k
            {
3423
7.63k
              DestroyJNG(chunk,&color_image,&color_image_info,
3424
7.63k
                         &alpha_image,&alpha_image_info);
3425
7.63k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3426
7.63k
                                    "    chunk reading was incomplete");
3427
7.63k
              ThrowException(exception,CorruptImageError,
3428
7.63k
                             InsufficientImageDataInFile,image->filename);
3429
7.63k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3430
7.63k
              return ((Image*)NULL);
3431
7.63k
            }
3432
288k
          p=chunk;
3433
288k
        }
3434
1.60M
      (void) ReadBlobMSBLong(image);  /* read crc word */
3435
3436
1.60M
      if (!memcmp(type,mng_JHDR,4))
3437
77.9k
        {
3438
77.9k
          if (length == 16)
3439
62.7k
            {
3440
62.7k
              jng_width=(unsigned long) mng_get_long(p);
3441
62.7k
              jng_height=(unsigned long) mng_get_long(&p[4]);
3442
62.7k
              jng_color_type=p[8];
3443
62.7k
              jng_image_sample_depth=p[9];
3444
62.7k
              jng_image_compression_method=p[10];
3445
62.7k
              jng_image_interlace_method=p[11];
3446
62.7k
              jng_alpha_sample_depth=p[12];
3447
62.7k
              jng_alpha_compression_method=p[13];
3448
62.7k
              jng_alpha_filter_method=p[14];
3449
62.7k
              jng_alpha_interlace_method=p[15];
3450
62.7k
              if (logging)
3451
0
                {
3452
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3453
0
                                        "    jng_width:      %16lu",
3454
0
                                        jng_width);
3455
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3456
0
                                        "    jng_height:     %16lu",
3457
0
                                        jng_height);
3458
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3459
0
                                        "    jng_color_type: %16d",
3460
0
                                        jng_color_type);
3461
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3462
0
                                        "    jng_image_sample_depth:      %3d",
3463
0
                                        jng_image_sample_depth);
3464
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3465
0
                                        "    jng_image_compression_method:%3d",
3466
0
                                        jng_image_compression_method);
3467
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3468
0
                                        "    jng_image_interlace_method:  %3d",
3469
0
                                        jng_image_interlace_method);
3470
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3471
0
                                        "    jng_alpha_sample_depth:      %3d",
3472
0
                                        jng_alpha_sample_depth);
3473
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3474
0
                                        "    jng_alpha_compression_method:%3d",
3475
0
                                        jng_alpha_compression_method);
3476
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3477
0
                                        "    jng_alpha_filter_method:     %3d",
3478
0
                                        jng_alpha_filter_method);
3479
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3480
0
                                        "    jng_alpha_interlace_method:  %3d",
3481
0
                                        jng_alpha_interlace_method);
3482
0
                }
3483
62.7k
            }
3484
3485
77.9k
          MagickFreeMemory(chunk);
3486
3487
77.9k
          if (jng_width > 65535 || jng_height > 65535 ||
3488
74.4k
              (long) jng_width > GetMagickResourceLimit(WidthResource) ||
3489
73.2k
              (long) jng_height > GetMagickResourceLimit(HeightResource))
3490
6.25k
            {
3491
6.25k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3492
6.25k
                                    "    JNG width or height too large: (%lu x %lu)",
3493
6.25k
                                    jng_width, jng_height);
3494
6.25k
              ThrowException(exception,CorruptImageError,
3495
6.25k
                             ImproperImageHeader,image->filename);
3496
6.25k
              DestroyJNG(chunk,&color_image,&color_image_info,
3497
6.25k
                         &alpha_image,&alpha_image_info);
3498
6.25k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3499
6.25k
              return ((Image *)NULL);
3500
6.25k
            }
3501
3502
          /* Rationalize dimensions with blob size if it is available */
3503
71.7k
          if ((blob_size == 0) ||
3504
71.7k
              ((((double) jng_width*jng_height)/blob_size) > 512.0))
3505
0
            {
3506
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3507
0
                                    "    Unreasonable dimensions: "
3508
0
                                    "geometry = %lux%lu, "
3509
0
                                    "blob size = %" MAGICK_OFF_F "d",
3510
0
                                    jng_width, jng_height, blob_size);
3511
3512
0
              ThrowException(exception,CorruptImageError,
3513
0
                             InsufficientImageDataInFile,image->filename);
3514
0
              DestroyJNG(chunk,&color_image,&color_image_info,
3515
0
                         &alpha_image,&alpha_image_info);
3516
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3517
0
              return ((Image *)NULL);
3518
0
            }
3519
3520
          /* Temporarily set width and height resources to match JHDR */
3521
71.7k
          SetMagickResourceLimit(WidthResource,jng_width);
3522
71.7k
          SetMagickResourceLimit(HeightResource,jng_height);
3523
3524
71.7k
          continue;
3525
71.7k
        }
3526
3527
1.53M
      if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3528
247k
          ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3529
215k
           (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3530
40.8k
        {
3531
          /*
3532
            o create color_image
3533
            o open color_blob, attached to color_image
3534
            o if (color type has alpha)
3535
            open alpha_blob, attached to alpha_image
3536
          */
3537
3538
40.8k
          color_image_info=MagickAllocateMemory(ImageInfo *,sizeof(ImageInfo));
3539
40.8k
          if (color_image_info == (ImageInfo *) NULL)
3540
0
            {
3541
0
              DestroyJNG(chunk,&color_image,&color_image_info,
3542
0
                         &alpha_image,&alpha_image_info);
3543
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3544
0
                                    "    could not allocate color_image_info");
3545
0
              ThrowException(exception,ResourceLimitError,
3546
0
                             MemoryAllocationFailed,image->filename);
3547
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3548
0
              return ((Image *)NULL);
3549
0
            }
3550
40.8k
          GetImageInfo(color_image_info);
3551
40.8k
          color_image=AllocateImage(color_image_info);
3552
40.8k
          if (color_image == (Image *) NULL)
3553
0
            {
3554
0
              DestroyJNG(chunk,&color_image,&color_image_info,
3555
0
                         &alpha_image,&alpha_image_info);
3556
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3557
0
                                    "    could not allocate color_image");
3558
0
              ThrowException(exception,ResourceLimitError,
3559
0
                             MemoryAllocationFailed,image->filename);
3560
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3561
0
              return ((Image *)NULL);
3562
0
            }
3563
40.8k
          if (logging)
3564
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3565
0
                                  "    Creating color_blob.");
3566
40.8k
          (void) AcquireTemporaryFileName(color_image->filename);
3567
40.8k
          status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3568
40.8k
                          exception);
3569
40.8k
          if (status == MagickFalse)
3570
0
            {
3571
0
              CopyException(exception,&color_image->exception);
3572
0
              DestroyJNG(chunk,&color_image,&color_image_info,
3573
0
                         &alpha_image,&alpha_image_info);
3574
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3575
0
                                    "    could not open color_image blob");
3576
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3577
0
              return ((Image *)NULL);
3578
0
            }
3579
3580
40.8k
          if (!image_info->ping && jng_color_type >= 12)
3581
8.40k
            {
3582
8.40k
              if ((jng_alpha_compression_method != 0) &&
3583
476
                  (jng_alpha_compression_method != 8))
3584
160
                {
3585
160
                  if (logging)
3586
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3587
0
                                          "Unsupported Alpha_compression_method: %u"
3588
0
                                          " (returning NULL)",
3589
0
                                          jng_alpha_compression_method);
3590
160
                  DestroyJNG(chunk,&color_image,&color_image_info,
3591
160
                             &alpha_image,&alpha_image_info);
3592
160
                  ThrowException(exception,CorruptImageError,ImproperImageHeader,
3593
160
                                 image->filename);
3594
160
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3595
160
                  return ((Image *)NULL);
3596
160
                }
3597
3598
8.24k
              alpha_image_info=MagickAllocateMemory(ImageInfo *,
3599
8.24k
                                                    sizeof(ImageInfo));
3600
8.24k
              if (alpha_image_info == (ImageInfo *) NULL)
3601
0
                {
3602
0
                  DestroyJNG(chunk,&color_image,&color_image_info,
3603
0
                             &alpha_image,&alpha_image_info);
3604
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3605
0
                                        "    could not allocate alpha_image_info (returning NULL)");
3606
0
                  ThrowException(exception,ResourceLimitError,
3607
0
                                 MemoryAllocationFailed,image->filename);
3608
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3609
0
                  return ((Image *)NULL);
3610
0
                }
3611
8.24k
              GetImageInfo(alpha_image_info);
3612
8.24k
              alpha_image=AllocateImage(alpha_image_info);
3613
8.24k
              if (alpha_image == (Image *) NULL)
3614
0
                {
3615
0
                  DestroyJNG(chunk,&color_image,&color_image_info,
3616
0
                             &alpha_image,&alpha_image_info);
3617
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3618
0
                                        "    could not allocate alpha_image (returning NULL)");
3619
0
                  ThrowException(exception,ResourceLimitError,
3620
0
                                 MemoryAllocationFailed,image->filename);
3621
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3622
0
                  return ((Image *)NULL);
3623
0
                }
3624
8.24k
              if (logging)
3625
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3626
0
                                      "    Creating alpha_blob.");
3627
8.24k
              (void) AcquireTemporaryFileName(alpha_image->filename); /* Freed by DestroyJNG() */
3628
8.24k
              status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3629
8.24k
                              exception);
3630
8.24k
              if (status == MagickFalse)
3631
0
                {
3632
0
                  DestroyJNG(chunk,&color_image,&color_image_info,
3633
0
                             &alpha_image,&alpha_image_info);
3634
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3635
0
                                        "    could not open alpha_image blob (returning NULL)");
3636
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3637
0
                  return ((Image *)NULL);
3638
0
                }
3639
8.24k
              if (jng_alpha_compression_method == 0)
3640
7.93k
                {
3641
7.93k
                  unsigned char
3642
7.93k
                    data[18];
3643
3644
7.93k
                  if (logging)
3645
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3646
0
                                          "    Writing IHDR chunk"
3647
0
                                          " to alpha_blob.");
3648
7.93k
                  (void) WriteBlob(alpha_image,8,"\211PNG\r\n\032\n");
3649
7.93k
                  (void) WriteBlobMSBULong(alpha_image,13L);
3650
7.93k
                  PNGType(data,mng_IHDR);
3651
7.93k
                  LogPNGChunk(logging,mng_IHDR,13L);
3652
7.93k
                  PNGLong(data+4,jng_width);
3653
7.93k
                  PNGLong(data+8,jng_height);
3654
7.93k
                  data[12]=jng_alpha_sample_depth;
3655
7.93k
                  data[13]=0; /* color_type gray */
3656
7.93k
                  data[14]=0; /* compression method 0 */
3657
7.93k
                  data[15]=0; /* filter_method 0 */
3658
7.93k
                  data[16]=0; /* interlace_method 0 */
3659
7.93k
                  (void) WriteBlob(alpha_image,17,data);
3660
7.93k
                  (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3661
7.93k
                }
3662
8.24k
            }
3663
40.6k
          reading_idat=MagickTrue;
3664
40.6k
        }
3665
3666
1.53M
      if (!memcmp(type,mng_JDAT,4))
3667
18.8k
        {
3668
          /*
3669
            Copy chunk to color_image->blob
3670
          */
3671
3672
3673
18.8k
          if (length && color_image != (Image *)NULL)
3674
16.2k
            {
3675
16.2k
              if (logging)
3676
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3677
0
                                      "    Copying %" MAGICK_SIZE_T_F "u"
3678
0
                                      " bytes of JDAT chunk data"
3679
0
                                      " to color_blob.",
3680
0
                                      (MAGICK_SIZE_T) length);
3681
16.2k
              (void) WriteBlob(color_image,length,(char *) chunk);
3682
16.2k
            }
3683
2.62k
          else
3684
2.62k
            {
3685
2.62k
              if (logging)
3686
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3687
0
                                      "    Skipping copy of %" MAGICK_SIZE_T_F "u"
3688
0
                                      " bytes of JDAT chunk data"
3689
0
                                      " to color_blob (color_image=%p).",
3690
0
                                      (MAGICK_SIZE_T) length, color_image);
3691
2.62k
            }
3692
18.8k
          MagickFreeMemory(chunk);
3693
18.8k
          continue;
3694
18.8k
        }
3695
3696
1.51M
      if (!memcmp(type,mng_IDAT,4))
3697
52.4k
        {
3698
52.4k
          png_byte
3699
52.4k
            data[5];
3700
3701
          /*
3702
            Copy IDAT header and chunk data to alpha_image->blob
3703
          */
3704
3705
52.4k
          if (alpha_image != NULL && image_info->ping == MagickFalse)
3706
45.2k
            {
3707
45.2k
              if (logging)
3708
0
                {
3709
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3710
0
                                        "    Copying IDAT chunk data"
3711
0
                                        " to alpha_blob.");
3712
0
                }
3713
45.2k
              if (length == 0)
3714
424
                {
3715
424
                  if (logging)
3716
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3717
0
                                          "    IDAT chunk has length 0");
3718
424
                  MagickFreeMemory(chunk);
3719
424
                  continue;
3720
424
                }
3721
44.7k
              (void) WriteBlobMSBULong(alpha_image,(unsigned long) length);
3722
44.7k
              PNGType(data,mng_IDAT);
3723
44.7k
              LogPNGChunk(logging,mng_IDAT,length);
3724
44.7k
              (void) WriteBlob(alpha_image,4,(char *) data);
3725
44.7k
              (void) WriteBlob(alpha_image,length,(char *) chunk);
3726
44.7k
              (void) WriteBlobMSBULong(alpha_image,
3727
44.7k
                                       crc32(crc32(0,data,4),chunk,(uInt) length));
3728
44.7k
            }
3729
51.9k
          MagickFreeMemory(chunk);
3730
51.9k
          continue;
3731
52.4k
        }
3732
3733
1.45M
      if (!memcmp(type,mng_JDAA,4) || !memcmp(type,mng_JdAA,4))
3734
103k
        {
3735
          /*
3736
            Copy chunk data to alpha_image->blob
3737
          */
3738
3739
103k
          if (alpha_image != NULL && image_info->ping == MagickFalse && length != 0)
3740
87.2k
            {
3741
87.2k
              if (logging)
3742
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3743
0
                                      "    Copying JDAA chunk data"
3744
0
                                      " to alpha_blob.");
3745
3746
87.2k
              (void) WriteBlob(alpha_image,length,(char *) chunk);
3747
87.2k
            }
3748
103k
          MagickFreeMemory(chunk);
3749
103k
          continue;
3750
103k
        }
3751
3752
1.35M
      if (!memcmp(type,mng_JSEP,4))
3753
2.35k
        {
3754
2.35k
          read_JSEP=MagickTrue;
3755
2.35k
          MagickFreeMemory(chunk);
3756
2.35k
          continue;
3757
2.35k
        }
3758
3759
1.35M
      if (!memcmp(type,mng_bKGD,4))
3760
2.29k
        {
3761
2.29k
          if (length == 2)
3762
734
            {
3763
734
              image->background_color.red=ScaleCharToQuantum(p[1]);
3764
734
              image->background_color.green=image->background_color.red;
3765
734
              image->background_color.blue=image->background_color.red;
3766
734
            }
3767
2.29k
          if (length == 6)
3768
1.01k
            {
3769
1.01k
              image->background_color.red=ScaleCharToQuantum(p[1]);
3770
1.01k
              image->background_color.green=ScaleCharToQuantum(p[3]);
3771
1.01k
              image->background_color.blue=ScaleCharToQuantum(p[5]);
3772
1.01k
            }
3773
2.29k
          MagickFreeMemory(chunk);
3774
2.29k
          continue;
3775
2.29k
        }
3776
3777
1.35M
      if (!memcmp(type,mng_gAMA,4))
3778
2.36k
        {
3779
2.36k
          if (length == 4)
3780
643
            image->gamma=((float) mng_get_long(p))*0.00001;
3781
2.36k
          MagickFreeMemory(chunk);
3782
2.36k
          continue;
3783
2.36k
        }
3784
3785
1.34M
      if (!memcmp(type,mng_cHRM,4))
3786
3.34k
        {
3787
3.34k
          if (length == 32)
3788
906
            {
3789
906
              image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3790
906
              image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3791
906
              image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3792
906
              image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3793
906
              image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3794
906
              image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3795
906
              image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3796
906
              image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3797
906
            }
3798
3.34k
          MagickFreeMemory(chunk);
3799
3.34k
          continue;
3800
3.34k
        }
3801
3802
1.34M
      if (!memcmp(type,mng_sRGB,4))
3803
1.91k
        {
3804
1.91k
          if (length == 1)
3805
955
            {
3806
955
              image->rendering_intent=(RenderingIntent) (p[0]+1);
3807
955
              image->gamma=0.45455f;
3808
955
              image->chromaticity.red_primary.x=0.6400f;
3809
955
              image->chromaticity.red_primary.y=0.3300f;
3810
955
              image->chromaticity.green_primary.x=0.3000f;
3811
955
              image->chromaticity.green_primary.y=0.6000f;
3812
955
              image->chromaticity.blue_primary.x=0.1500f;
3813
955
              image->chromaticity.blue_primary.y=0.0600f;
3814
955
              image->chromaticity.white_point.x=0.3127f;
3815
955
              image->chromaticity.white_point.y=0.3290f;
3816
955
            }
3817
1.91k
          MagickFreeMemory(chunk);
3818
1.91k
          continue;
3819
1.91k
        }
3820
3821
1.34M
      if (!memcmp(type,mng_oFFs,4))
3822
4.05k
        {
3823
4.05k
          if (length > 8)
3824
2.23k
            {
3825
2.23k
              image->page.x=mng_get_long(p);
3826
2.23k
              image->page.y=mng_get_long(&p[4]);
3827
2.23k
              if ((int) p[8] != 0)
3828
614
                {
3829
614
                  image->page.x/=10000;
3830
614
                  image->page.y/=10000;
3831
614
                }
3832
2.23k
            }
3833
4.05k
          MagickFreeMemory(chunk);
3834
4.05k
          continue;
3835
4.05k
        }
3836
3837
1.33M
      if (!memcmp(type,mng_pHYs,4))
3838
3.94k
        {
3839
3.94k
          if (length > 8)
3840
1.05k
            {
3841
1.05k
              image->x_resolution=(double) mng_get_long(p);
3842
1.05k
              image->y_resolution=(double) mng_get_long(&p[4]);
3843
1.05k
              if ((int) p[8] == PNG_RESOLUTION_METER)
3844
340
                {
3845
340
                  image->units=PixelsPerCentimeterResolution;
3846
340
                  image->x_resolution=image->x_resolution/100.0f;
3847
340
                  image->y_resolution=image->y_resolution/100.0f;
3848
340
                }
3849
1.05k
            }
3850
3.94k
          MagickFreeMemory(chunk);
3851
3.94k
          continue;
3852
3.94k
        }
3853
3854
#if 0
3855
      if (!memcmp(type,mng_iCCP,4))
3856
        {
3857
          /* To do. */
3858
          MagickFreeMemory(chunk);
3859
          continue;
3860
        }
3861
#endif
3862
3863
1.33M
      MagickFreeMemory(chunk);
3864
3865
1.33M
      if (memcmp(type,mng_IEND,4))
3866
1.32M
        continue;
3867
14.0k
      break;
3868
1.33M
    }
3869
3870
3871
  /* IEND found or loop ended */
3872
3873
  /*
3874
    Finish up reading image data:
3875
3876
    o read main image from color_blob.
3877
3878
    o close color_blob.
3879
3880
    o if (color_type has alpha)
3881
    if alpha_encoding is PNG
3882
    read secondary image from alpha_blob via ReadPNG
3883
    if alpha_encoding is JPEG
3884
    read secondary image from alpha_blob via ReadJPEG
3885
3886
    o close alpha_blob.
3887
3888
    o copy intensity of secondary image into
3889
    opacity samples of main image.
3890
3891
    o destroy the secondary image.
3892
  */
3893
3894
14.0k
  if (color_image_info == (ImageInfo *) NULL || color_image == (Image *) NULL)
3895
399
    {
3896
3897
399
      if (logging)
3898
0
        {
3899
0
          if (color_image_info == (ImageInfo *) NULL)
3900
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3901
0
                                  "Color image info is NULL!");
3902
0
          if (color_image == (Image *) NULL)
3903
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3904
0
                                  "Color image is NULL!");
3905
0
        }
3906
399
      if (color_image == (Image *) NULL)
3907
399
        {
3908
399
          ThrowException(exception,CorruptImageError,
3909
399
                         ImageFileDoesNotContainAnyImageData,image->filename);
3910
399
        }
3911
399
      DestroyImageList(color_image);
3912
399
      color_image=(Image *) NULL;
3913
399
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3914
399
      return (Image *) NULL;
3915
399
    }
3916
3917
13.6k
  else
3918
13.6k
    {
3919
13.6k
      status &= CloseBlob(color_image);
3920
13.6k
      if (logging)
3921
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3922
0
                              "    Reading jng_image from color_blob.");
3923
3924
13.6k
      MagickFormatString(color_image_info->filename,sizeof(color_image_info->filename),"JPEG:%.1024s",color_image->filename);
3925
3926
13.6k
      color_image_info->ping=MagickFalse;   /* To do: avoid this */
3927
13.6k
      color_image_info->subimage=0;
3928
13.6k
      color_image_info->subrange=1;
3929
3930
13.6k
      jng_image=ReadImage(color_image_info,exception);
3931
13.6k
      (void) LiberateTemporaryFile(color_image->filename);
3932
13.6k
      DestroyImage(color_image);
3933
13.6k
      color_image = (Image *)NULL;
3934
13.6k
      DestroyImageInfo(color_image_info);
3935
13.6k
      color_image_info = (ImageInfo *)NULL;
3936
3937
13.6k
      if (jng_image == (Image *) NULL)
3938
9.52k
        {
3939
          /*
3940
            Don't throw exception here since ReadImage() will already
3941
            have thrown it.
3942
          */
3943
9.52k
          DestroyJNG(/*chunk*/ NULL,&color_image,&color_image_info,
3944
9.52k
                     &alpha_image,&alpha_image_info);
3945
9.52k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3946
9.52k
          return (Image *) NULL;
3947
9.52k
        }
3948
3949
4.09k
      if (logging)
3950
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3951
0
                              "jng_height=%lu, jng_width=%lu",
3952
0
                              jng_height, jng_width);
3953
4.09k
      image->rows=jng_height;
3954
4.09k
      image->columns=jng_width;
3955
4.09k
      length=MagickArraySize(image->columns,sizeof(PixelPacket));
3956
4.09k
      if (jng_height == 0 || jng_width == 0 || length == 0)
3957
1.17k
        {
3958
1.17k
          if (logging)
3959
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3960
0
                                  "  jng_width=%lu jng_height=%lu",
3961
0
                                  (unsigned long)jng_width,(unsigned long)jng_height);
3962
1.17k
          DestroyJNG(NULL,&color_image,&color_image_info,
3963
1.17k
                     &alpha_image,&alpha_image_info);
3964
1.17k
          DestroyImageList(jng_image);
3965
1.17k
          ThrowException(exception,CorruptImageError,
3966
1.17k
                         ImproperImageHeader,image->filename);
3967
1.17k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3968
1.17k
          return ((Image *)NULL);
3969
1.17k
        }
3970
2.91k
      if ((image->columns != jng_image->columns) ||
3971
2.91k
          (image->rows != jng_image->rows))
3972
0
        {
3973
0
          if (logging)
3974
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3975
0
                                  "image dimensions %lux%lu do not"
3976
0
                                  " match JPEG dimensions %lux%lu",
3977
0
                                  image->columns,image->rows,
3978
0
                                  jng_image->columns,jng_image->rows);
3979
0
          DestroyJNG(NULL,&color_image,&color_image_info,
3980
0
                     &alpha_image,&alpha_image_info);
3981
0
          DestroyImage(jng_image);
3982
0
          ThrowException(exception,CorruptImageError,
3983
0
                         ImproperImageHeader,image->filename);
3984
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
3985
0
          return ((Image *)NULL);
3986
0
        }
3987
2.91k
      if (logging)
3988
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3989
0
                              "copying jng_image pixels to main image");
3990
5.82k
      for (y=0; y < (long) image->rows; y++)
3991
2.91k
        {
3992
2.91k
          s=AcquireImagePixels(jng_image,0,y,image->columns,1,
3993
2.91k
                               exception);
3994
2.91k
          q=SetImagePixelsEx(image,0,y,image->columns,1,exception);
3995
2.91k
          if ((s == (const PixelPacket *) NULL) ||
3996
2.91k
              (q == (PixelPacket *) NULL))
3997
0
            break;
3998
2.91k
          (void) memcpy(q,s,length);
3999
2.91k
          if (!SyncImagePixels(image))
4000
0
            break;
4001
2.91k
        }
4002
2.91k
      DestroyImage(jng_image);
4003
2.91k
      jng_image = (Image *)NULL;
4004
2.91k
      if ((unsigned long) y != image->rows)
4005
0
        {
4006
0
          if (logging)
4007
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4008
0
                                  "Failed to transfer JPEG scanlines");
4009
0
          DestroyJNG(NULL,&color_image,&color_image_info,
4010
0
                     &alpha_image,&alpha_image_info);
4011
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadOneJNGImage()");
4012
0
          return ((Image *)NULL);
4013
0
        }
4014
2.91k
      if (alpha_image != (Image *)NULL && !image_info->ping)
4015
2.90k
        {
4016
2.90k
          if (jng_color_type >= 12)
4017
2.90k
            {
4018
              /*
4019
                Alpha is stored in PNG or JPEG format:
4020
                Alpha_compression_method:
4021
                1 byte.
4022
                0: PNG grayscale IDAT format.
4023
                8: JNG 8-bit grayscale JDAA format
4024
              */
4025
2.90k
              const char *jng_alpha_magick=
4026
2.90k
                (jng_alpha_compression_method == 0 ? "PNG" :
4027
2.90k
                 (jng_alpha_compression_method == 8 ? "JPEG" :
4028
11
                  "UNKNOWN"));
4029
2.90k
              if (jng_alpha_compression_method == 0)
4030
2.89k
                {
4031
2.89k
                  png_byte
4032
2.89k
                    data[5];
4033
2.89k
                  (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4034
2.89k
                  PNGType(data,mng_IEND);
4035
2.89k
                  LogPNGChunk(logging,mng_IEND,0L);
4036
2.89k
                  (void) WriteBlob(alpha_image,4,(char *) data);
4037
2.89k
                  (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4038
2.89k
                }
4039
2.90k
              status &= CloseBlob(alpha_image);
4040
2.90k
              if (logging)
4041
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4042
0
                                      "    Reading opacity from %s alpha_blob.",
4043
0
                                      jng_alpha_magick);
4044
2.90k
              MagickFormatString(alpha_image_info->filename,sizeof(alpha_image_info->filename),
4045
2.90k
                                 "%s:%.1024s", jng_alpha_magick, alpha_image->filename);
4046
2.90k
              alpha_image_info->subimage=0;
4047
2.90k
              alpha_image_info->subrange=1;
4048
4049
2.90k
              jng_image=ReadImage(alpha_image_info,exception);
4050
4051
2.90k
              if (jng_image == (Image *)NULL)
4052
2.18k
                {
4053
2.18k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4054
2.18k
                                        "    jng_image is NULL.");
4055
2.18k
                  DestroyJNG(NULL,&color_image,&color_image_info,
4056
2.18k
                             &alpha_image,&alpha_image_info);
4057
2.18k
                }
4058
721
              else
4059
721
                {
4060
4061
721
                  if (logging)
4062
0
                    {
4063
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4064
0
                                            "    Read jng_image (%s)",image->magick);
4065
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4066
0
                                            "      jng_image->width=%lu, jng_image->height=%lu",
4067
0
                                            (unsigned long)jng_width,(unsigned long)jng_height);
4068
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4069
0
                                            "      image->rows=%lu, image->columns=%lu",
4070
0
                                            (unsigned long)image->rows,
4071
0
                                            (unsigned long)image->columns);
4072
0
                    }
4073
4074
1.44k
                  for (y=0; y < (long) image->rows; y++)
4075
721
                    {
4076
721
                      s=AcquireImagePixels(jng_image,0,y,image->columns,1,
4077
721
                                           &image->exception);
4078
721
                      if (s == (PixelPacket *) NULL)
4079
0
                        break;
4080
721
                      if (image->matte)
4081
0
                        {
4082
0
                          q=SetImagePixels(image,0,y,image->columns,1);
4083
0
                          if (q == (PixelPacket *) NULL)
4084
0
                            break;
4085
0
                          for (x=(long) image->columns; x > 0; x--,q++,s++)
4086
0
                            q->opacity=(Quantum) MaxRGB-s->red;
4087
0
                        }
4088
721
                      else
4089
721
                        {
4090
721
                          q=SetImagePixels(image,0,y,image->columns,1);
4091
721
                          if (q == (PixelPacket *) NULL)
4092
0
                            break;
4093
1.44k
                          for (x=(long) image->columns; x > 0; x--,q++,s++)
4094
721
                            {
4095
721
                              q->opacity=(Quantum) MaxRGB-s->red;
4096
721
                              if (q->opacity != OpaqueOpacity)
4097
639
                                image->matte=MagickTrue;
4098
721
                            }
4099
721
                        }
4100
721
                      if (!SyncImagePixels(image))
4101
0
                        break;
4102
721
                    }
4103
721
                  DestroyJNG(NULL,&color_image,&color_image_info,
4104
721
                             &alpha_image,&alpha_image_info);
4105
721
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4106
721
                                        " Destroy the JNG image");
4107
721
                  DestroyImageList(jng_image);
4108
721
                  jng_image = (Image *)NULL;
4109
721
                }
4110
2.90k
            }
4111
2.90k
        }
4112
4113
      /*
4114
        Read the JNG image.
4115
      */
4116
2.91k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4117
2.91k
                            " Read the JNG image");
4118
2.91k
      image->page.width=jng_width;
4119
2.91k
      image->page.height=jng_height;
4120
2.91k
      image->page.x=mng_info->x_off[mng_info->object_id];
4121
2.91k
      image->page.y=mng_info->y_off[mng_info->object_id];
4122
2.91k
      mng_info->image_found++;
4123
2.91k
      if (QuantumTick(2*GetBlobSize(image),2*GetBlobSize(image)))
4124
795
        (void) MagickMonitorFormatted(2*GetBlobSize(image),2*GetBlobSize(image),
4125
795
                                      exception,LoadImagesText,image->filename);
4126
2.91k
    }
4127
4128
  /* Clean up in case we didn't earlier */
4129
4130
2.91k
  DestroyJNG(NULL,&color_image,&color_image_info,
4131
2.91k
             &alpha_image,&alpha_image_info);
4132
4133
2.91k
  if (logging)
4134
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4135
0
                          "  exit ReadOneJNGImage()");
4136
4137
2.91k
  SetMagickResourceLimit(WidthResource,width_resource);
4138
2.91k
  SetMagickResourceLimit(HeightResource,height_resource);
4139
4140
2.91k
  StopTimer(&image->timer);
4141
4142
2.91k
  return (image);
4143
14.0k
}
4144
4145
/*
4146
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4147
%                                                                             %
4148
%                                                                             %
4149
%                                                                             %
4150
%   R e a d J N G I m a g e                                                   %
4151
%                                                                             %
4152
%                                                                             %
4153
%                                                                             %
4154
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4155
%
4156
%  Method ReadJNGImage reads a JPEG Network Graphics (JNG) image file
4157
%  (including the 8-byte signature)  and returns it.  It allocates the memory
4158
%  necessary for the new Image structure and returns a pointer to the new
4159
%  image.
4160
%
4161
%  JNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu.
4162
%
4163
%  The format of the ReadJNGImage method is:
4164
%
4165
%      Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4166
%         *exception)
4167
%
4168
%  A description of each parameter follows:
4169
%
4170
%    o image:  Method ReadJNGImage returns a pointer to the image after
4171
%      reading.  A null image is returned if there is a memory shortage or
4172
%      if the image cannot be read.
4173
%
4174
%    o image_info: Specifies a pointer to a ImageInfo structure.
4175
%
4176
%    o exception: return any errors or warnings in this structure.
4177
%
4178
*/
4179
4180
static Image *ReadJNGImage(const ImageInfo *image_info,
4181
                           ExceptionInfo *exception)
4182
44.7k
{
4183
44.7k
  Image
4184
44.7k
    *image;
4185
4186
44.7k
  MngInfo
4187
44.7k
    *mng_info;
4188
4189
44.7k
  char
4190
44.7k
    magic_number[MaxTextExtent];
4191
4192
44.7k
  int
4193
44.7k
    have_mng_structure,
4194
44.7k
    logging;
4195
4196
44.7k
  unsigned int
4197
44.7k
    status;
4198
4199
  /*
4200
    Open image file.
4201
  */
4202
44.7k
  assert(image_info != (const ImageInfo *) NULL);
4203
44.7k
  assert(image_info->signature == MagickSignature);
4204
44.7k
  assert(exception != (ExceptionInfo *) NULL);
4205
44.7k
  assert(exception->signature == MagickSignature);
4206
44.7k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
4207
44.7k
  image=AllocateImage(image_info);
4208
44.7k
  mng_info=(MngInfo *) NULL;
4209
44.7k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4210
44.7k
  if (status == MagickFalse)
4211
0
  {
4212
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Unable to open file");
4213
0
    ThrowException(exception,FileOpenError,UnableToOpenFile,image->filename);
4214
0
    DestroyImageList(image);
4215
0
    image=(Image *) NULL;
4216
0
    return ((Image *)NULL);
4217
0
  }
4218
44.7k
  if (LocaleCompare(image_info->magick,"JNG") != 0)
4219
0
  {
4220
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header");
4221
0
    ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename);
4222
0
    DestroyImageList(image);
4223
0
    image=(Image *) NULL;
4224
0
    return((Image *)NULL);
4225
0
  }
4226
  /*
4227
    Verify JNG signature.
4228
  */
4229
44.7k
  if ((ReadBlob(image,8,magic_number) != 8) ||
4230
44.7k
      (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0))
4231
76
  {
4232
76
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header");
4233
76
    ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename);
4234
76
    DestroyImageList(image);
4235
76
    image=(Image *) NULL;
4236
76
    return((Image *)NULL);
4237
76
  }
4238
4239
44.6k
  if (BlobIsSeekable(image) && GetBlobSize(image) < 147)
4240
624
  {
4241
624
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4242
624
        "Insufficient Image Data");
4243
624
    ThrowException(exception,CorruptImageError,InsufficientImageDataInFile,image->filename);
4244
624
    DestroyImageList(image);
4245
624
    image=(Image *) NULL;
4246
624
    return((Image *)NULL);
4247
624
  }
4248
4249
  /*
4250
    Allocate a MngInfo structure.
4251
  */
4252
44.0k
  have_mng_structure=MagickFalse;
4253
44.0k
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
4254
44.0k
  if (mng_info == (MngInfo *) NULL)
4255
0
  {
4256
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4257
0
        "Memory Allocation Failed");
4258
0
    ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename);
4259
0
    DestroyImageList(image);
4260
0
    image=(Image *) NULL;
4261
0
    return((Image *)NULL);
4262
0
  }
4263
  /*
4264
    Initialize members of the MngInfo structure.
4265
  */
4266
44.0k
  (void) memset(mng_info,0,sizeof(MngInfo));
4267
44.0k
  have_mng_structure=MagickTrue;
4268
4269
44.0k
  mng_info->image=image;
4270
44.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  calling ReadOneJNGImage()");
4271
44.0k
  image=ReadOneJNGImage(mng_info,image_info,exception);
4272
44.0k
  if (image == (Image *) NULL || image->columns == 0 || image->rows == 0)
4273
41.1k
    {
4274
41.1k
      if (logging)
4275
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4276
0
            "exit ReadJNGImage() with error");
4277
41.1k
      if (image != (Image *) NULL)
4278
0
        {
4279
0
          DestroyImageList(image);
4280
0
          image=(Image *) NULL;
4281
0
        }
4282
41.1k
      if (mng_info->image != (Image *) NULL)
4283
41.1k
        {
4284
41.1k
          DestroyImageList(mng_info->image);
4285
41.1k
          mng_info->image=(Image *) NULL;
4286
41.1k
        }
4287
41.1k
      MngInfoFreeStruct(mng_info,&have_mng_structure);
4288
41.1k
      return((Image *)NULL);
4289
41.1k
    }
4290
4291
2.91k
  status &= CloseBlob(image);
4292
2.91k
  MngInfoFreeStruct(mng_info,&have_mng_structure);
4293
4294
2.91k
  if (logging)
4295
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4296
2.91k
  return (image);
4297
44.0k
}
4298
#endif
4299
4300
static Image *ReadMNGImage(const ImageInfo *image_info,
4301
                           ExceptionInfo *exception)
4302
259k
{
4303
259k
  char
4304
259k
    page_geometry[MaxTextExtent];
4305
4306
259k
  Image
4307
259k
    *image;
4308
4309
259k
  int
4310
259k
    have_mng_structure;
4311
4312
259k
  volatile int
4313
259k
    first_mng_object,
4314
259k
    logging,
4315
259k
    object_id,
4316
259k
    term_chunk_found,
4317
259k
    skip_to_iend;
4318
4319
259k
  volatile long
4320
259k
    image_count=0;
4321
4322
259k
  MngInfo
4323
259k
    *mng_info;
4324
4325
259k
  MngBox
4326
259k
    default_fb,
4327
259k
    fb,
4328
259k
    previous_fb;
4329
4330
259k
#ifdef MNG_INSERT_LAYERS
4331
259k
  PixelPacket
4332
259k
    mng_background_color;
4333
259k
#endif
4334
4335
259k
  register long
4336
259k
    i;
4337
4338
259k
  size_t
4339
259k
    count;
4340
4341
259k
  short
4342
259k
    loop_level
4343
#if defined(PNG_DEBUG_LOOPS_ACTIVE)
4344
    ,loops_active = 0
4345
#endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */
4346
259k
    ;
4347
4348
259k
  volatile short
4349
259k
    skipping_loop;
4350
4351
259k
  unsigned int
4352
259k
#ifdef MNG_INSERT_LAYERS
4353
259k
    mandatory_back=0,
4354
259k
#endif
4355
259k
    status;
4356
4357
259k
  volatile unsigned int
4358
#ifdef MNG_OBJECT_BUFFERS
4359
    mng_background_object=0,
4360
#endif
4361
259k
    mng_type=0;   /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4362
4363
259k
  unsigned long
4364
259k
    default_frame_timeout,
4365
259k
    frame_timeout,
4366
259k
#ifdef MNG_INSERT_LAYERS
4367
259k
    image_height,
4368
259k
    image_width,
4369
259k
#endif
4370
259k
    length;
4371
4372
259k
  volatile unsigned long
4373
259k
    default_frame_delay,
4374
259k
    final_delay,
4375
259k
    final_image_delay,
4376
259k
    frame_delay,
4377
259k
#ifdef MNG_INSERT_LAYERS
4378
259k
    insert_layers,
4379
259k
#endif
4380
259k
    mng_iterations=1,
4381
259k
    simplicity=0,
4382
259k
    subframe_height=0,
4383
259k
    subframe_width=0;
4384
4385
259k
  magick_off_t
4386
259k
    blob_size;
4387
4388
259k
  previous_fb.top=0;
4389
259k
  previous_fb.bottom=0;
4390
259k
  previous_fb.left=0;
4391
259k
  previous_fb.right=0;
4392
259k
  default_fb.top=0;
4393
259k
  default_fb.bottom=0;
4394
259k
  default_fb.left=0;
4395
259k
  default_fb.right=0;
4396
4397
  /*
4398
    Open image file.
4399
  */
4400
259k
  assert(image_info != (const ImageInfo *) NULL);
4401
259k
  assert(image_info->signature == MagickSignature);
4402
259k
  assert(exception != (ExceptionInfo *) NULL);
4403
259k
  assert(exception->signature == MagickSignature);
4404
259k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4405
259k
  image=AllocateImage(image_info);
4406
259k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ALLOCATED %p", image);
4407
259k
  mng_info=(MngInfo *) NULL;
4408
259k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4409
259k
  if (status == MagickFalse)
4410
259k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
4411
259k
  blob_size=GetBlobSize(image);
4412
259k
  first_mng_object=MagickFalse;
4413
259k
  skipping_loop=(-1);
4414
259k
  have_mng_structure=MagickFalse;
4415
  /*
4416
    Allocate a MngInfo structure.
4417
  */
4418
259k
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
4419
259k
  if (mng_info == (MngInfo *) NULL)
4420
259k
    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
4421
  /*
4422
    Initialize members of the MngInfo structure.
4423
  */
4424
259k
  (void) memset(mng_info,0,sizeof(MngInfo));
4425
259k
  mng_info->image=image;
4426
259k
  have_mng_structure=MagickTrue;
4427
4428
259k
  if (LocaleCompare(image_info->magick,"MNG") == 0)
4429
259k
    {
4430
259k
      char
4431
259k
        magic_number[MaxTextExtent];
4432
4433
      /*
4434
        Verify MNG signature.
4435
      */
4436
259k
      if ((ReadBlob(image,8,magic_number) != 8) ||
4437
259k
          (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0))
4438
71
        {
4439
71
          MngInfoFreeStruct(mng_info,&have_mng_structure);
4440
71
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
4441
0
        }
4442
      /*
4443
        Initialize some nonzero members of the MngInfo structure.
4444
      */
4445
66.6M
      for (i=0; i < MNG_MAX_OBJECTS; i++)
4446
66.4M
        {
4447
66.4M
          mng_info->object_clip[i].right=PNG_MAX_UINT;
4448
66.4M
          mng_info->object_clip[i].bottom=PNG_MAX_UINT;
4449
66.4M
        }
4450
259k
      mng_info->exists[0]=MagickTrue;
4451
259k
    }
4452
259k
  first_mng_object=MagickTrue;
4453
259k
  mng_type=0;
4454
259k
#ifdef MNG_INSERT_LAYERS
4455
259k
  insert_layers=MagickFalse;  /* should be False if converting or mogrifying */
4456
259k
#endif
4457
259k
  default_frame_delay=0;
4458
259k
  default_frame_timeout=0;
4459
259k
  frame_delay=0;
4460
259k
  final_delay=1;
4461
259k
  mng_info->ticks_per_second=100;
4462
259k
  object_id=0;
4463
259k
  skip_to_iend=MagickFalse;
4464
259k
  term_chunk_found=MagickFalse;
4465
259k
  mng_info->framing_mode=1;
4466
259k
#ifdef MNG_INSERT_LAYERS
4467
259k
  mandatory_back=MagickFalse;
4468
259k
#endif
4469
259k
#ifdef MNG_INSERT_LAYERS
4470
259k
  mng_background_color=image->background_color;
4471
259k
#endif
4472
259k
  do
4473
1.58M
    {
4474
1.58M
      char
4475
1.58M
        type[MaxTextExtent];
4476
4477
1.58M
      if (LocaleCompare(image_info->magick,"MNG") == 0)
4478
1.58M
        {
4479
1.58M
          register unsigned char
4480
1.58M
            *p = 0;
4481
4482
1.58M
          unsigned char
4483
1.58M
            *chunk = (unsigned char *) NULL;
4484
4485
          /*
4486
            Read a new chunk.
4487
          */
4488
1.58M
          type[0]='\0';
4489
1.58M
          (void) strlcat(type,"errr",sizeof(type));
4490
1.58M
          length=(size_t) ReadBlobMSBLong(image);
4491
1.58M
          count=ReadBlob(image,4,type);
4492
1.58M
          if (count != 4)
4493
44.4k
            {
4494
44.4k
              if (logging)
4495
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4496
0
                                      "  Reading MNG chunk, count: "
4497
0
                                      "%" MAGICK_SIZE_T_F  "u",
4498
0
                                      (MAGICK_SIZE_T) count);
4499
44.4k
              MngInfoFreeStruct(mng_info,&have_mng_structure);
4500
44.4k
              ThrowReaderException(CorruptImageError,CorruptImage,image);
4501
0
            }
4502
4503
1.53M
          if (logging)
4504
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4505
0
                                  "  Reading MNG chunk type %c%c%c%c,"
4506
0
                                  " length: %lu",
4507
0
                                  type[0],type[1],type[2],type[3],length);
4508
4509
1.53M
          if (length > PNG_MAX_UINT)
4510
24.6k
            {
4511
24.6k
              MngInfoFreeStruct(mng_info,&have_mng_structure);
4512
24.6k
              ThrowReaderException(CorruptImageError,CorruptImage,image);
4513
0
            }
4514
1.51M
          if (length > (size_t) blob_size)
4515
85.5k
            {
4516
85.5k
              if (image->logging)
4517
85.5k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4518
85.5k
                                      "chunk length (%" MAGICK_SIZE_T_F "u)"
4519
85.5k
                                      " is greater than input size"
4520
85.5k
                                      " (%" MAGICK_OFF_F "d)",
4521
85.5k
                                      (MAGICK_SIZE_T) length,
4522
85.5k
                                      blob_size);
4523
85.5k
              MngInfoFreeStruct(mng_info,&have_mng_structure);
4524
85.5k
              ThrowReaderException(CorruptImageError,CorruptImage,image);
4525
0
            }
4526
1.42M
          if (length)
4527
574k
            {
4528
574k
              chunk=MagickAllocateMemory(unsigned char *,length);
4529
574k
              if (chunk == (unsigned char *) NULL)
4530
0
                ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
4531
574k
                                     image);
4532
574k
              if (ReadBlob(image,length,chunk) != length)
4533
15.7k
                {
4534
15.7k
                  MagickFreeMemory(chunk);
4535
15.7k
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4536
15.7k
                  ThrowReaderException(CorruptImageError,CorruptImage,image);
4537
0
                }
4538
558k
              p=chunk;
4539
558k
            }
4540
1.41M
          (void) ReadBlobMSBLong(image);  /* read crc word */
4541
4542
#if !defined(JNG_SUPPORTED)
4543
          if (!memcmp(type,mng_JHDR,4))
4544
            {
4545
              skip_to_iend=MagickTrue;
4546
              if (!mng_info->jhdr_warning)
4547
                (void) ThrowException(exception,CoderError,
4548
                                      JNGCompressionNotSupported,
4549
                                      image->filename);
4550
              mng_info->jhdr_warning++;
4551
            }
4552
#endif
4553
1.41M
          if (!memcmp(type,mng_DHDR,4))
4554
2.91k
            {
4555
2.91k
              skip_to_iend=MagickTrue;
4556
2.91k
              if (!mng_info->dhdr_warning)
4557
1.60k
                (void) ThrowException(exception,CoderError,
4558
2.91k
                                      DeltaPNGNotSupported,image->filename);
4559
2.91k
              mng_info->dhdr_warning++;
4560
2.91k
            }
4561
1.41M
          if (!memcmp(type,mng_MEND,4))
4562
7.21k
            {
4563
7.21k
              MagickFreeMemory(chunk);
4564
7.21k
              break;
4565
7.21k
            }
4566
1.40M
          if (skip_to_iend)
4567
12.1k
            {
4568
12.1k
              if (!memcmp(type,mng_IEND,4))
4569
1.29k
                skip_to_iend=MagickFalse;
4570
12.1k
              MagickFreeMemory(chunk);
4571
12.1k
              if (logging)
4572
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4573
0
                                      "  Skip to IEND.");
4574
12.1k
              continue;
4575
12.1k
            }
4576
1.39M
          if (!memcmp(type,mng_MHDR,4))
4577
31.9k
            {
4578
31.9k
              if (length < 16)
4579
8.14k
                {
4580
8.14k
                  MagickFreeMemory(chunk);
4581
8.14k
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4582
8.14k
                  ThrowReaderException(CorruptImageError,CorruptImage,image);
4583
0
                }
4584
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
4585
              /* To quiet a Coverity complaint */
4586
              LockSemaphoreInfo(png_semaphore);
4587
#endif
4588
23.7k
              mng_info->mng_width=(unsigned long) mng_get_long(p);
4589
23.7k
              mng_info->mng_height=(unsigned long) mng_get_long(&p[4]);
4590
23.7k
              if (logging)
4591
0
                {
4592
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4593
0
                                        "  MNG width: %lu",
4594
0
                                        mng_info->mng_width);
4595
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4596
0
                                        "  MNG height: %lu",
4597
0
                                        mng_info->mng_height);
4598
0
                }
4599
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
4600
              UnlockSemaphoreInfo(png_semaphore);
4601
#endif
4602
23.7k
              if ((mng_info->mng_width == 0) ||
4603
12.9k
                  (mng_info->mng_height == 0))
4604
13.7k
                {
4605
13.7k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4606
13.7k
                                        "   MNG width or height is zero: width %lu, height %lu",
4607
13.7k
                                        mng_info->mng_width,mng_info->mng_height);
4608
13.7k
                  MagickFreeMemory(chunk);
4609
13.7k
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4610
13.7k
                  ThrowReaderException(CorruptImageError,ImproperImageHeader,
4611
13.7k
                                       image);
4612
0
                }
4613
10.0k
              if ((long) mng_info->mng_width >
4614
10.0k
                  GetMagickResourceLimit(WidthResource) ||
4615
7.06k
                  (long) mng_info->mng_height >
4616
7.06k
                  GetMagickResourceLimit(HeightResource))
4617
3.57k
                {
4618
3.57k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4619
3.57k
                                        "   MNG width or height too large: width %lu, height %lu",
4620
3.57k
                                        mng_info->mng_width,mng_info->mng_height);
4621
3.57k
                  MagickFreeMemory(chunk);
4622
3.57k
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4623
3.57k
                  ThrowReaderException(CorruptImageError,ImproperImageHeader,
4624
3.57k
                                       image);
4625
0
                }
4626
4627
6.49k
              p+=8;
4628
6.49k
              mng_info->ticks_per_second=mng_get_long(p);
4629
6.49k
              if (mng_info->ticks_per_second == 0)
4630
3.50k
                default_frame_delay=0;
4631
2.98k
              else
4632
2.98k
                default_frame_delay=100/mng_info->ticks_per_second;
4633
6.49k
              frame_delay=default_frame_delay;
4634
6.49k
              simplicity=0;
4635
6.49k
              if (length >= 28)
4636
330
                {
4637
330
                  p+=16;
4638
330
                  simplicity=mng_get_long(p);
4639
330
                }
4640
6.49k
              if (logging)
4641
0
                {
4642
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4643
0
                                        "  MNG simplicity: %lx",simplicity);
4644
0
                }
4645
6.49k
              mng_type=1;    /* Full MNG */
4646
6.49k
              if ((simplicity != 0) && ((simplicity | 11) == 11))
4647
94
                mng_type=2; /* LC */
4648
6.49k
              if ((simplicity != 0) && ((simplicity | 9) == 9))
4649
62
                mng_type=3; /* VLC */
4650
6.49k
#ifdef MNG_INSERT_LAYERS
4651
6.49k
              if (mng_type != 3 && !image_info->ping)
4652
6.43k
                insert_layers=MagickTrue;
4653
6.49k
#endif
4654
6.49k
              if (AccessMutablePixels(image) != (PixelPacket *) NULL)
4655
253
                {
4656
253
                  StopTimer(&image->timer);
4657
                  /*
4658
                    Allocate next image structure.
4659
                  */
4660
253
                  AllocateNextImage(image_info,image);
4661
253
                  if (image->next == (Image *) NULL)
4662
0
                    {
4663
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
4664
0
                      return((Image *) NULL);
4665
0
                    }
4666
253
                  image=SyncNextImageInList(image);
4667
253
                  mng_info->image=image;
4668
253
                }
4669
4670
6.49k
              if ((mng_info->mng_width > 65535L) ||
4671
6.49k
                  (mng_info->mng_height > 65535L))
4672
0
                {
4673
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4674
0
                                        "  MNG width or height is too large: %lu, %lu",
4675
0
                                        mng_info->mng_width,mng_info->mng_height);
4676
0
                  MagickFreeMemory(chunk);
4677
0
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4678
0
                  ThrowReaderException(CorruptImageError,
4679
0
                                       ImproperImageHeader,image);
4680
0
                }
4681
4682
6.49k
              MagickFormatString(page_geometry,sizeof(page_geometry),"%lux%lu+0+0",
4683
6.49k
                                 mng_info->mng_width,mng_info->mng_height);
4684
6.49k
              mng_info->frame.left=0;
4685
6.49k
              mng_info->frame.right=(long) mng_info->mng_width;
4686
6.49k
              mng_info->frame.top=0;
4687
6.49k
              mng_info->frame.bottom=(long) mng_info->mng_height;
4688
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
4689
              /* To quiet a Coverity complaint */
4690
              LockSemaphoreInfo(png_semaphore);
4691
#endif
4692
6.49k
              mng_info->clip=default_fb=previous_fb=mng_info->frame;
4693
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
4694
              UnlockSemaphoreInfo(png_semaphore);
4695
#endif
4696
1.66M
              for (i=0; i < MNG_MAX_OBJECTS; i++)
4697
1.66M
                mng_info->object_clip[i]=mng_info->frame;
4698
6.49k
              MagickFreeMemory(chunk);
4699
6.49k
              continue;
4700
6.49k
            }
4701
4702
1.36M
          if (!memcmp(type,mng_TERM,4))
4703
13.5k
            {
4704
13.5k
              int
4705
13.5k
                repeat=0;
4706
4707
13.5k
              if (length)
4708
9.85k
                repeat=p[0];
4709
13.5k
              if (repeat == 3 && length > 9)
4710
1.01k
                {
4711
1.01k
                  final_delay=(png_uint_32) mng_get_long(&p[2]);
4712
1.01k
                  mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4713
1.01k
                  if (mng_iterations == PNG_MAX_UINT)
4714
142
                    mng_iterations=0;
4715
1.01k
                  image->iterations=mng_iterations;
4716
1.01k
                  term_chunk_found=MagickTrue;
4717
1.01k
                }
4718
13.5k
              if (logging)
4719
0
                {
4720
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4721
0
                                        "    repeat=%d",repeat);
4722
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4723
0
                                        "    final_delay=%ld",final_delay);
4724
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4725
0
                                        "    image->iterations=%ld",
4726
0
                                        image->iterations);
4727
0
                }
4728
13.5k
              MagickFreeMemory(chunk);
4729
13.5k
              continue;
4730
13.5k
            }
4731
1.34M
          if (!memcmp(type,mng_DEFI,4))
4732
57.8k
            {
4733
57.8k
              if (mng_type == 3)
4734
136
                {
4735
136
                  if (logging)
4736
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4737
0
                                          "DEFI chunk found in MNG-VLC"
4738
0
                                          " datastream");
4739
136
                  MagickFreeMemory(chunk);
4740
136
                  continue;
4741
136
                }
4742
57.7k
              if (length < 2)
4743
2.79k
                {
4744
2.79k
                  if (logging)
4745
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4746
0
                                          "  DEFI chunk must be at least"
4747
0
                                          " 2 bytes long");
4748
2.79k
                  MagickFreeMemory(chunk);
4749
2.79k
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
4750
2.79k
                  ThrowReaderException(CorruptImageError,CorruptImage,image);
4751
0
                }
4752
54.9k
              object_id=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
4753
54.9k
              if (mng_type == 2 && object_id != 0)
4754
181
                (void) ThrowException2(exception,CoderError,
4755
54.9k
                                       "Nonzero object_id in MNG-LC"
4756
54.9k
                                       " datastream",
4757
54.9k
                                       (char *) NULL);
4758
54.9k
              if (object_id >= MNG_MAX_OBJECTS)
4759
49.7k
                {
4760
                  /*
4761
                    Instead of issuing a warning we should allocate a larger
4762
                    MngInfo structure and continue.
4763
                  */
4764
49.7k
                  if (logging)
4765
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4766
0
                                          "object id (%u) too large", object_id);
4767
49.7k
                  object_id=MNG_MAX_OBJECTS-1;
4768
49.7k
                }
4769
54.9k
              if (mng_info->exists[object_id])
4770
5.88k
                if (mng_info->frozen[object_id])
4771
1.22k
                  {
4772
1.22k
                    if (logging)
4773
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4774
0
                                            "DEFI cannot redefine a frozen"
4775
0
                                            " MNG object");
4776
1.22k
                    MagickFreeMemory(chunk);
4777
1.22k
                    continue;
4778
1.22k
                  }
4779
53.6k
              mng_info->exists[object_id]=MagickTrue;
4780
53.6k
              if (length > 2)
4781
51.8k
                mng_info->invisible[object_id]=p[2];
4782
              /*
4783
                Extract object offset info.
4784
              */
4785
53.6k
              if (length > 11)
4786
50.7k
                {
4787
50.7k
                  mng_info->x_off[object_id]= mng_get_long(&p[4]);
4788
50.7k
                  mng_info->y_off[object_id]= mng_get_long(&p[8]);
4789
50.7k
                  if (logging)
4790
0
                    {
4791
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4792
0
                                            "  x_off[%d]: %lu",object_id,
4793
0
                                            mng_info->x_off[object_id]);
4794
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4795
0
                                            "  y_off[%d]: %lu",object_id,
4796
0
                                            mng_info->y_off[object_id]);
4797
0
                    }
4798
50.7k
                }
4799
              /*
4800
                Extract object clipping info.
4801
              */
4802
53.6k
              if (length > 27)
4803
50.1k
                mng_info->object_clip[object_id]
4804
50.1k
                  =mng_read_box( mng_info->frame,0,&p[12]);
4805
53.6k
              MagickFreeMemory(chunk);
4806
53.6k
              continue;
4807
54.9k
            }
4808
1.28M
          if (!memcmp(type,mng_bKGD,4))
4809
1.96k
            {
4810
1.96k
              mng_info->have_global_bkgd=MagickFalse;
4811
1.96k
              if (length > 5)
4812
526
                {
4813
526
                  mng_info->mng_global_bkgd.red
4814
526
                    =ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) |
4815
526
                                          (magick_uint32_t) p[1]));
4816
526
                  mng_info->mng_global_bkgd.green
4817
526
                    =ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) |
4818
526
                                          (magick_uint32_t) p[3]));
4819
526
                  mng_info->mng_global_bkgd.blue
4820
526
                    =ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) |
4821
526
                                          (magick_uint32_t) p[5]));
4822
526
                  mng_info->have_global_bkgd=MagickTrue;
4823
526
                }
4824
1.96k
              MagickFreeMemory(chunk);
4825
1.96k
              continue;
4826
1.96k
            }
4827
1.28M
          if (!memcmp(type,mng_BACK,4))
4828
10.1k
            {
4829
10.1k
#ifdef MNG_INSERT_LAYERS
4830
10.1k
              if (length > 6)
4831
8.54k
                mandatory_back=p[6];
4832
1.64k
              else
4833
1.64k
                mandatory_back=0;
4834
10.1k
              if (mandatory_back && length > 5)
4835
4.84k
                {
4836
4.84k
                  mng_background_color.red=
4837
4.84k
                    ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) |
4838
4.84k
                                         (magick_uint32_t) p[1]));
4839
4.84k
                  mng_background_color.green=
4840
4.84k
                    ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) |
4841
4.84k
                                         (magick_uint32_t) p[3]));
4842
4.84k
                  mng_background_color.blue=
4843
4.84k
                    ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) |
4844
4.84k
                                         (magick_uint32_t) p[5]));
4845
4.84k
                  mng_background_color.opacity=OpaqueOpacity;
4846
4.84k
                }
4847
#ifdef MNG_OBJECT_BUFFERS
4848
              if (length > 8)
4849
                mng_background_object=((magick_uint32_t) p[7] << 8) |
4850
                  (magick_uint32_t) p[8];
4851
#endif
4852
10.1k
#endif
4853
10.1k
              MagickFreeMemory(chunk);
4854
10.1k
              continue;
4855
10.1k
            }
4856
1.27M
          if (!memcmp(type,mng_PLTE,4))
4857
3.39k
            {
4858
              /*
4859
                Read global PLTE.
4860
              */
4861
3.39k
              if (length && (length < 769))
4862
3.00k
                {
4863
3.00k
                  if (mng_info->global_plte == (png_colorp) NULL)
4864
604
                    mng_info->global_plte=
4865
604
                      MagickAllocateMemory(png_colorp,256*sizeof(png_color));
4866
3.00k
                  if (mng_info->global_plte == (png_colorp) NULL)
4867
0
                    {
4868
0
                      mng_info->global_plte_length=0;
4869
0
                      MagickFreeMemory(chunk);
4870
0
                      MngInfoFreeStruct(mng_info,&have_mng_structure);
4871
0
                      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
4872
0
                                           image);
4873
0
                    }
4874
30.4k
                  for (i=0; i < (long) (length/3); i++)
4875
27.4k
                    {
4876
27.4k
                      mng_info->global_plte[i].red=p[3*i];
4877
27.4k
                      mng_info->global_plte[i].green=p[3*i+1];
4878
27.4k
                      mng_info->global_plte[i].blue=p[3*i+2];
4879
27.4k
                    }
4880
3.00k
                  mng_info->global_plte_length=length/3;
4881
3.00k
                }
4882
#ifdef MNG_LOOSE
4883
              for ( ; i < 256; i++)
4884
                {
4885
                  mng_info->global_plte[i].red=i;
4886
                  mng_info->global_plte[i].green=i;
4887
                  mng_info->global_plte[i].blue=i;
4888
                }
4889
              if (length)
4890
                mng_info->global_plte_length=256;
4891
#endif
4892
395
              else
4893
395
                mng_info->global_plte_length=0;
4894
3.39k
              MagickFreeMemory(chunk);
4895
3.39k
              continue;
4896
3.39k
            }
4897
1.27M
          if (!memcmp(type,mng_tRNS,4))
4898
12.3k
            {
4899
              /* read global tRNS */
4900
4901
12.3k
              if (length < 257)
4902
77.1k
                for (i=0; i < (long) length; i++)
4903
64.8k
                  mng_info->global_trns[i]=p[i];
4904
4905
#ifdef MNG_LOOSE
4906
              for ( ; i < 256; i++)
4907
                mng_info->global_trns[i]=255;
4908
#endif
4909
12.3k
              mng_info->global_trns_length=length;
4910
12.3k
              MagickFreeMemory(chunk);
4911
12.3k
              continue;
4912
12.3k
            }
4913
1.26M
          if (!memcmp(type,mng_gAMA,4))
4914
1.45k
            {
4915
1.45k
              if (length == 4)
4916
678
                {
4917
678
                  long
4918
678
                    igamma;
4919
4920
678
                  igamma=mng_get_long(p);
4921
678
                  mng_info->global_gamma=((float) igamma*0.00001f);
4922
678
                  mng_info->have_global_gama=MagickTrue;
4923
678
                }
4924
777
              else
4925
777
                mng_info->have_global_gama=MagickFalse;
4926
1.45k
              MagickFreeMemory(chunk);
4927
1.45k
              continue;
4928
1.45k
            }
4929
4930
1.26M
          if (!memcmp(type,mng_cHRM,4))
4931
5.86k
            {
4932
              /*
4933
                Read global cHRM
4934
              */
4935
5.86k
              if (length == 32)
4936
4.18k
                {
4937
4.18k
                  mng_info->global_chrm.white_point.x=0.00001*
4938
4.18k
                    mng_get_long(p);
4939
4.18k
                  mng_info->global_chrm.white_point.y=0.00001*
4940
4.18k
                    mng_get_long(&p[4]);
4941
4.18k
                  mng_info->global_chrm.red_primary.x=0.00001*
4942
4.18k
                    mng_get_long(&p[8]);
4943
4.18k
                  mng_info->global_chrm.red_primary.y=0.00001*
4944
4.18k
                    mng_get_long(&p[12]);
4945
4.18k
                  mng_info->global_chrm.green_primary.x=0.00001*
4946
4.18k
                    mng_get_long(&p[16]);
4947
4.18k
                  mng_info->global_chrm.green_primary.y=0.00001*
4948
4.18k
                    mng_get_long(&p[20]);
4949
4.18k
                  mng_info->global_chrm.blue_primary.x=0.00001*
4950
4.18k
                    mng_get_long(&p[24]);
4951
4.18k
                  mng_info->global_chrm.blue_primary.y=0.00001*
4952
4.18k
                    mng_get_long(&p[28]);
4953
4.18k
                  mng_info->have_global_chrm=MagickTrue;
4954
4.18k
                }
4955
1.67k
              else
4956
1.67k
                mng_info->have_global_chrm=MagickFalse;
4957
5.86k
              MagickFreeMemory(chunk);
4958
5.86k
              continue;
4959
5.86k
            }
4960
1.25M
          if (!memcmp(type,mng_sRGB,4))
4961
1.12k
            {
4962
              /*
4963
                Read global sRGB.
4964
              */
4965
1.12k
              if (length)
4966
636
                {
4967
636
                  mng_info->global_srgb_intent=(RenderingIntent) (p[0]+1);
4968
636
                  mng_info->have_global_srgb=MagickTrue;
4969
636
                }
4970
484
              else
4971
484
                mng_info->have_global_srgb=MagickFalse;
4972
1.12k
              MagickFreeMemory(chunk);
4973
1.12k
              continue;
4974
1.12k
            }
4975
1.25M
          if (!memcmp(type,mng_iCCP,4))
4976
3.83k
            {
4977
              /* To do. */
4978
4979
              /*
4980
                Read global iCCP.
4981
              */
4982
3.83k
              MagickFreeMemory(chunk);
4983
3.83k
              continue;
4984
3.83k
            }
4985
1.24M
          if (!memcmp(type,mng_FRAM,4))
4986
112k
            {
4987
112k
              if (mng_type == 3)
4988
523
                (void) ThrowException2(exception,CoderError,
4989
112k
                                       "FRAM chunk found in MNG-VLC"
4990
112k
                                       " datastream",
4991
112k
                                       (char *) NULL);
4992
112k
              if ((mng_info->framing_mode == 2) ||
4993
112k
                  (mng_info->framing_mode == 4))
4994
32.8k
                image->delay=frame_delay;
4995
112k
              frame_delay=default_frame_delay;
4996
112k
              frame_timeout=default_frame_timeout;
4997
112k
              fb=default_fb;
4998
112k
              if (length)
4999
108k
                if (p[0])
5000
73.2k
                  mng_info->framing_mode=p[0];
5001
112k
              if (logging)
5002
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5003
0
                                      "    Framing_mode=%d",
5004
0
                                      mng_info->framing_mode);
5005
112k
              if (length > 6)
5006
107k
                {
5007
                  /*
5008
                    Note the delay and frame clipping boundaries.
5009
                  */
5010
107k
                  p++; /* framing mode */
5011
340k
                  while (((p-chunk) < (long) length) && *p)
5012
232k
                    p++;  /* frame name */
5013
107k
                  p++;  /* frame name terminator */
5014
107k
                  if ((p-chunk) < (long) (length-4))
5015
70.4k
                    {
5016
70.4k
                      int
5017
70.4k
                        change_delay,
5018
70.4k
                        change_timeout,
5019
70.4k
                        change_clipping;
5020
5021
70.4k
                      change_delay=(*p++);
5022
70.4k
                      change_timeout=(*p++);
5023
70.4k
                      change_clipping=(*p++);
5024
70.4k
                      p++; /* change_sync */
5025
70.4k
                      if (change_delay && ((p-chunk) < (ssize_t) (length-4)))
5026
4.84k
                        {
5027
4.84k
                          if (mng_info->ticks_per_second == 0)
5028
119
                            frame_delay=0;
5029
4.72k
                          else
5030
4.72k
                            frame_delay=(100*(mng_get_long(p))/
5031
4.72k
                                         mng_info->ticks_per_second);
5032
4.84k
                          if (change_delay == 2)
5033
268
                            default_frame_delay=frame_delay;
5034
4.84k
                          p+=4;
5035
4.84k
                          if (logging)
5036
0
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5037
0
                                                  "    Framing_delay=%ld",
5038
0
                                                  frame_delay);
5039
4.84k
                        }
5040
70.4k
                      if (change_timeout && (p-chunk) < (ssize_t) (length-4))
5041
5.22k
                        {
5042
5.22k
                          if (mng_info->ticks_per_second == 0)
5043
95
                            frame_timeout=0;
5044
5.13k
                          else
5045
5.13k
                            frame_timeout=
5046
5.13k
                              (100*(mng_get_long(p))/mng_info->ticks_per_second);
5047
5.22k
                          if (change_timeout == 2)
5048
2
                            default_frame_timeout=frame_timeout;
5049
5.22k
                          p+=4;
5050
5.22k
                          if (logging)
5051
0
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5052
0
                                                  "    Framing_timeout=%ld",
5053
0
                                                  frame_timeout);
5054
5.22k
                        }
5055
70.4k
                      if (change_clipping && (p-chunk) < (ssize_t) (length-16))
5056
53.3k
                        {
5057
53.3k
                          fb=mng_read_box(previous_fb,p[0],&p[1]);
5058
53.3k
                          p+=16;
5059
53.3k
                          previous_fb=fb;
5060
53.3k
                          if (logging)
5061
0
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5062
0
                                                  "    Frame_clipping:"
5063
0
                                                  " L=%ld R=%ld T=%ld B=%ld",
5064
0
                                                  fb.left, fb.right,fb.top,
5065
0
                                                  fb.bottom);
5066
53.3k
                          if (change_clipping == 2)
5067
48.1k
                            default_fb=fb;
5068
53.3k
                        }
5069
70.4k
                    }
5070
107k
                }
5071
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
5072
              /* To quiet a Coverity complaint */
5073
              LockSemaphoreInfo(png_semaphore);
5074
#endif
5075
112k
              mng_info->clip=fb;
5076
112k
              mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5077
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
5078
              UnlockSemaphoreInfo(png_semaphore);
5079
#endif
5080
112k
              subframe_width=(mng_info->clip.right-mng_info->clip.left);
5081
112k
              subframe_height=(mng_info->clip.bottom-mng_info->clip.top);
5082
              /*
5083
                Insert a background layer behind the frame
5084
                if framing_mode is 4.
5085
              */
5086
112k
#ifdef MNG_INSERT_LAYERS
5087
112k
              if (logging)
5088
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5089
0
                                      "   subframe_width=%lu,"
5090
0
                                      " subframe_height=%lu",
5091
0
                                      subframe_width, subframe_height);
5092
112k
              if (insert_layers && (mng_info->framing_mode == 4) &&
5093
32.6k
                  (subframe_width) && (subframe_height))
5094
32.2k
                {
5095
                  /*
5096
                    Allocate next image structure.
5097
                  */
5098
32.2k
                  if (AccessMutablePixels(image) != (PixelPacket *) NULL)
5099
31.1k
                    {
5100
31.1k
                      StopTimer(&image->timer);
5101
31.1k
                      AllocateNextImage(image_info,image);
5102
31.1k
                      if (image->next == (Image *) NULL)
5103
0
                        {
5104
0
                          DestroyImageList(image);
5105
0
                          MngInfoFreeStruct(mng_info,&have_mng_structure);
5106
0
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5107
0
                          return((Image *) NULL);
5108
0
                        }
5109
31.1k
                      image=SyncNextImageInList(image);
5110
31.1k
                    }
5111
32.2k
                  mng_info->image=image;
5112
32.2k
                  if (term_chunk_found)
5113
116
                    {
5114
116
                      image->start_loop=MagickTrue;
5115
116
                      image->iterations=mng_iterations;
5116
116
                      term_chunk_found=MagickFalse;
5117
116
                    }
5118
32.0k
                  else
5119
32.0k
                    image->start_loop=MagickFalse;
5120
32.2k
                  image->columns=subframe_width;
5121
32.2k
                  image->rows=subframe_height;
5122
32.2k
                  image->page.width=subframe_width;
5123
32.2k
                  image->page.height=subframe_height;
5124
32.2k
                  image->page.x=mng_info->clip.left;
5125
32.2k
                  image->page.y=mng_info->clip.top;
5126
32.2k
                  image->background_color=mng_background_color;
5127
32.2k
                  image->matte=MagickFalse;
5128
32.2k
                  image->delay=0;
5129
32.2k
                  if (SetImage(image,OpaqueOpacity) != MagickPass)
5130
236
                    {
5131
236
                      if (logging)
5132
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5133
0
                                              "  Failed to insert background layer,"
5134
0
                                              " L=%ld, R=%ld, T=%ld, B=%ld",
5135
0
                                              mng_info->clip.left,
5136
0
                                              mng_info->clip.right,
5137
0
                                              mng_info->clip.top,
5138
0
                                              mng_info->clip.bottom);
5139
236
                      CopyException(exception,&image->exception);
5140
236
                      MagickFreeMemory(chunk);
5141
236
                      DestroyImageList(image);
5142
236
                      MngInfoFreeStruct(mng_info,&have_mng_structure);
5143
236
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5144
236
                      return((Image *) NULL);
5145
236
                    }
5146
31.9k
                  if (logging)
5147
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5148
0
                                          "  Inserted background layer,"
5149
0
                                          " L=%ld, R=%ld, T=%ld, B=%ld",
5150
0
                                          mng_info->clip.left,
5151
0
                                          mng_info->clip.right,
5152
0
                                          mng_info->clip.top,
5153
0
                                          mng_info->clip.bottom);
5154
31.9k
                }
5155
112k
#endif
5156
112k
              MagickFreeMemory(chunk);
5157
112k
              continue;
5158
112k
            }
5159
1.13M
          if (!memcmp(type,mng_CLIP,4))
5160
5.72k
            {
5161
5.72k
              unsigned int
5162
5.72k
                first_object,
5163
5.72k
                last_object;
5164
5165
              /*
5166
                Read CLIP.
5167
              */
5168
5.72k
              if (length > 3)
5169
2.59k
                {
5170
2.59k
                  first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
5171
2.59k
                  last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
5172
2.59k
                  p+=4;
5173
5174
14.6M
                  for (i=(int) first_object; i <= (int) last_object; i++)
5175
14.6M
                    {
5176
14.6M
                      if (i >= MNG_MAX_OBJECTS)
5177
14.4M
                        continue;
5178
263k
                      if (mng_info->exists[i] && !mng_info->frozen[i])
5179
2.69k
                        {
5180
2.69k
                          MngBox
5181
2.69k
                            box;
5182
5183
2.69k
                          box=mng_info->object_clip[i];
5184
2.69k
                          if ((p-chunk) < (ssize_t) (length-17))
5185
1.52k
                            mng_info->object_clip[i]=
5186
1.52k
                              mng_read_box(box,p[0],&p[1]);
5187
2.69k
                        }
5188
263k
                    }
5189
2.59k
                }
5190
5.72k
              MagickFreeMemory(chunk);
5191
5.72k
              continue;
5192
5.72k
            }
5193
1.13M
          if (!memcmp(type,mng_SAVE,4))
5194
27.7k
            {
5195
7.09M
              for (i=1; i < MNG_MAX_OBJECTS; i++)
5196
7.06M
                if (mng_info->exists[i])
5197
26.4k
                  {
5198
26.4k
                    mng_info->frozen[i]=MagickTrue;
5199
#ifdef MNG_OBJECT_BUFFERS
5200
                    if (mng_info->ob[i] != (MngBuffer *) NULL)
5201
                      mng_info->ob[i]->frozen=MagickTrue;
5202
#endif
5203
26.4k
                  }
5204
27.7k
              MagickFreeMemory(chunk);
5205
27.7k
              continue;
5206
27.7k
            }
5207
5208
1.10M
          if (!memcmp(type,mng_DISC,4) || !memcmp(type,mng_SEEK,4))
5209
15.1k
            {
5210
              /*
5211
                Read DISC or SEEK.
5212
              */
5213
15.1k
              if ((length == 0) || (length % 2) || !memcmp(type,mng_SEEK,4))
5214
9.99k
                {
5215
2.55M
                  for (i=1; i < MNG_MAX_OBJECTS; i++)
5216
2.54M
                    MngInfoDiscardObject(mng_info,i);
5217
9.99k
                }
5218
5.14k
              else
5219
5.14k
                {
5220
5.14k
                  register long
5221
5.14k
                    j;
5222
5223
179k
                  for (j=0; j < (long) length; j+=2)
5224
173k
                    {
5225
173k
                      i=(magick_uint32_t) p[j] << 8 | (magick_uint32_t) p[j+1];
5226
173k
                      MngInfoDiscardObject(mng_info,i);
5227
173k
                    }
5228
5.14k
                }
5229
15.1k
              MagickFreeMemory(chunk);
5230
15.1k
              continue;
5231
15.1k
            }
5232
1.08M
          if (!memcmp(type,mng_MOVE,4))
5233
4.83k
            {
5234
4.83k
              unsigned long
5235
4.83k
                first_object,
5236
4.83k
                last_object;
5237
5238
              /*
5239
                read MOVE
5240
              */
5241
5242
4.83k
              if (length > 3)
5243
3.86k
                {
5244
3.86k
                  first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
5245
3.86k
                  last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
5246
3.86k
                  p+=4;
5247
5248
28.4M
                  for (i=(long) first_object; i <= (long) last_object; i++)
5249
28.4M
                    {
5250
28.4M
                      if (i >= MNG_MAX_OBJECTS)
5251
28.2M
                        continue;
5252
218k
                      if (mng_info->exists[i] && !mng_info->frozen[i] &&
5253
1.97k
                          (p-chunk) < (ssize_t) (length-8))
5254
787
                        {
5255
787
                          MngPair
5256
787
                            new_pair;
5257
5258
787
                          MngPair
5259
787
                            old_pair;
5260
5261
787
                          old_pair.a=mng_info->x_off[i];
5262
787
                          old_pair.b=mng_info->y_off[i];
5263
787
                          new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]);
5264
787
                          mng_info->x_off[i]=new_pair.a;
5265
787
                          mng_info->y_off[i]=new_pair.b;
5266
787
                        }
5267
218k
                    }
5268
3.86k
                }
5269
4.83k
              MagickFreeMemory(chunk);
5270
4.83k
              continue;
5271
4.83k
            }
5272
5273
1.08M
          if (!memcmp(type,mng_LOOP,4))
5274
4.01k
            {
5275
4.01k
              long loop_iters=1;
5276
5277
4.01k
              if (logging)
5278
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5279
0
                                      "Handling LOOP chunk");
5280
4.01k
              if (length >= 5) /* To do: check spec, if empty LOOP is allowed */
5281
2.86k
                {
5282
2.86k
                  loop_level=chunk[0]; /* 1 byte */
5283
#if defined(PNG_DEBUG_LOOPS_ACTIVE)
5284
                  loops_active++;
5285
#endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */
5286
2.86k
                  mng_info->loop_active[loop_level]=1;  /* mark loop active */
5287
                  /*
5288
                    Record starting point.
5289
                  */
5290
2.86k
                  loop_iters=mng_get_long(&chunk[1]); /* 4 bytes */
5291
2.86k
                  if (logging)
5292
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5293
0
                                          "Loop iterations requested: %ld", loop_iters);
5294
2.86k
                  if (loop_iters <= 0)
5295
1.37k
                    skipping_loop=loop_level;
5296
1.48k
                  else
5297
1.48k
                    {
5298
1.48k
                      long
5299
1.48k
                        loop_iters_max = 512;
5300
5301
1.48k
                      const char
5302
1.48k
                        *definition_value;
5303
5304
1.48k
                      if (image_info->subrange != 0)
5305
1.48k
                        {
5306
                          /*
5307
                            FIXME: This is a quick hack to adjust the
5308
                            maximum loop iterations based on the
5309
                            subrange specification.  A proper solution
5310
                            would be to handle scene/subimage/subrange
5311
                            for MNG as it should have been in the
5312
                            first place.
5313
                          */
5314
1.48k
                          if (logging)
5315
0
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5316
0
                                                  "Adjusting loop ierations based on subrange:"
5317
0
                                                  " scene: %lu: subimage: %lu, subrange: %lu",
5318
0
                                                  image->scene, image_info->subimage,
5319
0
                                                  image_info->subrange);
5320
1.48k
                          loop_iters=Min(image_info->subrange,(unsigned long) loop_iters);
5321
1.48k
                        }
5322
1.48k
                      if ((definition_value=AccessDefinition(image_info,"mng","maximum-loops")))
5323
0
                        loop_iters_max=atol(definition_value);
5324
1.48k
                      if (loop_iters > loop_iters_max)
5325
0
                        loop_iters=loop_iters_max;
5326
5327
                      /*
5328
                        The LOOP chunk allows an iteration count in the range 0..2^31-1
5329
                      */
5330
1.48k
                      if (loop_iters >= 2147483647L)
5331
0
                        loop_iters=2147483647L;
5332
1.48k
                      else if (loop_iters < 0)
5333
0
                        loop_iters=1;
5334
5335
1.48k
                      if (logging)
5336
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5337
0
                                              "Loop iterations allowed: %ld", loop_iters);
5338
5339
1.48k
                      mng_info->loop_jump[loop_level]=TellBlob(image);
5340
1.48k
                      mng_info->loop_count[loop_level]=loop_iters;
5341
1.48k
                    }
5342
2.86k
                  mng_info->loop_iteration[loop_level]=0;
5343
2.86k
                }
5344
1.15k
              else
5345
1.15k
                {
5346
1.15k
                  if (logging)
5347
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5348
0
                                          "Ignoring short LOOP chunk (%lu bytes)", length);
5349
1.15k
                }
5350
4.01k
              MagickFreeMemory(chunk);
5351
4.01k
              continue;
5352
4.01k
            }
5353
1.07M
          if (!memcmp(type,mng_ENDL,4))
5354
5.80k
            {
5355
5.80k
              if (length < 1)
5356
934
                {
5357
934
                  if (logging)
5358
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5359
0
                                          "Ignoring empty ENDL chunk");
5360
934
                  MagickFreeMemory(chunk);
5361
934
                  continue;
5362
934
                }
5363
4.86k
              loop_level=chunk[0];
5364
#if defined(PNG_DEBUG_LOOPS_ACTIVE)
5365
              if (logging)
5366
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5367
                                      "ENDL: loop_level = %d,"
5368
                                      " loop_active[%d]=%d,"
5369
                                      " mng_info->loop_count[%d]=%ld,"
5370
                                      " loop_iteration[%d]=%ld",
5371
                                      (int) loop_level,
5372
                                      (int) loop_level, (int) mng_info->loop_active[loop_level],
5373
                                      (int) loop_level, mng_info->loop_count[loop_level],
5374
                                      (int) loop_level, mng_info->loop_iteration[loop_level]);
5375
#endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */
5376
4.86k
              if (skipping_loop > 0)
5377
1.59k
                {
5378
1.59k
                  if (skipping_loop == loop_level)
5379
836
                    {
5380
                      /*
5381
                        Found end of zero-iteration loop.
5382
                      */
5383
836
                      skipping_loop=(-1);
5384
#if defined(PNG_DEBUG_LOOPS_ACTIVE)
5385
                      loops_active--;
5386
#endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */
5387
836
                      mng_info->loop_active[loop_level]=0;
5388
836
                    }
5389
1.59k
                }
5390
3.27k
              else
5391
3.27k
                {
5392
3.27k
                  if (mng_info->loop_active[loop_level] == 1)
5393
783
                    {
5394
783
                      mng_info->loop_count[loop_level]--;
5395
783
                      mng_info->loop_iteration[loop_level]++;
5396
783
                      if (mng_info->loop_count[loop_level] > 0)
5397
0
                        (void) SeekBlob(image,mng_info->loop_jump[loop_level],
5398
0
                                        SEEK_SET);
5399
783
                      else
5400
783
                        {
5401
783
                          short
5402
783
                            last_level;
5403
5404
                          /*
5405
                            Finished loop.
5406
                          */
5407
#if defined(PNG_DEBUG_LOOPS_ACTIVE)
5408
                          loops_active--;
5409
#endif /* if defined(PNG_DEBUG_LOOPS_ACTIVE) */
5410
783
                          mng_info->loop_active[loop_level]=0;
5411
783
                          last_level=(-1);
5412
15.0k
                          for (i=0; i < loop_level; i++)
5413
14.2k
                            if (mng_info->loop_active[i] == 1)
5414
254
                              last_level=(short) i;
5415
783
                          loop_level=last_level;
5416
783
                        }
5417
783
                    }
5418
3.27k
                }
5419
4.86k
              MagickFreeMemory(chunk);
5420
4.86k
              continue;
5421
5.80k
            }
5422
1.07M
          if (!memcmp(type,mng_CLON,4))
5423
2.37k
            {
5424
2.37k
              if (!mng_info->clon_warning)
5425
1.00k
                (void) ThrowException2(exception,CoderError,
5426
2.37k
                                       "CLON is not implemented yet",
5427
2.37k
                                       image->filename);
5428
2.37k
              mng_info->clon_warning++;
5429
2.37k
            }
5430
1.07M
          if (!memcmp(type,mng_MAGN,4))
5431
50.8k
            {
5432
50.8k
              png_uint_16
5433
50.8k
                magn_first,
5434
50.8k
                magn_last,
5435
50.8k
                magn_mb,
5436
50.8k
                magn_ml,
5437
50.8k
                magn_mr,
5438
50.8k
                magn_mt,
5439
50.8k
                magn_mx,
5440
50.8k
                magn_my,
5441
50.8k
                magn_methx,
5442
50.8k
                magn_methy;
5443
5444
50.8k
              if (length > 1)
5445
45.4k
                magn_first=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
5446
5.36k
              else
5447
5.36k
                magn_first=0;
5448
50.8k
              if (length > 3)
5449
45.4k
                magn_last=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
5450
5.43k
              else
5451
5.43k
                magn_last=magn_first;
5452
50.8k
#ifndef MNG_OBJECT_BUFFERS
5453
50.8k
              if (magn_first || magn_last)
5454
43.5k
                if (!mng_info->magn_warning)
5455
35.6k
                  {
5456
35.6k
                    (void) ThrowException2(exception,CoderError,
5457
35.6k
                                           "MAGN is not implemented yet"
5458
35.6k
                                           " for nonzero objects",
5459
35.6k
                                           image->filename);
5460
35.6k
                    mng_info->magn_warning++;
5461
35.6k
                  }
5462
50.8k
#endif
5463
50.8k
              if (length > 4)
5464
45.2k
                magn_methx=p[4];
5465
5.58k
              else
5466
5.58k
                magn_methx=0;
5467
5468
50.8k
              if (length > 6)
5469
44.7k
                magn_mx=((magick_uint32_t) p[5] << 8) | (magick_uint32_t) p[6];
5470
6.05k
              else
5471
6.05k
                magn_mx=1;
5472
50.8k
              if (magn_mx == 0)
5473
9.91k
                magn_mx=1;
5474
5475
50.8k
              if (length > 8)
5476
41.9k
                magn_my=((magick_uint32_t) p[7] << 8) | (magick_uint32_t) p[8];
5477
8.93k
              else
5478
8.93k
                magn_my=magn_mx;
5479
50.8k
              if (magn_my == 0)
5480
32.2k
                magn_my=1;
5481
5482
50.8k
              if (length > 10)
5483
10.3k
                magn_ml=((magick_uint32_t) p[9] << 8) | (magick_uint32_t) p[10];
5484
40.4k
              else
5485
40.4k
                magn_ml=magn_mx;
5486
50.8k
              if (magn_ml == 0)
5487
5.45k
                magn_ml=1;
5488
5489
50.8k
              if (length > 12)
5490
10.3k
                magn_mr=((magick_uint32_t) p[11] << 8) | (magick_uint32_t) p[12];
5491
40.4k
              else
5492
40.4k
                magn_mr=magn_mx;
5493
50.8k
              if (magn_mr == 0)
5494
4.50k
                magn_mr=1;
5495
5496
50.8k
              if (length > 14)
5497
9.15k
                magn_mt=((magick_uint32_t) p[13] << 8) | (magick_uint32_t) p[14];
5498
41.6k
              else
5499
41.6k
                magn_mt=magn_my;
5500
50.8k
              if (magn_mt == 0)
5501
7.75k
                magn_mt=1;
5502
5503
50.8k
              if (length > 16)
5504
9.13k
                magn_mb=((magick_uint32_t) p[15] << 8) | (magick_uint32_t) p[16];
5505
41.7k
              else
5506
41.7k
                magn_mb=magn_my;
5507
50.8k
              if (magn_mb == 0)
5508
4.87k
                magn_mb=1;
5509
5510
50.8k
              if (length > 17)
5511
2.65k
                magn_methy=p[17];
5512
48.1k
              else
5513
48.1k
                magn_methy=magn_methx;
5514
5515
50.8k
              if (logging)
5516
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5517
0
                                      "MAGN chunk (%lu bytes): "
5518
0
                                      "First_magnified_object_id=%u, Last_magnified_object_id=%u, "
5519
0
                                      "MB=%u, ML=%u, MR=%u, MT=%u, MX=%u, MY=%u, "
5520
0
                                      "X_method=%u, Y_method=%u",
5521
0
                                      length,
5522
0
                                      (unsigned) magn_first, (unsigned) magn_last,
5523
0
                                      (unsigned) magn_mb,
5524
0
                                      (unsigned) magn_ml, (unsigned) magn_mr,
5525
0
                                      (unsigned) magn_mt,
5526
0
                                      (unsigned) magn_mx, (unsigned) magn_my,
5527
0
                                      (unsigned) magn_methx, (unsigned) magn_methy);
5528
5529
5530
50.8k
              if (magn_methx > 5 || magn_methy > 5)
5531
8.46k
                if (!mng_info->magn_warning)
5532
119
                  {
5533
119
                    (void) ThrowException2(exception,CoderError,
5534
119
                                           "Unknown MAGN method in"
5535
119
                                           " MNG datastream",
5536
119
                                           image->filename);
5537
119
                    mng_info->magn_warning++;
5538
119
                  }
5539
#ifdef MNG_OBJECT_BUFFERS
5540
              /* Magnify existing objects in the range magn_first
5541
                 to magn_last */
5542
#endif
5543
50.8k
              if (magn_first == 0 || magn_last == 0)
5544
47.7k
                {
5545
                  /* Save the magnification factors for object 0 */
5546
47.7k
                  if (logging)
5547
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5548
0
                                          "MAGN chunk factors saved for object 0");
5549
47.7k
                  mng_info->magn_mb=magn_mb;
5550
47.7k
                  mng_info->magn_ml=magn_ml;
5551
47.7k
                  mng_info->magn_mr=magn_mr;
5552
47.7k
                  mng_info->magn_mt=magn_mt;
5553
47.7k
                  mng_info->magn_mx=magn_mx;
5554
47.7k
                  mng_info->magn_my=magn_my;
5555
47.7k
                  mng_info->magn_methx=magn_methx;
5556
47.7k
                  mng_info->magn_methy=magn_methy;
5557
47.7k
                }
5558
50.8k
            }
5559
1.07M
          if (!memcmp(type,mng_PAST,4))
5560
3.52k
            {
5561
3.52k
              if (!mng_info->past_warning)
5562
2.36k
                (void) ThrowException2(exception,CoderError,
5563
3.52k
                                       "PAST is not implemented yet",
5564
3.52k
                                       image->filename);
5565
3.52k
              mng_info->past_warning++;
5566
3.52k
            }
5567
1.07M
          if (!memcmp(type,mng_SHOW,4))
5568
40.2k
            {
5569
40.2k
              if (!mng_info->show_warning)
5570
34.9k
                (void) ThrowException2(exception,CoderError,
5571
40.2k
                                       "SHOW is not implemented yet",
5572
40.2k
                                       image->filename);
5573
40.2k
              mng_info->show_warning++;
5574
40.2k
            }
5575
1.07M
          if (!memcmp(type,mng_sBIT,4))
5576
3.68k
            {
5577
3.68k
              if (length < 4)
5578
836
                mng_info->have_global_sbit=MagickFalse;
5579
2.85k
              else
5580
2.85k
                {
5581
2.85k
                  mng_info->global_sbit.gray=p[0];
5582
2.85k
                  mng_info->global_sbit.red=p[0];
5583
2.85k
                  mng_info->global_sbit.green=p[1];
5584
2.85k
                  mng_info->global_sbit.blue=p[2];
5585
2.85k
                  mng_info->global_sbit.alpha=p[3];
5586
2.85k
                  mng_info->have_global_sbit=MagickTrue;
5587
2.85k
                }
5588
3.68k
            }
5589
1.07M
          if (!memcmp(type,mng_pHYs,4))
5590
2.61k
            {
5591
2.61k
              if (length > 8)
5592
1.27k
                {
5593
1.27k
                  mng_info->global_x_pixels_per_unit=mng_get_long(p);
5594
1.27k
                  mng_info->global_y_pixels_per_unit=mng_get_long(&p[4]);
5595
1.27k
                  mng_info->global_phys_unit_type=p[8];
5596
1.27k
                  mng_info->have_global_phys=MagickTrue;
5597
1.27k
                }
5598
1.34k
              else
5599
1.34k
                mng_info->have_global_phys=MagickFalse;
5600
2.61k
            }
5601
1.07M
          if (!memcmp(type,mng_pHYg,4))
5602
2.47k
            {
5603
2.47k
              if (!mng_info->phyg_warning)
5604
1.43k
                (void) ThrowException2(exception,CoderError,
5605
2.47k
                                       "pHYg is not implemented.",
5606
2.47k
                                       image->filename);
5607
2.47k
              mng_info->phyg_warning++;
5608
2.47k
            }
5609
1.07M
          if (!memcmp(type,mng_BASI,4))
5610
1.82k
            {
5611
1.82k
              skip_to_iend=MagickTrue;
5612
1.82k
              if (!mng_info->basi_warning)
5613
1.13k
                (void) ThrowException2(exception,CoderError,
5614
1.82k
                                       "BASI is not implemented yet",
5615
1.82k
                                       image->filename);
5616
1.82k
              mng_info->basi_warning++;
5617
#ifdef MNG_BASI_SUPPORTED
5618
              basi_width=(unsigned long) mng_get_long(p);
5619
              ((magick_uint32_t) p[1] << 16) |
5620
                ((magick_uint32_t) p[2] << 8) |
5621
                (magick_uint32_t) p[3]);
5622
          basi_height=(unsigned long) mng_get_long(&p[4]);
5623
          basi_color_type=p[8];
5624
          basi_compression_method=p[9];
5625
          basi_filter_type=p[10];
5626
          basi_interlace_method=p[11];
5627
          if (length > 11)
5628
            basi_red=((magick_uint32_t) p[12] << 8) & (magick_uint32_t) p[13];
5629
          else
5630
            basi_red=0;
5631
          if (length > 13)
5632
            basi_green=((magick_uint32_t) p[14] << 8) & (magick_uint32_t) p[15];
5633
          else
5634
            basi_green=0;
5635
          if (length > 15)
5636
            basi_blue=((magick_uint32_t) p[16] << 8) & (magick_uint32_t) p[17];
5637
          else
5638
            basi_blue=0;
5639
          if (length > 17)
5640
            basi_alpha=((magick_uint32_t) p[18] << 8) & (magick_uint32_t) p[19];
5641
          else
5642
            {
5643
              if (basi_sample_depth == 16)
5644
                basi_alpha=65535L;
5645
              else
5646
                basi_alpha=255;
5647
            }
5648
          if (length > 19)
5649
            basi_viewable=p[20];
5650
          else
5651
            basi_viewable=0;
5652
#endif
5653
1.82k
          MagickFreeMemory(chunk);
5654
1.82k
          continue;
5655
1.82k
        }
5656
1.07M
      if (memcmp(type,mng_IHDR,4)
5657
953k
#if defined(JNG_SUPPORTED)
5658
953k
          && memcmp(type,mng_JHDR,4)
5659
1.07M
#endif
5660
1.07M
          )
5661
924k
        {
5662
          /* Not an IHDR or JHDR chunk */
5663
924k
          MagickFreeMemory(chunk);
5664
924k
          continue;
5665
924k
        }
5666
      /* Process IHDR */
5667
147k
      if (logging)
5668
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5669
0
                              "  Processing %c%c%c%c chunk",
5670
0
                              type[0],type[1],type[2],type[3]);
5671
147k
      mng_info->exists[object_id]=MagickTrue;
5672
147k
      mng_info->viewable[object_id]=MagickTrue;
5673
147k
      if (mng_info->invisible[object_id])
5674
925
        {
5675
925
          if (logging)
5676
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5677
0
                                  "  Skipping invisible object");
5678
925
          skip_to_iend=MagickTrue;
5679
925
          MagickFreeMemory(chunk);
5680
925
          continue;
5681
925
        }
5682
146k
#ifdef MNG_INSERT_LAYERS
5683
146k
      if (length < 8)
5684
1.80k
        {
5685
1.80k
          MagickFreeMemory(chunk);
5686
1.80k
          MngInfoFreeStruct(mng_info,&have_mng_structure);
5687
1.80k
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
5688
0
        }
5689
144k
      image_width=mng_get_long(p);
5690
144k
      image_height=mng_get_long(&p[4]);
5691
144k
#endif
5692
144k
      MagickFreeMemory(chunk);
5693
5694
      /*
5695
        Insert a transparent background layer behind the entire animation
5696
        if it is not full screen.
5697
      */
5698
144k
#ifdef MNG_INSERT_LAYERS
5699
144k
      if (insert_layers && mng_type && first_mng_object)
5700
1.02k
        {
5701
1.02k
          if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5702
756
              (image_width < mng_info->mng_width) ||
5703
748
              (mng_info->clip.right < (long) mng_info->mng_width) ||
5704
746
              (image_height < mng_info->mng_height) ||
5705
733
              (mng_info->clip.bottom < (long) mng_info->mng_height))
5706
296
            {
5707
296
              if (AccessMutablePixels(image) != (PixelPacket *) NULL)
5708
15
                {
5709
15
                  StopTimer(&image->timer);
5710
                  /*
5711
                    Allocate next image structure.
5712
                  */
5713
15
                  AllocateNextImage(image_info,image);
5714
15
                  if (image->next == (Image *) NULL)
5715
0
                    {
5716
0
                      DestroyImageList(image);
5717
0
                      MngInfoFreeStruct(mng_info,&have_mng_structure);
5718
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5719
0
                      return((Image *) NULL);
5720
0
                    }
5721
15
                  image=SyncNextImageInList(image);
5722
15
                }
5723
296
              mng_info->image=image;
5724
296
              if (term_chunk_found)
5725
3
                {
5726
3
                  image->start_loop=MagickTrue;
5727
3
                  image->iterations=mng_iterations;
5728
3
                  term_chunk_found=MagickFalse;
5729
3
                }
5730
293
              else
5731
293
                image->start_loop=MagickFalse;
5732
              /*
5733
                Make a background rectangle.
5734
              */
5735
296
              image->delay=0;
5736
296
              image->columns=mng_info->mng_width;
5737
296
              image->rows=mng_info->mng_height;
5738
296
              image->page.width=mng_info->mng_width;
5739
296
              image->page.height=mng_info->mng_height;
5740
296
              image->page.x=0;
5741
296
              image->page.y=0;
5742
296
              image->background_color=mng_background_color;
5743
296
              (void) SetImage(image,TransparentOpacity);
5744
296
              if (logging)
5745
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5746
0
                                      "  Inserted transparent background"
5747
0
                                      " layer, W=%lud, H=%lud",
5748
0
                                      mng_info->mng_width,
5749
0
                                      mng_info->mng_height);
5750
296
            }
5751
1.02k
        }
5752
      /*
5753
        Insert a background layer behind the upcoming image if
5754
        framing_mode is 3, and we haven't already inserted one.
5755
      */
5756
144k
      if (insert_layers && (mng_info->framing_mode == 3) &&
5757
2.53k
          (subframe_width) && (subframe_height) && (simplicity == 0 ||
5758
391
                                                    (simplicity & 0x08)))
5759
1.63k
        {
5760
1.63k
          if (AccessMutablePixels(image) != (PixelPacket *) NULL)
5761
551
            {
5762
551
              StopTimer(&image->timer);
5763
              /*
5764
                Allocate next image structure.
5765
              */
5766
551
              AllocateNextImage(image_info,image);
5767
551
              if (image->next == (Image *) NULL)
5768
0
                {
5769
0
                  DestroyImageList(image);
5770
0
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
5771
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5772
0
                  return((Image *) NULL);
5773
0
                }
5774
551
              image=SyncNextImageInList(image);
5775
551
            }
5776
1.63k
          mng_info->image=image;
5777
1.63k
          if (term_chunk_found)
5778
11
            {
5779
11
              image->start_loop=MagickTrue;
5780
11
              image->iterations=mng_iterations;
5781
11
              term_chunk_found=MagickFalse;
5782
11
            }
5783
1.62k
          else
5784
1.62k
            image->start_loop=MagickFalse;
5785
1.63k
          image->delay=0;
5786
1.63k
          image->columns=subframe_width;
5787
1.63k
          image->rows=subframe_height;
5788
1.63k
          image->page.width=subframe_width;
5789
1.63k
          image->page.height=subframe_height;
5790
1.63k
          image->page.x=mng_info->clip.left;
5791
1.63k
          image->page.y=mng_info->clip.top;
5792
1.63k
          image->background_color=mng_background_color;
5793
1.63k
          image->matte=MagickFalse;
5794
1.63k
          if (SetImage(image,OpaqueOpacity) == MagickFail)
5795
134
            {
5796
134
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SetImage() returned MagickFail!");
5797
134
              DestroyImageList(image);
5798
134
              MngInfoFreeStruct(mng_info,&have_mng_structure);
5799
134
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5800
134
              return((Image *) NULL);
5801
134
            }
5802
1.49k
          if (logging)
5803
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5804
0
                                  "  Inserted background layer,"
5805
0
                                  " L=%ld, R=%ld, T=%ld, B=%ld",
5806
0
                                  mng_info->clip.left,
5807
0
                                  mng_info->clip.right,
5808
0
                                  mng_info->clip.top,
5809
0
                                  mng_info->clip.bottom);
5810
1.49k
        }
5811
144k
#endif /* MNG_INSERT_LAYERS */
5812
144k
      first_mng_object=MagickFalse;
5813
144k
      if (AccessMutablePixels(image) != (PixelPacket *) NULL)
5814
71.1k
        {
5815
71.1k
          StopTimer(&image->timer);
5816
          /*
5817
            Allocate next image structure.
5818
          */
5819
71.1k
          AllocateNextImage(image_info,image);
5820
71.1k
          if (image->next == (Image *) NULL)
5821
0
            {
5822
0
              DestroyImageList(image);
5823
0
              MngInfoFreeStruct(mng_info,&have_mng_structure);
5824
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5825
0
              return((Image *) NULL);
5826
0
            }
5827
71.1k
          image=SyncNextImageInList(image);
5828
71.1k
        }
5829
144k
      mng_info->image=image;
5830
144k
      if (QuantumTick(TellBlob(image),GetBlobSize(image)))
5831
48.6k
        if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
5832
48.6k
                                    exception,LoadImagesText,
5833
48.6k
                                    image->filename))
5834
0
          break;
5835
144k
      if (term_chunk_found)
5836
124
        {
5837
124
          image->start_loop=MagickTrue;
5838
124
          term_chunk_found=MagickFalse;
5839
124
        }
5840
144k
      else
5841
144k
        image->start_loop=MagickFalse;
5842
144k
      if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5843
135k
        {
5844
135k
          image->delay=frame_delay;
5845
135k
          frame_delay=default_frame_delay;
5846
135k
        }
5847
8.87k
      else
5848
8.87k
        image->delay=0;
5849
144k
      image->page.width=mng_info->mng_width;
5850
144k
      image->page.height=mng_info->mng_height;
5851
144k
      image->page.x=mng_info->x_off[object_id];
5852
144k
      image->page.y=mng_info->y_off[object_id];
5853
144k
      image->iterations=mng_iterations;
5854
      /*
5855
        Seek back to the beginning of the IHDR or JHDR chunk's
5856
        length field.
5857
      */
5858
144k
      if (logging)
5859
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5860
0
                              "  Seeking back to beginning of"
5861
0
                              " %c%c%c%c chunk",
5862
0
                              type[0],type[1],
5863
0
                              type[2],type[3]);
5864
144k
      (void) SeekBlob(image,-((long) length+12),SEEK_CUR);
5865
144k
    }
5866
5867
144k
  mng_info->image=image;
5868
144k
  mng_info->mng_type=mng_type;
5869
144k
  mng_info->object_id=object_id;
5870
5871
144k
  if (!memcmp(type,mng_IHDR,4))
5872
117k
    {
5873
117k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  calling ReadOnePNGImage()");
5874
      /* If NULL is returned, then mng_info->image was already freed by ReadOnePNGImage! */
5875
117k
      image=ReadOnePNGImage(mng_info,image_info,exception);
5876
117k
    }
5877
26.8k
#if defined(JNG_SUPPORTED)
5878
26.8k
  else
5879
26.8k
    {
5880
26.8k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  calling ReadOneJNGImage()");
5881
      /* ReadOneJNGImage() does not free mng_info->image as ReadOnePNGImage() does! */
5882
26.8k
      image=ReadOneJNGImage(mng_info,image_info,exception);
5883
26.8k
    }
5884
144k
#endif
5885
5886
144k
  if (image == (Image *) NULL)
5887
51.3k
    {
5888
51.3k
      if (mng_info->image != (Image *) NULL)
5889
26.8k
        {
5890
26.8k
          status &= CloseBlob(mng_info->image);
5891
26.8k
          DestroyImageList(mng_info->image);
5892
26.8k
          mng_info->image=(Image *) NULL;
5893
26.8k
        }
5894
51.3k
      MngInfoFreeStruct(mng_info,&have_mng_structure);
5895
51.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5896
51.3k
      return((Image *) NULL);
5897
51.3k
    }
5898
93.4k
  if (image->columns == 0 || image->rows == 0)
5899
0
    {
5900
0
      status &= CloseBlob(image);
5901
0
      DestroyImageList(image);
5902
0
      MngInfoFreeStruct(mng_info,&have_mng_structure);
5903
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
5904
0
      return((Image *) NULL);
5905
0
    }
5906
5907
93.4k
  mng_info->image=image;
5908
5909
93.4k
  if (mng_type)
5910
15.6k
    {
5911
15.6k
      MngBox
5912
15.6k
        crop_box;
5913
5914
      /*
5915
        If magnifying and a supported method is requested then
5916
        magnify the image.
5917
5918
        http://www.libpng.org/pub/mng/spec/mng-1.0-20010209-pdg.html#mng-MAGN
5919
5920
        Extracted summary of magnification options:
5921
5922
        X_method:       1 byte
5923
        0 or omitted: No magnification
5924
        1: Pixel replication of color and alpha samples.
5925
        2: Magnified intervals with linear interpolation of
5926
        color and alpha samples.
5927
        3: Magnified intervals with replication of color and
5928
        alpha samples from the closest pixel.
5929
        4: Magnified intervals with linear interpolation of
5930
        color samples and replication of alpha samples from
5931
        the closest pixel.
5932
        5: Magnified intervals with linear interpolation of
5933
        alpha samples and replication of color samples from
5934
        the closest pixel.
5935
        MX:             2 bytes. X magnification factor, range 1-65535.  If
5936
        omitted, MX=1.  Ignored if X_method is 0 and assumed to
5937
        be 1.
5938
        MY:             2 bytes. Y magnification factor.  If omitted, MY=MX.
5939
        ML:             2 bytes. Left X magnification factor.  If omitted, ML=MX.
5940
        MR:             2 bytes. Right X magnification factor.  If omitted, MR=MX.
5941
        MT:             2 bytes. Top Y magnification factor.  If omitted, MT=MY.
5942
        Ignored if Y_method is 0 and assumed to be 1.
5943
        MB:             2 bytes. Bottom Y magnification factor.  If omitted,
5944
        MB=MY.
5945
        Y_method:       1 byte.  If omitted, Y_method is the same as X_method.
5946
5947
5948
      */
5949
15.6k
      if (((mng_info->magn_methx > 0) && (mng_info->magn_methx <= 5)) &&
5950
2.93k
          ((mng_info->magn_methy > 0) && (mng_info->magn_methy <= 5)))
5951
2.13k
        {
5952
2.13k
          png_uint_32
5953
2.13k
            magnified_height,
5954
2.13k
            magnified_width;
5955
5956
2.13k
          if (logging)
5957
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5958
0
                                  "  Processing MNG MAGN chunk: MB=%u, ML=%u,"
5959
0
                                  " MR=%u, MT=%u, MX=%u, MY=%u,"
5960
0
                                  " X_method=%u, Y_method=%u",
5961
0
                                  mng_info->magn_mb,mng_info->magn_ml,
5962
0
                                  mng_info->magn_mr,mng_info->magn_mt,
5963
0
                                  mng_info->magn_mx,mng_info->magn_my,
5964
0
                                  mng_info->magn_methx,
5965
0
                                  mng_info->magn_methy);
5966
5967
          /*
5968
            If the image width is 1, then X magnification is done
5969
            by simple pixel replication.
5970
          */
5971
2.13k
          if (image->columns == 1)
5972
2.13k
            {
5973
2.13k
              if (logging)
5974
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5975
0
                                      "  MNG MAGN X_method reduced from %u to 1 due to columns = 1",
5976
0
                                      mng_info->magn_methx);
5977
2.13k
              mng_info->magn_methx = 1;
5978
2.13k
            }
5979
5980
          /*
5981
            If the image height is 1, then Y magnification is done
5982
            by simple pixel replication.
5983
          */
5984
2.13k
          if (image->rows == 1)
5985
2.13k
            {
5986
2.13k
              if (logging)
5987
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5988
0
                                      "  MNG MAGN Y_method reduced from %u to 1 due to rows = 1",
5989
0
                                      mng_info->magn_methy);
5990
2.13k
              mng_info->magn_methy = 1;
5991
2.13k
            }
5992
5993
2.13k
          if (mng_info->magn_methx == 1)
5994
2.13k
            {
5995
2.13k
              magnified_width=mng_info->magn_ml;
5996
2.13k
              if (image->columns > 1)
5997
0
                magnified_width += mng_info->magn_mr;
5998
2.13k
              if (image->columns > 2)
5999
0
                magnified_width += (image->columns-2)*(mng_info->magn_mx);
6000
2.13k
            }
6001
0
          else
6002
0
            {
6003
0
              magnified_width=image->columns;
6004
0
              if (image->columns > 1)
6005
0
                magnified_width += mng_info->magn_ml-1;
6006
0
              if (image->columns > 2)
6007
0
                magnified_width += mng_info->magn_mr-1;
6008
0
              if (image->columns > 3)
6009
0
                magnified_width += (image->columns-3)*
6010
0
                  (mng_info->magn_mx-1);
6011
0
            }
6012
2.13k
          if (mng_info->magn_methy == 1)
6013
2.13k
            {
6014
2.13k
              magnified_height=mng_info->magn_mt;
6015
2.13k
              if (image->rows > 1)
6016
0
                magnified_height += mng_info->magn_mb;
6017
2.13k
              if (image->rows > 2)
6018
0
                magnified_height += (image->rows-2)*(mng_info->magn_my);
6019
2.13k
            }
6020
0
          else
6021
0
            {
6022
0
              magnified_height=image->rows;
6023
0
              if (image->rows > 1)
6024
0
                magnified_height += mng_info->magn_mt-1;
6025
0
              if (image->rows > 2)
6026
0
                magnified_height += mng_info->magn_mb-1;
6027
0
              if (image->rows > 3)
6028
0
                magnified_height += (image->rows-3)*(mng_info->magn_my-1);
6029
0
            }
6030
2.13k
          if (magnified_height > image->rows ||
6031
1.03k
              magnified_width > image->columns)
6032
1.77k
            {
6033
1.77k
              Image
6034
1.77k
                *large_image;
6035
6036
1.77k
              long
6037
1.77k
                m,
6038
1.77k
                y,
6039
1.77k
                yy;
6040
6041
1.77k
              register long
6042
1.77k
                x;
6043
6044
1.77k
              register PixelPacket
6045
1.77k
                *n,
6046
1.77k
                *p,
6047
1.77k
                *q;
6048
6049
1.77k
              PixelPacket
6050
1.77k
                *next,
6051
1.77k
                *prev;
6052
6053
1.77k
              size_t
6054
1.77k
                row_length;
6055
6056
1.77k
              png_uint_16
6057
1.77k
                magn_methx,
6058
1.77k
                magn_methy;
6059
6060
              /*
6061
                Allocate next image structure.
6062
              */
6063
1.77k
              if (logging)
6064
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6065
0
                                      "    Allocate magnified image (%lux%lu ==> %ux%u)",
6066
0
                                      image->columns, image->rows,
6067
0
                                      (unsigned) magnified_width,
6068
0
                                      (unsigned) magnified_height);
6069
1.77k
              AllocateNextImage(image_info,image);
6070
1.77k
              if (image->next == (Image *) NULL)
6071
0
                {
6072
0
                  DestroyImageList(image);
6073
0
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
6074
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
6075
0
                  return((Image *) NULL);
6076
0
                }
6077
6078
1.77k
              large_image=SyncNextImageInList(image);
6079
6080
1.77k
              large_image->columns=magnified_width;
6081
1.77k
              large_image->rows=magnified_height;
6082
6083
1.77k
              magn_methx=mng_info->magn_methx;
6084
1.77k
              magn_methy=mng_info->magn_methy;
6085
6086
#if (QuantumDepth == 32)
6087
#define QM unsigned short
6088
              if (magn_methx != 1 || magn_methy != 1)
6089
                {
6090
                  /*
6091
                    Scale pixels to unsigned shorts to prevent
6092
                    overflow of intermediate values of interpolations
6093
                  */
6094
                  for (y=0; y < (long) image->rows; y++)
6095
                    {
6096
                      q=GetImagePixels(image,0,y,image->columns,1);
6097
                      if(q == (PixelPacket *) NULL)
6098
                        break;
6099
                      for (x=(long) image->columns; x > 0; x--)
6100
                        {
6101
                          q->red=ScaleQuantumToShort(q->red);
6102
                          q->green=ScaleQuantumToShort(q->green);
6103
                          q->blue=ScaleQuantumToShort(q->blue);
6104
                          q->opacity=ScaleQuantumToShort(q->opacity);
6105
                          q++;
6106
                        }
6107
                      if (!SyncImagePixels(image))
6108
                        break;
6109
                    }
6110
                }
6111
#else
6112
1.77k
#define QM Quantum
6113
1.77k
#endif
6114
6115
1.77k
              if (image->matte)
6116
889
                (void) SetImage(large_image,TransparentOpacity);
6117
887
              else
6118
887
                {
6119
887
                  large_image->background_color.opacity=OpaqueOpacity;
6120
887
                  (void) SetImage(large_image,OpaqueOpacity);
6121
887
                  if (magn_methx == 4)
6122
0
                    magn_methx=2;
6123
887
                  if (magn_methx == 5)
6124
0
                    magn_methx=3;
6125
887
                  if (magn_methy == 4)
6126
0
                    magn_methy=2;
6127
887
                  if (magn_methy == 5)
6128
0
                    magn_methy=3;
6129
887
                }
6130
6131
              /* magnify the rows into the right side of the large image */
6132
6133
1.77k
              if (logging)
6134
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6135
0
                                      "    Magnify the rows to %lu",
6136
0
                                      large_image->rows);
6137
1.77k
              m=mng_info->magn_mt;
6138
1.77k
              yy=0;
6139
1.77k
              row_length=MagickArraySize(image->columns,sizeof(PixelPacket));
6140
1.77k
              next=MagickAllocateMemory(PixelPacket *,row_length);
6141
1.77k
              prev=MagickAllocateMemory(PixelPacket *,row_length);
6142
1.77k
              if ((prev == (PixelPacket *) NULL) ||
6143
1.77k
                  (next == (PixelPacket *) NULL))
6144
0
                {
6145
0
                  MagickFreeMemory(next);
6146
0
                  MagickFreeMemory(prev);
6147
0
                  DestroyImageList(image);
6148
0
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
6149
0
                  ThrowReaderException(ResourceLimitError,
6150
0
                                       MemoryAllocationFailed,image)
6151
0
                    }
6152
1.77k
              n=GetImagePixels(image,0,0,image->columns,1);
6153
1.77k
              if(n == (PixelPacket *) NULL)
6154
6
                {
6155
6
                  MagickFreeMemory(next);
6156
6
                  MagickFreeMemory(prev);
6157
6
                  DestroyImageList(image);
6158
6
                  MngInfoFreeStruct(mng_info,&have_mng_structure);
6159
6
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6160
6
                                        "  return NULL from ReadMNGImage()");
6161
6
                  return ((Image *) NULL);
6162
6
                }
6163
1.77k
              (void) memcpy(next,n,row_length);
6164
3.54k
              for (y=0; y < (long) image->rows; y++)
6165
1.77k
                {
6166
1.77k
                  if (y == 0)
6167
1.77k
                    m=mng_info->magn_mt;
6168
0
                  else if (magn_methy > 1 && y == (long) image->rows-2)
6169
0
                    m=mng_info->magn_mb;
6170
0
                  else if (magn_methy <= 1 && y == (long) image->rows-1)
6171
0
                    m=mng_info->magn_mb;
6172
0
                  else if (magn_methy > 1 && y == (long) image->rows-1)
6173
0
                    m=1;
6174
0
                  else
6175
0
                    m=mng_info->magn_my;
6176
1.77k
                  n=prev;
6177
1.77k
                  prev=next;
6178
1.77k
                  next=n;
6179
1.77k
                  if (y < (long) image->rows-1)
6180
0
                    {
6181
0
                      n=GetImagePixels(image,0,y+1,image->columns,1);
6182
0
                      if(n == (PixelPacket *) NULL)
6183
0
                        break;
6184
0
                      (void) memcpy(next,n,row_length);
6185
0
                    }
6186
1.77k
                  for (i=0; i < m; i++, yy++)
6187
1.77k
                    {
6188
1.77k
                      assert(yy < (long) large_image->rows);
6189
1.77k
                      p=prev;
6190
1.77k
                      n=next;
6191
1.77k
                      q=SetImagePixelsEx(large_image,0,yy,
6192
1.77k
                                         large_image->columns,1,exception);
6193
1.77k
                      if (q == (const PixelPacket *) NULL)
6194
1.77k
                        break;
6195
0
                      q+=(large_image->columns-image->columns);
6196
0
                      for (x=(long) image->columns; x > 0; x--)
6197
0
                        {
6198
                          /* TO DO: get color as function of indexes[x] */
6199
                          /*
6200
                            if (image->storage_class == PseudoClass)
6201
                            {
6202
                            }
6203
                          */
6204
6205
0
                          if (magn_methy <= 1)
6206
0
                            {
6207
0
                              *q=(*p); /* replicate previous */
6208
0
                            }
6209
0
                          else if (magn_methy == 2 || magn_methy == 4)
6210
0
                            {
6211
0
                              if (i == 0)
6212
0
                                *q=(*p);
6213
0
                              else
6214
0
                                {
6215
                                  /* Interpolate */
6216
0
                                  (*q).red=(QM) (((long) (2*i*((*n).red
6217
0
                                                               -(*p).red)+m))/
6218
0
                                                 ((long) (m*2))+(*p).red);
6219
0
                                  (*q).green=(QM) (((long) (2*i*((*n).green
6220
0
                                                                 -(*p).green)+m))/
6221
0
                                                   ((long) (m*2))+(*p).green);
6222
0
                                  (*q).blue=(QM) (((long) (2*i*((*n).blue
6223
0
                                                                -(*p).blue)+m))/
6224
0
                                                  ((long) (m*2))+(*p).blue);
6225
0
                                  if (image->matte)
6226
0
                                    (*q).opacity=(QM) (((long)
6227
0
                                                        (2*i*((*n).opacity-
6228
0
                                                              (*p).opacity)+m))
6229
0
                                                       /((long) (m*2))+
6230
0
                                                       (*p).opacity);
6231
0
                                }
6232
0
                              if (magn_methy == 4)
6233
0
                                {
6234
                                  /* Replicate nearest */
6235
0
                                  if (i <= ((m+1) << 1))
6236
0
                                    (*q).opacity=(*p).opacity+0;
6237
0
                                  else
6238
0
                                    (*q).opacity=(*n).opacity+0;
6239
0
                                }
6240
0
                            }
6241
0
                          else /* if (magn_methy == 3 ||
6242
                                  magn_methy == 5) */
6243
0
                            {
6244
                              /* Replicate nearest */
6245
0
                              if (i <= ((m+1) << 1))
6246
0
                                *q=(*p);
6247
0
                              else
6248
0
                                *q=(*n);
6249
0
                              if (magn_methy == 5)
6250
0
                                {
6251
0
                                  if (i == 0)
6252
0
                                    {
6253
                                      /* Copy */
6254
0
                                      (*q).opacity=(*p).opacity;
6255
0
                                    }
6256
0
                                  else
6257
0
                                    {
6258
                                      /* Interpolate */
6259
0
                                      (*q).opacity=(QM) (
6260
0
                                                         ((long) (2*i*((*n).opacity
6261
0
                                                                       -(*p).opacity)+m))/
6262
0
                                                         ((long) (m*2))+
6263
0
                                                         (*p).opacity);
6264
0
                                    }
6265
0
                                }
6266
0
                            }
6267
0
                          n++;
6268
0
                          q++;
6269
0
                          p++;
6270
0
                        } /* x */
6271
0
                      if (!SyncImagePixels(large_image))
6272
0
                        break;
6273
0
                    } /* i */
6274
1.77k
                } /* y */
6275
1.77k
              MagickFreeMemory(prev);
6276
1.77k
              MagickFreeMemory(next);
6277
6278
1.77k
              row_length=image->columns;
6279
6280
1.77k
              if (logging)
6281
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6282
0
                                      "    Delete original image");
6283
6284
1.77k
              DeleteImageFromList(&image);
6285
6286
1.77k
              image=large_image;
6287
6288
1.77k
              mng_info->image=image;
6289
6290
              /* magnify the columns */
6291
1.77k
              if (logging)
6292
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6293
0
                                      "    Magnify the columns to %lu",
6294
0
                                      image->columns);
6295
6296
1.77k
              for (y=0; y < (long) image->rows; y++)
6297
1.77k
                {
6298
1.77k
                  q=GetImagePixels(image,0,y,image->columns,1);
6299
1.77k
                  if(q == (PixelPacket * ) NULL)
6300
1.77k
                    break;
6301
0
                  p=q+(image->columns-row_length);
6302
0
                  n=p+1;
6303
0
                  for (x=(long) (image->columns-row_length);
6304
0
                       x < (long) image->columns; x++)
6305
0
                    {
6306
0
                      if (x == (long) (image->columns-row_length))
6307
0
                        m=mng_info->magn_ml;
6308
0
                      else if (magn_methx > 1 &&
6309
0
                               x == (long) image->columns-2)
6310
0
                        m=mng_info->magn_mr;
6311
0
                      else if (magn_methx <= 1 &&
6312
0
                               x == (long) image->columns-1)
6313
0
                        m=mng_info->magn_mr;
6314
0
                      else if (magn_methx > 1 &&
6315
0
                               x == (long) image->columns-1)
6316
0
                        m=1;
6317
0
                      else
6318
0
                        m=mng_info->magn_mx;
6319
0
                      for (i=0; i < m; i++)
6320
0
                        {
6321
0
                          if (magn_methx <= 1)
6322
0
                            {
6323
                              /* replicate previous */
6324
0
                              *q=(*p);
6325
0
                            }
6326
0
                          else if (magn_methx == 2 || magn_methx == 4)
6327
0
                            {
6328
0
                              if (i == 0)
6329
0
                                *q=(*p);
6330
0
                              else
6331
0
                                {
6332
                                  /* Interpolate */
6333
0
                                  (*q).red=(QM) ((2*i*((*n).red-
6334
0
                                                       (*p).red)+m)
6335
0
                                                 /((long) (m*2))+
6336
0
                                                 (*p).red);
6337
0
                                  (*q).green=(QM) ((2*i*((*n).green-
6338
0
                                                         (*p).green)
6339
0
                                                    +m)/((long) (m*2))+
6340
0
                                                   (*p).green);
6341
0
                                  (*q).blue=(QM) ((2*i*((*n).blue-
6342
0
                                                        (*p).blue)+m)
6343
0
                                                  /((long) (m*2))+
6344
0
                                                  (*p).blue);
6345
0
                                  if (image->matte)
6346
0
                                    (*q).opacity=(QM) ((2*i*((*n).opacity
6347
0
                                                             -(*p).opacity)+m)/
6348
0
                                                       ((long) (m*2))
6349
0
                                                       +(*p).opacity);
6350
0
                                }
6351
0
                              if (magn_methx == 4)
6352
0
                                {
6353
                                  /* Replicate nearest */
6354
0
                                  if (i <= ((m+1) << 1))
6355
0
                                    (*q).opacity=(*p).opacity+0;
6356
0
                                  else
6357
0
                                    (*q).opacity=(*n).opacity+0;
6358
0
                                }
6359
0
                            }
6360
0
                          else /* if (magn_methx == 3 ||
6361
                                  magn_methx == 5) */
6362
0
                            {
6363
                              /* Replicate nearest */
6364
0
                              if (i <= ((m+1) << 1))
6365
0
                                *q=(*p);
6366
0
                              else
6367
0
                                *q=(*n);
6368
0
                              if (magn_methx == 5)
6369
0
                                {
6370
0
                                  if (i == 0)
6371
0
                                    {
6372
                                      /* Copy */
6373
0
                                      (*q).opacity=(*p).opacity;
6374
0
                                    }
6375
0
                                  else
6376
0
                                    {
6377
                                      /* Interpolate */
6378
0
                                      (*q).opacity=(QM) ((2*i*((*n).opacity
6379
0
                                                               -(*p).opacity)+m)/
6380
0
                                                         ((long) (m*2))
6381
0
                                                         +(*p).opacity);
6382
0
                                    }
6383
0
                                }
6384
0
                            }
6385
0
                          q++;
6386
0
                        }
6387
0
                      n++;
6388
0
                      p++;
6389
0
                    }
6390
0
                  if (!SyncImagePixels(image))
6391
0
                    break;
6392
0
                }
6393
#if (QuantumDepth == 32)
6394
              if (magn_methx != 1 || magn_methy != 1)
6395
                {
6396
                  /*
6397
                    Rescale pixels to Quantum
6398
                  */
6399
                  for (y=0; y < (long) image->rows; y++)
6400
                    {
6401
                      q=GetImagePixels(image,0,y,image->columns,1);
6402
                      if(q == (PixelPacket *) NULL)
6403
                        break;
6404
                      for (x=(long) image->columns; x > 0; x--)
6405
                        {
6406
                          q->red=ScaleShortToQuantum(q->red);
6407
                          q->green=ScaleShortToQuantum(q->green);
6408
                          q->blue=ScaleShortToQuantum(q->blue);
6409
                          q->opacity=ScaleShortToQuantum(q->opacity);
6410
                          q++;
6411
                        }
6412
                      if (!SyncImagePixels(image))
6413
                        break;
6414
                    }
6415
                }
6416
#endif
6417
1.77k
              if (logging)
6418
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6419
0
                                      "  Finished MAGN processing");
6420
1.77k
            }
6421
2.13k
        }
6422
6423
      /*
6424
        Crop_box is with respect to the upper left corner of the MNG.
6425
      */
6426
15.6k
      crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6427
15.6k
      crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6428
15.6k
      crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6429
15.6k
      crop_box.bottom=mng_info->image_box.bottom+
6430
15.6k
        mng_info->y_off[object_id];
6431
15.6k
      crop_box=mng_minimum_box(crop_box,mng_info->clip);
6432
15.6k
      crop_box=mng_minimum_box(crop_box,mng_info->frame);
6433
15.6k
      crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6434
15.6k
      if ((crop_box.left != (mng_info->image_box.left
6435
15.6k
                             +mng_info->x_off[object_id])) ||
6436
14.5k
          (crop_box.right != (mng_info->image_box.right
6437
14.5k
                              +mng_info->x_off[object_id])) ||
6438
13.7k
          (crop_box.top != (mng_info->image_box.top
6439
13.7k
                            +mng_info->y_off[object_id])) ||
6440
6.39k
          (crop_box.bottom != (mng_info->image_box.bottom
6441
6.39k
                               +mng_info->y_off[object_id])))
6442
9.49k
        {
6443
9.49k
          if (logging)
6444
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6445
0
                                  "  Crop the PNG image");
6446
9.49k
          if ((crop_box.left < crop_box.right) &&
6447
7.59k
              (crop_box.top < crop_box.bottom))
6448
0
            {
6449
0
              Image
6450
0
                *p;
6451
6452
0
              RectangleInfo
6453
0
                crop_info;
6454
6455
              /*
6456
                Crop_info is with respect to the upper left corner of
6457
                the image.
6458
              */
6459
0
              crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6460
0
              crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6461
0
              crop_info.width=(crop_box.right-crop_box.left);
6462
0
              crop_info.height=(crop_box.bottom-crop_box.top);
6463
0
              image->page.width=image->columns;
6464
0
              image->page.height=image->rows;
6465
0
              image->page.x=0;
6466
0
              image->page.y=0;
6467
0
              p=CropImage(image,&crop_info,exception);
6468
0
              if (p != (Image *) NULL)
6469
0
                {
6470
0
                  image->columns=p->columns;
6471
0
                  image->rows=p->rows;
6472
0
                  DestroyImage(p);
6473
0
                  image->page.width=image->columns;
6474
0
                  image->page.height=image->rows;
6475
0
                  image->page.x=crop_box.left;
6476
0
                  image->page.y=crop_box.top;
6477
0
                }
6478
0
            }
6479
9.49k
          else
6480
9.49k
            {
6481
              /*
6482
                No pixels in crop area.  The MNG spec still requires
6483
                a layer, though, so make a single transparent pixel in
6484
                the top left corner.
6485
              */
6486
9.49k
              image->columns=1;
6487
9.49k
              image->rows=1;
6488
9.49k
              if (ReallocateImageColormap(image,2) == MagickFail)
6489
0
                {
6490
0
                  ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
6491
0
                                       image);
6492
0
                }
6493
9.49k
              (void) SetImage(image,TransparentOpacity);
6494
9.49k
              image->page.width=1;
6495
9.49k
              image->page.height=1;
6496
9.49k
              image->page.x=0;
6497
9.49k
              image->page.y=0;
6498
9.49k
            }
6499
9.49k
        }
6500
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6501
      image=mng_info->image;
6502
#endif
6503
15.6k
    }
6504
6505
  /*
6506
    Transfer most significant exception to exception argument
6507
    FIXME: should status be used to terminate processing?
6508
  */
6509
93.4k
  GetImageException(image,exception);
6510
93.4k
  if (image_info->subrange != 0)
6511
93.4k
    {
6512
93.4k
      if (mng_info->scenes_found > (long) (image_info->subimage+
6513
93.4k
                                           image_info->subrange))
6514
15
        break;
6515
93.4k
    }
6516
93.4k
  if (logging)
6517
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6518
0
                          "  Finished reading image datastream.");
6519
1.32M
} while (LocaleCompare(image_info->magick,"MNG") == 0);
6520
7.22k
  status &= CloseBlob(image);
6521
7.22k
  if (logging)
6522
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6523
0
                          "  Finished reading all image datastreams.");
6524
7.22k
#ifdef MNG_INSERT_LAYERS
6525
7.22k
  if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6526
684
      (mng_info->mng_height))
6527
684
    {
6528
      /*
6529
        Insert a background layer if nothing else was found.
6530
      */
6531
684
      if (logging)
6532
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6533
0
                              "  No images found.  Inserting a"
6534
0
                              " background layer.");
6535
684
      if (AccessMutablePixels(image) != (PixelPacket *) NULL)
6536
506
        {
6537
506
          StopTimer(&image->timer);
6538
          /*
6539
            Allocate next image structure.
6540
          */
6541
506
          AllocateNextImage(image_info,image);
6542
506
          if (image->next == (Image *) NULL)
6543
0
            {
6544
0
              DestroyImageList(image);
6545
0
              MngInfoFreeStruct(mng_info,&have_mng_structure);
6546
0
              if (logging)
6547
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6548
0
                                      "  Allocation failed, returning NULL.");
6549
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
6550
0
              return((Image *) NULL);
6551
0
            }
6552
506
          image=SyncNextImageInList(image);
6553
506
        }
6554
684
      image->columns=mng_info->mng_width;
6555
684
      image->rows=mng_info->mng_height;
6556
684
      image->page.width=mng_info->mng_width;
6557
684
      image->page.height=mng_info->mng_height;
6558
684
      image->page.x=0;
6559
684
      image->page.y=0;
6560
684
      image->background_color=mng_background_color;
6561
684
      image->matte=MagickFalse;
6562
684
      if (!image_info->ping)
6563
684
        (void) SetImage(image,OpaqueOpacity);
6564
684
      mng_info->image_found++;
6565
684
    }
6566
7.22k
#endif
6567
7.22k
  image->iterations=mng_iterations;
6568
7.22k
  if (mng_iterations == 1)
6569
7.06k
    image->start_loop=MagickTrue;
6570
34.4k
  while (image->previous != (Image *) NULL)
6571
27.2k
    {
6572
27.2k
      image_count++;
6573
#if 0
6574
      /* This code triggers and fails to release memory in oss-fuzz 8710 */
6575
      if (image_count > 10*mng_info->image_found)
6576
        {
6577
          if (logging)
6578
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6579
                                  "  No beginning");
6580
          MngInfoFreeStruct(mng_info,&have_mng_structure);
6581
          (void) ThrowException2(exception,(ExceptionType) CoderError,
6582
                                 "Linked list is corrupted,"
6583
                                 " beginning of list not found",
6584
                                 image_info->filename);
6585
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
6586
          return((Image *) NULL);
6587
        }
6588
#endif
6589
27.2k
      image=image->previous;
6590
27.2k
      if (image->next == (Image *) NULL)
6591
0
        {
6592
0
          if (logging)
6593
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6594
0
                                  "  Corrupt list");
6595
0
          (void) ThrowException2(exception,(ExceptionType) CoderError,
6596
0
                                 "Linked list is corrupted;"
6597
0
                                 " next_image is NULL",
6598
0
                                 image_info->filename);
6599
0
        }
6600
27.2k
    }
6601
7.22k
  if (mng_info->ticks_per_second && mng_info->image_found > 1 && image->next ==
6602
166
      (Image *) NULL)
6603
4
    {
6604
4
      if (logging)
6605
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6606
0
                              "  First image null");
6607
4
      (void) ThrowException2(exception,(ExceptionType) CoderError,
6608
4
                             "image->next for first image is NULL but"
6609
4
                             " shouldn't be.",
6610
4
                             image_info->filename);
6611
4
    }
6612
7.22k
  if (!mng_info->image_found)
6613
6.32k
    {
6614
6.32k
      if (logging)
6615
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6616
0
                              "  No visible images found.");
6617
6.32k
      (void) ThrowException2(exception,(ExceptionType) CoderError,
6618
6.32k
                             "No visible images in file",image_info->filename);
6619
6.32k
      if (image != (Image *) NULL)
6620
6.32k
        DestroyImageList(image);
6621
6.32k
      MngInfoFreeStruct(mng_info,&have_mng_structure);
6622
6.32k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
6623
6.32k
      return((Image *) NULL);
6624
6.32k
    }
6625
6626
897
  if (mng_info->ticks_per_second)
6627
872
    final_delay=100*final_delay/mng_info->ticks_per_second;
6628
25
  else
6629
25
    image->start_loop=MagickTrue;
6630
  /* Find final nonzero image delay */
6631
897
  final_image_delay=0;
6632
28.1k
  while (image->next != (Image *) NULL)
6633
27.2k
    {
6634
27.2k
      if (image->delay)
6635
22.4k
        final_image_delay=image->delay;
6636
27.2k
      image=image->next;
6637
27.2k
    }
6638
897
  if (final_delay < final_image_delay)
6639
89
    final_delay=final_image_delay;
6640
897
  image->delay=final_delay;
6641
897
  if (logging)
6642
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6643
0
                          "  image->delay=%lu, final_delay=%lu",
6644
0
                          image->delay,final_delay);
6645
897
  if (logging)
6646
0
    {
6647
0
      int
6648
0
        scene;
6649
6650
0
      scene=0;
6651
0
      while (image->previous != (Image *) NULL)
6652
0
        image=image->previous;
6653
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6654
0
                            "  Before coalesce:");
6655
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6656
0
                            "    scene 0 delay=%lu",image->delay);
6657
0
      while (image->next != (Image *) NULL)
6658
0
        {
6659
0
          image=image->next;
6660
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6661
0
                                "    scene %d delay=%lu",++scene,image->delay);
6662
0
        }
6663
0
    }
6664
6665
28.1k
  while (image->previous != (Image *) NULL)
6666
27.2k
    image=image->previous;
6667
897
#ifdef MNG_COALESCE_LAYERS
6668
897
  if (insert_layers && image->next)
6669
676
    {
6670
676
      Image
6671
676
        *next_image,
6672
676
        *next;
6673
6674
676
      unsigned long
6675
676
        scene;
6676
6677
676
      if (logging)
6678
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6679
0
                              "  Coalesce Images");
6680
676
      scene=image->scene;
6681
676
      next_image=CoalesceImages(image,exception);
6682
676
      DestroyImageList(image);
6683
676
      if (next_image == (Image *) NULL)
6684
0
        {
6685
0
          MngInfoFreeStruct(mng_info,&have_mng_structure);
6686
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  return NULL from ReadMNGImage()");
6687
0
          return((Image *) NULL);
6688
0
        }
6689
676
      image=next_image;
6690
27.7k
      for (next=image; next != (Image *) NULL; next=next_image)
6691
27.7k
        {
6692
27.7k
          next->page.width=mng_info->mng_width;
6693
27.7k
          next->page.height=mng_info->mng_height;
6694
27.7k
          next->page.x=0;
6695
27.7k
          next->page.y=0;
6696
27.7k
          next->scene=scene++;
6697
27.7k
          next_image=next->next;
6698
27.7k
          if (next_image == (Image *) NULL)
6699
676
            break;
6700
27.1k
          if (next->delay == 0)
6701
4.60k
            {
6702
4.60k
              scene--;
6703
4.60k
              next_image->previous=next->previous;
6704
4.60k
              if (next->previous == (Image *) NULL)
6705
3.15k
                image=next_image;
6706
1.45k
              else
6707
1.45k
                next->previous->next=next_image;
6708
4.60k
              DestroyImage(next);
6709
4.60k
            }
6710
27.1k
        }
6711
676
    }
6712
897
#endif
6713
6714
23.5k
  while (image->next != (Image *) NULL)
6715
22.6k
    image=image->next;
6716
897
  image->dispose=BackgroundDispose;
6717
6718
897
  if (logging)
6719
0
    {
6720
0
      int
6721
0
        scene;
6722
6723
0
      scene=0;
6724
0
      while (image->previous != (Image *) NULL)
6725
0
        image=image->previous;
6726
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6727
0
                            "  After coalesce:");
6728
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6729
0
                            "    scene 0 delay=%lu dispose=%d",
6730
0
                            image->delay,(int) image->dispose);
6731
0
      while (image->next != (Image *) NULL)
6732
0
        {
6733
0
          image=image->next;
6734
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6735
0
                                "    scene %d delay=%lu dispose=%d",++scene,
6736
0
                                image->delay,(int) image->dispose);
6737
0
        }
6738
0
    }
6739
23.5k
  while (image->previous != (Image *) NULL)
6740
22.6k
    image=image->previous;
6741
897
  MngInfoFreeStruct(mng_info,&have_mng_structure);
6742
897
  have_mng_structure=MagickFalse;
6743
897
  if (logging)
6744
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6745
897
  return(image);
6746
897
}
6747
#else /* PNG_LIBPNG_VER > 10011 */
6748
static Image *ReadPNGImage(const ImageInfo *image_info,
6749
                           ExceptionInfo *exception)
6750
{
6751
  printf("Your PNG library is too old: You have libpng-%s\n",
6752
     PNG_LIBPNG_VER_STRING);
6753
  (void) ThrowException2(exception,CoderError,"PNG library is too old",
6754
    image_info->filename);
6755
  return (Image *) NULL;
6756
}
6757
static Image *ReadMNGImage(const ImageInfo *image_info,
6758
                           ExceptionInfo *exception)
6759
{
6760
  return (ReadPNGImage(image_info,exception));
6761
}
6762
#endif /* PNG_LIBPNG_VER > 10011 */
6763
#endif
6764

6765
/*
6766
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6767
%                                                                             %
6768
%                                                                             %
6769
%                                                                             %
6770
%   R e g i s t e r P N G I m a g e                                           %
6771
%                                                                             %
6772
%                                                                             %
6773
%                                                                             %
6774
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6775
%
6776
%  Method RegisterPNGImage adds attributes for the PNG image format to
6777
%  the list of supported formats.  The attributes include the image format
6778
%  tag, a method to read and/or write the format, whether the format
6779
%  supports the saving of more than one frame to the same file or blob,
6780
%  whether the format supports native in-memory I/O, and a brief
6781
%  description of the format.
6782
%
6783
%  The format of the RegisterPNGImage method is:
6784
%
6785
%      RegisterPNGImage(void)
6786
%
6787
*/
6788
ModuleExport void RegisterPNGImage(void)
6789
17
{
6790
17
  static char
6791
17
    version[32];
6792
6793
17
  MagickInfo
6794
17
    *entry;
6795
6796
17
  static const char
6797
17
    PNGNote[]=
6798
17
    {
6799
17
      "See http://www.libpng.org/ for information on PNG.."
6800
17
    };
6801
6802
17
  static const char
6803
17
    JNGNote[]=
6804
17
    {
6805
17
      "See http://www.libpng.org/pub/mng/ for information on JNG."
6806
17
    };
6807
6808
17
  static const char
6809
17
    MNGNote[]=
6810
17
    {
6811
17
      "See http://www.libpng.org/pub/mng/ for information on MNG."
6812
17
    };
6813
6814
17
      *version='\0';
6815
17
#if defined(PNG_LIBPNG_VER_STRING)
6816
17
      (void) strlcat(version,"libpng ",sizeof(version));
6817
17
      (void) strlcat(version,PNG_LIBPNG_VER_STRING,sizeof(version));
6818
17
#if (PNG_LIBPNG_VER > 10005)
6819
17
      if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6820
0
        {
6821
0
          (void) strlcat(version,",",sizeof(version));
6822
0
          (void) strlcat(version,png_get_libpng_ver(NULL),sizeof(version));
6823
0
        }
6824
17
#endif
6825
17
#endif
6826
6827
17
#if defined(ZLIB_VERSION)
6828
17
      if (*version != '\0')
6829
17
        (void) strlcat(version,", ",sizeof(version));
6830
17
      (void) strlcat(version,"zlib ",sizeof(version));
6831
17
      (void) strlcat(version,ZLIB_VERSION,sizeof(version));
6832
17
      if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6833
0
        {
6834
0
          (void) strlcat(version,",",sizeof(version));
6835
0
          (void) strlcat(version,zlib_version,sizeof(version));
6836
0
        }
6837
17
#endif
6838
6839
17
      entry=SetMagickInfo("MNG");
6840
17
      entry->seekable_stream=MagickTrue;  /* To do: eliminate this. */
6841
17
      entry->thread_support=MagickTrue;
6842
17
#if defined(HasPNG)
6843
17
      entry->decoder=(DecoderHandler) ReadMNGImage;
6844
17
      entry->encoder=(EncoderHandler) WriteMNGImage;
6845
17
#endif
6846
17
      entry->magick=(MagickHandler) IsMNG;
6847
17
      entry->description="Multiple-image Network Graphics";
6848
17
      if (*version != '\0')
6849
17
        entry->version=version;
6850
17
      entry->module="PNG";
6851
17
      entry->coder_class=StableCoderClass;
6852
17
      entry->note=MNGNote;
6853
17
      (void) RegisterMagickInfo(entry);
6854
6855
17
      entry=SetMagickInfo("PNG");
6856
17
#if defined(HasPNG)
6857
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6858
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6859
17
#endif
6860
17
      entry->magick=(MagickHandler) IsPNG;
6861
17
      entry->adjoin=MagickFalse;
6862
17
      entry->thread_support=MagickTrue;
6863
17
      entry->description="Portable Network Graphics";
6864
17
      if (*version != '\0')
6865
17
        entry->version=version;
6866
17
      entry->note=PNGNote;
6867
17
      entry->module="PNG";
6868
17
      entry->coder_class=PrimaryCoderClass;
6869
17
      (void) RegisterMagickInfo(entry);
6870
6871
17
      entry=SetMagickInfo("PNG8");
6872
17
#if defined(HasPNG)
6873
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6874
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6875
17
#endif
6876
17
      entry->magick=(MagickHandler) IsPNG;
6877
17
      entry->adjoin=MagickFalse;
6878
17
      entry->thread_support=MagickTrue;
6879
17
      entry->description="8-bit indexed PNG, binary transparency only";
6880
17
      if (*version != '\0')
6881
17
        entry->version=version;
6882
17
      entry->module="PNG";
6883
17
      entry->coder_class=PrimaryCoderClass;
6884
17
      (void) RegisterMagickInfo(entry);
6885
6886
17
      entry=SetMagickInfo("PNG24");
6887
17
#if defined(HasPNG)
6888
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6889
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6890
17
#endif
6891
17
      entry->magick=(MagickHandler) IsPNG;
6892
17
      entry->adjoin=MagickFalse;
6893
17
      entry->thread_support=MagickTrue;
6894
17
      entry->description="24-bit RGB PNG, opaque only";
6895
17
      if (*version != '\0')
6896
17
        entry->version=version;
6897
17
      entry->module="PNG";
6898
17
      entry->coder_class=PrimaryCoderClass;
6899
17
      (void) RegisterMagickInfo(entry);
6900
6901
17
      entry=SetMagickInfo("PNG32");
6902
17
#if defined(HasPNG)
6903
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6904
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6905
17
#endif
6906
17
      entry->magick=(MagickHandler) IsPNG;
6907
17
      entry->adjoin=MagickFalse;
6908
17
      entry->thread_support=MagickTrue;
6909
17
      entry->description="32-bit RGBA PNG, semitransparency OK";
6910
17
      if (*version != '\0')
6911
17
        entry->version=version;
6912
17
      entry->module="PNG";
6913
17
      entry->coder_class=PrimaryCoderClass;
6914
17
      (void) RegisterMagickInfo(entry);
6915
6916
17
      entry=SetMagickInfo("PNG48");
6917
6918
17
#if defined(HasPNG)
6919
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6920
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6921
17
#endif
6922
6923
17
      entry->magick=(MagickHandler) IsPNG;
6924
17
      entry->adjoin=MagickFalse;
6925
17
      entry->thread_support=MagickTrue;
6926
17
      entry->description="opaque or binary transparent 48-bit RGB";
6927
17
      if (*version != '\0')
6928
17
         entry->version=version;
6929
17
      entry->module="PNG";
6930
17
      entry->coder_class=PrimaryCoderClass;
6931
17
      (void) RegisterMagickInfo(entry);
6932
6933
17
      entry=SetMagickInfo("PNG64");
6934
6935
17
#if defined(HasPNG)
6936
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6937
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6938
17
#endif
6939
6940
17
      entry->magick=(MagickHandler) IsPNG;
6941
17
      entry->adjoin=MagickFalse;
6942
17
      entry->thread_support=MagickTrue;
6943
17
      entry->description="opaque or transparent 64-bit RGBA";
6944
17
      if (*version != '\0')
6945
17
        entry->version=version;
6946
17
      entry->module="PNG";
6947
17
      entry->coder_class=PrimaryCoderClass;
6948
17
      (void) RegisterMagickInfo(entry);
6949
6950
17
      entry=SetMagickInfo("PNG00");
6951
6952
17
#if defined(HasPNG)
6953
17
      entry->decoder=(DecoderHandler) ReadPNGImage;
6954
17
      entry->encoder=(EncoderHandler) WritePNGImage;
6955
17
#endif
6956
6957
17
      entry->magick=(MagickHandler) IsPNG;
6958
17
      entry->adjoin=MagickFalse;
6959
17
      entry->thread_support=MagickTrue;
6960
17
      entry->description="PNG that inherits type and depth from original";
6961
17
      if (*version != '\0')
6962
17
        entry->version=version;
6963
17
      entry->module="PNG";
6964
17
      entry->coder_class=PrimaryCoderClass;
6965
17
      (void) RegisterMagickInfo(entry);
6966
6967
17
      entry=SetMagickInfo("JNG");
6968
17
#if defined(JNG_SUPPORTED)
6969
17
#if defined(HasPNG)
6970
17
      entry->decoder=(DecoderHandler) ReadJNGImage;
6971
17
      entry->encoder=(EncoderHandler) WriteJNGImage;
6972
17
#endif
6973
17
#endif
6974
17
      entry->magick=(MagickHandler) IsJNG;
6975
17
      entry->seekable_stream=MagickTrue;  /* To do: eliminate this. */
6976
17
      entry->adjoin=MagickFalse;
6977
17
      entry->thread_support=MagickTrue;
6978
17
      entry->description="JPEG Network Graphics";
6979
17
      entry->note=JNGNote;
6980
17
      if (*version != '\0')
6981
17
        entry->version=version;
6982
17
      entry->module="PNG";
6983
17
      entry->coder_class=StableCoderClass;
6984
17
      (void) RegisterMagickInfo(entry);
6985
6986
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
6987
      png_semaphore=AllocateSemaphoreInfo();
6988
#endif
6989
17
}
6990

6991
/*
6992
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6993
%                                                                             %
6994
%                                                                             %
6995
%                                                                             %
6996
%   U n r e g i s t e r P N G I m a g e                                       %
6997
%                                                                             %
6998
%                                                                             %
6999
%                                                                             %
7000
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7001
%
7002
%  Method UnregisterPNGImage removes format registrations made by the
7003
%  PNG module from the list of supported formats.
7004
%
7005
%  The format of the UnregisterPNGImage method is:
7006
%
7007
%      UnregisterPNGImage(void)
7008
%
7009
*/
7010
ModuleExport void UnregisterPNGImage(void)
7011
0
{
7012
0
  (void) UnregisterMagickInfo("MNG");
7013
0
  (void) UnregisterMagickInfo("PNG");
7014
0
  (void) UnregisterMagickInfo("PNG8");
7015
0
  (void) UnregisterMagickInfo("PNG24");
7016
0
  (void) UnregisterMagickInfo("PNG32");
7017
0
  (void) UnregisterMagickInfo("PNG48");
7018
0
  (void) UnregisterMagickInfo("PNG64");
7019
0
  (void) UnregisterMagickInfo("PNG00");
7020
0
  (void) UnregisterMagickInfo("JNG");
7021
7022
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
7023
  DestroySemaphoreInfo(&png_semaphore);
7024
#endif
7025
0
}
7026

7027
#if defined(HasPNG)
7028
#if PNG_LIBPNG_VER > 10011
7029
/*
7030
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7031
%                                                                             %
7032
%                                                                             %
7033
%                                                                             %
7034
%   W r i t e M N G I m a g e                                                 %
7035
%                                                                             %
7036
%                                                                             %
7037
%                                                                             %
7038
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7039
%
7040
%  Method WriteMNGImage writes an image in the Portable Network Graphics
7041
%  Group's "Multiple-image Network Graphics" encoded image format.
7042
%
7043
%  MNG support written by Glenn Randers-Pehrson, randeg@alum.rpi.edu
7044
%
7045
%  The format of the WriteMNGImage method is:
7046
%
7047
%      unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image)
7048
%
7049
%  A description of each parameter follows.
7050
%
7051
%    o status: Method WriteMNGImage return True if the image is written.
7052
%      MagickFalse is returned is there is a memory shortage or if the
7053
%      image file fails to write.
7054
%
7055
%    o image_info: Specifies a pointer to a ImageInfo structure.
7056
%
7057
%    o image:  A pointer to an Image structure.
7058
%
7059
%
7060
%  To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7061
%    "To do" under ReadPNGImage):
7062
%
7063
%    Fix problem with palette sorting (when PNG_SORT_PALETTE is enabled,
7064
%    some GIF animations don't convert properly)
7065
%
7066
%    Preserve all unknown and not-yet-handled known chunks found in input
7067
%    PNG file and copy them  into output PNG files according to the PNG
7068
%    copying rules.
7069
%
7070
%    Write the iCCP chunk at MNG level when (image->color_profile.length > 0)
7071
%
7072
%    Improve selection of color type (use indexed-colour or indexed-colour
7073
%    with tRNS when 256 or fewer unique RGBA values are present).
7074
%
7075
%    Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7076
%    This will be complicated if we limit ourselves to generating MNG-LC
7077
%    files.  For now we ignore disposal method 3 and simply overlay the next
7078
%    image on it.
7079
%
7080
%    Check for identical PLTE's or PLTE/tRNS combinations and use a
7081
%    global MNG PLTE or PLTE/tRNS combination when appropriate.
7082
%    [mostly done 15 June 1999 but still need to take care of tRNS]
7083
%
7084
%    Check for identical sRGB and replace with a global sRGB (and remove
7085
%    gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7086
%    replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7087
%    local gAMA/cHRM with local sRGB if appropriate).
7088
%
7089
%    Check for identical sBIT chunks and write global ones.
7090
%
7091
%    Provide option to skip writing the signature tEXt chunks.
7092
%
7093
%    Use signatures to detect identical objects and reuse the first
7094
%    instance of such objects instead of writing duplicate objects.
7095
%
7096
%    Use a smaller-than-32k value of compression window size when
7097
%    appropriate.
7098
%
7099
%    Encode JNG datastreams.  Mostly done as of 5.5.2; need to write
7100
%    ancillary text chunks and save profiles.
7101
%
7102
%    Provide an option to force LC files (to ensure exact framing rate)
7103
%    instead of VLC.
7104
%
7105
%    Provide an option to force VLC files instead of LC, even when offsets
7106
%    are present.  This will involve expanding the embedded images with a
7107
%    transparent region at the top and/or left.
7108
*/
7109
7110
7111
static MagickPassFail
7112
png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7113
                      png_info *ping_info, const char *profile_type,
7114
                      const char *profile_description,
7115
                      const unsigned char *profile_data,
7116
                      size_t length,ExceptionInfo *exception)
7117
1.78k
{
7118
1.78k
  png_textp
7119
1.78k
    text = (png_textp) NULL;
7120
7121
1.78k
  register long
7122
1.78k
    i;
7123
7124
1.78k
  const unsigned char
7125
1.78k
    *sp;
7126
7127
1.78k
  png_charp
7128
1.78k
    dp;
7129
7130
1.78k
  size_t
7131
1.78k
    allocated_length,
7132
1.78k
    description_length;
7133
7134
1.78k
  unsigned int
7135
1.78k
    status = MagickPass;
7136
7137
1.78k
  static const unsigned char
7138
1.78k
    hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7139
7140
1.78k
  if (image_info->verbose)
7141
0
    {
7142
0
      (void) printf("writing raw profile: type=%.1024s, length=%zu\n",
7143
0
                    profile_type, length);
7144
0
    }
7145
1.78k
  if (length >= (PNG_UINT_31_MAX / 2))
7146
0
    {
7147
0
      ThrowException(exception,ResourceLimitError,UnableToAddOrRemoveProfile,image_info->filename);
7148
0
      status=MagickFail;
7149
0
      return status;
7150
0
    }
7151
1.78k
  description_length=strlen((const char *) profile_description);
7152
1.78k
  allocated_length=(length*2 + (length >> 5) + 20 + description_length);
7153
1.78k
  if (((png_uint_32)allocated_length) < length)
7154
0
    {
7155
0
      ThrowException(exception,CoderError,ArithmeticOverflow,image_info->filename);
7156
0
      status=MagickFail;
7157
0
      return status;
7158
0
    }
7159
#if PNG_LIBPNG_VER >= 14000
7160
  text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7161
#else
7162
1.78k
  text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7163
1.78k
#endif
7164
1.78k
  if (text == (png_textp) NULL)
7165
0
    {
7166
0
      ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image_info->filename);
7167
0
      status=MagickFail;
7168
0
      return status;
7169
0
    }
7170
1.78k
  (void) memset(&text[0],0,sizeof(png_text));
7171
7172
#if PNG_LIBPNG_VER >= 14000
7173
  text[0].text=(png_charp) png_malloc(ping,(png_alloc_size_t) allocated_length);
7174
  text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7175
#else
7176
1.78k
  text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7177
1.78k
  text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7178
1.78k
#endif
7179
1.78k
  if ((text[0].text == (png_charp) NULL) || (text[0].key == (png_charp) NULL))
7180
0
    {
7181
0
      ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image_info->filename);
7182
0
      status=MagickFail;
7183
0
      goto png_write_raw_profile_cleanup;
7184
0
    }
7185
1.78k
  text[0].key[0]='\0';
7186
1.78k
  (void) strlcat(text[0].key, "Raw profile type ", 80);
7187
1.78k
  (void) strncat(text[0].key, (const char *) profile_type, 61);
7188
1.78k
  sp=profile_data;
7189
1.78k
  dp=text[0].text;
7190
1.78k
  *dp++='\n';
7191
1.78k
  (void) strlcpy(dp,(const char *) profile_description,(allocated_length-(dp-text[0].text)));
7192
1.78k
  dp+=strlen(dp);
7193
1.78k
  *dp++='\n';
7194
1.78k
  (void) snprintf(dp,(allocated_length-(dp-text[0].text)),"%8zu ",length);
7195
1.78k
  dp+=strlen(dp);
7196
57.0k
  for (i=0; i < (long) length; i++)
7197
55.2k
    {
7198
55.2k
      if (i%36 == 0)
7199
3.12k
        *dp++='\n';
7200
55.2k
      *(dp++)=hex[((*sp >> 4) & 0x0f)];
7201
55.2k
      *(dp++)=hex[((*sp++ ) & 0x0f)];
7202
55.2k
    }
7203
1.78k
  *dp++='\n';
7204
1.78k
  *dp='\0';
7205
1.78k
  text[0].text_length=dp-text[0].text;
7206
1.78k
  if (text[0].text_length > allocated_length)
7207
0
    {
7208
0
      ThrowException(exception,CoderError,ArithmeticOverflow,image_info->filename);
7209
0
      status=MagickFail;
7210
0
      goto png_write_raw_profile_cleanup;
7211
0
    }
7212
1.78k
  text[0].compression=image_info->compression == NoCompression ||
7213
1.78k
    (image_info->compression == UndefinedCompression &&
7214
1.78k
     text[0].text_length < 128) ? -1 : 0;
7215
1.78k
  png_set_text(ping,ping_info,text,1); /* returns void */
7216
1.78k
 png_write_raw_profile_cleanup:
7217
1.78k
  png_free(ping,text[0].text);
7218
1.78k
  png_free(ping,text[0].key);
7219
1.78k
  png_free(ping,text);
7220
1.78k
  return status;
7221
1.78k
}
7222
7223
static MagickPassFail WriteOnePNGImage(MngInfo *mng_info,
7224
                                       const ImageInfo *image_info,Image *imagep)
7225
29.6k
{
7226
29.6k
  const char
7227
29.6k
    *gm_vers,
7228
29.6k
    *libpng_runv,
7229
29.6k
    *libpng_vers,
7230
29.6k
    *zlib_runv,
7231
29.6k
    *zlib_vers;
7232
7233
29.6k
#ifdef HasLCMS
7234
29.6k
  char
7235
29.6k
    lcms_vers[32];
7236
29.6k
#endif
7237
7238
29.6k
  char
7239
29.6k
    filename[MaxTextExtent];
7240
7241
29.6k
  Image
7242
29.6k
    * volatile imagev = imagep,  /* Use only 'imagev' before setjmp() */
7243
29.6k
    *image;                      /* Use only 'image' after setjmp() */
7244
7245
  /* Write one PNG image */
7246
29.6k
  const ImageAttribute
7247
29.6k
    *attribute;
7248
7249
29.6k
  char
7250
29.6k
    s[2];
7251
7252
29.6k
  int
7253
29.6k
    num_passes,
7254
29.6k
    pass,
7255
29.6k
    ping_bit_depth = 0,
7256
29.6k
    ping_colortype = 0,
7257
29.6k
    ping_interlace_method = 0,
7258
29.6k
    ping_compression_method = 0;
7259
7260
29.6k
  volatile int
7261
29.6k
    ping_filter_method = 0,
7262
29.6k
    ping_num_trans = 0,
7263
29.6k
    ping_valid_trns = 0;
7264
7265
29.6k
  volatile png_bytep
7266
29.6k
    ping_trans_alpha = NULL;
7267
7268
29.6k
  png_colorp
7269
29.6k
    palette;
7270
7271
29.6k
  png_color_16
7272
29.6k
    ping_background,
7273
29.6k
    ping_trans_color;
7274
7275
29.6k
  png_info
7276
29.6k
    *ping_info;
7277
7278
29.6k
  png_struct
7279
29.6k
    *ping;
7280
7281
29.6k
  png_uint_32
7282
29.6k
    ping_width,
7283
29.6k
    ping_height;
7284
7285
29.6k
  long
7286
29.6k
    y;
7287
7288
29.6k
  register const IndexPacket
7289
29.6k
    *indexes;
7290
7291
29.6k
  register unsigned long
7292
29.6k
    i;
7293
7294
29.6k
  register long
7295
29.6k
    x;
7296
7297
29.6k
  unsigned char
7298
29.6k
    *png_pixels;
7299
7300
29.6k
  unsigned int
7301
29.6k
    image_colors,
7302
29.6k
    image_depth,
7303
29.6k
    image_matte,
7304
29.6k
    logging,
7305
29.6k
    matte;
7306
7307
29.6k
  unsigned long
7308
29.6k
    quantum_size,  /* depth for ExportImage */
7309
29.6k
    rowbytes,
7310
29.6k
    save_image_depth;
7311
7312
29.6k
  ImageCharacteristics
7313
29.6k
    characteristics;
7314
7315
29.6k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7316
29.6k
                         "  enter WriteOnePNGImage()");
7317
7318
29.6k
  assert(mng_info->png_pixels == (unsigned char *) NULL);
7319
7320
29.6k
  if (imagev == (Image *) NULL)
7321
0
    return(MagickFalse);
7322
7323
29.6k
  (void) MagickStrlCpy(filename, imagev->filename, sizeof(filename));
7324
7325
  /* Define these outside of the following "if logging()" block so they will
7326
   * show in debuggers.
7327
   */
7328
29.6k
  gm_vers=MagickLibVersionText;
7329
29.6k
#ifdef HasLCMS
7330
29.6k
  (void) snprintf(lcms_vers,sizeof(lcms_vers),"%.4d",LCMS_VERSION);
7331
29.6k
#endif
7332
29.6k
  libpng_runv=png_get_libpng_ver(NULL);
7333
29.6k
  libpng_vers=PNG_LIBPNG_VER_STRING;
7334
29.6k
  zlib_runv=zlib_version;
7335
29.6k
  zlib_vers=ZLIB_VERSION;
7336
7337
29.6k
  if (logging != MagickFalse)
7338
0
    {
7339
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7340
0
                            "    GM version     = %.31s", gm_vers);
7341
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7342
0
                            "    Libpng version = %.31s", libpng_vers);
7343
0
      if (LocaleCompare(libpng_vers,libpng_runv) != 0)
7344
0
        {
7345
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7346
0
                                "      running with   %.31s", libpng_runv);
7347
0
        }
7348
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7349
0
                            "    Zlib version   = %.31s", zlib_vers);
7350
0
      if (LocaleCompare(zlib_vers,zlib_runv) != 0)
7351
0
        {
7352
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7353
0
                                "      running with   %.31s", zlib_runv);
7354
0
        }
7355
0
#ifdef HasLCMS
7356
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7357
0
                            "    LCMS version   = %.31s", lcms_vers);
7358
0
#endif
7359
0
    }
7360
  /* Initialize some stuff */
7361
29.6k
  ping_background.red = 0;
7362
29.6k
  ping_background.green = 0;
7363
29.6k
  ping_background.blue = 0;
7364
29.6k
  ping_background.gray = 0;
7365
29.6k
  ping_background.index = 0;
7366
7367
29.6k
  ping_trans_color.red=0;
7368
29.6k
  ping_trans_color.green=0;
7369
29.6k
  ping_trans_color.blue=0;
7370
29.6k
  ping_trans_color.gray=0;
7371
7372
  /*
7373
    Allocate the PNG structures
7374
  */
7375
29.6k
#ifdef PNG_USER_MEM_SUPPORTED
7376
29.6k
  ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,imagev,
7377
29.6k
                                 PNGErrorHandler,PNGWarningHandler,
7378
29.6k
                                 (void *) NULL,
7379
29.6k
                                 (png_malloc_ptr) png_IM_malloc,
7380
29.6k
                                 (png_free_ptr) png_IM_free);
7381
#else
7382
  ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,imagev,
7383
                               PNGErrorHandler,PNGWarningHandler);
7384
#endif
7385
29.6k
  if (ping == (png_struct *) NULL)
7386
29.6k
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,imagev);
7387
29.6k
  ping_info=png_create_info_struct(ping);
7388
29.6k
  if (ping_info == (png_info *) NULL)
7389
0
    {
7390
0
      png_destroy_write_struct(&ping,(png_info **) NULL);
7391
0
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,imagev);
7392
0
    }
7393
29.6k
  png_set_write_fn(ping,imagev,png_put_data,png_flush_data);
7394
29.6k
  png_pixels=(unsigned char *) NULL;
7395
7396
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
7397
  LockSemaphoreInfo(png_semaphore);
7398
#endif
7399
7400
29.6k
  if (setjmp(png_jmpbuf(ping)))
7401
80
    {
7402
      /*
7403
        PNG write failed.
7404
      */
7405
80
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7406
80
                            "Setjmp return from longjmp!");
7407
80
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7408
80
                            "PNG write has failed!");
7409
80
      png_destroy_write_struct(&ping,&ping_info);
7410
80
      MagickFreeResourceLimitedMemory(unsigned char *,mng_info->png_pixels);
7411
7412
      /*
7413
        Handle write failure by removing the output file.
7414
      */
7415
80
      if (unlink(filename) != -1)
7416
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7417
0
                              "Removed broken output file \"%s\"",filename);
7418
7419
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
7420
      UnlockSemaphoreInfo(png_semaphore);
7421
#endif
7422
80
      return(MagickFail);
7423
80
    }
7424
7425
  /* { For navigation to end of setjmp-controlled block */
7426
7427
29.5k
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
7428
  /* Allow benign errors */
7429
29.5k
  png_set_benign_errors(ping, 1);
7430
29.5k
#endif
7431
7432
29.5k
  image=imagev;  /* Use 'image' after this point for optimization */
7433
7434
  /*
7435
    Make sure that image is in an RGB type space.
7436
  */
7437
29.5k
  if (!TransformColorspace(image,RGBColorspace))
7438
0
    {
7439
0
      CloseBlob(image);
7440
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
7441
      UnlockSemaphoreInfo(png_semaphore);
7442
#endif
7443
0
      return MagickFail;
7444
0
    }
7445
7446
  /*
7447
    Analyze image to be written.
7448
  */
7449
29.5k
  if (!GetImageCharacteristics(image,&characteristics,
7450
29.5k
                               (OptimizeType == image_info->type),
7451
29.5k
                               &image->exception))
7452
0
    {
7453
0
      CloseBlob(image);
7454
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
7455
      UnlockSemaphoreInfo(png_semaphore);
7456
#endif
7457
0
      return MagickFail;
7458
0
    }
7459
7460
29.5k
  if (logging)
7461
0
    {
7462
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7463
0
                            "  Image Characteristics:\n"
7464
0
                            "    CMYK:       %u\n"
7465
0
                            "    Grayscale:  %u\n"
7466
0
                            "    Monochrome: %u\n"
7467
0
                            "    Opaque:     %u\n"
7468
0
                            "    Palette:    %u",
7469
0
                            characteristics.cmyk,
7470
0
                            characteristics.grayscale ,
7471
0
                            characteristics.monochrome,
7472
0
                            characteristics.opaque,
7473
0
                            characteristics.palette);
7474
0
    }
7475
7476
29.5k
  if (image->storage_class == PseudoClass)
7477
28.2k
    image_colors=image->colors;
7478
1.36k
  else
7479
1.36k
    image_colors=0;
7480
7481
29.5k
  image_depth=image->depth;
7482
29.5k
  image_matte=image->matte;
7483
7484
29.5k
  if (image->storage_class == PseudoClass &&
7485
28.2k
      image_colors <= 256)
7486
28.1k
    {
7487
28.1k
      mng_info->IsPalette=MagickTrue;
7488
28.1k
      image_depth=8;
7489
28.1k
    }
7490
7491
29.5k
  if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7492
5.25k
    image_depth=8;
7493
7494
24.3k
  else if (mng_info->write_png48 || mng_info->write_png64)
7495
3.32k
    image_depth=16;
7496
7497
21.0k
  else if (image_depth < 8)
7498
0
    image_depth=8;
7499
7500
21.0k
  else if (image_depth > 8)
7501
82
    image_depth=16;
7502
7503
  /*
7504
    Prepare PNG for writing.
7505
  */
7506
7507
29.5k
#if defined(PNG_MNG_FEATURES_SUPPORTED)
7508
29.5k
  if (mng_info->write_mng)
7509
17.6k
    {
7510
17.6k
# ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
7511
      /* Disable new libpng-1.5.10 feature when writing a MNG */
7512
17.6k
      png_set_check_for_invalid_index (ping, 0);
7513
17.6k
# endif
7514
17.6k
      (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7515
17.6k
    }
7516
#else
7517
# ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7518
  if (mng_info->write_mng)
7519
    png_permit_empty_plte(ping,MagickTrue);
7520
# endif
7521
#endif
7522
29.5k
  x=0;
7523
29.5k
  ping_width=image->columns;
7524
29.5k
  ping_height=image->rows;
7525
29.5k
  if (logging)
7526
0
    {
7527
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7528
0
                            "    width=%lu",
7529
0
                            (unsigned long)ping_width);
7530
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7531
0
                            "    height=%lu",
7532
0
                            (unsigned long)ping_height);
7533
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7534
0
                            "    image->depth=%u",image_depth);
7535
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7536
0
                            "  image_colors=%u",image_colors);
7537
0
    }
7538
7539
7540
29.5k
  quantum_size=(image_depth > 8) ? 16:8;
7541
7542
29.5k
  save_image_depth=image_depth;
7543
29.5k
  ping_bit_depth=(png_byte) save_image_depth;
7544
29.5k
  if (logging)
7545
0
    {
7546
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7547
0
                            "    ping_bit_depth=%u",
7548
0
                            ping_bit_depth);
7549
0
    }
7550
  /*
7551
    Select the color type.
7552
  */
7553
29.5k
  matte=image_matte;
7554
29.5k
  if (mng_info->write_png8)
7555
1.85k
    {
7556
1.85k
      QuantizeInfo
7557
1.85k
        quantize_info;
7558
7559
1.85k
      unsigned long
7560
1.85k
        number_colors;
7561
7562
1.85k
      if (logging)
7563
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7564
0
                              "    Entering PNG8 block");
7565
7566
1.85k
      ping_colortype=PNG_COLOR_TYPE_PALETTE;
7567
1.85k
      ping_bit_depth=8;
7568
7569
1.85k
      number_colors=image_colors;
7570
1.85k
      if ((number_colors == 0) || (number_colors > 256))
7571
494
        {
7572
494
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7573
494
                                "    Quantizing image...");
7574
494
          GetQuantizeInfo(&quantize_info);
7575
494
          quantize_info.dither=image_info->dither;
7576
494
          quantize_info.number_colors=256;
7577
494
          (void) QuantizeImage(&quantize_info,image);
7578
494
          number_colors=image->colors;
7579
494
          if (logging)
7580
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7581
0
                                  "    Colors quantized to %lu colors",
7582
0
                                  number_colors);
7583
494
          image_colors=image->colors;
7584
494
        }
7585
7586
1.85k
      if (!characteristics.opaque) /* Previously image->matte or image_matte */
7587
328
        {
7588
          /*
7589
            Analyze the image pixels to see if just one color index
7590
            is transparent, and if it matches the background
7591
            color.
7592
          */
7593
328
          unsigned int num_transparent = 0;
7594
328
          unsigned int background_index = 0;
7595
328
          MagickBool background_index_transparent = MagickFalse;
7596
7597
          /*
7598
            Refresh index for background color
7599
          */
7600
3.19k
          for (i=0; i < Max(Max(1,number_colors)-1,1); i++)
7601
3.05k
            {
7602
3.05k
              if (RGBColorMatchExact(ping_background,image->colormap[i]))
7603
186
                {
7604
186
                  background_index=i;
7605
186
                  ping_background.index=(png_uint_16) background_index;
7606
186
                  if (logging)
7607
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7608
0
                                          "    background index %u (%u, %u, %u)",
7609
0
                                          ping_background.index,
7610
0
                                          image->colormap[ping_background.index].red,
7611
0
                                          image->colormap[ping_background.index].green,
7612
0
                                          image->colormap[ping_background.index].blue);
7613
186
                  break;
7614
186
                }
7615
3.05k
            }
7616
7617
          /*
7618
            Determine which colormap indexes are non-opaque.
7619
          */
7620
18.0k
          for (i=0; i < image->colors; i++)
7621
17.6k
            {
7622
17.6k
              image->colormap[i].opacity=OpaqueOpacity;
7623
17.6k
            }
7624
23.3k
          for (y=0; y < (long) image->rows; y++)
7625
23.0k
            {
7626
23.0k
              register const PixelPacket
7627
23.0k
                *p;
7628
7629
23.0k
              p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
7630
23.0k
              if (p == (const PixelPacket *) NULL)
7631
0
                break;
7632
23.0k
              indexes=AccessImmutableIndexes(image);
7633
7.60M
              for (x=0; x < (long) image->columns; x++)
7634
7.58M
                {
7635
7.58M
                  if (p->opacity != OpaqueOpacity)
7636
7.05M
                    {
7637
7.05M
                      IndexPacket
7638
7.05M
                        index;
7639
7640
7.05M
                      index=indexes[x];
7641
7.05M
                      image->colormap[index].opacity = p->opacity;
7642
7.05M
                    }
7643
7.58M
                  p++;
7644
7.58M
                }
7645
23.0k
            }
7646
          /*
7647
            Is background color index fully transparent?
7648
          */
7649
18.0k
          for (i=0; i < image->colors; i++)
7650
17.6k
            {
7651
17.6k
              if (image->colormap[i].opacity != OpaqueOpacity)
7652
7.91k
                {
7653
7.91k
                  if ((i == background_index) &&
7654
185
                      (image->colormap[i].opacity == TransparentOpacity))
7655
116
                    background_index_transparent = MagickTrue;
7656
7.91k
                  num_transparent++;
7657
7.91k
                }
7658
17.6k
            }
7659
328
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7660
328
                                "    quantized image has %u transparent colors,"
7661
328
                                " background color index "
7662
328
                                "%u (%u, %u, %u)"
7663
328
                                " %s fully transparent",
7664
328
                                num_transparent,
7665
328
                                background_index,
7666
328
                                image->colormap[background_index].red,
7667
328
                                image->colormap[background_index].green,
7668
328
                                image->colormap[background_index].blue,
7669
328
                                background_index_transparent ? "is" : "is not");
7670
7671
          /*
7672
            If we have more than one transparent color, and the
7673
            background color is fully transparent, then remove
7674
            transparency for non-background pixels so there will now
7675
            be only one transparent (the background) color.
7676
          */
7677
328
          if ((num_transparent > 1) && (background_index_transparent))
7678
101
            {
7679
101
              if (logging)
7680
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7681
0
                                      "    Fixing non-background pixels which are not opaque...");
7682
5.34k
              for (y=0; y < (long) image->rows; y++)
7683
5.24k
                {
7684
5.24k
                  register PixelPacket
7685
5.24k
                    *p;
7686
7687
5.24k
                  p=GetImagePixelsEx(image,0,y,image->columns,1,&image->exception);
7688
5.24k
                  if (p == (const PixelPacket *) NULL)
7689
0
                    break;
7690
                  /* indexes=AccessImmutableIndexes(image); */
7691
5.24k
                  indexes=AccessMutableIndexes(image);
7692
1.54M
                  for (x=0; x < (long) image->columns; x++)
7693
1.53M
                    {
7694
                      /*
7695
                        Replace non-opaque pixels which are very close
7696
                        to the transparent background color with the
7697
                        transparent background color.
7698
                      */
7699
1.53M
                      if ((indexes[x] != background_index) && (p->opacity != OpaqueOpacity))
7700
852k
                        {
7701
852k
                          double distance = DistanceVector(&image->colormap[background_index],p);
7702
852k
                          if (distance < 0.3)
7703
181k
                            {
7704
181k
                              *p=image->colormap[background_index];
7705
181k
                              p->opacity=TransparentOpacity;
7706
181k
                            }
7707
671k
                          else
7708
671k
                            {
7709
671k
                              p->opacity=OpaqueOpacity;
7710
671k
                            }
7711
852k
                        }
7712
1.53M
                      p++;
7713
1.53M
                    }
7714
5.24k
                  SyncImagePixelsEx(image,&image->exception);
7715
5.24k
                }
7716
7717
              /* Re-quantize */
7718
101
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7719
101
                                    "    Quantizing image...");
7720
101
              image->storage_class=DirectClass;
7721
101
              GetQuantizeInfo(&quantize_info);
7722
101
              quantize_info.dither=image_info->dither;
7723
101
              quantize_info.number_colors=256;
7724
101
              (void) QuantizeImage(&quantize_info,image);
7725
101
              number_colors=image->colors;
7726
101
              if (logging)
7727
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7728
0
                                      "    colors quantized to %lu colors",
7729
0
                                      number_colors);
7730
101
              image_colors=image->colors;
7731
7732
              /*
7733
                Refresh index for background color
7734
              */
7735
1.47k
              for (i=0; i < Max(Max(1,number_colors)-1,1); i++)
7736
1.41k
                {
7737
1.41k
                  if (RGBColorMatchExact(ping_background,image->colormap[i]))
7738
50
                    {
7739
50
                      background_index=i;
7740
50
                      ping_background.index=(png_uint_16) background_index;
7741
50
                      if (logging)
7742
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7743
0
                                              "    background index %u (%u, %u, %u)",
7744
0
                                              ping_background.index,
7745
0
                                              image->colormap[ping_background.index].red,
7746
0
                                              image->colormap[ping_background.index].green,
7747
0
                                              image->colormap[ping_background.index].blue);
7748
50
                      break;
7749
50
                    }
7750
1.41k
                }
7751
101
            }
7752
328
        } /* End of if (!characteristics.opaque) */
7753
7754
      /*
7755
        Set image palette.
7756
      */
7757
1.85k
      ping_colortype=PNG_COLOR_TYPE_PALETTE;
7758
7759
1.85k
      if (logging)
7760
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7761
0
                              "  Setting up PLTE chunk with %d colors",
7762
0
                              (int) number_colors);
7763
1.85k
      palette=MagickAllocateMemory(png_color *,
7764
1.85k
                                   number_colors*sizeof(png_color));
7765
1.85k
      if (palette == (png_color *) NULL)
7766
0
        {
7767
0
          png_error(ping, "Could not allocate palette");
7768
0
        }
7769
1.85k
      else
7770
1.85k
        {
7771
93.8k
          for (i=0; i < number_colors; i++)
7772
92.0k
            {
7773
92.0k
              palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7774
92.0k
              palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7775
92.0k
              palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7776
92.0k
              if (logging)
7777
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7778
#if QuantumDepth == 8
7779
                                      "    %3ld (%3d,%3d,%3d)",
7780
#else
7781
0
                                      "    %5ld (%5d,%5d,%5d)",
7782
0
#endif
7783
0
                                      i,palette[i].red,palette[i].green,
7784
0
                                      palette[i].blue);
7785
7786
92.0k
            }
7787
1.85k
          if (logging)
7788
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7789
0
                                  "  Setting up PLTE chunk with %d colors",
7790
0
                                  (int) number_colors);
7791
1.85k
          png_set_PLTE(ping,ping_info,palette,(int) number_colors);
7792
1.85k
          MagickFreeMemory(palette);
7793
1.85k
        }
7794
1.85k
      if (!characteristics.opaque) /* Previously image->matte or image_matte */
7795
328
        {
7796
          /*
7797
            Determine which (and how many) colormap indexes are non-opaque.
7798
          */
7799
328
          unsigned int
7800
328
            transparent_index = 0;
7801
7802
328
          assert(number_colors <= 256);
7803
7804
328
          ping_num_trans=0;
7805
17.3k
          for (i=0; i < image->colors; i++)
7806
17.0k
            {
7807
17.0k
              image->colormap[i].opacity=OpaqueOpacity;
7808
17.0k
            }
7809
23.3k
          for (y=0; y < (long) image->rows; y++)
7810
23.0k
            {
7811
23.0k
              register const PixelPacket
7812
23.0k
                *p;
7813
7814
23.0k
              p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
7815
23.0k
              if (p == (const PixelPacket *) NULL)
7816
0
                break;
7817
23.0k
              indexes=AccessImmutableIndexes(image);
7818
7.60M
              for (x=0; x < (long) image->columns; x++)
7819
7.58M
                {
7820
7.58M
                  if (p->opacity != OpaqueOpacity)
7821
6.38M
                    {
7822
6.38M
                      IndexPacket
7823
6.38M
                        index;
7824
7825
6.38M
                      index=indexes[x];
7826
6.38M
                      image->colormap[index].opacity = p->opacity;
7827
6.38M
                    }
7828
7.58M
                  p++;
7829
7.58M
                }
7830
23.0k
            }
7831
17.3k
          for (i=0; i < image->colors; i++)
7832
17.0k
            {
7833
17.0k
              if (image->colormap[i].opacity != OpaqueOpacity)
7834
6.41k
                {
7835
6.41k
                  transparent_index=i;
7836
6.41k
                  ++ping_num_trans;
7837
6.41k
                }
7838
17.0k
            }
7839
328
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7840
328
                                "    image has %u transparent color%s",
7841
328
                                ping_num_trans, (ping_num_trans > 1) ? "s" : "");
7842
328
          if (ping_num_trans > 1)
7843
125
            {
7844
125
              png_warning(ping,
7845
125
                          "PNG8 only supports 1 transparent color, disabling transparency...");
7846
125
              image->matte=MagickFalse;
7847
125
              ping_num_trans=0;
7848
125
            }
7849
7850
328
          if (ping_num_trans != 0)
7851
190
            {
7852
190
                unsigned int
7853
190
                  mask = 0x00ff; /* For ping_bit_depth == 8 */
7854
7855
190
                const PixelPacket *
7856
190
                  p = &image->colormap[transparent_index];
7857
7858
190
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7859
190
                                      "    %u transparent colors, enable tRNS",
7860
190
                                      ping_num_trans);
7861
7862
190
                ping_trans_color.red=ScaleQuantumToShort(p->red)&mask;
7863
190
                ping_trans_color.green=ScaleQuantumToShort(p->green)
7864
190
                  &mask;
7865
190
                ping_trans_color.blue=ScaleQuantumToShort(p->blue)
7866
190
                  &mask;
7867
190
                ping_trans_color.gray=
7868
190
                  (png_uint_16) ScaleQuantumToShort(PixelIntensity(p))&mask;
7869
190
                if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
7870
190
                  ping_trans_color.index = (png_byte) ping_background.index;
7871
0
                else
7872
0
                  ping_trans_color.index=(unsigned char)
7873
0
                    (ScaleQuantumToChar(MaxRGB-p->opacity));
7874
190
                ping_valid_trns=1;
7875
190
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7876
190
                                      "Single transparent color (%d,%d,%d index=%d)",
7877
190
                                      ping_trans_color.red,ping_trans_color.green,
7878
190
                                      ping_trans_color.blue,ping_trans_color.index);
7879
7880
              /*
7881
                FIXME: To optimize file size, we want just one entry
7882
                in tRNS, and this requires that the transparent color
7883
                should be at the first index in the palette.  Libpng
7884
                appears to optimize the chunk size by trimming
7885
                trailing opaque entries.
7886
              */
7887
190
              ping_trans_alpha=
7888
190
                MagickAllocateMemory(unsigned char *, number_colors);
7889
190
              if (ping_trans_alpha == (unsigned char *) NULL)
7890
0
                png_error(ping, "Could not allocate trans_alpha");
7891
7892
6.18k
              for (i=0; i < number_colors; i++)
7893
5.99k
                ping_trans_alpha[i]=255;
7894
190
              ping_trans_alpha[ping_trans_color.index]=0;
7895
190
            }
7896
328
        }
7897
7898
      /*
7899
        Identify which colormap entry is the background color.
7900
      */
7901
34.1k
      for (i=0; i < Max(Max(1,number_colors)-1,1); i++)
7902
33.7k
        {
7903
33.7k
          if (RGBColorMatchExact(ping_background,image->colormap[i]))
7904
1.46k
            {
7905
              /* background_index=i; */
7906
1.46k
              ping_background.index=(png_uint_16) i;
7907
1.46k
              if (logging)
7908
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7909
0
                                      "    background index %u (%u, %u, %u)",
7910
0
                                      ping_background.index,
7911
0
                                      image->colormap[ping_background.index].red,
7912
0
                                      image->colormap[ping_background.index].green,
7913
0
                                      image->colormap[ping_background.index].blue);
7914
1.46k
              break;
7915
1.46k
            }
7916
33.7k
        }
7917
7918
1.85k
      if (logging)
7919
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7920
0
                              "    Leaving PNG8 block");
7921
1.85k
    }
7922
27.7k
  else if (mng_info->write_png24 || mng_info->write_png48)
7923
3.41k
    {
7924
3.41k
      image_matte=MagickFalse;
7925
3.41k
      ping_colortype=PNG_COLOR_TYPE_RGB;
7926
3.41k
    }
7927
24.3k
  else if (mng_info->write_png32 || mng_info->write_png64)
7928
3.30k
    {
7929
3.30k
      image_matte=MagickTrue;
7930
3.30k
      ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA;
7931
3.30k
    }
7932
21.0k
  else
7933
21.0k
    {
7934
21.0k
      if (ping_bit_depth < 8)
7935
0
        ping_bit_depth=8;
7936
7937
21.0k
      ping_colortype=PNG_COLOR_TYPE_RGB;
7938
21.0k
      if (characteristics.monochrome)
7939
4.26k
        {
7940
4.26k
          if (characteristics.opaque)
7941
4.26k
            {
7942
4.26k
              ping_colortype=PNG_COLOR_TYPE_GRAY;
7943
4.26k
              ping_bit_depth=1;
7944
4.26k
            }
7945
0
          else
7946
0
            {
7947
0
              ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA;
7948
0
            }
7949
4.26k
        }
7950
16.7k
      else if (characteristics.grayscale)
7951
1.49k
        {
7952
1.49k
          if (characteristics.opaque)
7953
1.46k
            ping_colortype=PNG_COLOR_TYPE_GRAY;
7954
27
          else
7955
27
            ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA;
7956
1.49k
        }
7957
15.2k
      else if (characteristics.palette && image_colors <= 256)
7958
14.7k
        {
7959
14.7k
          ping_colortype=PNG_COLOR_TYPE_PALETTE;
7960
14.7k
          ping_bit_depth=8;
7961
14.7k
          mng_info->IsPalette=MagickTrue;
7962
14.7k
        }
7963
521
      else
7964
521
        {
7965
521
          if (characteristics.opaque)
7966
70
            ping_colortype=PNG_COLOR_TYPE_RGB;
7967
451
          else
7968
451
            ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA;
7969
521
        }
7970
21.0k
      if (image_info->type == BilevelType)
7971
0
        {
7972
0
          if (characteristics.monochrome)
7973
0
            {
7974
0
              if (!image_matte)
7975
0
                ping_bit_depth=1;
7976
0
            }
7977
0
        }
7978
21.0k
      if (image_info->type == GrayscaleType)
7979
0
        ping_colortype=PNG_COLOR_TYPE_GRAY;
7980
21.0k
      if (image_info->type == GrayscaleMatteType)
7981
0
        ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA;
7982
7983
21.0k
      if (logging)
7984
0
        {
7985
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7986
0
                                "    Tentative PNG color type: %s (%d)",
7987
0
                                PngColorTypeToString(ping_colortype),
7988
0
                                ping_colortype);
7989
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7990
0
                                "    image_info->type: %d",image_info->type);
7991
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7992
0
                                "    image->depth: %u",image_depth);
7993
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7994
0
                                "    ping_bit_depth: %d",
7995
0
                                ping_bit_depth);
7996
0
        }
7997
7998
21.0k
      if (matte && mng_info->IsPalette)
7999
21
        {
8000
21
          register const PixelPacket
8001
21
            *p=NULL;
8002
8003
21
          if (characteristics.opaque)
8004
0
            {
8005
              /*
8006
                No transparent pixels are present.  Change 4 or 6 to 0 or 2,
8007
                and unset the ping_valid_trns flag.
8008
              */
8009
0
              image_matte=MagickFalse;
8010
0
              ping_colortype&=0x03;
8011
0
              ping_valid_trns=0;
8012
0
            }
8013
21
          else
8014
21
            {
8015
21
              unsigned int
8016
21
                mask;
8017
8018
21
              MagickBool
8019
21
                opaque = MagickTrue;
8020
8021
21
              mask=0xffff;
8022
21
              if (ping_bit_depth == 8)
8023
21
                mask=0x00ff;
8024
21
              if (ping_bit_depth == 4)
8025
0
                mask=0x000f;
8026
21
              if (ping_bit_depth == 2)
8027
0
                mask=0x0003;
8028
21
              if (ping_bit_depth == 1)
8029
0
                mask=0x0001;
8030
8031
              /*
8032
                Find a transparent color.
8033
              */
8034
86
              for (y=0; y < (long) image->rows; y++)
8035
85
                {
8036
85
                  p=AcquireImagePixels(image,0,y,image->columns,1,
8037
85
                                       &image->exception);
8038
85
                  if (p == (const PixelPacket *) NULL)
8039
0
                    break;
8040
8.27k
                  for (x=(long) image->columns; x > 0; x--)
8041
8.21k
                    {
8042
8.21k
                      if (p->opacity != OpaqueOpacity)
8043
20
                        {
8044
20
                          opaque=MagickFalse;
8045
20
                          break;
8046
20
                        }
8047
8.19k
                      p++;
8048
8.19k
                    }
8049
85
                  if (!opaque)
8050
20
                    break;
8051
85
                }
8052
21
              if ((!opaque) && (p != (const PixelPacket *) NULL))
8053
20
                {
8054
20
                  ping_trans_color.red=ScaleQuantumToShort(p->red)&mask;
8055
20
                  ping_trans_color.green=ScaleQuantumToShort(p->green)
8056
20
                    &mask;
8057
20
                  ping_trans_color.blue=ScaleQuantumToShort(p->blue)
8058
20
                    &mask;
8059
20
                  ping_trans_color.gray=
8060
20
                    (png_uint_16) ScaleQuantumToShort(PixelIntensity(p))&mask;
8061
20
                  if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
8062
0
                    ping_trans_color.index = (png_byte) ping_background.index;
8063
20
                  else
8064
20
                    ping_trans_color.index=(unsigned char)
8065
20
                    (ScaleQuantumToChar(MaxRGB-p->opacity));
8066
20
                  ping_valid_trns=1;
8067
20
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8068
20
                                        "  Found transparent color: (%d,%d,%d)",
8069
20
                                        ping_trans_color.red, ping_trans_color.green,
8070
20
                                        ping_trans_color.blue);
8071
20
                }
8072
21
            }
8073
21
          if (ping_valid_trns != 0)
8074
20
            {
8075
              /*
8076
                Determine if there is one and only one transparent color
8077
                and if so if it is fully transparent.
8078
              */
8079
20
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8080
20
                                    "  Determine if there is exactly one transparent color");
8081
72
              for (y=0; y < (long) image->rows; y++)
8082
63
                {
8083
63
                  p=AcquireImagePixels(image,0,y,image->columns,1,
8084
63
                                       &image->exception);
8085
63
                  x=0;
8086
63
                  if (p == (const PixelPacket *) NULL)
8087
0
                    break;
8088
208
                  for (x=(long) image->columns; x > 0; x--)
8089
156
                    {
8090
156
                      if (p->opacity != OpaqueOpacity)
8091
155
                        {
8092
155
                          if (!RGBColorMatchExact(ping_trans_color,*p))
8093
7
                            {
8094
7
                              break;  /* Can't use RGB + tRNS for multiple
8095
                                         transparent colors.  */
8096
7
                            }
8097
148
                          if (p->opacity != TransparentOpacity)
8098
4
                            {
8099
4
                              break;  /* Can't use RGB + tRNS for
8100
                                         semitransparency. */
8101
4
                            }
8102
148
                        }
8103
1
                      else
8104
1
                        {
8105
1
                          if (RGBColorMatchExact(ping_trans_color,*p))
8106
0
                            break; /* Can't use RGB + tRNS when another pixel
8107
                                      having the same RGB samples is
8108
                                      transparent. */
8109
1
                        }
8110
145
                      p++;
8111
145
                    }
8112
63
                  if (x != 0)
8113
11
                    break;
8114
63
                }
8115
20
              if (x != 0)
8116
11
                {
8117
11
                  ping_valid_trns = 0;
8118
11
                }
8119
9
              else if (logging)
8120
0
                {
8121
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8122
0
                                        "Single transparent color (%d,%d,%d index=%d)",
8123
0
                                        ping_trans_color.red,ping_trans_color.green,
8124
0
                                        ping_trans_color.blue,ping_trans_color.index);
8125
0
                }
8126
20
            }
8127
21
          if (ping_valid_trns != 0)
8128
9
            {
8129
9
              ping_colortype &= 0x03;  /* changes 4 or 6 to 0 or 2 */
8130
9
              if (image_depth == 8)
8131
9
                {
8132
9
                  ping_trans_color.red&=0xff;
8133
9
                  ping_trans_color.green&=0xff;
8134
9
                  ping_trans_color.blue&=0xff;
8135
9
                  ping_trans_color.gray&=0xff;
8136
9
                }
8137
9
            }
8138
21
        }
8139
21.0k
      matte=image_matte;
8140
21.0k
      if (ping_valid_trns != 0)
8141
9
        image_matte=MagickFalse;
8142
21.0k
      if (mng_info->IsPalette &&
8143
20.4k
          characteristics.grayscale && (!image_matte || image_depth >= 8))
8144
5.72k
        {
8145
5.72k
          if (image_matte)
8146
12
            ping_colortype=PNG_COLOR_TYPE_GRAY_ALPHA;
8147
5.71k
          else
8148
5.71k
            {
8149
5.71k
              ping_colortype=PNG_COLOR_TYPE_GRAY;
8150
5.71k
              if (save_image_depth == 16 && image_depth == 8)
8151
0
                ping_trans_color.gray*=0x0101;
8152
5.71k
            }
8153
5.72k
          if (image_depth > QuantumDepth)
8154
0
            image_depth=QuantumDepth;
8155
5.72k
          if (image_colors == 0 || image_colors-1 > MaxRGB)
8156
0
            image_colors=1U << image_depth;
8157
5.72k
          if (image_depth > 8)
8158
0
            ping_bit_depth=16;
8159
5.72k
          else
8160
5.72k
            {
8161
5.72k
              if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
8162
0
                {
8163
0
                  ping_bit_depth=1;
8164
0
                  while ((int) (1U << ping_bit_depth) <
8165
0
                         (long) image_colors)
8166
0
                    ping_bit_depth <<= 1;
8167
0
                }
8168
5.72k
            }
8169
5.72k
        }
8170
15.2k
      else
8171
15.2k
        if (mng_info->IsPalette)
8172
14.7k
          {
8173
14.7k
            if (image_depth <= 8)
8174
14.7k
              {
8175
14.7k
                unsigned long
8176
14.7k
                  number_colors;
8177
8178
14.7k
                number_colors=image_colors;
8179
                /*
8180
                  Set image palette.
8181
                */
8182
14.7k
                ping_colortype=PNG_COLOR_TYPE_PALETTE;
8183
14.7k
                if (mng_info->have_write_global_plte && !matte)
8184
1.95k
                  {
8185
1.95k
                    png_set_PLTE(ping,ping_info,NULL,0);
8186
1.95k
                    if (logging)
8187
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8188
0
                                            "  Setting up empty PLTE chunk");
8189
1.95k
                  }
8190
12.7k
                else
8191
12.7k
                  {
8192
12.7k
                    palette=MagickAllocateArray(png_color *,
8193
12.7k
                                                number_colors,
8194
12.7k
                                                sizeof(png_color));
8195
12.7k
                    if (palette == (png_color *) NULL)
8196
0
                      png_error(ping, "Could not allocate palette");
8197
35.8k
                    for (i=0; i < number_colors; i++)
8198
23.1k
                      {
8199
23.1k
                        palette[i].red=ScaleQuantumToChar
8200
23.1k
                          (image->colormap[i].red);
8201
23.1k
                        palette[i].green=ScaleQuantumToChar
8202
23.1k
                          (image->colormap[i].green);
8203
23.1k
                        palette[i].blue=ScaleQuantumToChar
8204
23.1k
                          (image->colormap[i].blue);
8205
23.1k
                      }
8206
12.7k
                    if (logging)
8207
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8208
0
                                            "  Setting up PLTE chunk with %d colors",
8209
0
                                            (int) number_colors);
8210
12.7k
                    png_set_PLTE(ping,ping_info,palette,(int) number_colors);
8211
12.7k
                    MagickFreeMemory(palette);
8212
12.7k
                  }
8213
14.7k
                ping_bit_depth=1;
8214
15.2k
                while ((1U << ping_bit_depth) < number_colors)
8215
558
                  ping_bit_depth <<= 1;
8216
14.7k
                ping_num_trans=0;
8217
14.7k
                if (matte)
8218
0
                  {
8219
0
                    int
8220
0
                      num_alpha=0,
8221
0
                      trans_alpha[256];
8222
8223
                    /*
8224
                      Identify which colormap entry is transparent.
8225
                    */
8226
0
                    assert(number_colors <= 256);
8227
8228
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8229
0
                                          "  Look for transparent colormap entry, number_colors=%d",
8230
0
                                          (int) number_colors);
8231
8232
0
                    for (i=0; i < number_colors; i++)
8233
0
                      trans_alpha[i]=256;
8234
8235
0
                    for (y=0; y < (long) image->rows; y++)
8236
0
                      {
8237
0
                        register const PixelPacket
8238
0
                          *p=NULL;
8239
8240
0
                        p=AcquireImagePixels(image,0,y,image->columns,1,
8241
0
                                             &image->exception);
8242
0
                        if (p == (const PixelPacket *) NULL)
8243
0
                          break;
8244
0
                        indexes=AccessImmutableIndexes(image);
8245
0
                        for (x=0; x < (long) image->columns; x++)
8246
0
                          {
8247
0
                            if (p->opacity != OpaqueOpacity)
8248
0
                              {
8249
0
                                IndexPacket
8250
0
                                  index;
8251
8252
0
                                index=indexes[x];
8253
0
                                assert((unsigned long) index < number_colors);
8254
0
                                if (trans_alpha[index] == 256)
8255
0
                                  {
8256
0
                                    (void) LogMagickEvent(CoderEvent,
8257
0
                                                          GetMagickModule(),
8258
0
                                                          "  Index=%d is transparent",
8259
0
                                                          (int) index);
8260
0
                                    trans_alpha[index]=(png_byte) (255-
8261
0
                                                                   ScaleQuantumToChar(p->opacity));
8262
0
                                    num_alpha++;
8263
0
                                  }
8264
0
                              }
8265
0
                            p++;
8266
0
                          }
8267
0
                      }
8268
8269
0
                    (void) LogMagickEvent(CoderEvent, GetMagickModule(),
8270
0
                                          "  num_alpha = %d",num_alpha);
8271
0
                    if (num_alpha == 0)
8272
0
                      {
8273
0
                        image_matte = MagickFalse;
8274
0
                        ping_valid_trns = 0;
8275
0
                      }
8276
0
                    else if (num_alpha == 1)
8277
0
                      {
8278
0
                        ping_valid_trns = 1;
8279
0
                      }
8280
0
                    else
8281
0
                      {
8282
0
                        ping_colortype=PNG_COLOR_TYPE_RGB_ALPHA;
8283
0
                        ping_num_trans=0;
8284
0
                        if (ping_bit_depth < 8)
8285
0
                          ping_bit_depth=8;
8286
0
                        ping_valid_trns = 0;
8287
0
                        png_set_invalid(ping, ping_info, PNG_INFO_PLTE);
8288
0
                        mng_info->IsPalette=MagickFalse;
8289
0
                        image_matte=MagickTrue;
8290
0
                        (void) SyncImage(image);
8291
0
                        if (logging)
8292
0
                          (void) LogMagickEvent(CoderEvent,
8293
0
                                                GetMagickModule(),
8294
0
                                                "    Cannot write image"
8295
0
                                                " as indexed PNG,"
8296
0
                                                " writing RGBA.");
8297
0
                      }
8298
8299
0
                    if (ping_valid_trns != 0)
8300
0
                      {
8301
0
                        for (i=0; i < number_colors; i++)
8302
0
                          {
8303
0
                            if (trans_alpha[i] == 256)
8304
0
                              trans_alpha[i]=255;
8305
0
                            if (trans_alpha[i] != 255)
8306
0
                              ping_num_trans=(unsigned short) (i+1);
8307
0
                          }
8308
0
                        (void) LogMagickEvent(CoderEvent, GetMagickModule(),
8309
0
                                              "  ping_num_trans = %d",ping_num_trans);
8310
0
                      }
8311
0
                    if (ping_num_trans == 0)
8312
0
                      ping_valid_trns = 0;
8313
0
                    else
8314
0
                      ping_valid_trns = 1;
8315
0
                    if (ping_valid_trns == 0)
8316
0
                      ping_num_trans=0;
8317
8318
0
                    if (ping_valid_trns != 0)
8319
0
                      {
8320
0
                        ping_trans_alpha=
8321
0
                          MagickAllocateMemory(unsigned char *, number_colors);
8322
0
                        if (ping_trans_alpha == (unsigned char *) NULL)
8323
0
                          png_error(ping, "Could not allocate trans_alpha");
8324
8325
0
                        for (i=0; i < number_colors; i++)
8326
0
                          {
8327
0
                            if (trans_alpha[i] == 256)
8328
0
                              ping_trans_alpha[i]=255;
8329
0
                            else
8330
0
                              ping_trans_alpha[i]=(png_byte) trans_alpha[i];
8331
0
                            (void) LogMagickEvent(CoderEvent, GetMagickModule(),
8332
0
                                                  "    Alpha[%d]=%d",(int) i,
8333
0
                                                  (int) trans_alpha[i]);
8334
0
                          }
8335
0
                      }
8336
0
                  } /* if (matte) */
8337
8338
                /*
8339
                  Identify which colormap entry is the background color.
8340
                */
8341
33.6k
                for (i=0; i < Max(Max(1,number_colors)-1,1); i++)
8342
19.1k
                  if (RGBColorMatchExact(ping_background,
8343
19.1k
                                         image->colormap[i]))
8344
203
                    break;
8345
14.7k
                ping_background.index=(png_uint_16) i;
8346
14.7k
                if (logging)
8347
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8348
0
                                        "    background index %u (%u, %u, %u)",
8349
0
                                        ping_background.index,
8350
0
                                        image->colormap[ping_background.index].red,
8351
0
                                        image->colormap[ping_background.index].green,
8352
0
                                        image->colormap[ping_background.index].blue);
8353
14.7k
              }
8354
14.7k
          }
8355
557
        else
8356
557
          {
8357
557
            if (image_depth < 8)
8358
0
              image_depth=8;
8359
557
            if ((save_image_depth == 16) && (image_depth == 8))
8360
0
              {
8361
0
                ping_trans_color.red*=0x0101;
8362
0
                ping_trans_color.green*=0x0101;
8363
0
                ping_trans_color.blue*=0x0101;
8364
0
                ping_trans_color.gray*=0x0101;
8365
0
              }
8366
557
          }
8367
8368
      /*
8369
        Adjust background and transparency samples in sub-8-bit
8370
        grayscale files.
8371
      */
8372
21.0k
      if (ping_bit_depth < 8 && ping_colortype ==
8373
18.9k
          PNG_COLOR_TYPE_GRAY)
8374
4.26k
        {
8375
4.26k
          png_uint_16
8376
4.26k
            maxval;
8377
8378
4.26k
          maxval=(1U << ping_bit_depth)-1;
8379
8380
4.26k
          ping_trans_color.gray=(png_uint_16)(maxval*
8381
4.26k
                                              ping_trans_color.gray/
8382
4.26k
                                              MaxRGB);
8383
4.26k
        }
8384
21.0k
    }
8385
8386
29.5k
  if (logging)
8387
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8388
0
                          "    PNG color type: %s (%d)",
8389
0
                          PngColorTypeToString(ping_colortype),
8390
0
                          ping_colortype);
8391
  /*
8392
    Initialize compression level and filtering.
8393
  */
8394
29.5k
  if (logging)
8395
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8396
0
                          "  Setting up deflate compression");
8397
29.5k
  if (logging)
8398
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8399
0
                          "    Compression buffer size: 32768");
8400
29.5k
  png_set_compression_buffer_size(ping,32768L);
8401
29.5k
  if (logging)
8402
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8403
0
                          "    Compression mem level: 9");
8404
29.5k
  png_set_compression_mem_level(ping, 9);
8405
29.5k
  if (image_info->quality > 9)
8406
29.6k
    {
8407
29.6k
      int
8408
29.6k
        level;
8409
8410
29.6k
      level=(int) Min(image_info->quality/10,9);
8411
29.6k
      if (logging)
8412
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8413
0
                              "    Compression level: %d",level);
8414
29.6k
      png_set_compression_level(ping,level);
8415
29.6k
    }
8416
18.4E
  else
8417
18.4E
    {
8418
18.4E
      if (logging)
8419
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8420
0
                              "    Compression strategy: Z_HUFFMAN_ONLY");
8421
18.4E
      png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8422
18.4E
      png_set_compression_level(ping,2);
8423
18.4E
    }
8424
29.5k
  if (logging)
8425
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8426
0
                          "  Setting up filtering");
8427
29.5k
#if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8428
8429
  /* This became available in libpng-1.0.9.  Output must be a MNG. */
8430
29.5k
  if (mng_info->write_mng && ((image_info->quality % 10) == 7))
8431
0
    {
8432
0
      if (logging)
8433
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8434
0
                              "    Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8435
0
      ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8436
0
    }
8437
29.5k
  else
8438
29.5k
    if (logging)
8439
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8440
0
                            "    Filter_type: 0");
8441
29.5k
#endif
8442
29.5k
  {
8443
29.5k
    int
8444
29.5k
      base_filter;
8445
8446
29.5k
    if ((image_info->quality % 10) > 5)
8447
0
      base_filter=PNG_ALL_FILTERS;
8448
29.5k
    else
8449
29.5k
      if ((image_info->quality % 10) != 5)
8450
0
        base_filter=(int) image_info->quality % 10;
8451
29.5k
      else
8452
29.5k
        if ((ping_colortype == PNG_COLOR_TYPE_GRAY) ||
8453
23.9k
            (ping_colortype == PNG_COLOR_TYPE_PALETTE) ||
8454
7.34k
            (image_info->quality < 50))
8455
22.3k
          base_filter=PNG_NO_FILTERS;
8456
7.26k
        else
8457
7.26k
          base_filter=PNG_ALL_FILTERS;
8458
29.5k
    if (logging)
8459
0
      {
8460
0
        if (base_filter == PNG_ALL_FILTERS)
8461
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8462
0
                                "    Base filter method: ADAPTIVE");
8463
0
        else
8464
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8465
0
                                "    Base filter method: NONE");
8466
0
      }
8467
29.5k
    png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8468
29.5k
  }
8469
8470
29.5k
  ping_interlace_method=(image_info->interlace == LineInterlace);
8471
8472
29.5k
  if (mng_info->write_mng)
8473
17.6k
    png_set_sig_bytes(ping,8);
8474
8475
29.5k
  if (logging)
8476
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8477
0
                          "  Writing PNG header chunks");
8478
8479
29.5k
  png_set_IHDR(ping,ping_info,
8480
29.5k
               ping_width,
8481
29.5k
               ping_height,
8482
29.5k
               ping_bit_depth,
8483
29.5k
               ping_colortype,
8484
29.5k
               ping_interlace_method,
8485
29.5k
               ping_compression_method,
8486
29.5k
               ping_filter_method);
8487
8488
29.5k
  if (ping_colortype == 3 && ping_valid_trns != 0)
8489
190
    {
8490
190
      if (logging)
8491
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8492
0
                              "  Setting up tRNS chunk");
8493
190
      (void) png_set_tRNS(ping, ping_info,
8494
190
                          ping_trans_alpha,
8495
190
                          ping_num_trans,
8496
190
                          &ping_trans_color);
8497
190
    }
8498
8499
29.5k
  MagickFreeMemory(ping_trans_alpha);
8500
8501
29.5k
  if (image_matte && (!mng_info->adjoin || !mng_info->equal_backgrounds))
8502
4.18k
    {
8503
4.18k
      if (logging)
8504
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8505
0
                              "  Setting up bKGD chunk for %s image",
8506
0
                              PngColorTypeToString(ping_colortype));
8507
8508
4.18k
      if (ping_bit_depth < 8 && ping_colortype == PNG_COLOR_TYPE_GRAY)
8509
0
        {
8510
0
          png_uint_16
8511
0
            maxval;
8512
8513
0
          png_color_16
8514
0
            background;
8515
8516
0
          maxval=(1U << ping_bit_depth)-1;
8517
8518
8519
0
          background.gray=(png_uint_16)
8520
0
            (maxval*(PixelIntensity(&image->background_color))/MaxRGB);
8521
0
          if (logging)
8522
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8523
0
                                  "      bKGD gray %u", background.gray);
8524
8525
0
          png_set_bKGD(ping,ping_info,&background);
8526
0
        }
8527
8528
4.18k
      else
8529
4.18k
        {
8530
4.18k
          png_color_16
8531
4.18k
            background;
8532
8533
4.18k
          if (image_depth < QuantumDepth)
8534
2.44k
            {
8535
2.44k
              int
8536
2.44k
                maxval;
8537
8538
2.44k
              maxval=(1U << image_depth)-1;
8539
2.44k
              background.red=(png_uint_16)
8540
2.44k
                (maxval*image->background_color.red/MaxRGB);
8541
2.44k
              background.green=(png_uint_16)
8542
2.44k
                (maxval*image->background_color.green/MaxRGB);
8543
2.44k
              background.blue=(png_uint_16)
8544
2.44k
                (maxval*image->background_color.blue/MaxRGB);
8545
2.44k
              background.gray=(png_uint_16)
8546
2.44k
                (maxval*PixelIntensity(&image->background_color)/MaxRGB);
8547
2.44k
              if (logging)
8548
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8549
0
                                      "      background (red=%u, green=%u, blue=%u, gray=%u)",
8550
0
                                      background.red, background.green, background.blue,
8551
0
                                      background.gray);
8552
2.44k
            }
8553
1.73k
          else
8554
1.73k
            {
8555
1.73k
              background.red=image->background_color.red;
8556
1.73k
              background.green=image->background_color.green;
8557
1.73k
              background.blue=image->background_color.blue;
8558
1.73k
              background.gray=
8559
1.73k
                (png_uint_16) PixelIntensity(&image->background_color);
8560
1.73k
              if (logging)
8561
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8562
0
                                      "      background (red=%u, green=%u, blue=%u, gray=%u)",
8563
0
                                      background.red, background.green, background.blue,
8564
0
                                      background.gray);
8565
1.73k
            }
8566
4.18k
          if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
8567
328
            background.index=(png_byte) ping_background.index;
8568
3.85k
          else
8569
3.85k
            background.index=(png_byte) background.gray;
8570
4.18k
          if (logging)
8571
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8572
0
                                  "      bKGD index %u",
8573
0
                                  background.index);
8574
4.18k
          png_set_bKGD(ping,ping_info,&background);
8575
4.18k
        }
8576
4.18k
    }
8577
8578
29.5k
#if defined(PNG_pHYs_SUPPORTED)
8579
29.5k
  if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
8580
75
      (!mng_info->write_mng || !mng_info->equal_physs))
8581
75
    {
8582
75
      int
8583
75
        unit_type;
8584
8585
75
      png_uint_32
8586
75
        x_resolution,
8587
75
        y_resolution;
8588
8589
75
      if (image->units == PixelsPerInchResolution)
8590
0
        {
8591
0
          unit_type=PNG_RESOLUTION_METER;
8592
0
          x_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->x_resolution+0.5)/2.54);
8593
0
          y_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->y_resolution+0.5)/2.54);
8594
0
        }
8595
75
      else if (image->units == PixelsPerCentimeterResolution)
8596
19
        {
8597
19
          unit_type=PNG_RESOLUTION_METER;
8598
19
          x_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->x_resolution+0.5);
8599
19
          y_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->y_resolution+0.5);
8600
19
        }
8601
56
      else
8602
56
        {
8603
56
          unit_type=PNG_RESOLUTION_UNKNOWN;
8604
56
          x_resolution=(png_uint_32) MagickDoubleToUInt(image->x_resolution);
8605
56
          y_resolution=(png_uint_32) MagickDoubleToUInt(image->y_resolution);
8606
56
        }
8607
8608
75
      png_set_pHYs(ping,ping_info,x_resolution,y_resolution,unit_type);
8609
8610
75
      if (logging)
8611
0
        {
8612
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8613
0
                                "    Setting up pHYs chunk");
8614
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8615
0
                                "      x_resolution=%u",(unsigned int) x_resolution);
8616
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8617
0
                                "      y_resolution=%u",(unsigned int) y_resolution);
8618
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8619
0
                                "      unit_type=%lu",(unsigned long) unit_type);
8620
0
        }
8621
75
    }
8622
29.5k
#endif
8623
8624
29.5k
#if defined(PNG_oFFs_SUPPORTED)
8625
29.5k
  if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
8626
1.47k
    {
8627
1.47k
      if (!((image->page.width != 0 && image->page.width != image->columns) ||
8628
1.09k
            (image->page.height != 0 && image->page.height != image->rows)))
8629
778
        {
8630
778
          png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8631
778
                       (png_int_32) image->page.y, 0);
8632
778
          if (logging)
8633
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8634
0
                                  "    Setting up oFFs chunk");
8635
778
        }
8636
      /* else write caNv instead, later */
8637
1.47k
    }
8638
29.5k
#endif
8639
8640
29.5k
  {
8641
29.5k
    ImageProfileIterator
8642
29.5k
      profile_iterator;
8643
8644
29.5k
    profile_iterator=AllocateImageProfileIterator(image);
8645
29.5k
    if (profile_iterator)
8646
3.04k
      {
8647
3.04k
        const char
8648
3.04k
          *profile_name_uc;
8649
8650
3.04k
        const unsigned char
8651
3.04k
          *profile_info;
8652
8653
3.04k
        char
8654
3.04k
          profile_name[MaxTextExtent];
8655
8656
3.04k
        size_t
8657
3.04k
          profile_length;
8658
8659
7.35k
        while (NextImageProfile(profile_iterator,&profile_name_uc,&profile_info,
8660
7.35k
                                &profile_length) != MagickFail)
8661
4.30k
          {
8662
4.30k
            (void) strlcpy(profile_name, profile_name_uc, sizeof(profile_name));
8663
4.30k
            LocaleLower(profile_name);
8664
4.30k
            if (LocaleCompare(profile_name,"ICM") == 0)
8665
90
              {
8666
90
                if (profile_length < 132)
8667
32
                  {
8668
32
                    if (logging)
8669
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8670
0
                                            "  Ignoring %s profile (%u byte%s)"
8671
0
                                            " because it is too short!",
8672
0
                                            profile_name,
8673
0
                                            (unsigned int) profile_length,
8674
0
                                            profile_length > 1 ? "s" : "");
8675
32
                  }
8676
58
                else
8677
58
                  {
8678
58
#if defined(PNG_WRITE_iCCP_SUPPORTED)
8679
58
                    {
8680
58
                      if (logging)
8681
0
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8682
0
                                              "  Setting up iCCP chunk (%u byte%s)",
8683
0
                                              (unsigned int) profile_length,
8684
0
                                              profile_length > 1 ? "s" : "");
8685
8686
58
                      png_set_iCCP(ping,ping_info,(png_charp) "icm",
8687
58
                                   (int) 0,
8688
#if (PNG_LIBPNG_VER < 10500)
8689
                                   (png_charp) profile_info,
8690
#else
8691
58
                                   (png_const_bytep) profile_info,
8692
58
#endif
8693
8694
58
                                   (png_uint_32) profile_length);
8695
58
                    }
8696
#else
8697
                    {
8698
                      if (logging)
8699
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8700
                                              "  Setting up text chunk with"
8701
                                              " iCCP Profile");
8702
                      (void) png_write_raw_profile(image_info,ping,ping_info,
8703
                                                   "icm",
8704
                                                   "ICC Profile",
8705
                                                   profile_info,
8706
                                                   (png_uint_32) profile_length,
8707
                                                   &image->exception);
8708
                    }
8709
#endif
8710
58
                  }
8711
90
              }
8712
4.21k
            else if (LocaleCompare(profile_name,"IPTC") == 0)
8713
23
              {
8714
23
                if (logging)
8715
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8716
0
                                        "  Setting up text chunk with"
8717
0
                                        " iPTC Profile");
8718
23
                (void) png_write_raw_profile(image_info,ping,ping_info,
8719
23
                                             "iptc",
8720
23
                                             "IPTC profile",
8721
23
                                             profile_info,
8722
23
                                             (png_uint_32) profile_length,
8723
23
                                             &image->exception);
8724
23
              }
8725
4.19k
            else if (LocaleCompare(profile_name,"exif") == 0)
8726
              /* Do not write exif; we'll write it later as eXIf */
8727
2.43k
              ;
8728
1.76k
            else
8729
1.76k
              {
8730
1.76k
                if (logging)
8731
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8732
0
                                        "  Setting up text chunk with"
8733
0
                                        " %s profile",
8734
0
                                        profile_name);
8735
1.76k
                (void) png_write_raw_profile(image_info,ping,ping_info,
8736
1.76k
                                             profile_name,
8737
1.76k
                                             "generic profile",
8738
1.76k
                                             profile_info,
8739
1.76k
                                             (png_uint_32) profile_length,
8740
1.76k
                                             &image->exception);
8741
1.76k
              }
8742
4.30k
          }
8743
8744
3.04k
        DeallocateImageProfileIterator(profile_iterator);
8745
3.04k
      }
8746
29.5k
  }
8747
8748
29.5k
#if defined(PNG_WRITE_sRGB_SUPPORTED)
8749
29.5k
  if (!mng_info->have_write_global_srgb &&
8750
29.6k
      ((image->rendering_intent != UndefinedIntent) ||
8751
29.5k
       image_info->colorspace == sRGBColorspace))
8752
68
    {
8753
      /*
8754
        Note image rendering intent.
8755
      */
8756
68
      if (logging)
8757
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8758
0
                              "  Setting up sRGB chunk");
8759
68
      if (image->rendering_intent != UndefinedIntent)
8760
68
        (void) png_set_sRGB(ping,ping_info,(int) (image->rendering_intent-1));
8761
0
      else
8762
0
        (void) png_set_sRGB(ping,ping_info,PerceptualIntent);
8763
68
      png_set_gAMA(ping,ping_info,0.45455);
8764
68
    }
8765
29.5k
  if ((!mng_info->write_mng) ||
8766
17.6k
      !png_get_valid(ping, ping_info, PNG_INFO_sRGB))
8767
29.6k
#endif
8768
29.6k
    {
8769
29.6k
      if (!mng_info->have_write_global_gama && (image->gamma != 0.0))
8770
487
        {
8771
          /*
8772
            Note image gamma.
8773
            To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8774
          */
8775
487
          if (logging)
8776
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8777
0
                                  "  Setting up gAMA chunk gamma=%f", image->gamma);
8778
487
          png_set_gAMA(ping,ping_info,image->gamma);
8779
487
        }
8780
29.6k
      if (!mng_info->have_write_global_chrm &&
8781
29.6k
          (image->chromaticity.red_primary.x != 0.0))
8782
84
        {
8783
          /*
8784
            Note image chromaticity.
8785
            To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8786
          */
8787
84
          PrimaryInfo
8788
84
            bp,
8789
84
            gp,
8790
84
            rp,
8791
84
            wp;
8792
8793
84
          wp=image->chromaticity.white_point;
8794
84
          rp=image->chromaticity.red_primary;
8795
84
          gp=image->chromaticity.green_primary;
8796
84
          bp=image->chromaticity.blue_primary;
8797
8798
84
          if (logging)
8799
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8800
0
                                  "  Setting up cHRM chunk");
8801
84
          png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8802
84
                       bp.x,bp.y);
8803
84
        }
8804
29.6k
    }
8805
8806
29.5k
  png_write_info(ping,ping_info);
8807
8808
  /* write orNT if image->orientation is defined and not TopLeft */
8809
29.5k
  if (image->orientation > 1 && image->orientation < 9)
8810
21
    {
8811
21
      unsigned char
8812
21
        chunk[6];
8813
21
      (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
8814
21
      PNGType(chunk,mng_orNT);
8815
21
      LogPNGChunk(logging,mng_orNT,1L);
8816
21
      chunk[4]=image->orientation;
8817
21
      (void) WriteBlob(image,5,chunk);
8818
21
      (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
8819
21
    }
8820
8821
  /* write caNv chunk */
8822
29.6k
  if ((image->page.width != 0 && image->page.width != image->columns) ||
8823
29.2k
      (image->page.height != 0 && image->page.height != image->rows) ||
8824
28.9k
      image->page.x != 0 || image->page.y != 0)
8825
1.47k
    {
8826
1.47k
      unsigned char
8827
1.47k
        chunk[22];
8828
8829
1.47k
      (void) WriteBlobMSBULong(image,16L);  /* data length=16 */
8830
1.47k
      PNGType(chunk,mng_caNv);
8831
1.47k
      LogPNGChunk(logging,mng_caNv,16L);
8832
1.47k
      PNGLong(chunk+4,(png_uint_32) image->page.width);
8833
1.47k
      PNGLong(chunk+8,(png_uint_32) image->page.height);
8834
1.47k
      PNGsLong(chunk+12,(png_int_32) image->page.x);
8835
1.47k
      PNGsLong(chunk+16,(png_int_32) image->page.y);
8836
1.47k
      (void) WriteBlob(image,20,chunk);
8837
1.47k
      (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
8838
1.47k
    }
8839
8840
#if (PNG_LIBPNG_VER == 10206)
8841
  /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8842
#define PNG_HAVE_IDAT               0x04
8843
  ping->mode |= PNG_HAVE_IDAT;
8844
#undef PNG_HAVE_IDAT
8845
#endif
8846
8847
29.5k
  png_set_packing(ping);
8848
  /*
8849
    Allocate memory.
8850
  */
8851
29.5k
  if (logging)
8852
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8853
0
                          "  mng_info: columns=%lu, image_depth=%u, "
8854
0
                          "write_png8=%u, write_png24=%u, write_png32=%u "
8855
0
                          "write_png48=%u, write_png64=%u, IsPalette=%u, "
8856
0
                          "image_matte=%u",
8857
0
                          image->columns, image_depth, mng_info->write_png8,
8858
0
                          mng_info->write_png24, mng_info->write_png32,
8859
0
                          mng_info->write_png48, mng_info->write_png64,
8860
0
                          mng_info->IsPalette, image_matte
8861
0
                          );
8862
29.5k
  rowbytes=image->columns;
8863
29.5k
  if (image_depth <= 8)
8864
26.2k
    {
8865
26.2k
      if (mng_info->write_png24)
8866
1.78k
        rowbytes*=3;
8867
24.4k
      else if (mng_info->write_png32)
8868
1.61k
        rowbytes*=4;
8869
22.8k
      else if (!mng_info->write_png8 && (mng_info->IsPalette &&
8870
20.4k
                                         IsGrayImage(image,&image->exception)))
8871
5.72k
        rowbytes*=(image_matte ? 2 : 1);
8872
17.1k
      else
8873
17.1k
        {
8874
17.1k
          if (!mng_info->IsPalette)
8875
1.04k
            rowbytes*=(image_matte ? 4 : 3);
8876
17.1k
        }
8877
26.2k
    }
8878
3.32k
  else
8879
3.32k
    {
8880
3.32k
      if (mng_info->write_png48)
8881
1.62k
        rowbytes*=6;
8882
8883
1.69k
      else if (mng_info->write_png64)
8884
1.69k
        rowbytes*=8;
8885
8886
2
      else if (mng_info->IsPalette &&
8887
0
               IsGrayImage(image,&image->exception))
8888
0
        rowbytes*=(image_matte ? 4 : 2);
8889
8890
2
      else
8891
18.4E
        rowbytes*=(image_matte ? 8 : 6);
8892
3.32k
    }
8893
29.5k
  if (logging)
8894
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8895
0
                          "  Allocating %lu bytes of memory for pixels",
8896
0
                          rowbytes);
8897
29.5k
  png_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,rowbytes);
8898
29.5k
  if (png_pixels == (unsigned char *) NULL)
8899
0
    png_error(ping, "Could not allocate png_pixels");
8900
29.5k
  mng_info->png_pixels=png_pixels; /* For free in setjmp handler */
8901
  /*
8902
    Initialize image scanlines.
8903
  */
8904
29.5k
  num_passes=png_set_interlace_handling(ping);
8905
29.5k
  if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8906
26.0k
       !mng_info->write_png32 && !mng_info->write_png48 &&
8907
22.7k
       !mng_info->write_png64) && (mng_info->IsPalette ||
8908
637
                                   image_info->type == BilevelType) &&
8909
20.4k
      !image_matte &&
8910
20.4k
      IsMonochromeImage(image,&image->exception))
8911
8.53k
    for (pass=0; pass < num_passes; pass++)
8912
4.26k
      {
8913
        /*
8914
          Convert PseudoClass image to a PNG monochrome image.
8915
        */
8916
4.26k
        if (logging)
8917
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8918
0
                                "  pass %d, Image Is Monochrome",pass);
8919
9.82k
        for (y=0; y < (long) image->rows; y++)
8920
5.55k
          {
8921
5.55k
            if (!AcquireImagePixels(image,0,y,image->columns,1,
8922
5.55k
                                    &image->exception))
8923
0
              break;
8924
5.55k
            if (mng_info->IsPalette)
8925
5.55k
              (void) ExportImagePixelArea(image,(QuantumType) GrayQuantum,
8926
5.55k
                                          quantum_size,png_pixels,0,0);
8927
0
            else
8928
0
              (void) ExportImagePixelArea(image,(QuantumType) RedQuantum,
8929
0
                                          quantum_size,png_pixels,0,0);
8930
167k
            for (i=0; i < image->columns; i++)
8931
161k
              *(png_pixels+i)=(*(png_pixels+i) > 128) ? 255 : 0;
8932
5.55k
            png_write_row(ping,png_pixels);
8933
5.55k
            if (image->previous == (Image *) NULL)
8934
2.79k
              if (QuantumTick((magick_uint64_t) y*((magick_uint64_t)pass+1),
8935
2.79k
                              (magick_uint64_t) image->rows * num_passes))
8936
2.67k
                if (!MagickMonitorFormatted((magick_uint64_t) y*((magick_uint64_t)pass+1),
8937
2.67k
                                            (magick_uint64_t) image->rows*
8938
2.67k
                                            num_passes,
8939
2.67k
                                            &image->exception,
8940
2.67k
                                            SaveImageText,
8941
2.67k
                                            image->filename,
8942
2.67k
                                            image->columns,image->rows))
8943
0
                  break;
8944
8945
5.55k
          }
8946
4.26k
      }
8947
25.3k
  else
8948
50.7k
    for (pass=0; pass < num_passes; pass++)
8949
25.3k
      {
8950
25.3k
        if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8951
21.7k
             !mng_info->write_png32 && !mng_info->write_png48 &&
8952
18.5k
             !mng_info->write_png64) &&
8953
16.8k
            (!image_matte || (ping_bit_depth >= QuantumDepth)) &&
8954
16.3k
            mng_info->IsPalette &&
8955
16.1k
            IsGrayImage(image,&image->exception))
8956
1.44k
          {
8957
1.44k
            if (logging)
8958
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8959
0
                                    "  pass %d, Image Is Gray",pass);
8960
8.65k
            for (y=0; y < (long) image->rows; y++)
8961
7.20k
              {
8962
7.20k
                if (!AcquireImagePixels(image,0,y,image->columns,1,
8963
7.20k
                                        &image->exception))
8964
0
                  break;
8965
7.20k
                if (ping_colortype == PNG_COLOR_TYPE_GRAY)
8966
7.20k
                  {
8967
7.20k
                    if (mng_info->IsPalette)
8968
7.20k
                      (void) ExportImagePixelArea(image,
8969
7.20k
                                                  (QuantumType) GrayQuantum,
8970
7.20k
                                                  quantum_size,png_pixels,0,0);
8971
0
                    else
8972
0
                      (void) ExportImagePixelArea(image,
8973
0
                                                  (QuantumType) RedQuantum,
8974
0
                                                  quantum_size,
8975
0
                                                  png_pixels,0,0);
8976
7.20k
                  }
8977
0
                else if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
8978
0
                  {
8979
0
                    (void) ExportImagePixelArea(image,(QuantumType)
8980
0
                                                IndexQuantum,
8981
0
                                                quantum_size,
8982
0
                                                png_pixels,0,0);
8983
0
                  }
8984
0
                else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8985
0
                  {
8986
0
                    (void) ExportImagePixelArea(image,(QuantumType)
8987
0
                                                GrayAlphaQuantum,
8988
0
                                                quantum_size,
8989
0
                                                png_pixels,0,0);
8990
0
                  }
8991
7.20k
                png_write_row(ping,png_pixels);
8992
7.20k
                if (image->previous == (Image *) NULL)
8993
6.96k
                  if (QuantumTick((magick_uint64_t) y*((magick_uint64_t) pass+1),
8994
6.96k
                                  (magick_uint64_t) image->rows * num_passes))
8995
5.61k
                    if (!MagickMonitorFormatted((magick_uint64_t) y*((magick_uint64_t) pass+1),
8996
5.61k
                                                (magick_uint64_t) image->rows*
8997
5.61k
                                                num_passes,
8998
5.61k
                                                &image->exception,SaveImageText,
8999
5.61k
                                                image->filename,
9000
5.61k
                                                image->columns,image->rows))
9001
0
                      break;
9002
7.20k
              }
9003
1.44k
          }
9004
23.9k
        else
9005
47.8k
          for (pass=0; pass < num_passes; pass++)
9006
23.9k
            {
9007
23.9k
              if ((image_depth > 8) ||
9008
20.5k
                  (mng_info->write_png24 || mng_info->write_png32 ||
9009
17.1k
                   mng_info->write_png48 || mng_info->write_png64 ||
9010
17.1k
                   (!mng_info->write_png8 && !mng_info->IsPalette)))
9011
7.35k
                {
9012
7.35k
                  if (logging)
9013
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9014
0
                                          "  pass %d, Image Is RGB,"
9015
0
                                          " PNG colortype is %s (%d)",pass,
9016
0
                                          PngColorTypeToString(
9017
0
                                                               ping_colortype),
9018
0
                                          ping_colortype);
9019
249k
                  for (y=0; y < (long) image->rows; y++)
9020
242k
                    {
9021
242k
                      if (!AcquireImagePixels(image,0,y,image->columns,1,
9022
242k
                                              &image->exception))
9023
0
                        break;
9024
242k
                      if (ping_colortype == PNG_COLOR_TYPE_GRAY)
9025
899
                        {
9026
899
                          if (image->storage_class == DirectClass)
9027
0
                            (void) ExportImagePixelArea(image,(QuantumType)
9028
0
                                                        RedQuantum,
9029
0
                                                        quantum_size,
9030
0
                                                        png_pixels,0,0);
9031
899
                          else
9032
899
                            (void) ExportImagePixelArea(image,(QuantumType)
9033
899
                                                        GrayQuantum,
9034
899
                                                        quantum_size,
9035
899
                                                        png_pixels,0,0);
9036
899
                        }
9037
241k
                      else if (ping_colortype ==
9038
241k
                               PNG_COLOR_TYPE_GRAY_ALPHA)
9039
70
                        (void) ExportImagePixelArea(image,(QuantumType)
9040
70
                                                    GrayAlphaQuantum,
9041
70
                                                    quantum_size,
9042
70
                                                    png_pixels,0,0);
9043
241k
                      else if (image_matte)
9044
142k
                        (void) ExportImagePixelArea(image,(QuantumType)
9045
142k
                                                    RGBAQuantum,
9046
142k
                                                    quantum_size,
9047
142k
                                                    png_pixels,0,0);
9048
99.3k
                      else
9049
99.3k
                        {
9050
99.3k
                          (void) ExportImagePixelArea(image,(QuantumType)
9051
99.3k
                                                      RGBQuantum,
9052
99.3k
                                                      quantum_size,
9053
99.3k
                                                      png_pixels,0,0);
9054
99.3k
                        }
9055
242k
                      png_write_row(ping,png_pixels);
9056
242k
                      if (image->previous == (Image *) NULL)
9057
242k
                        if (QuantumTick((magick_uint64_t) y * ((magick_uint64_t) pass+1),
9058
242k
                                        (magick_uint64_t) image->rows *
9059
242k
                                        num_passes))
9060
147k
                          if (!MagickMonitorFormatted((magick_uint64_t)
9061
147k
                                                      y*((magick_uint64_t) pass+1),
9062
147k
                                                      (magick_uint64_t)
9063
147k
                                                      image->rows*num_passes,
9064
147k
                                                      &image->exception,
9065
147k
                                                      SaveImageText,
9066
147k
                                                      image->filename,
9067
147k
                                                      image->columns,image->rows))
9068
0
                            break;
9069
242k
                    }
9070
7.35k
                  if (logging)
9071
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9072
0
                                          "  pass %d done",pass);
9073
7.35k
                }
9074
16.5k
              else
9075
16.5k
                {
9076
16.5k
                  if (logging)
9077
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9078
0
                                          "  pass %d, Image Is RGB,"
9079
0
                                          " 16-bit GRAY, or GRAY_ALPHA",pass);
9080
92.6k
                  for (y=0; y < (long) image->rows; y++)
9081
76.0k
                    {
9082
76.0k
                      if (!AcquireImagePixels(image,0,y,image->columns,1,
9083
76.0k
                                              &image->exception))
9084
0
                        break;
9085
76.0k
                      if (ping_colortype == PNG_COLOR_TYPE_GRAY)
9086
0
                        (void) ExportImagePixelArea(image,(QuantumType)
9087
0
                                                    GrayQuantum,
9088
0
                                                    quantum_size,
9089
0
                                                    png_pixels,0,0);
9090
76.0k
                      else if (ping_colortype ==
9091
76.0k
                               PNG_COLOR_TYPE_GRAY_ALPHA)
9092
1.02k
                        (void) ExportImagePixelArea(image,(QuantumType)
9093
1.02k
                                                    GrayAlphaQuantum,
9094
1.02k
                                                    quantum_size,
9095
1.02k
                                                    png_pixels,0,0);
9096
75.0k
                      else
9097
75.0k
                        (void) ExportImagePixelArea(image,(QuantumType)
9098
75.0k
                                                    IndexQuantum,
9099
75.0k
                                                    quantum_size,
9100
75.0k
                                                    png_pixels,0,0);
9101
76.0k
                      png_write_row(ping,png_pixels);
9102
76.0k
                      if (image->previous == (Image *) NULL)
9103
61.9k
                        if (QuantumTick((magick_uint64_t) y * ((magick_uint64_t) pass+1),
9104
61.9k
                                        (magick_uint64_t) image->rows *
9105
61.9k
                                        num_passes))
9106
35.1k
                          if (!MagickMonitorFormatted((magick_uint64_t)
9107
35.1k
                                                      y*((magick_uint64_t) pass+1),
9108
35.1k
                                                      (magick_uint64_t)
9109
35.1k
                                                      image->rows*num_passes,
9110
35.1k
                                                      &image->exception,
9111
35.1k
                                                      SaveImageText,
9112
35.1k
                                                      image->filename,
9113
35.1k
                                                      image->columns,
9114
35.1k
                                                      image->rows))
9115
0
                            break;
9116
76.0k
                    }
9117
16.5k
                }
9118
23.9k
            }
9119
25.3k
      }
9120
9121
29.5k
  MagickFreeResourceLimitedMemory(unsigned char *,png_pixels);
9122
29.5k
  mng_info->png_pixels = (unsigned char *) NULL;
9123
9124
29.5k
  if (logging)
9125
0
    {
9126
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9127
0
                            "  Writing PNG image data");
9128
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9129
0
                            "    Width: %lu",
9130
0
                            (unsigned long)ping_width);
9131
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9132
0
                            "    Height: %lu",
9133
0
                            (unsigned long)ping_height);
9134
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9135
0
                            "    PNG sample depth: %d",ping_bit_depth);
9136
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9137
0
                            "    PNG color type: %s (%d)",
9138
0
                            PngColorTypeToString(ping_colortype),
9139
0
                            ping_colortype);
9140
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9141
0
                            "    PNG Interlace method: %d",
9142
0
                            ping_interlace_method);
9143
0
    }
9144
  /*
9145
    Generate text chunks.
9146
  */
9147
29.5k
  attribute=GetImageAttribute(image,(char *) NULL);
9148
110k
  for ( ; attribute != (const ImageAttribute *) NULL;
9149
80.7k
        attribute=attribute->next)
9150
80.7k
    {
9151
80.7k
      png_textp
9152
80.7k
        text;
9153
9154
80.7k
      if (*attribute->key == '[')
9155
249
        continue;
9156
80.4k
      if (LocaleCompare(attribute->key,"png:IHDR.color-type-orig") == 0 ||
9157
68.5k
          LocaleCompare(attribute->key,"png:IHDR.bit-depth-orig") == 0)
9158
23.9k
        continue;
9159
#if PNG_LIBPNG_VER >= 14000
9160
      text=(png_textp) png_malloc(ping,
9161
                                  (png_alloc_size_t) sizeof(png_text));
9162
#else
9163
56.5k
      text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
9164
56.5k
#endif
9165
56.5k
      text[0].key=attribute->key;
9166
56.5k
      text[0].text=attribute->value;
9167
56.5k
      text[0].text_length=strlen(attribute->value);
9168
56.5k
      text[0].compression=image_info->compression == NoCompression ||
9169
56.5k
        (image_info->compression == UndefinedCompression &&
9170
56.5k
         text[0].text_length < 128) ? -1 : 0;
9171
56.5k
      if (logging)
9172
0
        {
9173
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9174
0
                                "  Setting up text chunk");
9175
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9176
0
                                "    keyword: %s",text[0].key);
9177
0
        }
9178
56.5k
      png_set_text(ping,ping_info,text,1);
9179
56.5k
      png_free(ping,text);
9180
56.5k
    }
9181
9182
  /* write eXIf profile */
9183
29.5k
  {
9184
29.5k
    ImageProfileIterator
9185
29.5k
      profile_iterator;
9186
9187
29.5k
    profile_iterator=AllocateImageProfileIterator(image);
9188
29.5k
    if (profile_iterator)
9189
3.04k
      {
9190
3.04k
        const char
9191
3.04k
          *profile_name;
9192
9193
3.04k
        const unsigned char
9194
3.04k
          *profile_info;
9195
9196
3.04k
        size_t
9197
3.04k
          profile_length;
9198
9199
4.77k
        while (NextImageProfile(profile_iterator,&profile_name,&profile_info,
9200
4.77k
                                &profile_length) != MagickFail)
9201
4.16k
          {
9202
4.16k
            if (LocaleCompare(profile_name,"exif") == 0)
9203
2.43k
              {
9204
2.43k
                png_uint_32
9205
2.43k
                  length;
9206
2.43k
                unsigned char
9207
2.43k
                  chunk[4];
9208
2.43k
                const unsigned char
9209
2.43k
                  *data;
9210
9211
2.43k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9212
2.43k
                                      "  Have eXIf profile");
9213
9214
2.43k
                data=profile_info;
9215
9216
2.43k
                length=(png_uint_32) profile_length;
9217
9218
2.43k
                PNGType(chunk,mng_eXIf);
9219
9220
2.43k
                if (length < 7)
9221
54
                  break;  /* otherwise crashes */
9222
9223
2.37k
                if (data[0] == 'E' && data[1] == 'x' && data[2] == 'i' &&
9224
2.21k
                    data[3] == 'f' && data[4] == '\0' && data[5] == '\0')
9225
2.16k
                  {
9226
                    /* skip the optional Exif identifier code ("Exif\0\0") */
9227
2.16k
                    length -= 6;
9228
2.16k
                    data += 6;
9229
2.16k
                  }
9230
9231
2.37k
                LogPNGChunk(logging,chunk,length);
9232
2.37k
                (void) WriteBlobMSBULong(image,length);
9233
2.37k
                (void) WriteBlob(image,4,chunk);
9234
2.37k
                (void) WriteBlob(image,length,data);
9235
2.37k
                (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),
9236
2.37k
                                                     data, (uInt) length));
9237
2.37k
                break;
9238
2.43k
              }
9239
4.16k
          }
9240
3.04k
        DeallocateImageProfileIterator(profile_iterator);
9241
3.04k
      }
9242
29.5k
  }
9243
9244
29.5k
  if (logging)
9245
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9246
0
                          "  Writing PNG end info");
9247
29.5k
  png_write_end(ping,ping_info);
9248
29.5k
  if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9249
177
    {
9250
177
      if (mng_info->page.x || mng_info->page.y || (ping_width !=
9251
177
                                                   mng_info->page.width) ||
9252
177
          (ping_height != mng_info->page.height))
9253
0
        {
9254
0
          unsigned char
9255
0
            chunk[32];
9256
9257
          /*
9258
            Write FRAM 4 with clipping boundaries followed by FRAM 1.
9259
          */
9260
0
          (void) WriteBlobMSBULong(image,27L);  /* data length=27 */
9261
0
          PNGType(chunk,mng_FRAM);
9262
0
          LogPNGChunk(logging,mng_FRAM,27L);
9263
0
          chunk[4]=4;
9264
0
          chunk[5]=0;  /* frame name separator (no name) */
9265
0
          chunk[6]=1;  /* flag for changing delay, for next frame only */
9266
0
          chunk[7]=0;  /* flag for changing frame timeout */
9267
0
          chunk[8]=1;  /* flag for changing frame clipping for next frame */
9268
0
          chunk[9]=0;  /* flag for changing frame sync_id */
9269
0
          PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9270
0
          chunk[14]=0; /* clipping boundaries delta type */
9271
0
          PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9272
0
          PNGLong(chunk+19,(png_uint_32) (mng_info->page.x +
9273
0
                                          ping_width));
9274
0
          PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9275
0
          PNGLong(chunk+27,(png_uint_32) (mng_info->page.y +
9276
0
                                          ping_height));
9277
0
          (void) WriteBlob(image,31,(char *) chunk);
9278
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9279
0
          mng_info->old_framing_mode=4;
9280
0
          mng_info->framing_mode=1;
9281
0
        }
9282
177
      else
9283
177
        mng_info->framing_mode=3;
9284
177
    }
9285
29.5k
  if (mng_info->write_mng && !mng_info->need_fram &&
9286
15.7k
      ((int) image->dispose == 3))
9287
0
    png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
9288
29.5k
  image->depth=save_image_depth;
9289
9290
  /* Save depth actually written */
9291
9292
29.5k
  s[0]=(char) ping_bit_depth;
9293
29.5k
  s[1]='\0';
9294
9295
29.5k
  (void) SetImageAttribute(image,"[png:bit-depth-written]",s);
9296
9297
  /*
9298
    Free PNG resources.
9299
  */
9300
29.5k
  png_destroy_write_struct(&ping,&ping_info);
9301
9302
#if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
9303
  UnlockSemaphoreInfo(png_semaphore);
9304
#endif
9305
9306
9307
29.5k
  if (logging)
9308
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9309
0
                          "  exit WriteOnePNGImage()");
9310
29.5k
  return (MagickPass);
9311
9312
  /* } end of setjmp-controlled block */
9313
9314
  /*  End write one PNG image */
9315
29.5k
}
9316
9317
/*
9318
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9319
%                                                                             %
9320
%                                                                             %
9321
%                                                                             %
9322
%   W r i t e P N G I m a g e                                                 %
9323
%                                                                             %
9324
%                                                                             %
9325
%                                                                             %
9326
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9327
%
9328
%  WritePNGImage() writes a Portable Network Graphics (PNG) or
9329
%  Multiple-image Network Graphics (MNG) image file.
9330
%
9331
%  MNG support written by Glenn Randers-Pehrson, glennrp@image...
9332
%
9333
%  The format of the WritePNGImage method is:
9334
%
9335
%      MagickPassFail WritePNGImage(const ImageInfo *image_info,Image *image)
9336
%
9337
%  A description of each parameter follows:
9338
%
9339
%    o image_info: the image info.
9340
%
9341
%    o image:  The image.
9342
%
9343
%  Returns MagickPass on success, MagickFail on failure.
9344
%
9345
%  While the datastream written is always in PNG format and normally
9346
%  would be given the "png" file extension, this method also writes
9347
%  the following pseudo-formats which are subsets of PNG:
9348
%
9349
%    o PNG8:  An 8-bit indexed PNG datastream is written.
9350
%             If transparency is present, the tRNS chunk
9351
%             must only have values 0 and 255 (i.e., transparency is binary:
9352
%             fully opaque or fully transparent).  The pixels contain 8-bit
9353
%             indices even if they could be represented with 1, 2, or 4 bits.
9354
%             Note: grayscale images will be written as indexed PNG files
9355
%             even though the PNG grayscale type might be slightly more
9356
%             efficient.
9357
%
9358
%    o PNG24: An 8-bit per sample RGB PNG datastream is written.  The tRNS
9359
%             chunk can be present to convey binary transparency by naming
9360
%             one of the colors as transparent.
9361
%
9362
%    o PNG32: An 8-bit per sample RGBA PNG is written.  Partial
9363
%             transparency is permitted, i.e., the alpha sample for
9364
%             each pixel can have any value from 0 to 255. The alpha
9365
%             channel is present even if the image is fully opaque.
9366
%
9367
%    o PNG48:   A 16-bit per sample RGB PNG datastream is written.  The tRNS
9368
%               chunk can be present to convey binary transparency by naming
9369
%               one of the colors as transparent.  If the image has more
9370
%               than one transparent color, has semitransparent pixels, or
9371
%               has an opaque pixel with the same RGB components as the
9372
%               transparent color, an image is not written.
9373
%
9374
%    o PNG64:   A 16-bit per sample RGBA PNG is written.  Partial
9375
%               transparency is permitted, i.e., the alpha sample for
9376
%               each pixel can have any value from 0 to 65535. The alpha
9377
%               channel is present even if the image is fully opaque.
9378
%
9379
%    o PNG00:   A PNG that inherits its colortype and bit-depth from the input
9380
%               image, if the input was a PNG, is written.  If these values
9381
%               cannot be found, then "PNG00" falls back to the regular "PNG"
9382
%               format.
9383
%
9384
%  If the image cannot be written in the requested PNG8|24|32|48|64
9385
%  format without loss, a PNG file will not be written, and MagickFail
9386
%  will be returned.  Since image encoders should not be responsible for
9387
%  the "heavy lifting", the user should make sure that GraphicsMagick has
9388
%  already reduced the image depth and number of colors and limit
9389
%  transparency to binary transparency prior to attempting to write the
9390
%  image in a format that is subject to depth, color, or transparency
9391
%  limitations.
9392
%
9393
%  TODO: Enforce the previous paragraph.
9394
%
9395
%  TODO: Allow all other PNG subformats to be requested via new
9396
%        "-define png:bit-depth -define png:color-type" options.
9397
%
9398
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9399
*/
9400
static MagickPassFail WritePNGImage(const ImageInfo *image_info,Image *image)
9401
11.9k
{
9402
11.9k
  MngInfo
9403
11.9k
    *mng_info;
9404
9405
11.9k
  int
9406
11.9k
    have_mng_structure;
9407
9408
11.9k
  unsigned int
9409
11.9k
    logging,
9410
11.9k
    status;
9411
9412
  /*
9413
    Open image file.
9414
  */
9415
11.9k
  assert(image_info != (const ImageInfo *) NULL);
9416
11.9k
  assert(image_info->signature == MagickSignature);
9417
11.9k
  assert(image != (Image *) NULL);
9418
11.9k
  assert(image->signature == MagickSignature);
9419
11.9k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9420
11.9k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
9421
11.9k
  if (status == MagickFalse)
9422
11.9k
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
9423
9424
  /*
9425
    Allocate a MngInfo structure.
9426
  */
9427
11.9k
  have_mng_structure=MagickFalse;
9428
11.9k
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
9429
11.9k
  if (mng_info == (MngInfo *) NULL)
9430
11.9k
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
9431
  /*
9432
    Initialize members of the MngInfo structure.
9433
  */
9434
11.9k
  (void) memset(mng_info,0,sizeof(MngInfo));
9435
11.9k
  mng_info->image=image;
9436
11.9k
  have_mng_structure=MagickTrue;
9437
11.9k
  mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9438
11.9k
  mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9439
11.9k
  mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9440
11.9k
  mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
9441
11.9k
  mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
9442
9443
11.9k
  if (LocaleCompare(image_info->magick,"png00") == 0)
9444
1.62k
    {
9445
1.62k
      const ImageAttribute
9446
1.62k
        *attribute;
9447
9448
      /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig */
9449
1.62k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9450
1.62k
                            "  Format=%s",image_info->magick);
9451
9452
1.62k
      attribute=GetImageAttribute(image,"png:IHDR.bit-depth-orig");
9453
9454
1.62k
      if (attribute != (ImageAttribute *) NULL)
9455
1.62k
        {
9456
1.62k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9457
1.62k
                                "  png00 inherited bit depth=%s",attribute->value);
9458
9459
1.62k
          if (LocaleCompare(attribute->value,"1") == 0)
9460
651
            mng_info->write_png_depth = 1;
9461
9462
972
          else if (LocaleCompare(attribute->value,"1") == 0)
9463
0
            mng_info->write_png_depth = 2;
9464
9465
972
          else if (LocaleCompare(attribute->value,"2") == 0)
9466
279
            mng_info->write_png_depth = 4;
9467
9468
693
          else if (LocaleCompare(attribute->value,"8") == 0)
9469
465
            mng_info->write_png_depth = 8;
9470
9471
228
          else if (LocaleCompare(attribute->value,"16") == 0)
9472
38
            mng_info->write_png_depth = 16;
9473
1.62k
        }
9474
9475
1.62k
      attribute=GetImageAttribute(image,"png:IHDR.color-type-orig");
9476
9477
1.62k
      if (attribute != (ImageAttribute *) NULL)
9478
1.62k
        {
9479
1.62k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9480
1.62k
                                "  png00 inherited color type=%s",attribute->value);
9481
9482
1.62k
          if (LocaleCompare(attribute->value,"0") == 0)
9483
1.07k
            mng_info->write_png_colortype = 1;
9484
9485
549
          else if (LocaleCompare(attribute->value,"2") == 0)
9486
32
            mng_info->write_png_colortype = 3;
9487
9488
517
          else if (LocaleCompare(attribute->value,"3") == 0)
9489
485
            mng_info->write_png_colortype = 4;
9490
9491
32
          else if (LocaleCompare(attribute->value,"4") == 0)
9492
10
            mng_info->write_png_colortype = 5;
9493
9494
22
          else if (LocaleCompare(attribute->value,"6") == 0)
9495
22
            mng_info->write_png_colortype = 7;
9496
1.62k
        }
9497
1.62k
    }
9498
9499
11.9k
  status=WriteOnePNGImage(mng_info,image_info,image);
9500
9501
11.9k
  status &= CloseBlob(image);
9502
9503
11.9k
  MngInfoFreeStruct(mng_info,&have_mng_structure);
9504
11.9k
  if (logging)
9505
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9506
11.9k
  return (status);
9507
11.9k
}
9508
9509
#if defined(JNG_SUPPORTED)
9510
9511
/* Write one JNG image */
9512
static MagickPassFail WriteOneJNGImage(MngInfo *mng_info,
9513
                                       const ImageInfo *image_info,Image *image)
9514
0
{
9515
0
  Image
9516
0
    *jpeg_image;
9517
9518
0
  ImageInfo
9519
0
    *jpeg_image_info;
9520
9521
0
  char
9522
0
    *blob;
9523
9524
0
  size_t
9525
0
    length;
9526
9527
0
  unsigned char
9528
0
    chunk[80],
9529
0
    *p;
9530
9531
0
  unsigned int
9532
0
    jng_alpha_compression_method,
9533
0
    jng_alpha_sample_depth,
9534
0
    jng_color_type,
9535
0
    logging,
9536
0
    status=MagickPass,
9537
0
    transparent;
9538
9539
0
  unsigned long
9540
0
    jng_quality;
9541
9542
0
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9543
0
                         "  enter WriteOneJNGImage()");
9544
9545
0
  if (image->columns > 65500U)
9546
0
    {
9547
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9548
0
                            "  JNG dimensions too large"
9549
0
                            " (%lu columns exceeds limit of 65500)",
9550
0
                            image->columns);
9551
0
      ThrowWriterException(CoderError,UnsupportedNumberOfColumns,
9552
0
                           image);
9553
0
    }
9554
0
  if (image->rows > 65500U)
9555
0
    {
9556
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9557
0
                            "  JNG dimensions too large"
9558
0
                            " (%lu rows exceeds limit of 65500)",
9559
0
                            image->rows);
9560
0
      ThrowWriterException(CoderError,UnsupportedNumberOfRows,
9561
0
                           image);
9562
0
    }
9563
9564
0
  blob=(char *) NULL;
9565
0
  jpeg_image=(Image *) NULL;
9566
0
  jpeg_image_info=(ImageInfo *) NULL;
9567
9568
0
  status=MagickTrue;
9569
0
  transparent=image_info->type==GrayscaleMatteType ||
9570
0
    image_info->type==TrueColorMatteType;
9571
0
  jng_color_type=10;
9572
0
  jng_alpha_sample_depth=0;
9573
0
  jng_quality=image_info->quality;
9574
0
  jng_alpha_compression_method=0;
9575
9576
0
  if (image->matte)
9577
0
    {
9578
      /* if any pixels are transparent */
9579
0
      transparent=MagickTrue;
9580
0
      if (image_info->compression==JPEGCompression)
9581
0
        jng_alpha_compression_method=8;
9582
0
    }
9583
9584
0
  if (transparent)
9585
0
    {
9586
0
      jng_color_type=14;
9587
      /* Create JPEG blob, image, and image_info */
9588
0
      if (logging)
9589
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9590
0
                              "  Creating jpeg_image_info for opacity.");
9591
0
      jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9592
0
      if (jpeg_image_info == (ImageInfo *) NULL)
9593
0
        ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9594
0
                             image);
9595
0
      if (logging)
9596
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9597
0
                              "  Creating jpeg_image.");
9598
0
      jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9599
0
      if (jpeg_image == (Image *) NULL)
9600
0
        {
9601
0
          if (jpeg_image_info != (ImageInfo *)NULL)
9602
0
            {
9603
0
              DestroyImageInfo(jpeg_image_info);
9604
0
            }
9605
0
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9606
0
                               image);
9607
0
        }
9608
0
      DestroyBlob(jpeg_image);
9609
0
      jpeg_image->blob=CloneBlobInfo((BlobInfo *) NULL);
9610
0
      status=ChannelImage(jpeg_image,OpacityChannel);
9611
0
      if (status != MagickFalse)
9612
0
        status=NegateImage(jpeg_image,MagickFalse);
9613
0
      if (status == MagickFalse)
9614
0
        {
9615
0
          DestroyImage(jpeg_image);
9616
0
          DestroyImageInfo(jpeg_image_info);
9617
0
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9618
0
                               image);
9619
0
        }
9620
0
      jpeg_image->matte=MagickFalse;
9621
0
      if (jng_quality >= 1000)
9622
0
        jpeg_image_info->quality=jng_quality/1000;
9623
0
      else
9624
0
        jpeg_image_info->quality=jng_quality;
9625
0
      jpeg_image_info->type=GrayscaleType;
9626
0
      status &= SetImageType(jpeg_image,GrayscaleType);
9627
0
      status &= AcquireTemporaryFileName(jpeg_image->filename);
9628
0
      (void) strlcpy(jpeg_image_info->filename,jpeg_image->filename,sizeof(jpeg_image_info->filename));
9629
0
    }
9630
9631
  /* To do: check bit depth of PNG alpha channel */
9632
9633
  /* Check if image is grayscale. */
9634
0
  if (image_info->type != TrueColorMatteType && image_info->type !=
9635
0
      TrueColorType && IsGrayImage(image,&image->exception))
9636
0
    jng_color_type-=2;
9637
9638
0
  if (transparent)
9639
0
    {
9640
0
      if (jng_alpha_compression_method==0)
9641
0
        {
9642
0
          const ImageAttribute
9643
0
            *attribute;
9644
9645
          /* Encode opacity as a grayscale PNG blob */
9646
0
          if (logging)
9647
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9648
0
                                  "  Creating grayscale PNG blob.");
9649
0
          status&=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9650
0
                                    &image->exception);
9651
0
          if (status != MagickFail)
9652
0
            {
9653
0
              length=0;
9654
0
              (void) strlcpy(jpeg_image_info->magick,"PNG",MaxTextExtent);
9655
0
              (void) strlcpy(jpeg_image->magick,"PNG",MaxTextExtent);
9656
0
              jpeg_image_info->interlace=NoInterlace;
9657
9658
0
              blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
9659
0
                                        &image->exception);
9660
0
              if ((blob == (char *) NULL) || (length == 0))
9661
0
                {
9662
0
                  if (logging)
9663
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9664
0
                                          "  Failed to encode opacity as a"
9665
0
                                          " grayscale PNG blob!");
9666
0
                  status=MagickFail;
9667
0
                }
9668
0
              else
9669
0
                {
9670
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9671
0
                                        "  Successfully read jpeg_image into a"
9672
0
                                        " grayscale PNG blob, length=%zu.",
9673
0
                                        length);
9674
0
                }
9675
              /* Retrieve sample depth used */
9676
0
              attribute=GetImageAttribute(jpeg_image,"[png:bit-depth-written]");
9677
0
              if ((attribute != (const ImageAttribute *) NULL) &&
9678
0
                  (attribute->value != (char *) NULL))
9679
0
                jng_alpha_sample_depth= (unsigned int) attribute->value[0];
9680
0
            }
9681
0
        }
9682
0
      else
9683
0
        {
9684
          /* Encode opacity as a grayscale JPEG blob */
9685
0
          if (logging)
9686
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9687
0
                                  "  Creating grayscale JPEG blob.");
9688
0
          status &= OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9689
0
                             &image->exception);
9690
0
          if (status != MagickFail)
9691
0
            {
9692
0
              length=0;
9693
0
              (void) strlcpy(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9694
0
              (void) strlcpy(jpeg_image->magick,"JPEG",MaxTextExtent);
9695
0
              jpeg_image_info->interlace=NoInterlace;
9696
0
              blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
9697
0
                                        &image->exception);
9698
0
              jng_alpha_sample_depth=8;
9699
0
              if ((blob == (char *) NULL) || (length == 0))
9700
0
                {
9701
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9702
0
                                        "  Failed to encode opacity as a"
9703
0
                                        " grayscale JPEG blob!");
9704
0
                  status=MagickFail;
9705
0
                }
9706
0
              else
9707
0
                {
9708
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9709
0
                                        "  Successfully read jpeg_image into a"
9710
0
                                        " JPEG blob, length=%zu.",
9711
0
                                        length);
9712
0
                }
9713
0
            }
9714
0
        }
9715
      /* Destroy JPEG image and image_info */
9716
0
      (void) LiberateTemporaryFile(jpeg_image_info->filename);
9717
0
      DestroyImage(jpeg_image);
9718
0
      DestroyImageInfo(jpeg_image_info);
9719
0
      if (status == MagickFail)
9720
0
        {
9721
0
          MagickFreeMemory(blob);
9722
0
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9723
0
                             image);
9724
0
        }
9725
0
    }
9726
9727
  /* Write JHDR chunk */
9728
0
  (void) WriteBlobMSBULong(image,16L);  /* chunk data length=16 */
9729
0
  PNGType(chunk,mng_JHDR);
9730
0
  LogPNGChunk(logging,mng_JHDR,16L);
9731
0
  PNGLong(chunk+4,image->columns);
9732
0
  PNGLong(chunk+8,image->rows);
9733
0
  chunk[12]=jng_color_type;
9734
0
  chunk[13]=8;  /* sample depth */
9735
0
  chunk[14]=8; /*jng_image_compression_method */
9736
0
  chunk[15]=(image_info->interlace == LineInterlace) ? 8 : 0;
9737
0
  chunk[16]=jng_alpha_sample_depth;
9738
0
  chunk[17]=jng_alpha_compression_method;
9739
0
  chunk[18]=0; /*jng_alpha_filter_method */
9740
0
  chunk[19]=0; /*jng_alpha_interlace_method */
9741
0
  (void) WriteBlob(image,20,(char *) chunk);
9742
0
  (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
9743
0
  if (logging)
9744
0
    {
9745
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9746
0
                            "    JNG width:%15lu",image->columns);
9747
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9748
0
                            "    JNG height:%14lu",image->rows);
9749
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9750
0
                            "    JNG color type:%10d",jng_color_type);
9751
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9752
0
                            "    JNG sample depth:%8d",8);
9753
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9754
0
                            "    JNG compression:%9d",8);
9755
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9756
0
                            "    JNG interlace:%11d",0);
9757
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9758
0
                            "    JNG alpha depth:%9d",jng_alpha_sample_depth);
9759
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9760
0
                            "    JNG alpha compression:%3d",
9761
0
                            jng_alpha_compression_method);
9762
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9763
0
                            "    JNG alpha filter:%8d",0);
9764
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9765
0
                            "    JNG alpha interlace:%5d",0);
9766
0
    }
9767
9768
  /*
9769
    Write leading ancillary chunks
9770
  */
9771
9772
0
  if (transparent)
9773
0
    {
9774
      /*
9775
        Write JNG bKGD chunk
9776
      */
9777
9778
0
      char
9779
0
        blue,
9780
0
        green,
9781
0
        red;
9782
9783
0
      long
9784
0
        num_bytes;
9785
9786
0
      if (jng_color_type == 8 || jng_color_type == 12)
9787
0
        num_bytes=6L;
9788
0
      else
9789
0
        num_bytes=10L;
9790
0
      (void) WriteBlobMSBULong(image,num_bytes-4L);
9791
0
      PNGType(chunk,mng_bKGD);
9792
0
      LogPNGChunk(logging,mng_bKGD,((size_t) num_bytes-4L));
9793
0
      red=ScaleQuantumToChar(image->background_color.red);
9794
0
      green=ScaleQuantumToChar(image->background_color.green);
9795
0
      blue=ScaleQuantumToChar(image->background_color.blue);
9796
0
      *(chunk+4)=0;
9797
0
      *(chunk+5)=red;
9798
0
      *(chunk+6)=0;
9799
0
      *(chunk+7)=green;
9800
0
      *(chunk+8)=0;
9801
0
      *(chunk+9)=blue;
9802
0
      (void) WriteBlob(image,num_bytes,(char *) chunk);
9803
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,num_bytes));
9804
0
    }
9805
9806
0
  if ((image_info->colorspace == sRGBColorspace || image->rendering_intent))
9807
0
    {
9808
      /*
9809
        Write JNG sRGB chunk
9810
      */
9811
0
      (void) WriteBlobMSBULong(image,1L);
9812
0
      PNGType(chunk,mng_sRGB);
9813
0
      LogPNGChunk(logging,mng_sRGB,1L);
9814
0
      if (image->rendering_intent != UndefinedIntent)
9815
0
        chunk[4]=(int) image->rendering_intent-1;
9816
0
      else
9817
0
        chunk[4]=(int) PerceptualIntent-1;
9818
0
      (void) WriteBlob(image,5,(char *) chunk);
9819
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
9820
0
    }
9821
0
  else
9822
0
    {
9823
0
      if (image->gamma)
9824
0
        {
9825
          /*
9826
            Write JNG gAMA chunk
9827
          */
9828
0
          (void) WriteBlobMSBULong(image,4L);
9829
0
          PNGType(chunk,mng_gAMA);
9830
0
          LogPNGChunk(logging,mng_gAMA,4L);
9831
0
          PNGLong(chunk+4,(unsigned long) (100000*image->gamma+0.5));
9832
0
          (void) WriteBlob(image,8,(char *) chunk);
9833
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
9834
0
        }
9835
0
      if (!mng_info->equal_chrms && image->chromaticity.red_primary.x != 0.0)
9836
0
        {
9837
0
          PrimaryInfo
9838
0
            primary;
9839
9840
          /*
9841
            Write JNG cHRM chunk
9842
          */
9843
0
          (void) WriteBlobMSBULong(image,32L);
9844
0
          PNGType(chunk,mng_cHRM);
9845
0
          LogPNGChunk(logging,mng_cHRM,32L);
9846
0
          primary=image->chromaticity.white_point;
9847
0
          PNGLong(chunk+4,(unsigned long) (100000*primary.x+0.5));
9848
0
          PNGLong(chunk+8,(unsigned long) (100000*primary.y+0.5));
9849
0
          primary=image->chromaticity.red_primary;
9850
0
          PNGLong(chunk+12,(unsigned long) (100000*primary.x+0.5));
9851
0
          PNGLong(chunk+16,(unsigned long) (100000*primary.y+0.5));
9852
0
          primary=image->chromaticity.green_primary;
9853
0
          PNGLong(chunk+20,(unsigned long) (100000*primary.x+0.5));
9854
0
          PNGLong(chunk+24,(unsigned long) (100000*primary.y+0.5));
9855
0
          primary=image->chromaticity.blue_primary;
9856
0
          PNGLong(chunk+28,(unsigned long) (100000*primary.x+0.5));
9857
0
          PNGLong(chunk+32,(unsigned long) (100000*primary.y+0.5));
9858
0
          (void) WriteBlob(image,36,(char *) chunk);
9859
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
9860
0
        }
9861
0
    }
9862
0
  if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
9863
0
    {
9864
      /*
9865
        Write JNG pHYs chunk
9866
      */
9867
0
      (void) WriteBlobMSBULong(image,9L);
9868
0
      PNGType(chunk,mng_pHYs);
9869
0
      LogPNGChunk(logging,mng_pHYs,9L);
9870
0
      if (image->units == PixelsPerInchResolution)
9871
0
        {
9872
0
          PNGLong(chunk+4,(unsigned long)
9873
0
                  (image->x_resolution*100.0/2.54+0.5));
9874
0
          PNGLong(chunk+8,(unsigned long)
9875
0
                  (image->y_resolution*100.0/2.54+0.5));
9876
0
          chunk[12]=1;
9877
0
        }
9878
0
      else
9879
0
        {
9880
0
          if (image->units == PixelsPerCentimeterResolution)
9881
0
            {
9882
0
              PNGLong(chunk+4,(unsigned long)
9883
0
                      (image->x_resolution*100.0+0.5));
9884
0
              PNGLong(chunk+8,(unsigned long)
9885
0
                      (image->y_resolution*100.0+0.5));
9886
0
              chunk[12]=1;
9887
0
            }
9888
0
          else
9889
0
            {
9890
0
              PNGLong(chunk+4,(unsigned long) (image->x_resolution+0.5));
9891
0
              PNGLong(chunk+8,(unsigned long) (image->y_resolution+0.5));
9892
0
              chunk[12]=0;
9893
0
            }
9894
0
        }
9895
0
      (void) WriteBlob(image,13,(char *) chunk);
9896
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
9897
0
    }
9898
9899
0
  if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
9900
0
    {
9901
      /*
9902
        Write JNG oFFs chunk
9903
      */
9904
0
      (void) WriteBlobMSBULong(image,9L);
9905
0
      PNGType(chunk,mng_oFFs);
9906
0
      LogPNGChunk(logging,mng_oFFs,9L);
9907
0
      PNGsLong(chunk+4,(long) (image->page.x));
9908
0
      PNGsLong(chunk+8,(long) (image->page.y));
9909
0
      chunk[12]=0;
9910
0
      (void) WriteBlob(image,13,(char *) chunk);
9911
0
      (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
9912
0
    }
9913
9914
0
  if (transparent)
9915
0
    {
9916
0
      if (jng_alpha_compression_method==0)
9917
0
        {
9918
0
          unsigned long
9919
0
            len;
9920
9921
0
          register long
9922
0
            i;
9923
9924
          /* Write IDAT chunk header */
9925
0
          if (logging)
9926
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9927
0
                                  "  Write IDAT chunks from blob, length=%lu.",
9928
0
                                  (unsigned long) length);
9929
9930
          /* Copy IDAT chunks */
9931
0
          len=0;
9932
0
          p=(unsigned char *) (blob+8);
9933
0
          for (i=8; i<(long)length; i+=len+12)
9934
0
            {
9935
0
              len=mng_get_long(p);
9936
0
              p+=4;
9937
0
              if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84)
9938
0
                {
9939
                  /* Found an IDAT chunk. */
9940
0
                  (void) WriteBlobMSBULong(image,(unsigned long) len);
9941
0
                  LogPNGChunk(logging,mng_IDAT,len);
9942
0
                  (void) WriteBlob(image,(size_t) len+4,(char *) p);
9943
0
                  (void) WriteBlobMSBULong(image,
9944
0
                                           crc32(0,p,len+4));
9945
0
                }
9946
0
              else
9947
0
                {
9948
0
                  if (logging)
9949
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9950
0
                                          "    Skipping %c%c%c%c chunk,"
9951
0
                                          " length=%lu.",
9952
0
                                          *(p),*(p+1),*(p+2),*(p+3),len);
9953
0
                }
9954
0
              p+=((size_t) 8+len);
9955
0
            }
9956
0
        }
9957
0
      else
9958
0
        {
9959
          /* Write JDAA chunk header */
9960
0
          if (logging)
9961
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9962
0
                                  "  Write JDAA chunk, length=%lu.",
9963
0
                                  (unsigned long) length);
9964
0
          (void) WriteBlobMSBULong(image,(unsigned long) length);
9965
0
          PNGType(chunk,mng_JDAA);
9966
0
          LogPNGChunk(logging,mng_JDAA,(unsigned long) length);
9967
          /* Write JDAT chunk(s) data */
9968
0
          (void) WriteBlob(image,4,(char *) chunk);
9969
0
          (void) WriteBlob(image,length,(char *) blob);
9970
0
          (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),
9971
0
                                               (unsigned char *) blob,(uInt) length));
9972
0
        }
9973
0
      MagickFreeMemory(blob);
9974
0
    }
9975
9976
  /* Encode image as a JPEG blob */
9977
0
  if (logging)
9978
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9979
0
                          "  Creating jpeg_image_info.");
9980
0
  jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9981
0
  if (jpeg_image_info == (ImageInfo *) NULL)
9982
0
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9983
0
                         image);
9984
9985
0
  if (logging)
9986
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9987
0
                          "  Creating jpeg_image.");
9988
9989
0
  jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9990
0
  if (jpeg_image == (Image *) NULL)
9991
0
    {
9992
0
      DestroyImageInfo(jpeg_image_info);
9993
0
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
9994
0
                           image);
9995
0
    }
9996
0
  DestroyBlob(jpeg_image);
9997
0
  jpeg_image->blob=CloneBlobInfo((BlobInfo *) NULL);
9998
0
  (void) AcquireTemporaryFileName(jpeg_image->filename);
9999
0
  MagickFormatString(jpeg_image_info->filename,sizeof(jpeg_image_info->filename),
10000
0
                     "%.1024s",jpeg_image->filename);
10001
10002
0
  status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10003
0
                  &image->exception);
10004
0
  if (status == MagickFalse)
10005
0
    {
10006
0
      if (jpeg_image != (Image *)NULL)
10007
0
        DestroyImage(jpeg_image);
10008
0
      if (jpeg_image_info != (ImageInfo *)NULL)
10009
0
        DestroyImageInfo(jpeg_image_info);
10010
0
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
10011
0
                           image);
10012
0
    }
10013
10014
0
  if (logging)
10015
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10016
0
                          "  Created jpeg_image, %lu x %lu.",
10017
0
                          jpeg_image->columns,
10018
0
                          jpeg_image->rows);
10019
10020
0
  if (jng_color_type == 8 || jng_color_type == 12)
10021
0
    jpeg_image_info->type=GrayscaleType;
10022
0
  jpeg_image_info->quality=jng_quality%1000;
10023
0
  (void) strlcpy(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10024
0
  (void) strlcpy(jpeg_image->magick,"JPEG",MaxTextExtent);
10025
0
  if (logging)
10026
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10027
0
                          "  Creating blob.");
10028
0
  blob=(char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
10029
0
                            &image->exception);
10030
0
  if (blob == (char *) NULL)
10031
0
    {
10032
0
      if (jpeg_image != (Image *)NULL)
10033
0
        DestroyImage(jpeg_image);
10034
0
      if (jpeg_image_info != (ImageInfo *)NULL)
10035
0
        DestroyImageInfo(jpeg_image_info);
10036
0
      return MagickFail;
10037
0
    }
10038
0
  if (logging)
10039
0
    {
10040
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10041
0
                            "  Successfully read jpeg_image into a blob,"
10042
0
                            " length=%lu.",
10043
0
                            (unsigned long) length);
10044
10045
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10046
0
                            "  Write JDAT chunk, length=%lu.",
10047
0
                            (unsigned long) length);
10048
0
    }
10049
  /* Write JDAT chunk(s) */
10050
0
  (void) WriteBlobMSBULong(image,(unsigned long) length);
10051
0
  PNGType(chunk,mng_JDAT);
10052
0
  LogPNGChunk(logging,mng_JDAT,(unsigned long) length);
10053
0
  (void) WriteBlob(image,4,(char *) chunk);
10054
0
  (void) WriteBlob(image,length,(char *) blob);
10055
0
  (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),(unsigned char *)
10056
0
                                       blob,(uInt)length));
10057
10058
0
  (void) LiberateTemporaryFile(jpeg_image_info->filename);
10059
0
  DestroyImage(jpeg_image);
10060
0
  DestroyImageInfo(jpeg_image_info);
10061
0
  MagickFreeMemory(blob);
10062
10063
  /* Write IEND chunk */
10064
0
  (void) WriteBlobMSBULong(image,0L);
10065
0
  PNGType(chunk,mng_IEND);
10066
0
  LogPNGChunk(logging,mng_IEND,0);
10067
0
  (void) WriteBlob(image,4,(char *) chunk);
10068
0
  (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10069
10070
0
  if (logging)
10071
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10072
0
                          "  exit WriteOneJNGImage()");
10073
0
  return(status);
10074
0
}
10075
10076
10077
/*
10078
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10079
%                                                                             %
10080
%                                                                             %
10081
%                                                                             %
10082
%   W r i t e J N G I m a g e                                                 %
10083
%                                                                             %
10084
%                                                                             %
10085
%                                                                             %
10086
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10087
%
10088
%  WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10089
%
10090
%  JNG support written by Glenn Randers-Pehrson, glennrp@image...
10091
%
10092
%  The format of the WriteJNGImage method is:
10093
%
10094
%      MagickPassFail WriteJNGImage(const ImageInfo *image_info,Image *image)
10095
%
10096
%  A description of each parameter follows:
10097
%
10098
%    o image_info: the image info.
10099
%
10100
%    o image:  The image.
10101
%
10102
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10103
*/
10104
static MagickPassFail WriteJNGImage(const ImageInfo *image_info,Image *image)
10105
0
{
10106
0
  MngInfo
10107
0
    *mng_info;
10108
10109
0
  int
10110
0
    have_mng_structure;
10111
10112
0
  unsigned int
10113
0
    logging,
10114
0
    status;
10115
10116
  /*
10117
    Open image file.
10118
  */
10119
0
  assert(image_info != (const ImageInfo *) NULL);
10120
0
  assert(image_info->signature == MagickSignature);
10121
0
  assert(image != (Image *) NULL);
10122
0
  assert(image->signature == MagickSignature);
10123
0
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10124
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10125
0
  if (status == MagickFalse)
10126
0
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
10127
10128
  /*
10129
    Allocate a MngInfo structure.
10130
  */
10131
0
  have_mng_structure=MagickFalse;
10132
0
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
10133
0
  if (mng_info == (MngInfo *) NULL)
10134
0
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
10135
  /*
10136
    Initialize members of the MngInfo structure.
10137
  */
10138
0
  (void) memset(mng_info,0,sizeof(MngInfo));
10139
0
  mng_info->image=image;
10140
0
  have_mng_structure=MagickTrue;
10141
10142
0
  (void) WriteBlob(image,8,"\213JNG\r\n\032\n");
10143
10144
0
  status=WriteOneJNGImage(mng_info,image_info,image);
10145
0
  status &= CloseBlob(image);
10146
10147
0
  MngInfoFreeStruct(mng_info,&have_mng_structure);
10148
0
  if (logging)
10149
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10150
0
  return (status);
10151
0
}
10152
#endif
10153
10154
10155
10156
static unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image)
10157
611
{
10158
611
  Image
10159
611
    *next_image;
10160
10161
611
  MngInfo
10162
611
    *mng_info;
10163
10164
611
  int
10165
611
    have_mng_structure,
10166
611
    image_count,
10167
611
    need_iterations,
10168
611
    need_matte;
10169
10170
611
  volatile int
10171
611
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) ||  \
10172
611
  defined(PNG_MNG_FEATURES_SUPPORTED)
10173
611
    need_local_plte,
10174
611
#endif
10175
611
    all_images_are_gray,
10176
611
    logging,
10177
611
    need_defi,
10178
611
    build_palette,
10179
611
    use_global_plte;
10180
10181
611
  register long
10182
611
    i;
10183
10184
611
#if 1
10185
611
  size_t
10186
611
    chunk_length=0;
10187
611
#endif
10188
10189
611
  MagickPassFail
10190
611
    status;
10191
10192
611
  volatile unsigned int
10193
611
    write_jng,
10194
611
    write_mng;
10195
10196
611
  volatile unsigned long
10197
611
    scene;
10198
10199
611
  unsigned long
10200
611
    final_delay=0,
10201
611
    initial_delay;
10202
10203
#if (PNG_LIBPNG_VER < 10200)
10204
  if (image_info->verbose)
10205
    printf("Your PNG library (libpng-%s) is rather old.\n",
10206
           PNG_LIBPNG_VER_STRING);
10207
#endif
10208
10209
  /*
10210
    Open image file.
10211
  */
10212
611
  assert(image_info != (const ImageInfo *) NULL);
10213
611
  assert(image_info->signature == MagickSignature);
10214
611
  assert(image != (Image *) NULL);
10215
611
  assert(image->signature == MagickSignature);
10216
611
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10217
611
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10218
611
  if (status == MagickFalse)
10219
611
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
10220
10221
  /*
10222
    Allocate a MngInfo structure.
10223
  */
10224
611
  have_mng_structure=MagickFalse;
10225
611
  mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
10226
611
  if (mng_info == (MngInfo *) NULL)
10227
611
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
10228
  /*
10229
    Initialize members of the MngInfo structure.
10230
  */
10231
611
  (void) memset(mng_info,0,sizeof(MngInfo));
10232
611
  mng_info->image=image;
10233
611
  have_mng_structure=MagickTrue;
10234
10235
611
  write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10236
10237
  /*
10238
    MNG only supports a color palette up to 256 colors
10239
   */
10240
611
  if ((write_mng != MagickFalse) && (image->storage_class == PseudoClass) &&
10241
0
      (image->colors > 256))
10242
0
    image->storage_class=DirectClass;
10243
10244
611
  mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10245
611
  mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10246
611
  mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10247
611
  mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
10248
611
  mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
10249
10250
611
  write_jng=MagickFalse;
10251
611
  if (image_info->compression==JPEGCompression)
10252
0
    write_jng=MagickTrue;
10253
611
  else
10254
611
    {
10255
611
      Image
10256
611
        *p;
10257
10258
18.2k
      for (p=image; p != (Image *) NULL; p=p->next)
10259
17.6k
        {
10260
17.6k
          if (p->compression==JPEGCompression)
10261
0
            write_jng=MagickTrue;
10262
17.6k
        }
10263
611
    }
10264
10265
611
  mng_info->adjoin=image_info->adjoin && (image->next != (Image *) NULL) &&
10266
433
    write_mng;
10267
10268
611
#ifdef GMPNG_BUILD_PALETTE
10269
611
  if (mng_info->write_png8)
10270
0
    build_palette=MagickTrue;
10271
611
  else if (mng_info->write_png24 || mng_info->write_png32 ||
10272
611
           mng_info->write_png48 || mng_info->write_png64)
10273
0
    build_palette=MagickFalse;
10274
611
  else
10275
611
    build_palette=(image_info->type == UndefinedType);
10276
611
#endif
10277
10278
611
  if (logging)
10279
0
    {
10280
      /* Log some info about the input */
10281
0
      Image
10282
0
        *p;
10283
10284
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10285
0
                            "  Checking input image(s)");
10286
10287
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10288
0
                            "    Image_info depth: %ld",
10289
0
                            image_info->depth);
10290
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10291
0
                            "    Type: %d",image_info->type);
10292
10293
0
      scene=0;
10294
0
      for (p=image; p != (Image *) NULL; p=p->next)
10295
0
        {
10296
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10297
0
                                "    Scene: %ld",scene++);
10298
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10299
0
                                "      Image depth: %u",p->depth);
10300
0
          if (p->matte)
10301
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10302
0
                                  "      Matte: True");
10303
0
          else
10304
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10305
0
                                  "      Matte: False");
10306
0
          if (p->storage_class == PseudoClass)
10307
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10308
0
                                  "      Storage class: PseudoClass");
10309
0
          else
10310
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10311
0
                                  "      Storage class: DirectClass");
10312
0
          if (p->colors)
10313
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10314
0
                                  "      Number of colors: %u",p->colors);
10315
0
          else
10316
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10317
0
                                  "      Number of colors: unspecified");
10318
0
          if (!mng_info->adjoin)
10319
0
            break;
10320
0
        }
10321
0
    }
10322
10323
  /*
10324
    Sometimes we get PseudoClass images whose RGB values don't match
10325
    the colors in the colormap.  This code syncs the RGB values.
10326
  */
10327
611
  {
10328
611
    Image
10329
611
      *p;
10330
10331
18.1k
    for (p=image; p != (Image *) NULL; p=p->next)
10332
17.6k
      {
10333
17.6k
        if (p->taint && p->storage_class == PseudoClass)
10334
0
          (void) SyncImage(p);
10335
17.6k
        if (!mng_info->adjoin)
10336
178
          break;
10337
17.6k
      }
10338
611
  }
10339
10340
611
#ifdef GMPNG_BUILD_PALETTE
10341
611
  if (build_palette)
10342
611
    {
10343
      /*
10344
        Sometimes we get DirectClass images that have 256 colors or fewer.
10345
        This code will convert them to PseudoClass and build a colormap.
10346
      */
10347
611
      Image
10348
611
        *p;
10349
10350
18.1k
      for (p=image; p != (Image *) NULL; p=p->next)
10351
17.6k
        {
10352
17.6k
          if (p->storage_class != PseudoClass)
10353
17.6k
            {
10354
17.6k
              p->colors=GetNumberColors(p,(FILE *) NULL,&p->exception);
10355
17.6k
              if (p->colors <= 256)
10356
17.6k
                {
10357
17.6k
                  p->colors=0;
10358
17.6k
                  if (p->matte)
10359
0
                    status &= SetImageType(p,PaletteMatteType);
10360
17.6k
                  else
10361
17.6k
                    status &= SetImageType(p,PaletteType);
10362
17.6k
                }
10363
17.6k
            }
10364
17.6k
          if (!mng_info->adjoin)
10365
178
            break;
10366
17.6k
        }
10367
611
    }
10368
611
#endif
10369
10370
611
  use_global_plte=MagickFalse;
10371
611
  all_images_are_gray=MagickFalse;
10372
611
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10373
611
  need_local_plte=MagickTrue;
10374
611
#endif
10375
611
  need_defi=MagickFalse;
10376
611
  need_matte=MagickFalse;
10377
611
  mng_info->framing_mode=1;
10378
611
  mng_info->old_framing_mode=1;
10379
10380
611
  if (write_mng)
10381
611
    if (image_info->page != (char *) NULL)
10382
0
      {
10383
        /*
10384
          Determine image bounding box.
10385
        */
10386
0
        SetGeometry(image,&mng_info->page);
10387
0
        (void) GetMagickGeometry(image_info->page,&mng_info->page.x,
10388
0
                                 &mng_info->page.y,&mng_info->page.width,
10389
0
                                 &mng_info->page.height);
10390
0
      }
10391
611
  if (write_mng)
10392
611
    {
10393
611
      unsigned char
10394
611
        chunk[800];
10395
10396
611
      unsigned int
10397
611
        need_geom;
10398
10399
611
      unsigned short
10400
611
        red,
10401
611
        green,
10402
611
        blue;
10403
10404
611
      mng_info->page=image->page;
10405
611
      need_geom=MagickTrue;
10406
611
      if (mng_info->page.width || mng_info->page.height)
10407
611
        need_geom=MagickFalse;
10408
      /*
10409
        Check all the scenes.
10410
      */
10411
611
      initial_delay=(long) image->delay;
10412
611
      need_iterations=MagickFalse;
10413
611
      mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10414
611
      mng_info->equal_physs=MagickTrue,
10415
611
        mng_info->equal_gammas=MagickTrue;
10416
611
      mng_info->equal_srgbs=MagickTrue;
10417
611
      mng_info->equal_backgrounds=MagickTrue;
10418
611
      image_count=0;
10419
611
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) ||  \
10420
611
  defined(PNG_MNG_FEATURES_SUPPORTED)
10421
611
      all_images_are_gray=MagickTrue;
10422
611
      mng_info->equal_palettes=MagickFalse;
10423
611
      need_local_plte=MagickFalse;
10424
611
#endif
10425
18.2k
      for (next_image=image; next_image != (Image *) NULL; )
10426
17.6k
        {
10427
17.6k
          if (need_geom)
10428
0
            {
10429
0
              if ((next_image->columns+next_image->page.x) >
10430
0
                  mng_info->page.width)
10431
0
                mng_info->page.width=next_image->columns+next_image->page.x;
10432
0
              if ((next_image->rows+next_image->page.y) >
10433
0
                  mng_info->page.height)
10434
0
                mng_info->page.height=next_image->rows+next_image->page.y;
10435
0
            }
10436
17.6k
          if (next_image->page.x || next_image->page.y)
10437
0
            need_defi=MagickTrue;
10438
17.6k
          if (next_image->matte)
10439
0
            need_matte=MagickTrue;
10440
17.6k
          if ((int) next_image->dispose >= BackgroundDispose)
10441
611
            if (next_image->matte || next_image->page.x ||
10442
611
                next_image->page.y ||
10443
611
                ((next_image->columns < mng_info->page.width) &&
10444
0
                 (next_image->rows < mng_info->page.height)))
10445
0
              mng_info->need_fram=MagickTrue;
10446
17.6k
          if (next_image->iterations)
10447
562
            need_iterations=MagickTrue;
10448
17.6k
          final_delay=next_image->delay;
10449
17.6k
          if (final_delay != initial_delay || final_delay > 100)
10450
1.84k
            mng_info->need_fram=1;
10451
17.6k
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) ||  \
10452
17.6k
  defined(PNG_MNG_FEATURES_SUPPORTED)
10453
          /*
10454
            check for global palette possibility.
10455
          */
10456
17.6k
          if (image->matte)
10457
0
            need_local_plte=MagickTrue;
10458
17.6k
          if (!need_local_plte)
10459
5.18k
            {
10460
5.18k
              if (!IsGrayImage(image,&image->exception))
10461
1.65k
                all_images_are_gray=MagickFalse;
10462
5.18k
              mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10463
5.18k
              if (!use_global_plte)
10464
611
                use_global_plte=mng_info->equal_palettes;
10465
5.18k
              need_local_plte=!mng_info->equal_palettes;
10466
5.18k
            }
10467
17.6k
#endif
10468
17.6k
          if (next_image->next != (Image *) NULL)
10469
17.0k
            {
10470
17.0k
              if (next_image->background_color.red !=
10471
17.0k
                  next_image->next->background_color.red ||
10472
17.0k
                  next_image->background_color.green !=
10473
17.0k
                  next_image->next->background_color.green ||
10474
17.0k
                  next_image->background_color.blue !=
10475
17.0k
                  next_image->next->background_color.blue)
10476
0
                mng_info->equal_backgrounds=MagickFalse;
10477
17.0k
              if (next_image->gamma != next_image->next->gamma)
10478
0
                mng_info->equal_gammas=MagickFalse;
10479
17.0k
              if (next_image->rendering_intent !=
10480
17.0k
                  next_image->next->rendering_intent)
10481
0
                mng_info->equal_srgbs=MagickFalse;
10482
17.0k
              if ((next_image->units != next_image->next->units) ||
10483
17.0k
                  (next_image->x_resolution !=
10484
17.0k
                   next_image->next->x_resolution) ||
10485
17.0k
                  (next_image->y_resolution != next_image->next->y_resolution))
10486
0
                mng_info->equal_physs=MagickFalse;
10487
17.0k
              if (mng_info->equal_chrms)
10488
0
                {
10489
0
                  if (next_image->chromaticity.red_primary.x !=
10490
0
                      next_image->next->chromaticity.red_primary.x ||
10491
0
                      next_image->chromaticity.red_primary.y !=
10492
0
                      next_image->next->chromaticity.red_primary.y ||
10493
0
                      next_image->chromaticity.green_primary.x !=
10494
0
                      next_image->next->chromaticity.green_primary.x ||
10495
0
                      next_image->chromaticity.green_primary.y !=
10496
0
                      next_image->next->chromaticity.green_primary.y ||
10497
0
                      next_image->chromaticity.blue_primary.x !=
10498
0
                      next_image->next->chromaticity.blue_primary.x ||
10499
0
                      next_image->chromaticity.blue_primary.y !=
10500
0
                      next_image->next->chromaticity.blue_primary.y ||
10501
0
                      next_image->chromaticity.white_point.x !=
10502
0
                      next_image->next->chromaticity.white_point.x ||
10503
0
                      next_image->chromaticity.white_point.y !=
10504
0
                      next_image->next->chromaticity.white_point.y)
10505
0
                    mng_info->equal_chrms=MagickFalse;
10506
0
                }
10507
17.0k
            }
10508
17.6k
          image_count++;
10509
17.6k
          next_image=next_image->next;
10510
17.6k
        }
10511
611
      if (image_count < 2)
10512
178
        {
10513
178
          mng_info->equal_backgrounds=MagickFalse;
10514
178
          mng_info->equal_chrms=MagickFalse;
10515
178
          mng_info->equal_gammas=MagickFalse;
10516
178
          mng_info->equal_srgbs=MagickFalse;
10517
178
          mng_info->equal_physs=MagickFalse;
10518
178
          use_global_plte=MagickFalse;
10519
178
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10520
178
          need_local_plte=MagickTrue;
10521
178
#endif
10522
178
          need_iterations=MagickFalse;
10523
178
        }
10524
611
      if (!mng_info->need_fram)
10525
434
        {
10526
          /*
10527
            Only certain framing rates 100/n are exactly representable without
10528
            the FRAM chunk but we'll allow some slop in VLC files
10529
          */
10530
434
          if (final_delay == 0)
10531
116
            {
10532
116
              if (need_iterations)
10533
0
                {
10534
                  /*
10535
                    It's probably a GIF with loop; don't run it *too* fast.
10536
                  */
10537
0
                  final_delay=10;
10538
0
                  (void) ThrowException2(&image->exception,CoderError,
10539
0
                                         "input has zero delay between"
10540
0
                                         " all frames; assuming 10 cs",
10541
0
                                         (char *) NULL);
10542
0
                }
10543
116
              else
10544
116
                mng_info->ticks_per_second=0;
10545
116
            }
10546
434
          if (final_delay)
10547
318
            mng_info->ticks_per_second=100/final_delay;
10548
434
          if (final_delay > 50)
10549
8
            mng_info->ticks_per_second=2;
10550
434
          if (final_delay > 75)
10551
5
            mng_info->ticks_per_second=1;
10552
434
          if (final_delay > 125)
10553
0
            mng_info->need_fram=MagickTrue;
10554
434
          if (need_defi && final_delay > 2 && (final_delay != 4) &&
10555
0
              (final_delay != 5) && (final_delay != 10) &&
10556
0
              (final_delay != 20) &&
10557
0
              (final_delay != 25) && (final_delay != 50) &&
10558
0
              (final_delay != 100))
10559
0
            mng_info->need_fram=MagickTrue;  /* make it exact;
10560
                                                cannot be VLC anyway */
10561
434
        }
10562
611
      if (mng_info->need_fram)
10563
177
        mng_info->ticks_per_second=100;
10564
      /*
10565
        If pseudocolor, we should also check to see if all the
10566
        palettes are identical and write a global PLTE if they are.
10567
        ../glennrp Feb 99.
10568
      */
10569
      /*
10570
        Write the MNG version 1.0 signature and MHDR chunk.
10571
      */
10572
611
      (void) WriteBlob(image,8,"\212MNG\r\n\032\n");
10573
611
      (void) WriteBlobMSBULong(image,28L);  /* chunk data length=28 */
10574
611
      PNGType(chunk,mng_MHDR);
10575
611
      LogPNGChunk(logging,mng_MHDR,28L);
10576
611
      PNGLong(chunk+4,mng_info->page.width);
10577
611
      PNGLong(chunk+8,mng_info->page.height);
10578
611
      PNGLong(chunk+12,mng_info->ticks_per_second);
10579
611
      PNGLong(chunk+16,0L);  /* layer count=unknown */
10580
611
      PNGLong(chunk+20,0L);  /* frame count=unknown */
10581
611
      PNGLong(chunk+24,0L);  /* play time=unknown   */
10582
611
      if (write_jng)
10583
0
        {
10584
0
          if (need_matte)
10585
0
            {
10586
0
              if (need_defi || mng_info->need_fram || use_global_plte)
10587
0
                PNGLong(chunk+28,27L);  /* simplicity=LC+JNG */
10588
0
              else
10589
0
                PNGLong(chunk+28,25L);  /* simplicity=VLC+JNG */
10590
0
            }
10591
0
          else
10592
0
            {
10593
0
              if (need_defi || mng_info->need_fram || use_global_plte)
10594
0
                PNGLong(chunk+28,19L);  /* simplicity=LC+JNG,
10595
                                           no transparency */
10596
0
              else
10597
0
                PNGLong(chunk+28,17L);  /* simplicity=VLC+JNG,
10598
                                           no transparency */
10599
0
            }
10600
0
        }
10601
611
      else
10602
611
        {
10603
611
          if (need_matte)
10604
0
            {
10605
0
              if (need_defi || mng_info->need_fram || use_global_plte)
10606
0
                PNGLong(chunk+28,11L);    /* simplicity=LC */
10607
0
              else
10608
0
                PNGLong(chunk+28,9L);    /* simplicity=VLC */
10609
0
            }
10610
611
          else
10611
611
            {
10612
611
              if (need_defi || mng_info->need_fram || use_global_plte)
10613
476
                PNGLong(chunk+28,3L);    /* simplicity=LC, no transparency */
10614
135
              else
10615
135
                PNGLong(chunk+28,1L);    /* simplicity=VLC, no transparency */
10616
611
            }
10617
611
        }
10618
611
      (void) WriteBlob(image,32,(char *) chunk);
10619
611
      (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10620
611
#if 1
10621
611
      if (AccessDefinition(image_info,"mng","need-cacheoff"))
10622
0
        {
10623
          /*
10624
            Add a "nEED CACHEOFF" request to disable frame caching in libmng.
10625
            Unfortunately, standard conformant players will reject the stream
10626
            if they do not support a nEED request.
10627
          */
10628
0
          PNGType(chunk,mng_nEED);
10629
0
          chunk_length = (strlcpy((char *) chunk+4, "CACHEOFF",20));
10630
0
          (void) WriteBlobMSBULong(image,(unsigned long) chunk_length);
10631
0
          LogPNGChunk(logging,mng_nEED,(unsigned long) chunk_length);
10632
0
          chunk_length += 4;
10633
0
          (void) WriteBlob(image,chunk_length,(char *) chunk);
10634
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) chunk_length));
10635
0
        }
10636
611
#endif
10637
611
      if ((image->previous == (Image *) NULL) &&
10638
611
          (image->next != (Image *) NULL) && (image->iterations != 1))
10639
430
        {
10640
          /*
10641
            Write MNG TERM chunk
10642
          */
10643
430
          (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
10644
430
          PNGType(chunk,mng_TERM);
10645
430
          LogPNGChunk(logging,mng_TERM,10L);
10646
430
          chunk[4]=3;  /* repeat animation */
10647
430
          chunk[5]=0;  /* show last frame when done */
10648
430
          PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10649
430
                                         final_delay/100));
10650
430
          if (image->iterations == 0)
10651
382
            PNGLong(chunk+10,PNG_MAX_UINT);
10652
48
          else
10653
48
            PNGLong(chunk+10,(png_uint_32) image->iterations);
10654
430
          if (logging)
10655
0
            {
10656
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10657
0
                                    "     TERM delay: %lu",
10658
0
                                    (unsigned long)
10659
0
                                    (mng_info->ticks_per_second*
10660
0
                                     final_delay/100));
10661
0
              if (image->iterations == 0)
10662
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10663
0
                                      "     TERM iterations: %lu",
10664
0
                                      (unsigned long)PNG_MAX_UINT);
10665
0
              else
10666
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10667
0
                                      "     Image iterations: %lu",
10668
0
                                      image->iterations);
10669
0
            }
10670
430
          (void) WriteBlob(image,14,(char *) chunk);
10671
430
          (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10672
430
        }
10673
      /*
10674
        To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10675
      */
10676
611
      if ((image_info->colorspace == sRGBColorspace ||
10677
611
           image->rendering_intent) && mng_info->equal_srgbs)
10678
0
        {
10679
          /*
10680
            Write MNG sRGB chunk
10681
          */
10682
0
          (void) WriteBlobMSBULong(image,1L);
10683
0
          PNGType(chunk,mng_sRGB);
10684
0
          LogPNGChunk(logging,mng_sRGB,1L);
10685
0
          if (image->rendering_intent != UndefinedIntent)
10686
0
            chunk[4]=(int) image->rendering_intent-1;
10687
0
          else
10688
0
            chunk[4]=(int) PerceptualIntent-1;
10689
0
          (void) WriteBlob(image,5,(char *) chunk);
10690
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10691
0
          mng_info->have_write_global_srgb=MagickTrue;
10692
0
        }
10693
611
      else
10694
611
        {
10695
611
          if (image->gamma && mng_info->equal_gammas)
10696
0
            {
10697
              /*
10698
                Write MNG gAMA chunk
10699
              */
10700
0
              (void) WriteBlobMSBULong(image,4L);
10701
0
              PNGType(chunk,mng_gAMA);
10702
0
              LogPNGChunk(logging,mng_gAMA,4L);
10703
0
              PNGLong(chunk+4,(unsigned long) (100000*image->gamma+0.5));
10704
0
              (void) WriteBlob(image,8,(char *) chunk);
10705
0
              (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10706
0
              mng_info->have_write_global_gama=MagickTrue;
10707
0
            }
10708
611
          if (mng_info->equal_chrms)
10709
0
            {
10710
0
              PrimaryInfo
10711
0
                primary;
10712
10713
              /*
10714
                Write MNG cHRM chunk
10715
              */
10716
0
              (void) WriteBlobMSBULong(image,32L);
10717
0
              PNGType(chunk,mng_cHRM);
10718
0
              LogPNGChunk(logging,mng_cHRM,32L);
10719
0
              primary=image->chromaticity.white_point;
10720
0
              PNGLong(chunk+4,(unsigned long) (100000*primary.x+0.5));
10721
0
              PNGLong(chunk+8,(unsigned long) (100000*primary.y+0.5));
10722
0
              primary=image->chromaticity.red_primary;
10723
0
              PNGLong(chunk+12,(unsigned long) (100000*primary.x+0.5));
10724
0
              PNGLong(chunk+16,(unsigned long) (100000*primary.y+0.5));
10725
0
              primary=image->chromaticity.green_primary;
10726
0
              PNGLong(chunk+20,(unsigned long) (100000*primary.x+0.5));
10727
0
              PNGLong(chunk+24,(unsigned long) (100000*primary.y+0.5));
10728
0
              primary=image->chromaticity.blue_primary;
10729
0
              PNGLong(chunk+28,(unsigned long) (100000*primary.x+0.5));
10730
0
              PNGLong(chunk+32,(unsigned long) (100000*primary.y+0.5));
10731
0
              (void) WriteBlob(image,36,(char *) chunk);
10732
0
              (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10733
0
              mng_info->have_write_global_chrm=MagickTrue;
10734
0
            }
10735
611
        }
10736
611
      if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
10737
0
        {
10738
          /*
10739
            Write MNG pHYs chunk
10740
          */
10741
0
          (void) WriteBlobMSBULong(image,9L);
10742
0
          PNGType(chunk,mng_pHYs);
10743
0
          LogPNGChunk(logging,mng_pHYs,9L);
10744
0
          if (image->units == PixelsPerInchResolution)
10745
0
            {
10746
0
              PNGLong(chunk+4,(unsigned long)
10747
0
                      (image->x_resolution*100.0/2.54+0.5));
10748
0
              PNGLong(chunk+8,(unsigned long)
10749
0
                      (image->y_resolution*100.0/2.54+0.5));
10750
0
              chunk[12]=1;
10751
0
            }
10752
0
          else
10753
0
            {
10754
0
              if (image->units == PixelsPerCentimeterResolution)
10755
0
                {
10756
0
                  PNGLong(chunk+4,(unsigned long)
10757
0
                          (image->x_resolution*100.0+0.5));
10758
0
                  PNGLong(chunk+8,(unsigned long)
10759
0
                          (image->y_resolution*100.0+0.5));
10760
0
                  chunk[12]=1;
10761
0
                }
10762
0
              else
10763
0
                {
10764
0
                  PNGLong(chunk+4,(unsigned long) (image->x_resolution+0.5));
10765
0
                  PNGLong(chunk+8,(unsigned long) (image->y_resolution+0.5));
10766
0
                  chunk[12]=0;
10767
0
                }
10768
0
            }
10769
0
          (void) WriteBlob(image,13,(char *) chunk);
10770
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10771
0
        }
10772
      /*
10773
        Write MNG BACK chunk and global bKGD chunk, if the image is transparent
10774
        or does not cover the entire frame.
10775
      */
10776
611
      if (write_mng && (image->matte || image->page.x > 0 ||
10777
611
                        image->page.y > 0 ||
10778
611
                        (image->page.width &&
10779
611
                         (image->page.width+image->page.x <
10780
611
                          mng_info->page.width))
10781
611
                        || (image->page.height &&
10782
611
                            (image->page.height+image->page.y <
10783
611
                             mng_info->page.height))))
10784
0
        {
10785
0
          (void) WriteBlobMSBULong(image,6L);
10786
0
          PNGType(chunk,mng_BACK);
10787
0
          LogPNGChunk(logging,mng_BACK,6L);
10788
0
          red=ScaleQuantumToShort(image->background_color.red);
10789
0
          green=ScaleQuantumToShort(image->background_color.green);
10790
0
          blue=ScaleQuantumToShort(image->background_color.blue);
10791
0
          PNGShort(chunk+4,red);
10792
0
          PNGShort(chunk+6,green);
10793
0
          PNGShort(chunk+8,blue);
10794
0
          (void) WriteBlob(image,10,(char *) chunk);
10795
0
          (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
10796
0
          if (mng_info->equal_backgrounds)
10797
0
            {
10798
0
              (void) WriteBlobMSBULong(image,6L);
10799
0
              PNGType(chunk,mng_bKGD);
10800
0
              LogPNGChunk(logging,mng_bKGD,6L);
10801
0
              (void) WriteBlob(image,10,(char *) chunk);
10802
0
              (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
10803
0
            }
10804
0
        }
10805
10806
611
#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10807
611
      if (!need_local_plte && image->storage_class == PseudoClass
10808
212
          && !all_images_are_gray)
10809
50
        {
10810
50
          unsigned long
10811
50
            data_length;
10812
10813
          /*
10814
            Write MNG PLTE chunk
10815
          */
10816
50
          data_length=3*image->colors;
10817
50
          (void) WriteBlobMSBULong(image,data_length);
10818
50
          PNGType(chunk,mng_PLTE);
10819
50
          LogPNGChunk(logging,mng_PLTE,data_length);
10820
100
          for (i=0; i < (long) image->colors; i++)
10821
50
            {
10822
50
              chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
10823
50
              chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
10824
50
              chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
10825
50
            }
10826
50
          (void) WriteBlob(image,(size_t) data_length+4,(char *) chunk);
10827
50
          (void) WriteBlobMSBULong(image,crc32(0,chunk,(int) (data_length+4)));
10828
50
          mng_info->have_write_global_plte=MagickTrue;
10829
50
        }
10830
611
#endif
10831
611
    }
10832
611
  scene=0;
10833
611
  mng_info->delay=0;
10834
611
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) ||  \
10835
611
  defined(PNG_MNG_FEATURES_SUPPORTED)
10836
611
  mng_info->equal_palettes=MagickFalse;
10837
611
#endif
10838
611
  do
10839
17.6k
    {
10840
17.6k
      unsigned char
10841
17.6k
        chunk[800];
10842
10843
17.6k
      if (mng_info->adjoin)
10844
17.5k
        {
10845
17.5k
#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) ||  \
10846
17.5k
  defined(PNG_MNG_FEATURES_SUPPORTED)
10847
          /*
10848
            If we aren't using a global palette for the entire MNG, check to
10849
            see if we can use one for two or more consecutive images.
10850
          */
10851
17.5k
          if (need_local_plte && use_global_plte && !all_images_are_gray)
10852
1.18k
            {
10853
1.18k
              if (mng_info->IsPalette)
10854
1.09k
                {
10855
                  /*
10856
                    When equal_palettes is true, this image has the
10857
                    same palette as the previous PseudoClass image
10858
                  */
10859
1.09k
                  mng_info->have_write_global_plte=mng_info->equal_palettes;
10860
1.09k
                  mng_info->equal_palettes=PalettesAreEqual(image,image->next);
10861
1.09k
                  if (mng_info->equal_palettes &&
10862
568
                      !mng_info->have_write_global_plte)
10863
206
                    {
10864
                      /*
10865
                        Write MNG PLTE chunk
10866
                      */
10867
206
                      unsigned long
10868
206
                        data_length;
10869
10870
206
                      data_length=3*image->colors;
10871
206
                      (void) WriteBlobMSBULong(image,data_length);
10872
206
                      PNGType(chunk,mng_PLTE);
10873
206
                      LogPNGChunk(logging,mng_PLTE,data_length);
10874
412
                      for (i=0; i < (long) image->colors; i++)
10875
206
                        {
10876
206
                          chunk[4+i*3]=
10877
206
                            ScaleQuantumToChar(image->colormap[i].red);
10878
206
                          chunk[5+i*3]=
10879
206
                            ScaleQuantumToChar(image->colormap[i].green);
10880
206
                          chunk[6+i*3]=
10881
206
                            ScaleQuantumToChar(image->colormap[i].blue);
10882
206
                        }
10883
206
                      (void) WriteBlob(image,(size_t) data_length+4,(char *) chunk);
10884
206
                      (void) WriteBlobMSBULong(image,
10885
206
                                               crc32(0,chunk,(int)
10886
206
                                                     (data_length+4)));
10887
206
                      mng_info->have_write_global_plte=MagickTrue;
10888
206
                    }
10889
1.09k
                }
10890
82
              else
10891
82
                mng_info->have_write_global_plte=MagickFalse;
10892
1.18k
            }
10893
17.5k
#endif
10894
17.5k
          if (need_defi)
10895
0
            {
10896
0
              long
10897
0
                previous_x,
10898
0
                previous_y;
10899
10900
0
              if (scene)
10901
0
                {
10902
0
                  previous_x=mng_info->page.x;
10903
0
                  previous_y=mng_info->page.y;
10904
0
                }
10905
0
              else
10906
0
                {
10907
0
                  previous_x=0;
10908
0
                  previous_y=0;
10909
0
                }
10910
0
              mng_info->page=image->page;
10911
0
              if ((mng_info->page.x !=  previous_x) || (mng_info->page.y !=
10912
0
                                                        previous_y))
10913
0
                {
10914
0
                  (void) WriteBlobMSBULong(image,12L);  /* data length=12 */
10915
0
                  PNGType(chunk,mng_DEFI);
10916
0
                  LogPNGChunk(logging,mng_DEFI,12L);
10917
0
                  chunk[4]=0; /* object 0 MSB */
10918
0
                  chunk[5]=0; /* object 0 LSB */
10919
0
                  chunk[6]=0; /* visible  */
10920
0
                  chunk[7]=0; /* abstract */
10921
0
                  PNGLong(chunk+8,mng_info->page.x);
10922
0
                  PNGLong(chunk+12,mng_info->page.y);
10923
0
                  (void) WriteBlob(image,16,(char *) chunk);
10924
0
                  (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
10925
0
                }
10926
0
            }
10927
17.5k
        }
10928
10929
17.6k
      mng_info->write_mng=write_mng;
10930
10931
17.6k
      if ((int) image->dispose >= 3)
10932
0
        mng_info->framing_mode=3;
10933
10934
17.6k
      if (mng_info->need_fram && mng_info->adjoin &&
10935
1.90k
          ((image->delay != mng_info->delay) ||
10936
1.58k
           (mng_info->framing_mode != mng_info->old_framing_mode)))
10937
314
        {
10938
314
          if (image->delay == mng_info->delay)
10939
0
            {
10940
              /*
10941
                Write a MNG FRAM chunk with the new framing mode.
10942
              */
10943
0
              (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
10944
0
              PNGType(chunk,mng_FRAM);
10945
0
              LogPNGChunk(logging,mng_FRAM,1L);
10946
0
              chunk[4]=(unsigned char) mng_info->framing_mode;
10947
0
              (void) WriteBlob(image,5,(char *) chunk);
10948
0
              (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10949
0
            }
10950
314
          else
10951
314
            {
10952
              /*
10953
                Write a MNG FRAM chunk with the delay.
10954
              */
10955
314
              (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
10956
314
              PNGType(chunk,mng_FRAM);
10957
314
              LogPNGChunk(logging,mng_FRAM,10L);
10958
314
              chunk[4]=(unsigned char) mng_info->framing_mode;
10959
314
              chunk[5]=0;  /* frame name separator (no name) */
10960
314
              chunk[6]=2;  /* flag for changing default delay */
10961
314
              chunk[7]=0;  /* flag for changing frame timeout */
10962
314
              chunk[8]=0;  /* flag for changing frame clipping */
10963
314
              chunk[9]=0;  /* flag for changing frame sync_id */
10964
314
              PNGLong(chunk+10,(png_uint_32)
10965
314
                      ((mng_info->ticks_per_second*image->delay)/100));
10966
314
              (void) WriteBlob(image,14,(char *) chunk);
10967
314
              (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10968
314
              mng_info->delay=(long) image->delay;
10969
314
            }
10970
314
          mng_info->old_framing_mode=mng_info->framing_mode;
10971
314
        }
10972
10973
17.6k
#if defined(JNG_SUPPORTED)
10974
17.6k
      if (image->compression == JPEGCompression)
10975
0
        {
10976
0
          if (logging)
10977
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10978
0
                                  "  Writing JNG object.");
10979
          /* To do: specify the desired alpha compression method. */
10980
0
          image->compression=UndefinedCompression;
10981
0
          status=WriteOneJNGImage(mng_info,image_info,image);
10982
0
        }
10983
17.6k
      else
10984
17.6k
#endif
10985
17.6k
        {
10986
17.6k
          if (logging)
10987
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10988
0
                                  "  Writing PNG object.");
10989
17.6k
          status=WriteOnePNGImage(mng_info,image_info,image);
10990
17.6k
        }
10991
10992
17.6k
      if (!status)
10993
0
        {
10994
0
          MngInfoFreeStruct(mng_info,&have_mng_structure);
10995
0
          CloseBlob(image);
10996
0
          return (MagickFail);
10997
0
        }
10998
17.6k
      (void) CatchImageException(image);
10999
17.6k
      if (image->next == (Image *) NULL)
11000
611
        break;
11001
17.0k
      image=SyncNextImageInList(image);
11002
17.0k
      if (QuantumTick(scene,GetImageListLength(image)))
11003
10.7k
        if (!MagickMonitorFormatted(scene++,GetImageListLength(image),
11004
10.7k
                                    &image->exception,SaveImagesText,
11005
10.7k
                                    image->filename))
11006
0
          break;
11007
17.0k
    } while (mng_info->adjoin);
11008
611
  if (write_mng)
11009
611
    {
11010
611
      unsigned char
11011
611
        chunk[16];
11012
11013
17.6k
      while (image->previous != (Image *) NULL)
11014
17.0k
        image=image->previous;
11015
      /*
11016
        Write the MEND chunk.
11017
      */
11018
611
      (void) WriteBlobMSBULong(image,0x00000000L);
11019
611
      PNGType(chunk,mng_MEND);
11020
611
      LogPNGChunk(logging,mng_MEND,0L);
11021
611
      (void) WriteBlob(image,4,(char *) chunk);
11022
611
      (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11023
611
    }
11024
  /*
11025
    Free memory.
11026
  */
11027
611
  status &= CloseBlob(image);
11028
611
  MngInfoFreeStruct(mng_info,&have_mng_structure);
11029
611
  if (logging)
11030
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11031
611
  return(status);
11032
611
}
11033
#else /* PNG_LIBPNG_VER > 10011 */
11034
static unsigned int WritePNGImage(const ImageInfo *image_info,Image *image)
11035
{
11036
  image=image;
11037
  printf("Your PNG library is too old: You have libpng-%s\n",
11038
         PNG_LIBPNG_VER_STRING);
11039
  ThrowBinaryException(CoderError,PNGLibraryTooOld,image_info->filename);
11040
}
11041
static unsigned int WriteMNGImage(const ImageInfo *image_info,Image *image)
11042
{
11043
  return (WritePNGImage(image_info,image));
11044
}
11045
#endif /* PNG_LIBPNG_VER > 10011 */
11046
#endif