Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            PPPP   N   N   GGGG                              %
      7 %                            P   P  NN  N  G                                  %
      8 %                            PPPP   N N N  G  GG                              %
      9 %                            P      N  NN  G   G                              %
     10 %                            P      N   N   GGG                               %
     11 %                                                                             %
     12 %                                                                             %
     13 %              Read/Write Portable Network Graphics Image Format              %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                           Glenn Randers-Pehrson                             %
     18 %                               November 1997                                 %
     19 %                                                                             %
     20 %                                                                             %
     21 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     22 %  dedicated to making software imaging solutions freely available.           %
     23 %                                                                             %
     24 %  You may not use this file except in compliance with the License.  You may  %
     25 %  obtain a copy of the License at                                            %
     26 %                                                                             %
     27 %    http://www.imagemagick.org/script/license.php                            %
     28 %                                                                             %
     29 %  Unless required by applicable law or agreed to in writing, software        %
     30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     32 %  See the License for the specific language governing permissions and        %
     33 %  limitations under the License.                                             %
     34 %                                                                             %
     35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     36 %
     37 %
     38 */
     39 
     40 
     41 /*
     43   Include declarations.
     44 */
     45 #include "MagickCore/studio.h"
     46 #include "MagickCore/artifact.h"
     47 #include "MagickCore/attribute.h"
     48 #include "MagickCore/blob.h"
     49 #include "MagickCore/blob-private.h"
     50 #include "MagickCore/cache.h"
     51 #include "MagickCore/channel.h"
     52 #include "MagickCore/color.h"
     53 #include "MagickCore/color-private.h"
     54 #include "MagickCore/colormap.h"
     55 #include "MagickCore/colorspace.h"
     56 #include "MagickCore/colorspace-private.h"
     57 #include "MagickCore/constitute.h"
     58 #include "MagickCore/enhance.h"
     59 #include "MagickCore/exception.h"
     60 #include "MagickCore/exception-private.h"
     61 #include "MagickCore/geometry.h"
     62 #include "MagickCore/histogram.h"
     63 #include "MagickCore/image.h"
     64 #include "MagickCore/image-private.h"
     65 #include "MagickCore/layer.h"
     66 #include "MagickCore/list.h"
     67 #include "MagickCore/log.h"
     68 #include "MagickCore/MagickCore.h"
     69 #include "MagickCore/memory_.h"
     70 #include "MagickCore/module.h"
     71 #include "MagickCore/monitor.h"
     72 #include "MagickCore/monitor-private.h"
     73 #include "MagickCore/option.h"
     74 #include "MagickCore/pixel.h"
     75 #include "MagickCore/pixel-accessor.h"
     76 #include "MagickCore/profile.h"
     77 #include "MagickCore/property.h"
     78 #include "MagickCore/quantum-private.h"
     79 #include "MagickCore/resource_.h"
     80 #include "MagickCore/semaphore.h"
     81 #include "MagickCore/quantum-private.h"
     82 #include "MagickCore/static.h"
     83 #include "MagickCore/statistic.h"
     84 #include "MagickCore/string_.h"
     85 #include "MagickCore/string-private.h"
     86 #include "MagickCore/transform.h"
     87 #include "MagickCore/utility.h"
     88 #if defined(MAGICKCORE_PNG_DELEGATE)
     89 
     90 /* Suppress libpng pedantic warnings that were added in
     91  * libpng-1.2.41 and libpng-1.4.0.  If you are working on
     92  * migration to libpng-1.5, remove these defines and then
     93  * fix any code that generates warnings.
     94  */
     95 /* #define PNG_DEPRECATED   Use of this function is deprecated */
     96 /* #define PNG_USE_RESULT   The result of this function must be checked */
     97 /* #define PNG_NORETURN     This function does not return */
     98 /* #define PNG_ALLOCATED    The result of the function is new memory */
     99 /* #define PNG_DEPSTRUCT    Access to this struct member is deprecated */
    100 
    101 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
    102 #define PNG_PTR_NORETURN
    103 
    104 #include "png.h"
    105 #include "zlib.h"
    106 
    107 /* ImageMagick differences */
    109 #define first_scene scene
    110 
    111 #if PNG_LIBPNG_VER > 10011
    112 /*
    113   Optional declarations. Define or undefine them as you like.
    114 */
    115 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
    116 
    117 /*
    118   Features under construction.  Define these to work on them.
    119 */
    120 #undef MNG_OBJECT_BUFFERS
    121 #undef MNG_BASI_SUPPORTED
    122 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
    123 #define MNG_INSERT_LAYERS   /* Troublesome, but seem to work as of 5.4.4 */
    124 #if defined(MAGICKCORE_JPEG_DELEGATE)
    125 #  define JNG_SUPPORTED /* Not finished as of 5.5.2.  See "To do" comments. */
    126 #endif
    127 #if !defined(RGBColorMatchExact)
    128 #define IsPNGColorEqual(color,target) \
    129        (((color).red == (target).red) && \
    130         ((color).green == (target).green) && \
    131         ((color).blue == (target).blue))
    132 #endif
    133 
    134 /* Table of recognized sRGB ICC profiles */
    135 struct sRGB_info_struct
    136 {
    137     png_uint_32 len;
    138     png_uint_32 crc;
    139     png_byte intent;
    140 };
    141 
    142 const struct sRGB_info_struct sRGB_info[] =
    143 {
    144     /* ICC v2 perceptual sRGB_IEC61966-2-1_black_scaled.icc */
    145     { 3048, 0x3b8772b9UL, 0},
    146 
    147     /* ICC v2 relative sRGB_IEC61966-2-1_no_black_scaling.icc */
    148     { 3052, 0x427ebb21UL, 1},
    149 
    150     /* ICC v4 perceptual sRGB_v4_ICC_preference_displayclass.icc */
    151     {60988, 0x306fd8aeUL, 0},
    152 
    153     /* ICC v4 perceptual sRGB_v4_ICC_preference.icc perceptual */
    154      {60960, 0xbbef7812UL, 0},
    155 
    156     /* HP? sRGB v2 media-relative sRGB_IEC61966-2-1_noBPC.icc */
    157      { 3024, 0x5d5129ceUL, 1},
    158 
    159      /* HP-Microsoft sRGB v2 perceptual */
    160      { 3144, 0x182ea552UL, 0},
    161 
    162      /* HP-Microsoft sRGB v2 media-relative */
    163      { 3144, 0xf29e526dUL, 1},
    164 
    165      /* Facebook's "2012/01/25 03:41:57", 524, "TINYsRGB.icc" */
    166      {  524, 0xd4938c39UL, 0},
    167 
    168      /* "2012/11/28 22:35:21", 3212, "Argyll_sRGB.icm") */
    169      { 3212, 0x034af5a1UL, 0},
    170 
    171      /* Not recognized */
    172      {    0, 0x00000000UL, 0},
    173 };
    174 
    175 /* Macros for left-bit-replication to ensure that pixels
    176  * and PixelInfos all have the same image->depth, and for use
    177  * in PNG8 quantization.
    178  */
    179 
    180 /* LBR01: Replicate top bit */
    181 
    182 #define LBR01PacketRed(pixelpacket) \
    183      (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
    184         0 : QuantumRange);
    185 
    186 #define LBR01PacketGreen(pixelpacket) \
    187      (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
    188         0 : QuantumRange);
    189 
    190 #define LBR01PacketBlue(pixelpacket) \
    191      (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
    192         0 : QuantumRange);
    193 
    194 #define LBR01PacketAlpha(pixelpacket) \
    195      (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
    196         0 : QuantumRange);
    197 
    198 #define LBR01PacketRGB(pixelpacket) \
    199         { \
    200         LBR01PacketRed((pixelpacket)); \
    201         LBR01PacketGreen((pixelpacket)); \
    202         LBR01PacketBlue((pixelpacket)); \
    203         }
    204 
    205 #define LBR01PacketRGBO(pixelpacket) \
    206         { \
    207         LBR01PacketRGB((pixelpacket)); \
    208         LBR01PacketAlpha((pixelpacket)); \
    209         }
    210 
    211 #define LBR01PixelRed(pixel) \
    212         (SetPixelRed(image, \
    213         ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
    214         0 : QuantumRange,(pixel)));
    215 
    216 #define LBR01PixelGreen(pixel) \
    217         (SetPixelGreen(image, \
    218         ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
    219         0 : QuantumRange,(pixel)));
    220 
    221 #define LBR01PixelBlue(pixel) \
    222         (SetPixelBlue(image, \
    223         ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
    224         0 : QuantumRange,(pixel)));
    225 
    226 #define LBR01PixelAlpha(pixel) \
    227         (SetPixelAlpha(image, \
    228         ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
    229         0 : QuantumRange,(pixel)));
    230 
    231 #define LBR01PixelRGB(pixel) \
    232         { \
    233         LBR01PixelRed((pixel)); \
    234         LBR01PixelGreen((pixel)); \
    235         LBR01PixelBlue((pixel)); \
    236         }
    237 
    238 #define LBR01PixelRGBA(pixel) \
    239         { \
    240         LBR01PixelRGB((pixel)); \
    241         LBR01PixelAlpha((pixel)); \
    242         }
    243 
    244 /* LBR02: Replicate top 2 bits */
    245 
    246 #define LBR02PacketRed(pixelpacket) \
    247    { \
    248      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
    249      (pixelpacket).red=ScaleCharToQuantum( \
    250        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
    251    }
    252 #define LBR02PacketGreen(pixelpacket) \
    253    { \
    254      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
    255      (pixelpacket).green=ScaleCharToQuantum( \
    256        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
    257    }
    258 #define LBR02PacketBlue(pixelpacket) \
    259    { \
    260      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
    261      (pixelpacket).blue=ScaleCharToQuantum( \
    262        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
    263    }
    264 #define LBR02PacketAlpha(pixelpacket) \
    265    { \
    266      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
    267      (pixelpacket).alpha=ScaleCharToQuantum( \
    268        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
    269    }
    270 
    271 #define LBR02PacketRGB(pixelpacket) \
    272         { \
    273         LBR02PacketRed((pixelpacket)); \
    274         LBR02PacketGreen((pixelpacket)); \
    275         LBR02PacketBlue((pixelpacket)); \
    276         }
    277 
    278 #define LBR02PacketRGBO(pixelpacket) \
    279         { \
    280         LBR02PacketRGB((pixelpacket)); \
    281         LBR02PacketAlpha((pixelpacket)); \
    282         }
    283 
    284 #define LBR02PixelRed(pixel) \
    285    { \
    286      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
    287        & 0xc0; \
    288      SetPixelRed(image, ScaleCharToQuantum( \
    289        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
    290        (pixel)); \
    291    }
    292 #define LBR02PixelGreen(pixel) \
    293    { \
    294      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
    295        & 0xc0; \
    296      SetPixelGreen(image, ScaleCharToQuantum( \
    297        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
    298        (pixel)); \
    299    }
    300 #define LBR02PixelBlue(pixel) \
    301    { \
    302      unsigned char lbr_bits= \
    303        ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
    304      SetPixelBlue(image, ScaleCharToQuantum( \
    305        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
    306        (pixel)); \
    307    }
    308 #define LBR02PixelAlpha(pixel) \
    309    { \
    310      unsigned char lbr_bits= \
    311        ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
    312      SetPixelAlpha(image, ScaleCharToQuantum( \
    313        (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
    314        (pixel) ); \
    315    }
    316 
    317 #define LBR02PixelRGB(pixel) \
    318         { \
    319         LBR02PixelRed((pixel)); \
    320         LBR02PixelGreen((pixel)); \
    321         LBR02PixelBlue((pixel)); \
    322         }
    323 
    324 #define LBR02PixelRGBA(pixel) \
    325         { \
    326         LBR02PixelRGB((pixel)); \
    327         LBR02PixelAlpha((pixel)); \
    328         }
    329 
    330 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
    331    PNG8 quantization) */
    332 
    333 #define LBR03PacketRed(pixelpacket) \
    334    { \
    335      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
    336      (pixelpacket).red=ScaleCharToQuantum( \
    337        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
    338    }
    339 #define LBR03PacketGreen(pixelpacket) \
    340    { \
    341      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
    342      (pixelpacket).green=ScaleCharToQuantum( \
    343        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
    344    }
    345 #define LBR03PacketBlue(pixelpacket) \
    346    { \
    347      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
    348      (pixelpacket).blue=ScaleCharToQuantum( \
    349        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
    350    }
    351 
    352 #define LBR03PacketRGB(pixelpacket) \
    353         { \
    354         LBR03PacketRed((pixelpacket)); \
    355         LBR03PacketGreen((pixelpacket)); \
    356         LBR03PacketBlue((pixelpacket)); \
    357         }
    358 
    359 #define LBR03PixelRed(pixel) \
    360    { \
    361      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
    362        & 0xe0; \
    363      SetPixelRed(image, ScaleCharToQuantum( \
    364        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
    365    }
    366 #define LBR03Green(pixel) \
    367    { \
    368      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
    369        & 0xe0; \
    370      SetPixelGreen(image, ScaleCharToQuantum( \
    371        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
    372    }
    373 #define LBR03Blue(pixel) \
    374    { \
    375      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
    376        & 0xe0; \
    377      SetPixelBlue(image, ScaleCharToQuantum( \
    378        (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
    379    }
    380 
    381 #define LBR03RGB(pixel) \
    382         { \
    383         LBR03PixelRed((pixel)); \
    384         LBR03Green((pixel)); \
    385         LBR03Blue((pixel)); \
    386         }
    387 
    388 /* LBR04: Replicate top 4 bits */
    389 
    390 #define LBR04PacketRed(pixelpacket) \
    391    { \
    392      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
    393      (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
    394    }
    395 #define LBR04PacketGreen(pixelpacket) \
    396    { \
    397      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
    398      (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
    399    }
    400 #define LBR04PacketBlue(pixelpacket) \
    401    { \
    402      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
    403      (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
    404    }
    405 #define LBR04PacketAlpha(pixelpacket) \
    406    { \
    407      unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
    408      (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
    409    }
    410 
    411 #define LBR04PacketRGB(pixelpacket) \
    412         { \
    413         LBR04PacketRed((pixelpacket)); \
    414         LBR04PacketGreen((pixelpacket)); \
    415         LBR04PacketBlue((pixelpacket)); \
    416         }
    417 
    418 #define LBR04PacketRGBO(pixelpacket) \
    419         { \
    420         LBR04PacketRGB((pixelpacket)); \
    421         LBR04PacketAlpha((pixelpacket)); \
    422         }
    423 
    424 #define LBR04PixelRed(pixel) \
    425    { \
    426      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
    427        & 0xf0; \
    428      SetPixelRed(image,\
    429        ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
    430    }
    431 #define LBR04PixelGreen(pixel) \
    432    { \
    433      unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
    434        & 0xf0; \
    435      SetPixelGreen(image,\
    436        ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
    437    }
    438 #define LBR04PixelBlue(pixel) \
    439    { \
    440      unsigned char lbr_bits= \
    441        ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
    442      SetPixelBlue(image,\
    443        ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
    444    }
    445 #define LBR04PixelAlpha(pixel) \
    446    { \
    447      unsigned char lbr_bits= \
    448        ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
    449      SetPixelAlpha(image,\
    450        ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
    451    }
    452 
    453 #define LBR04PixelRGB(pixel) \
    454         { \
    455         LBR04PixelRed((pixel)); \
    456         LBR04PixelGreen((pixel)); \
    457         LBR04PixelBlue((pixel)); \
    458         }
    459 
    460 #define LBR04PixelRGBA(pixel) \
    461         { \
    462         LBR04PixelRGB((pixel)); \
    463         LBR04PixelAlpha((pixel)); \
    464         }
    465 
    466 /*
    467   Establish thread safety.
    468   setjmp/longjmp is claimed to be safe on these platforms:
    469   setjmp/longjmp is alleged to be unsafe on these platforms:
    470 */
    471 #ifdef PNG_SETJMP_SUPPORTED
    472 # ifndef IMPNG_SETJMP_IS_THREAD_SAFE
    473 #   define IMPNG_SETJMP_NOT_THREAD_SAFE
    474 # endif
    475 
    476 # ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
    477 static SemaphoreInfo
    478   *ping_semaphore = (SemaphoreInfo *) NULL;
    479 # endif
    480 #endif
    481 
    482 /*
    483   This temporary until I set up malloc'ed object attributes array.
    484   Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
    485   waste more memory.
    486 */
    487 #define MNG_MAX_OBJECTS 256
    488 
    489 /*
    490   If this not defined, spec is interpreted strictly.  If it is
    491   defined, an attempt will be made to recover from some errors,
    492   including
    493       o global PLTE too short
    494 */
    495 #undef MNG_LOOSE
    496 
    497 /*
    498   Don't try to define PNG_MNG_FEATURES_SUPPORTED here.  Make sure
    499   it's defined in libpng/pngconf.h, version 1.0.9 or later.  It won't work
    500   with earlier versions of libpng.  From libpng-1.0.3a to libpng-1.0.8,
    501   PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
    502   libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
    503   PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
    504   will be enabled by default in libpng-1.2.0.
    505 */
    506 #ifdef PNG_MNG_FEATURES_SUPPORTED
    507 #  ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
    508 #    define PNG_READ_EMPTY_PLTE_SUPPORTED
    509 #  endif
    510 #  ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
    511 #    define PNG_WRITE_EMPTY_PLTE_SUPPORTED
    512 #  endif
    513 #endif
    514 
    515 /*
    516   Maximum valid size_t in PNG/MNG chunks is (2^31)-1
    517   This macro is only defined in libpng-1.0.3 and later.
    518   Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
    519 */
    520 #ifndef PNG_UINT_31_MAX
    521 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
    522 #endif
    523 
    524 /*
    525   Constant strings for known chunk types.  If you need to add a chunk,
    526   add a string holding the name here.   To make the code more
    527   portable, we use ASCII numbers like this, not characters.
    528 */
    529 
    530 static const png_byte mng_MHDR[5]={ 77,  72,  68,  82, (png_byte) '\0'};
    531 static const png_byte mng_BACK[5]={ 66,  65,  67,  75, (png_byte) '\0'};
    532 static const png_byte mng_BASI[5]={ 66,  65,  83,  73, (png_byte) '\0'};
    533 static const png_byte mng_CLIP[5]={ 67,  76,  73,  80, (png_byte) '\0'};
    534 static const png_byte mng_CLON[5]={ 67,  76,  79,  78, (png_byte) '\0'};
    535 static const png_byte mng_DEFI[5]={ 68,  69,  70,  73, (png_byte) '\0'};
    536 static const png_byte mng_DHDR[5]={ 68,  72,  68,  82, (png_byte) '\0'};
    537 static const png_byte mng_DISC[5]={ 68,  73,  83,  67, (png_byte) '\0'};
    538 static const png_byte mng_ENDL[5]={ 69,  78,  68,  76, (png_byte) '\0'};
    539 static const png_byte mng_FRAM[5]={ 70,  82,  65,  77, (png_byte) '\0'};
    540 static const png_byte mng_IEND[5]={ 73,  69,  78,  68, (png_byte) '\0'};
    541 static const png_byte mng_IHDR[5]={ 73,  72,  68,  82, (png_byte) '\0'};
    542 static const png_byte mng_JHDR[5]={ 74,  72,  68,  82, (png_byte) '\0'};
    543 static const png_byte mng_LOOP[5]={ 76,  79,  79,  80, (png_byte) '\0'};
    544 static const png_byte mng_MAGN[5]={ 77,  65,  71,  78, (png_byte) '\0'};
    545 static const png_byte mng_MEND[5]={ 77,  69,  78,  68, (png_byte) '\0'};
    546 static const png_byte mng_MOVE[5]={ 77,  79,  86,  69, (png_byte) '\0'};
    547 static const png_byte mng_PAST[5]={ 80,  65,  83,  84, (png_byte) '\0'};
    548 static const png_byte mng_PLTE[5]={ 80,  76,  84,  69, (png_byte) '\0'};
    549 static const png_byte mng_SAVE[5]={ 83,  65,  86,  69, (png_byte) '\0'};
    550 static const png_byte mng_SEEK[5]={ 83,  69,  69,  75, (png_byte) '\0'};
    551 static const png_byte mng_SHOW[5]={ 83,  72,  79,  87, (png_byte) '\0'};
    552 static const png_byte mng_TERM[5]={ 84,  69,  82,  77, (png_byte) '\0'};
    553 static const png_byte mng_bKGD[5]={ 98,  75,  71,  68, (png_byte) '\0'};
    554 static const png_byte mng_cHRM[5]={ 99,  72,  82,  77, (png_byte) '\0'};
    555 static const png_byte mng_gAMA[5]={103,  65,  77,  65, (png_byte) '\0'};
    556 static const png_byte mng_iCCP[5]={105,  67,  67,  80, (png_byte) '\0'};
    557 static const png_byte mng_nEED[5]={110,  69,  69,  68, (png_byte) '\0'};
    558 static const png_byte mng_pHYg[5]={112,  72,  89, 103, (png_byte) '\0'};
    559 static const png_byte mng_vpAg[5]={118, 112,  65, 103, (png_byte) '\0'};
    560 static const png_byte mng_pHYs[5]={112,  72,  89, 115, (png_byte) '\0'};
    561 static const png_byte mng_sBIT[5]={115,  66,  73,  84, (png_byte) '\0'};
    562 static const png_byte mng_sRGB[5]={115,  82,  71,  66, (png_byte) '\0'};
    563 static const png_byte mng_tRNS[5]={116,  82,  78,  83, (png_byte) '\0'};
    564 
    565 #if defined(JNG_SUPPORTED)
    566 static const png_byte mng_IDAT[5]={ 73,  68,  65,  84, (png_byte) '\0'};
    567 static const png_byte mng_JDAT[5]={ 74,  68,  65,  84, (png_byte) '\0'};
    568 static const png_byte mng_JDAA[5]={ 74,  68,  65,  65, (png_byte) '\0'};
    569 static const png_byte mng_JdAA[5]={ 74, 100,  65,  65, (png_byte) '\0'};
    570 static const png_byte mng_JSEP[5]={ 74,  83,  69,  80, (png_byte) '\0'};
    571 static const png_byte mng_oFFs[5]={111,  70,  70, 115, (png_byte) '\0'};
    572 #endif
    573 
    574 #if 0
    575 /* Other known chunks that are not yet supported by ImageMagick: */
    576 static const png_byte mng_hIST[5]={104,  73,  83,  84, (png_byte) '\0'};
    577 static const png_byte mng_iTXt[5]={105,  84,  88, 116, (png_byte) '\0'};
    578 static const png_byte mng_sPLT[5]={115,  80,  76,  84, (png_byte) '\0'};
    579 static const png_byte mng_sTER[5]={115,  84,  69,  82, (png_byte) '\0'};
    580 static const png_byte mng_tEXt[5]={116,  69,  88, 116, (png_byte) '\0'};
    581 static const png_byte mng_tIME[5]={116,  73,  77,  69, (png_byte) '\0'};
    582 static const png_byte mng_zTXt[5]={122,  84,  88, 116, (png_byte) '\0'};
    583 #endif
    584 
    585 typedef struct _MngBox
    586 {
    587   long
    588     left,
    589     right,
    590     top,
    591     bottom;
    592 } MngBox;
    593 
    594 typedef struct _MngPair
    595 {
    596   volatile long
    597     a,
    598     b;
    599 } MngPair;
    600 
    601 #ifdef MNG_OBJECT_BUFFERS
    602 typedef struct _MngBuffer
    603 {
    604 
    605   size_t
    606     height,
    607     width;
    608 
    609   Image
    610     *image;
    611 
    612   png_color
    613     plte[256];
    614 
    615   int
    616     reference_count;
    617 
    618   unsigned char
    619     alpha_sample_depth,
    620     compression_method,
    621     color_type,
    622     concrete,
    623     filter_method,
    624     frozen,
    625     image_type,
    626     interlace_method,
    627     pixel_sample_depth,
    628     plte_length,
    629     sample_depth,
    630     viewable;
    631 } MngBuffer;
    632 #endif
    633 
    634 typedef struct _MngInfo
    635 {
    636 
    637 #ifdef MNG_OBJECT_BUFFERS
    638   MngBuffer
    639     *ob[MNG_MAX_OBJECTS];
    640 #endif
    641 
    642   Image *
    643     image;
    644 
    645   RectangleInfo
    646     page;
    647 
    648   int
    649     adjoin,
    650 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
    651     bytes_in_read_buffer,
    652     found_empty_plte,
    653 #endif
    654     equal_backgrounds,
    655     equal_chrms,
    656     equal_gammas,
    657 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
    658     defined(PNG_MNG_FEATURES_SUPPORTED)
    659     equal_palettes,
    660 #endif
    661     equal_physs,
    662     equal_srgbs,
    663     framing_mode,
    664     have_global_bkgd,
    665     have_global_chrm,
    666     have_global_gama,
    667     have_global_phys,
    668     have_global_sbit,
    669     have_global_srgb,
    670     have_saved_bkgd_index,
    671     have_write_global_chrm,
    672     have_write_global_gama,
    673     have_write_global_plte,
    674     have_write_global_srgb,
    675     need_fram,
    676     object_id,
    677     old_framing_mode,
    678     saved_bkgd_index;
    679 
    680   int
    681     new_number_colors;
    682 
    683   ssize_t
    684     image_found,
    685     loop_count[256],
    686     loop_iteration[256],
    687     scenes_found,
    688     x_off[MNG_MAX_OBJECTS],
    689     y_off[MNG_MAX_OBJECTS];
    690 
    691   MngBox
    692     clip,
    693     frame,
    694     image_box,
    695     object_clip[MNG_MAX_OBJECTS];
    696 
    697   unsigned char
    698     /* These flags could be combined into one byte */
    699     exists[MNG_MAX_OBJECTS],
    700     frozen[MNG_MAX_OBJECTS],
    701     loop_active[256],
    702     invisible[MNG_MAX_OBJECTS],
    703     viewable[MNG_MAX_OBJECTS];
    704 
    705   MagickOffsetType
    706     loop_jump[256];
    707 
    708   png_colorp
    709     global_plte;
    710 
    711   png_color_8
    712     global_sbit;
    713 
    714   png_byte
    715 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
    716     read_buffer[8],
    717 #endif
    718     global_trns[256];
    719 
    720   float
    721     global_gamma;
    722 
    723   ChromaticityInfo
    724     global_chrm;
    725 
    726   RenderingIntent
    727     global_srgb_intent;
    728 
    729   unsigned int
    730     delay,
    731     global_plte_length,
    732     global_trns_length,
    733     global_x_pixels_per_unit,
    734     global_y_pixels_per_unit,
    735     mng_width,
    736     mng_height,
    737     ticks_per_second;
    738 
    739   MagickBooleanType
    740     need_blob;
    741 
    742   unsigned int
    743     IsPalette,
    744     global_phys_unit_type,
    745     basi_warning,
    746     clon_warning,
    747     dhdr_warning,
    748     jhdr_warning,
    749     magn_warning,
    750     past_warning,
    751     phyg_warning,
    752     phys_warning,
    753     sbit_warning,
    754     show_warning,
    755     mng_type,
    756     write_mng,
    757     write_png_colortype,
    758     write_png_depth,
    759     write_png_compression_level,
    760     write_png_compression_strategy,
    761     write_png_compression_filter,
    762     write_png8,
    763     write_png24,
    764     write_png32,
    765     write_png48,
    766     write_png64;
    767 
    768 #ifdef MNG_BASI_SUPPORTED
    769   size_t
    770     basi_width,
    771     basi_height;
    772 
    773   unsigned int
    774     basi_depth,
    775     basi_color_type,
    776     basi_compression_method,
    777     basi_filter_type,
    778     basi_interlace_method,
    779     basi_red,
    780     basi_green,
    781     basi_blue,
    782     basi_alpha,
    783     basi_viewable;
    784 #endif
    785 
    786   png_uint_16
    787     magn_first,
    788     magn_last,
    789     magn_mb,
    790     magn_ml,
    791     magn_mr,
    792     magn_mt,
    793     magn_mx,
    794     magn_my,
    795     magn_methx,
    796     magn_methy;
    797 
    798   PixelInfo
    799     mng_global_bkgd;
    800 
    801   /* Added at version 6.6.6-7 */
    802   MagickBooleanType
    803     ping_exclude_bKGD,
    804     ping_exclude_cHRM,
    805     ping_exclude_date,
    806     ping_exclude_EXIF,
    807     ping_exclude_gAMA,
    808     ping_exclude_iCCP,
    809     /* ping_exclude_iTXt, */
    810     ping_exclude_oFFs,
    811     ping_exclude_pHYs,
    812     ping_exclude_sRGB,
    813     ping_exclude_tEXt,
    814     ping_exclude_tRNS,
    815     ping_exclude_vpAg,
    816     ping_exclude_zCCP, /* hex-encoded iCCP */
    817     ping_exclude_zTXt,
    818     ping_preserve_colormap,
    819   /* Added at version 6.8.5-7 */
    820     ping_preserve_iCCP,
    821   /* Added at version 6.8.9-9 */
    822     ping_exclude_tIME;
    823 
    824 } MngInfo;
    825 #endif /* VER */
    826 
    827 /*
    829   Forward declarations.
    830 */
    831 static MagickBooleanType
    832   WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
    833 
    834 static MagickBooleanType
    835   WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
    836 
    837 #if defined(JNG_SUPPORTED)
    838 static MagickBooleanType
    839   WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
    840 #endif
    841 
    842 #if PNG_LIBPNG_VER > 10011
    843 
    844 
    845 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
    846 static MagickBooleanType
    847 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
    848 {
    849     /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
    850      *
    851      * This is true if the high byte and the next highest byte of
    852      * each sample of the image, the colormap, and the background color
    853      * are equal to each other.  We check this by seeing if the samples
    854      * are unchanged when we scale them down to 8 and back up to Quantum.
    855      *
    856      * We don't use the method GetImageDepth() because it doesn't check
    857      * background and doesn't handle PseudoClass specially.
    858      */
    859 
    860 #define QuantumToCharToQuantumEqQuantum(quantum) \
    861   ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
    862 
    863     MagickBooleanType
    864       ok_to_reduce=MagickFalse;
    865 
    866     if (image->depth >= 16)
    867       {
    868 
    869         const Quantum
    870           *p;
    871 
    872         ok_to_reduce=
    873            QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
    874            QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
    875            QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
    876            MagickTrue : MagickFalse;
    877 
    878         if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
    879           {
    880             int indx;
    881 
    882             for (indx=0; indx < (ssize_t) image->colors; indx++)
    883               {
    884                 ok_to_reduce=(
    885                    QuantumToCharToQuantumEqQuantum(
    886                    image->colormap[indx].red) &&
    887                    QuantumToCharToQuantumEqQuantum(
    888                    image->colormap[indx].green) &&
    889                    QuantumToCharToQuantumEqQuantum(
    890                    image->colormap[indx].blue)) ?
    891                    MagickTrue : MagickFalse;
    892 
    893                 if (ok_to_reduce == MagickFalse)
    894                    break;
    895               }
    896           }
    897 
    898         if ((ok_to_reduce != MagickFalse) &&
    899             (image->storage_class != PseudoClass))
    900           {
    901             ssize_t
    902               y;
    903 
    904             register ssize_t
    905               x;
    906 
    907             for (y=0; y < (ssize_t) image->rows; y++)
    908             {
    909               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    910 
    911               if (p == (const Quantum *) NULL)
    912                 {
    913                   ok_to_reduce = MagickFalse;
    914                   break;
    915                 }
    916 
    917               for (x=(ssize_t) image->columns-1; x >= 0; x--)
    918               {
    919                 ok_to_reduce=
    920                    QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
    921                    QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
    922                    QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
    923                    MagickTrue : MagickFalse;
    924 
    925                 if (ok_to_reduce == MagickFalse)
    926                   break;
    927 
    928                 p+=GetPixelChannels(image);
    929               }
    930               if (x >= 0)
    931                 break;
    932             }
    933           }
    934 
    935         if (ok_to_reduce != MagickFalse)
    936           {
    937             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    938                 "    OK to reduce PNG bit depth to 8 without loss of info");
    939           }
    940         else
    941           {
    942             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    943                 "    Not OK to reduce PNG bit depth to 8 without loss of info");
    944           }
    945       }
    946 
    947     return ok_to_reduce;
    948 }
    949 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
    950 
    951 static const char* PngColorTypeToString(const unsigned int color_type)
    952 {
    953   const char
    954     *result = "Unknown";
    955 
    956   switch (color_type)
    957     {
    958     case PNG_COLOR_TYPE_GRAY:
    959       result = "Gray";
    960       break;
    961     case PNG_COLOR_TYPE_GRAY_ALPHA:
    962       result = "Gray+Alpha";
    963       break;
    964     case PNG_COLOR_TYPE_PALETTE:
    965       result = "Palette";
    966       break;
    967     case PNG_COLOR_TYPE_RGB:
    968       result = "RGB";
    969       break;
    970     case PNG_COLOR_TYPE_RGB_ALPHA:
    971       result = "RGB+Alpha";
    972       break;
    973     }
    974 
    975   return result;
    976 }
    977 
    978 static int
    979 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
    980 {
    981   switch (intent)
    982   {
    983     case PerceptualIntent:
    984        return 0;
    985 
    986     case RelativeIntent:
    987        return 1;
    988 
    989     case SaturationIntent:
    990        return 2;
    991 
    992     case AbsoluteIntent:
    993        return 3;
    994 
    995     default:
    996        return -1;
    997   }
    998 }
    999 
   1000 static RenderingIntent
   1001 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
   1002 {
   1003   switch (ping_intent)
   1004   {
   1005     case 0:
   1006       return PerceptualIntent;
   1007 
   1008     case 1:
   1009       return RelativeIntent;
   1010 
   1011     case 2:
   1012       return SaturationIntent;
   1013 
   1014     case 3:
   1015       return AbsoluteIntent;
   1016 
   1017     default:
   1018       return UndefinedIntent;
   1019     }
   1020 }
   1021 
   1022 static const char *
   1023 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
   1024 {
   1025   switch (ping_intent)
   1026   {
   1027     case 0:
   1028       return "Perceptual Intent";
   1029 
   1030     case 1:
   1031       return "Relative Intent";
   1032 
   1033     case 2:
   1034       return "Saturation Intent";
   1035 
   1036     case 3:
   1037       return "Absolute Intent";
   1038 
   1039     default:
   1040       return "Undefined Intent";
   1041     }
   1042 }
   1043 
   1044 static const char *
   1045 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
   1046 {
   1047   switch (ping_colortype)
   1048   {
   1049     case 0:
   1050       return "Grayscale";
   1051 
   1052     case 2:
   1053       return "Truecolor";
   1054 
   1055     case 3:
   1056       return "Indexed";
   1057 
   1058     case 4:
   1059       return "GrayAlpha";
   1060 
   1061     case 6:
   1062       return "RGBA";
   1063 
   1064     default:
   1065       return "UndefinedColorType";
   1066     }
   1067 }
   1068 
   1069 #endif /* PNG_LIBPNG_VER > 10011 */
   1070 #endif /* MAGICKCORE_PNG_DELEGATE */
   1071 
   1072 /*
   1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1075 %                                                                             %
   1076 %                                                                             %
   1077 %                                                                             %
   1078 %   I s M N G                                                                 %
   1079 %                                                                             %
   1080 %                                                                             %
   1081 %                                                                             %
   1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1083 %
   1084 %  IsMNG() returns MagickTrue if the image format type, identified by the
   1085 %  magick string, is MNG.
   1086 %
   1087 %  The format of the IsMNG method is:
   1088 %
   1089 %      MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
   1090 %
   1091 %  A description of each parameter follows:
   1092 %
   1093 %    o magick: compare image format pattern against these bytes.
   1094 %
   1095 %    o length: Specifies the length of the magick string.
   1096 %
   1097 %
   1098 */
   1099 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
   1100 {
   1101   if (length < 8)
   1102     return(MagickFalse);
   1103 
   1104   if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
   1105     return(MagickTrue);
   1106 
   1107   return(MagickFalse);
   1108 }
   1109 
   1110 /*
   1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1113 %                                                                             %
   1114 %                                                                             %
   1115 %                                                                             %
   1116 %   I s J N G                                                                 %
   1117 %                                                                             %
   1118 %                                                                             %
   1119 %                                                                             %
   1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1121 %
   1122 %  IsJNG() returns MagickTrue if the image format type, identified by the
   1123 %  magick string, is JNG.
   1124 %
   1125 %  The format of the IsJNG method is:
   1126 %
   1127 %      MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
   1128 %
   1129 %  A description of each parameter follows:
   1130 %
   1131 %    o magick: compare image format pattern against these bytes.
   1132 %
   1133 %    o length: Specifies the length of the magick string.
   1134 %
   1135 %
   1136 */
   1137 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
   1138 {
   1139   if (length < 8)
   1140     return(MagickFalse);
   1141 
   1142   if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
   1143     return(MagickTrue);
   1144 
   1145   return(MagickFalse);
   1146 }
   1147 
   1148 /*
   1150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1151 %                                                                             %
   1152 %                                                                             %
   1153 %                                                                             %
   1154 %   I s P N G                                                                 %
   1155 %                                                                             %
   1156 %                                                                             %
   1157 %                                                                             %
   1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1159 %
   1160 %  IsPNG() returns MagickTrue if the image format type, identified by the
   1161 %  magick string, is PNG.
   1162 %
   1163 %  The format of the IsPNG method is:
   1164 %
   1165 %      MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
   1166 %
   1167 %  A description of each parameter follows:
   1168 %
   1169 %    o magick: compare image format pattern against these bytes.
   1170 %
   1171 %    o length: Specifies the length of the magick string.
   1172 %
   1173 */
   1174 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
   1175 {
   1176   if (length < 8)
   1177     return(MagickFalse);
   1178 
   1179   if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
   1180     return(MagickTrue);
   1181 
   1182   return(MagickFalse);
   1183 }
   1184 
   1185 #if defined(MAGICKCORE_PNG_DELEGATE)
   1187 #if defined(__cplusplus) || defined(c_plusplus)
   1188 extern "C" {
   1189 #endif
   1190 
   1191 #if (PNG_LIBPNG_VER > 10011)
   1192 static size_t WriteBlobMSBULong(Image *image,const size_t value)
   1193 {
   1194   unsigned char
   1195     buffer[4];
   1196 
   1197   assert(image != (Image *) NULL);
   1198   assert(image->signature == MagickCoreSignature);
   1199   buffer[0]=(unsigned char) (value >> 24);
   1200   buffer[1]=(unsigned char) (value >> 16);
   1201   buffer[2]=(unsigned char) (value >> 8);
   1202   buffer[3]=(unsigned char) value;
   1203   return((size_t) WriteBlob(image,4,buffer));
   1204 }
   1205 
   1206 static void PNGLong(png_bytep p,png_uint_32 value)
   1207 {
   1208   *p++=(png_byte) ((value >> 24) & 0xff);
   1209   *p++=(png_byte) ((value >> 16) & 0xff);
   1210   *p++=(png_byte) ((value >> 8) & 0xff);
   1211   *p++=(png_byte) (value & 0xff);
   1212 }
   1213 
   1214 #if defined(JNG_SUPPORTED)
   1215 static void PNGsLong(png_bytep p,png_int_32 value)
   1216 {
   1217   *p++=(png_byte) ((value >> 24) & 0xff);
   1218   *p++=(png_byte) ((value >> 16) & 0xff);
   1219   *p++=(png_byte) ((value >> 8) & 0xff);
   1220   *p++=(png_byte) (value & 0xff);
   1221 }
   1222 #endif
   1223 
   1224 static void PNGShort(png_bytep p,png_uint_16 value)
   1225 {
   1226   *p++=(png_byte) ((value >> 8) & 0xff);
   1227   *p++=(png_byte) (value & 0xff);
   1228 }
   1229 
   1230 static void PNGType(png_bytep p,const png_byte *type)
   1231 {
   1232   (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
   1233 }
   1234 
   1235 static void LogPNGChunk(MagickBooleanType logging, const png_byte *type,
   1236    size_t length)
   1237 {
   1238   if (logging != MagickFalse)
   1239     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1240       "  Writing %c%c%c%c chunk, length: %.20g",
   1241       type[0],type[1],type[2],type[3],(double) length);
   1242 }
   1243 #endif /* PNG_LIBPNG_VER > 10011 */
   1244 
   1245 #if defined(__cplusplus) || defined(c_plusplus)
   1246 }
   1247 #endif
   1248 
   1249 #if PNG_LIBPNG_VER > 10011
   1250 /*
   1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1252 %                                                                             %
   1253 %                                                                             %
   1254 %                                                                             %
   1255 %   R e a d P N G I m a g e                                                   %
   1256 %                                                                             %
   1257 %                                                                             %
   1258 %                                                                             %
   1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1260 %
   1261 %  ReadPNGImage() reads a Portable Network Graphics (PNG) or
   1262 %  Multiple-image Network Graphics (MNG) image file and returns it.  It
   1263 %  allocates the memory necessary for the new Image structure and returns a
   1264 %  pointer to the new image or set of images.
   1265 %
   1266 %  MNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   1267 %
   1268 %  The format of the ReadPNGImage method is:
   1269 %
   1270 %      Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   1271 %
   1272 %  A description of each parameter follows:
   1273 %
   1274 %    o image_info: the image info.
   1275 %
   1276 %    o exception: return any errors or warnings in this structure.
   1277 %
   1278 %  To do, more or less in chronological order (as of version 5.5.2,
   1279 %   November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
   1280 %
   1281 %    Get 16-bit cheap transparency working.
   1282 %
   1283 %    (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
   1284 %
   1285 %    Preserve all unknown and not-yet-handled known chunks found in input
   1286 %    PNG file and copy them into output PNG files according to the PNG
   1287 %    copying rules.
   1288 %
   1289 %    (At this point, PNG encoding should be in full MNG compliance)
   1290 %
   1291 %    Provide options for choice of background to use when the MNG BACK
   1292 %    chunk is not present or is not mandatory (i.e., leave transparent,
   1293 %    user specified, MNG BACK, PNG bKGD)
   1294 %
   1295 %    Implement LOOP/ENDL [done, but could do discretionary loops more
   1296 %    efficiently by linking in the duplicate frames.].
   1297 %
   1298 %    Decode and act on the MHDR simplicity profile (offer option to reject
   1299 %    files or attempt to process them anyway when the profile isn't LC or VLC).
   1300 %
   1301 %    Upgrade to full MNG without Delta-PNG.
   1302 %
   1303 %        o  BACK [done a while ago except for background image ID]
   1304 %        o  MOVE [done 15 May 1999]
   1305 %        o  CLIP [done 15 May 1999]
   1306 %        o  DISC [done 19 May 1999]
   1307 %        o  SAVE [partially done 19 May 1999 (marks objects frozen)]
   1308 %        o  SEEK [partially done 19 May 1999 (discard function only)]
   1309 %        o  SHOW
   1310 %        o  PAST
   1311 %        o  BASI
   1312 %        o  MNG-level tEXt/iTXt/zTXt
   1313 %        o  pHYg
   1314 %        o  pHYs
   1315 %        o  sBIT
   1316 %        o  bKGD
   1317 %        o  iTXt (wait for libpng implementation).
   1318 %
   1319 %    Use the scene signature to discover when an identical scene is
   1320 %    being reused, and just point to the original image->exception instead
   1321 %    of storing another set of pixels.  This not specific to MNG
   1322 %    but could be applied generally.
   1323 %
   1324 %    Upgrade to full MNG with Delta-PNG.
   1325 %
   1326 %    JNG tEXt/iTXt/zTXt
   1327 %
   1328 %    We will not attempt to read files containing the CgBI chunk.
   1329 %    They are really Xcode files meant for display on the iPhone.
   1330 %    These are not valid PNG files and it is impossible to recover
   1331 %    the original PNG from files that have been converted to Xcode-PNG,
   1332 %    since irretrievable loss of color data has occurred due to the
   1333 %    use of premultiplied alpha.
   1334 */
   1335 
   1336 #if defined(__cplusplus) || defined(c_plusplus)
   1337 extern "C" {
   1338 #endif
   1339 
   1340 /*
   1341   This the function that does the actual reading of data.  It is
   1342   the same as the one supplied in libpng, except that it receives the
   1343   datastream from the ReadBlob() function instead of standard input.
   1344 */
   1345 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
   1346 {
   1347   Image
   1348     *image;
   1349 
   1350   image=(Image *) png_get_io_ptr(png_ptr);
   1351   if (length != 0)
   1352     {
   1353       png_size_t
   1354         check;
   1355 
   1356       check=(png_size_t) ReadBlob(image,(size_t) length,data);
   1357       if (check != length)
   1358         {
   1359           char
   1360             msg[MagickPathExtent];
   1361 
   1362           (void) FormatLocaleString(msg,MagickPathExtent,
   1363             "Expected %.20g bytes; found %.20g bytes",(double) length,
   1364             (double) check);
   1365           png_warning(png_ptr,msg);
   1366           png_error(png_ptr,"Read Exception");
   1367         }
   1368     }
   1369 }
   1370 
   1371 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
   1372     !defined(PNG_MNG_FEATURES_SUPPORTED)
   1373 /* We use mng_get_data() instead of png_get_data() if we have a libpng
   1374  * older than libpng-1.0.3a, which was the first to allow the empty
   1375  * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
   1376  * ifdef'ed out.  Earlier versions would crash if the bKGD chunk was
   1377  * encountered after an empty PLTE, so we have to look ahead for bKGD
   1378  * chunks and remove them from the datastream that is passed to libpng,
   1379  * and store their contents for later use.
   1380  */
   1381 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
   1382 {
   1383   MngInfo
   1384     *mng_info;
   1385 
   1386   Image
   1387     *image;
   1388 
   1389   png_size_t
   1390     check;
   1391 
   1392   register ssize_t
   1393     i;
   1394 
   1395   i=0;
   1396   mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
   1397   image=(Image *) mng_info->image;
   1398   while (mng_info->bytes_in_read_buffer && length)
   1399   {
   1400     data[i]=mng_info->read_buffer[i];
   1401     mng_info->bytes_in_read_buffer--;
   1402     length--;
   1403     i++;
   1404   }
   1405   if (length != 0)
   1406     {
   1407       check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
   1408 
   1409       if (check != length)
   1410         png_error(png_ptr,"Read Exception");
   1411 
   1412       if (length == 4)
   1413         {
   1414           if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
   1415               (data[3] == 0))
   1416             {
   1417               check=(png_size_t) ReadBlob(image,(size_t) length,
   1418                 (char *) mng_info->read_buffer);
   1419               mng_info->read_buffer[4]=0;
   1420               mng_info->bytes_in_read_buffer=4;
   1421               if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
   1422                 mng_info->found_empty_plte=MagickTrue;
   1423               if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
   1424                 {
   1425                   mng_info->found_empty_plte=MagickFalse;
   1426                   mng_info->have_saved_bkgd_index=MagickFalse;
   1427                 }
   1428             }
   1429 
   1430           if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
   1431               (data[3] == 1))
   1432             {
   1433               check=(png_size_t) ReadBlob(image,(size_t) length,
   1434                 (char *) mng_info->read_buffer);
   1435               mng_info->read_buffer[4]=0;
   1436               mng_info->bytes_in_read_buffer=4;
   1437               if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
   1438                 if (mng_info->found_empty_plte)
   1439                   {
   1440                     /*
   1441                       Skip the bKGD data byte and CRC.
   1442                     */
   1443                     check=(png_size_t)
   1444                       ReadBlob(image,5,(char *) mng_info->read_buffer);
   1445                     check=(png_size_t) ReadBlob(image,(size_t) length,
   1446                       (char *) mng_info->read_buffer);
   1447                     mng_info->saved_bkgd_index=mng_info->read_buffer[0];
   1448                     mng_info->have_saved_bkgd_index=MagickTrue;
   1449                     mng_info->bytes_in_read_buffer=0;
   1450                   }
   1451             }
   1452         }
   1453     }
   1454 }
   1455 #endif
   1456 
   1457 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
   1458 {
   1459   Image
   1460     *image;
   1461 
   1462   image=(Image *) png_get_io_ptr(png_ptr);
   1463   if (length != 0)
   1464     {
   1465       png_size_t
   1466         check;
   1467 
   1468       check=(png_size_t) WriteBlob(image,(size_t) length,data);
   1469 
   1470       if (check != length)
   1471         png_error(png_ptr,"WriteBlob Failed");
   1472     }
   1473 }
   1474 
   1475 static void png_flush_data(png_structp png_ptr)
   1476 {
   1477   (void) png_ptr;
   1478 }
   1479 
   1480 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
   1481 static int PalettesAreEqual(Image *a,Image *b)
   1482 {
   1483   ssize_t
   1484     i;
   1485 
   1486   if ((a == (Image *) NULL) || (b == (Image *) NULL))
   1487     return((int) MagickFalse);
   1488 
   1489   if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
   1490     return((int) MagickFalse);
   1491 
   1492   if (a->colors != b->colors)
   1493     return((int) MagickFalse);
   1494 
   1495   for (i=0; i < (ssize_t) a->colors; i++)
   1496   {
   1497     if ((a->colormap[i].red != b->colormap[i].red) ||
   1498         (a->colormap[i].green != b->colormap[i].green) ||
   1499         (a->colormap[i].blue != b->colormap[i].blue))
   1500       return((int) MagickFalse);
   1501   }
   1502 
   1503   return((int) MagickTrue);
   1504 }
   1505 #endif
   1506 
   1507 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
   1508 {
   1509   if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
   1510       mng_info->exists[i] && !mng_info->frozen[i])
   1511     {
   1512 #ifdef MNG_OBJECT_BUFFERS
   1513       if (mng_info->ob[i] != (MngBuffer *) NULL)
   1514         {
   1515           if (mng_info->ob[i]->reference_count > 0)
   1516             mng_info->ob[i]->reference_count--;
   1517 
   1518           if (mng_info->ob[i]->reference_count == 0)
   1519             {
   1520               if (mng_info->ob[i]->image != (Image *) NULL)
   1521                 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
   1522 
   1523               mng_info->ob[i]=DestroyString(mng_info->ob[i]);
   1524             }
   1525         }
   1526       mng_info->ob[i]=(MngBuffer *) NULL;
   1527 #endif
   1528       mng_info->exists[i]=MagickFalse;
   1529       mng_info->invisible[i]=MagickFalse;
   1530       mng_info->viewable[i]=MagickFalse;
   1531       mng_info->frozen[i]=MagickFalse;
   1532       mng_info->x_off[i]=0;
   1533       mng_info->y_off[i]=0;
   1534       mng_info->object_clip[i].left=0;
   1535       mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
   1536       mng_info->object_clip[i].top=0;
   1537       mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
   1538     }
   1539 }
   1540 
   1541 static void MngInfoFreeStruct(MngInfo *mng_info,
   1542     MagickBooleanType *have_mng_structure)
   1543 {
   1544   if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
   1545     {
   1546       register ssize_t
   1547         i;
   1548 
   1549       for (i=1; i < MNG_MAX_OBJECTS; i++)
   1550         MngInfoDiscardObject(mng_info,i);
   1551 
   1552       if (mng_info->global_plte != (png_colorp) NULL)
   1553         mng_info->global_plte=(png_colorp)
   1554           RelinquishMagickMemory(mng_info->global_plte);
   1555 
   1556       mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
   1557       *have_mng_structure=MagickFalse;
   1558     }
   1559 }
   1560 
   1561 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
   1562 {
   1563   MngBox
   1564     box;
   1565 
   1566   box=box1;
   1567   if (box.left < box2.left)
   1568     box.left=box2.left;
   1569 
   1570   if (box.top < box2.top)
   1571     box.top=box2.top;
   1572 
   1573   if (box.right > box2.right)
   1574     box.right=box2.right;
   1575 
   1576   if (box.bottom > box2.bottom)
   1577     box.bottom=box2.bottom;
   1578 
   1579   return box;
   1580 }
   1581 
   1582 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
   1583 {
   1584    MngBox
   1585       box;
   1586 
   1587   /*
   1588     Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
   1589   */
   1590   box.left=(ssize_t) ((p[0]  << 24) | (p[1]  << 16) | (p[2]  << 8) | p[3]);
   1591   box.right=(ssize_t) ((p[4]  << 24) | (p[5]  << 16) | (p[6]  << 8) | p[7]);
   1592   box.top=(ssize_t) ((p[8]  << 24) | (p[9]  << 16) | (p[10] << 8) | p[11]);
   1593   box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
   1594   if (delta_type != 0)
   1595     {
   1596       box.left+=previous_box.left;
   1597       box.right+=previous_box.right;
   1598       box.top+=previous_box.top;
   1599       box.bottom+=previous_box.bottom;
   1600     }
   1601 
   1602   return(box);
   1603 }
   1604 
   1605 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
   1606   unsigned char *p)
   1607 {
   1608   MngPair
   1609     pair;
   1610   /*
   1611     Read two ssize_ts from CLON, MOVE or PAST chunk
   1612   */
   1613   pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
   1614   pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
   1615 
   1616   if (delta_type != 0)
   1617     {
   1618       pair.a+=previous_pair.a;
   1619       pair.b+=previous_pair.b;
   1620     }
   1621 
   1622   return(pair);
   1623 }
   1624 
   1625 static long mng_get_long(unsigned char *p)
   1626 {
   1627   return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
   1628 }
   1629 
   1630 typedef struct _PNGErrorInfo
   1631 {
   1632   Image
   1633     *image;
   1634 
   1635   ExceptionInfo
   1636     *exception;
   1637 } PNGErrorInfo;
   1638 
   1639 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
   1640 {
   1641   ExceptionInfo
   1642     *exception;
   1643 
   1644   Image
   1645     *image;
   1646 
   1647   PNGErrorInfo
   1648     *error_info;
   1649 
   1650   error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
   1651   image=error_info->image;
   1652   exception=error_info->exception;
   1653 
   1654   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1655     "  libpng-%s error: %s", png_get_libpng_ver(NULL),message);
   1656 
   1657   (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
   1658     "`%s'",image->filename);
   1659 
   1660 #if (PNG_LIBPNG_VER < 10500)
   1661   /* A warning about deprecated use of jmpbuf here is unavoidable if you
   1662    * are building with libpng-1.4.x and can be ignored.
   1663    */
   1664   longjmp(ping->jmpbuf,1);
   1665 #else
   1666   png_longjmp(ping,1);
   1667 #endif
   1668 }
   1669 
   1670 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
   1671 {
   1672   ExceptionInfo
   1673     *exception;
   1674 
   1675   Image
   1676     *image;
   1677 
   1678   PNGErrorInfo
   1679     *error_info;
   1680 
   1681   if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
   1682     png_error(ping, message);
   1683 
   1684   error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
   1685   image=error_info->image;
   1686   exception=error_info->exception;
   1687   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1688     "  libpng-%s warning: %s", png_get_libpng_ver(NULL),message);
   1689 
   1690   (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
   1691     message,"`%s'",image->filename);
   1692 }
   1693 
   1694 #ifdef PNG_USER_MEM_SUPPORTED
   1695 #if PNG_LIBPNG_VER >= 10400
   1696 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
   1697 #else
   1698 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
   1699 #endif
   1700 {
   1701   (void) png_ptr;
   1702   return((png_voidp) AcquireMagickMemory((size_t) size));
   1703 }
   1704 
   1705 /*
   1706   Free a pointer.  It is removed from the list at the same time.
   1707 */
   1708 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
   1709 {
   1710   (void) png_ptr;
   1711   ptr=RelinquishMagickMemory(ptr);
   1712   return((png_free_ptr) NULL);
   1713 }
   1714 #endif
   1715 
   1716 #if defined(__cplusplus) || defined(c_plusplus)
   1717 }
   1718 #endif
   1719 
   1720 static int
   1721 Magick_png_read_raw_profile(png_struct *ping,Image *image,
   1722    const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
   1723 {
   1724   register ssize_t
   1725     i;
   1726 
   1727   register unsigned char
   1728     *dp;
   1729 
   1730   register png_charp
   1731     sp;
   1732 
   1733   png_uint_32
   1734     length,
   1735     nibbles;
   1736 
   1737   StringInfo
   1738     *profile;
   1739 
   1740   const unsigned char
   1741     unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
   1742                  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
   1743                  0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
   1744                  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
   1745                  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
   1746                  13,14,15};
   1747 
   1748   sp=text[ii].text+1;
   1749   /* look for newline */
   1750   while (*sp != '\n')
   1751      sp++;
   1752 
   1753   /* look for length */
   1754   while (*sp == '\0' || *sp == ' ' || *sp == '\n')
   1755      sp++;
   1756 
   1757   length=(png_uint_32) StringToLong(sp);
   1758 
   1759   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1760        "      length: %lu",(unsigned long) length);
   1761 
   1762   while (*sp != ' ' && *sp != '\n')
   1763      sp++;
   1764 
   1765   /* allocate space */
   1766   if (length == 0)
   1767   {
   1768     png_warning(ping,"invalid profile length");
   1769     return(MagickFalse);
   1770   }
   1771 
   1772   profile=BlobToStringInfo((const void *) NULL,length);
   1773 
   1774   if (profile == (StringInfo *) NULL)
   1775   {
   1776     png_warning(ping, "unable to copy profile");
   1777     return(MagickFalse);
   1778   }
   1779 
   1780   /* copy profile, skipping white space and column 1 "=" signs */
   1781   dp=GetStringInfoDatum(profile);
   1782   nibbles=length*2;
   1783 
   1784   for (i=0; i < (ssize_t) nibbles; i++)
   1785   {
   1786     while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
   1787     {
   1788       if (*sp == '\0')
   1789         {
   1790           png_warning(ping, "ran out of profile data");
   1791           profile=DestroyStringInfo(profile);
   1792           return(MagickFalse);
   1793         }
   1794       sp++;
   1795     }
   1796 
   1797     if (i%2 == 0)
   1798       *dp=(unsigned char) (16*unhex[(int) *sp++]);
   1799 
   1800     else
   1801       (*dp++)+=unhex[(int) *sp++];
   1802   }
   1803   /*
   1804     We have already read "Raw profile type.
   1805   */
   1806   (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
   1807   profile=DestroyStringInfo(profile);
   1808 
   1809   if (image_info->verbose)
   1810     (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
   1811 
   1812   return MagickTrue;
   1813 }
   1814 
   1815 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   1816 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
   1817 {
   1818   Image
   1819     *image;
   1820 
   1821 
   1822   /* The unknown chunk structure contains the chunk data:
   1823      png_byte name[5];
   1824      png_byte *data;
   1825      png_size_t size;
   1826 
   1827      Note that libpng has already taken care of the CRC handling.
   1828   */
   1829 
   1830   LogMagickEvent(CoderEvent,GetMagickModule(),
   1831      " read_vpag_chunk: found %c%c%c%c chunk",
   1832        chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
   1833 
   1834   if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
   1835       chunk->name[2] != 65 ||chunk-> name[3] != 103)
   1836     return(0); /* Did not recognize */
   1837 
   1838   /* recognized vpAg */
   1839 
   1840   if (chunk->size != 9)
   1841     return(-1); /* Error return */
   1842 
   1843   if (chunk->data[8] != 0)
   1844     return(0);  /* ImageMagick requires pixel units */
   1845 
   1846   image=(Image *) png_get_user_chunk_ptr(ping);
   1847 
   1848   image->page.width=(size_t) ((chunk->data[0] << 24) |
   1849      (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
   1850 
   1851   image->page.height=(size_t) ((chunk->data[4] << 24) |
   1852      (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
   1853 
   1854   /* Return one of the following: */
   1855      /* return(-n);  chunk had an error */
   1856      /* return(0);  did not recognize */
   1857      /* return(n);  success */
   1858 
   1859   return(1);
   1860 
   1861 }
   1862 #endif
   1863 
   1864 #if defined(PNG_tIME_SUPPORTED)
   1865 static void read_tIME_chunk(Image *image,png_struct *ping,png_info *info,
   1866   ExceptionInfo *exception)
   1867 {
   1868   png_timep
   1869     time;
   1870 
   1871   if (png_get_tIME(ping,info,&time))
   1872     {
   1873       char
   1874         timestamp[21];
   1875 
   1876       FormatLocaleString(timestamp,21,"%04d-%02d-%02dT%02d:%02d:%02dZ",
   1877         time->year,time->month,time->day,time->hour,time->minute,time->second);
   1878       SetImageProperty(image,"png:tIME",timestamp,exception);
   1879     }
   1880 }
   1881 #endif
   1882 
   1883 /*
   1884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1885 %                                                                             %
   1886 %                                                                             %
   1887 %                                                                             %
   1888 %   R e a d O n e P N G I m a g e                                             %
   1889 %                                                                             %
   1890 %                                                                             %
   1891 %                                                                             %
   1892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1893 %
   1894 %  ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
   1895 %  (minus the 8-byte signature)  and returns it.  It allocates the memory
   1896 %  necessary for the new Image structure and returns a pointer to the new
   1897 %  image.
   1898 %
   1899 %  The format of the ReadOnePNGImage method is:
   1900 %
   1901 %      Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
   1902 %         ExceptionInfo *exception)
   1903 %
   1904 %  A description of each parameter follows:
   1905 %
   1906 %    o mng_info: Specifies a pointer to a MngInfo structure.
   1907 %
   1908 %    o image_info: the image info.
   1909 %
   1910 %    o exception: return any errors or warnings in this structure.
   1911 %
   1912 */
   1913 static Image *ReadOnePNGImage(MngInfo *mng_info,
   1914     const ImageInfo *image_info, ExceptionInfo *exception)
   1915 {
   1916   /* Read one PNG image */
   1917 
   1918   /* To do: Read the tEXt/Creation Time chunk into the date:create property */
   1919 
   1920   Image
   1921     *image;
   1922 
   1923   char
   1924     im_vers[32],
   1925     libpng_runv[32],
   1926     libpng_vers[32],
   1927     zlib_runv[32],
   1928     zlib_vers[32];
   1929 
   1930   int
   1931     intent, /* "PNG Rendering intent", which is ICC intent + 1 */
   1932     num_raw_profiles,
   1933     num_text,
   1934     num_text_total,
   1935     num_passes,
   1936     number_colors,
   1937     pass,
   1938     ping_bit_depth,
   1939     ping_color_type,
   1940     ping_file_depth,
   1941     ping_interlace_method,
   1942     ping_compression_method,
   1943     ping_filter_method,
   1944     ping_num_trans,
   1945     unit_type;
   1946 
   1947   double
   1948     file_gamma;
   1949 
   1950   MagickBooleanType
   1951     logging,
   1952     ping_found_cHRM,
   1953     ping_found_gAMA,
   1954     ping_found_iCCP,
   1955     ping_found_sRGB,
   1956     ping_found_sRGB_cHRM,
   1957     ping_preserve_iCCP,
   1958     status;
   1959 
   1960   MemoryInfo
   1961     *volatile pixel_info;
   1962 
   1963   PixelInfo
   1964     transparent_color;
   1965 
   1966   PNGErrorInfo
   1967     error_info;
   1968 
   1969   png_bytep
   1970      ping_trans_alpha;
   1971 
   1972   png_color_16p
   1973      ping_background,
   1974      ping_trans_color;
   1975 
   1976   png_info
   1977     *end_info,
   1978     *ping_info;
   1979 
   1980   png_struct
   1981     *ping;
   1982 
   1983   png_textp
   1984     text;
   1985 
   1986   png_uint_32
   1987     ping_height,
   1988     ping_width,
   1989     x_resolution,
   1990     y_resolution;
   1991 
   1992   QuantumInfo
   1993     *quantum_info;
   1994 
   1995   ssize_t
   1996     ping_rowbytes,
   1997     y;
   1998 
   1999   register unsigned char
   2000     *p;
   2001 
   2002   register ssize_t
   2003     i,
   2004     x;
   2005 
   2006   register Quantum
   2007     *q;
   2008 
   2009   size_t
   2010     length,
   2011     row_offset;
   2012 
   2013   ssize_t
   2014     j;
   2015 
   2016   unsigned char
   2017     *ping_pixels;
   2018 
   2019 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
   2020   png_byte unused_chunks[]=
   2021   {
   2022     104,  73,  83,  84, (png_byte) '\0',   /* hIST */
   2023     105,  84,  88, 116, (png_byte) '\0',   /* iTXt */
   2024     112,  67,  65,  76, (png_byte) '\0',   /* pCAL */
   2025     115,  67,  65,  76, (png_byte) '\0',   /* sCAL */
   2026     115,  80,  76,  84, (png_byte) '\0',   /* sPLT */
   2027 #if !defined(PNG_tIME_SUPPORTED)
   2028     116,  73,  77,  69, (png_byte) '\0',   /* tIME */
   2029 #endif
   2030 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
   2031                           /* ignore the APNG chunks */
   2032      97,  99,  84,  76, (png_byte) '\0',   /* acTL */
   2033     102,  99,  84,  76, (png_byte) '\0',   /* fcTL */
   2034     102, 100,  65,  84, (png_byte) '\0',   /* fdAT */
   2035 #endif
   2036   };
   2037 #endif
   2038 
   2039   /* Define these outside of the following "if logging()" block so they will
   2040    * show in debuggers.
   2041    */
   2042   *im_vers='\0';
   2043   (void) ConcatenateMagickString(im_vers,
   2044          MagickLibVersionText,32);
   2045   (void) ConcatenateMagickString(im_vers,
   2046          MagickLibAddendum,32);
   2047 
   2048   *libpng_vers='\0';
   2049   (void) ConcatenateMagickString(libpng_vers,
   2050          PNG_LIBPNG_VER_STRING,32);
   2051   *libpng_runv='\0';
   2052   (void) ConcatenateMagickString(libpng_runv,
   2053          png_get_libpng_ver(NULL),32);
   2054 
   2055   *zlib_vers='\0';
   2056   (void) ConcatenateMagickString(zlib_vers,
   2057          ZLIB_VERSION,32);
   2058   *zlib_runv='\0';
   2059   (void) ConcatenateMagickString(zlib_runv,
   2060          zlib_version,32);
   2061 
   2062   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
   2063        "  Enter ReadOnePNGImage()\n"
   2064        "    IM version     = %s\n"
   2065        "    Libpng version = %s",
   2066        im_vers, libpng_vers);
   2067 
   2068   if (logging != MagickFalse)
   2069   {
   2070     if (LocaleCompare(libpng_vers,libpng_runv) != 0)
   2071     {
   2072     LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
   2073         libpng_runv);
   2074     }
   2075     LogMagickEvent(CoderEvent,GetMagickModule(),"    Zlib version   = %s",
   2076         zlib_vers);
   2077     if (LocaleCompare(zlib_vers,zlib_runv) != 0)
   2078     {
   2079     LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
   2080         zlib_runv);
   2081     }
   2082   }
   2083 
   2084 #if (PNG_LIBPNG_VER < 10200)
   2085   if (image_info->verbose)
   2086     printf("Your PNG library (libpng-%s) is rather old.\n",
   2087        PNG_LIBPNG_VER_STRING);
   2088 #endif
   2089 
   2090 #if (PNG_LIBPNG_VER >= 10400)
   2091 #  ifndef  PNG_TRANSFORM_GRAY_TO_RGB    /* Added at libpng-1.4.0beta67 */
   2092   if (image_info->verbose)
   2093     {
   2094       printf("Your PNG library (libpng-%s) is an old beta version.\n",
   2095            PNG_LIBPNG_VER_STRING);
   2096       printf("Please update it.\n");
   2097     }
   2098 #  endif
   2099 #endif
   2100 
   2101 
   2102   quantum_info = (QuantumInfo *) NULL;
   2103   image=mng_info->image;
   2104 
   2105   if (logging != MagickFalse)
   2106   {
   2107     (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   2108        "    Before reading:\n"
   2109        "      image->alpha_trait=%d"
   2110        "      image->rendering_intent=%d\n"
   2111        "      image->colorspace=%d\n"
   2112        "      image->gamma=%f",
   2113        (int) image->alpha_trait, (int) image->rendering_intent,
   2114        (int) image->colorspace, image->gamma);
   2115   }
   2116   intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
   2117 
   2118   /* Set to an out-of-range color unless tRNS chunk is present */
   2119   transparent_color.red=65537;
   2120   transparent_color.green=65537;
   2121   transparent_color.blue=65537;
   2122   transparent_color.alpha=65537;
   2123 
   2124   number_colors=0;
   2125   num_text = 0;
   2126   num_text_total = 0;
   2127   num_raw_profiles = 0;
   2128 
   2129   ping_found_cHRM = MagickFalse;
   2130   ping_found_gAMA = MagickFalse;
   2131   ping_found_iCCP = MagickFalse;
   2132   ping_found_sRGB = MagickFalse;
   2133   ping_found_sRGB_cHRM = MagickFalse;
   2134   ping_preserve_iCCP = MagickFalse;
   2135 
   2136 
   2137   /*
   2138     Allocate the PNG structures
   2139   */
   2140 #ifdef PNG_USER_MEM_SUPPORTED
   2141  error_info.image=image;
   2142  error_info.exception=exception;
   2143  ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
   2144    MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
   2145    (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
   2146 #else
   2147   ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
   2148     MagickPNGErrorHandler,MagickPNGWarningHandler);
   2149 #endif
   2150   if (ping == (png_struct *) NULL)
   2151     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   2152 
   2153   ping_info=png_create_info_struct(ping);
   2154 
   2155   if (ping_info == (png_info *) NULL)
   2156     {
   2157       png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
   2158       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   2159     }
   2160 
   2161   end_info=png_create_info_struct(ping);
   2162 
   2163   if (end_info == (png_info *) NULL)
   2164     {
   2165       png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
   2166       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   2167     }
   2168 
   2169   pixel_info=(MemoryInfo *) NULL;
   2170 
   2171   if (setjmp(png_jmpbuf(ping)))
   2172     {
   2173       /*
   2174         PNG image is corrupt.
   2175       */
   2176       png_destroy_read_struct(&ping,&ping_info,&end_info);
   2177 
   2178 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   2179       UnlockSemaphoreInfo(ping_semaphore);
   2180 #endif
   2181 
   2182       if (pixel_info != (MemoryInfo *) NULL)
   2183         pixel_info=RelinquishVirtualMemory(pixel_info);
   2184 
   2185       if (logging != MagickFalse)
   2186         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2187           "  exit ReadOnePNGImage() with error.");
   2188 
   2189       if (image != (Image *) NULL)
   2190         {
   2191           const char
   2192             *option;
   2193 
   2194           option=GetImageOption(image_info,"png:preserve-corrupt-image");
   2195           if (IsStringTrue(option) == MagickFalse)
   2196             image->columns=0;
   2197         }
   2198 
   2199       return(GetFirstImageInList(image));
   2200     }
   2201 
   2202   /* {  For navigation to end of SETJMP-protected block.  Within this
   2203    *    block, use png_error() instead of Throwing an Exception, to ensure
   2204    *    that libpng is able to clean up, and that the semaphore is unlocked.
   2205    */
   2206 
   2207 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   2208   LockSemaphoreInfo(ping_semaphore);
   2209 #endif
   2210 
   2211 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
   2212   /* Allow benign errors */
   2213   png_set_benign_errors(ping, 1);
   2214 #endif
   2215 
   2216 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
   2217   /* Reject images with too many rows or columns */
   2218   png_set_user_limits(ping,
   2219     (png_uint_32) MagickMin(0x7fffffffL,
   2220         GetMagickResourceLimit(WidthResource)),
   2221     (png_uint_32) MagickMin(0x7fffffffL,
   2222         GetMagickResourceLimit(HeightResource)));
   2223 #endif /* PNG_SET_USER_LIMITS_SUPPORTED */
   2224 
   2225   /*
   2226     Prepare PNG for reading.
   2227   */
   2228 
   2229   mng_info->image_found++;
   2230   png_set_sig_bytes(ping,8);
   2231 
   2232   if (LocaleCompare(image_info->magick,"MNG") == 0)
   2233     {
   2234 #if defined(PNG_MNG_FEATURES_SUPPORTED)
   2235       (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
   2236       png_set_read_fn(ping,image,png_get_data);
   2237 #else
   2238 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
   2239       png_permit_empty_plte(ping,MagickTrue);
   2240       png_set_read_fn(ping,image,png_get_data);
   2241 #else
   2242       mng_info->image=image;
   2243       mng_info->bytes_in_read_buffer=0;
   2244       mng_info->found_empty_plte=MagickFalse;
   2245       mng_info->have_saved_bkgd_index=MagickFalse;
   2246       png_set_read_fn(ping,mng_info,mng_get_data);
   2247 #endif
   2248 #endif
   2249     }
   2250 
   2251   else
   2252     png_set_read_fn(ping,image,png_get_data);
   2253 
   2254   {
   2255     const char
   2256       *value;
   2257 
   2258     value=GetImageOption(image_info,"profile:skip");
   2259 
   2260     if (IsOptionMember("ICC",value) == MagickFalse)
   2261     {
   2262 
   2263        value=GetImageOption(image_info,"png:preserve-iCCP");
   2264 
   2265        if (value == NULL)
   2266           value=GetImageArtifact(image,"png:preserve-iCCP");
   2267 
   2268        if (value != NULL)
   2269           ping_preserve_iCCP=MagickTrue;
   2270 
   2271 #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
   2272        /* Don't let libpng check for ICC/sRGB profile because we're going
   2273         * to do that anyway.  This feature was added at libpng-1.6.12.
   2274         * If logging, go ahead and check and issue a warning as appropriate.
   2275         */
   2276        if (logging == MagickFalse)
   2277           png_set_option(ping, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
   2278 #endif
   2279     }
   2280 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   2281     else
   2282     {
   2283        png_set_keep_unknown_chunks(ping, 1, mng_iCCP, 1);
   2284     }
   2285 #endif
   2286   }
   2287 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   2288   /* Ignore unused chunks and all unknown chunks except for vpAg */
   2289 #if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
   2290   png_set_keep_unknown_chunks(ping, 2, NULL, 0);
   2291 #else
   2292   png_set_keep_unknown_chunks(ping, 1, NULL, 0);
   2293 #endif
   2294   png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
   2295   png_set_keep_unknown_chunks(ping, 1, unused_chunks,
   2296      (int)sizeof(unused_chunks)/5);
   2297   /* Callback for other unknown chunks */
   2298   png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
   2299 #endif
   2300 
   2301 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
   2302 #  if (PNG_LIBPNG_VER >= 10400)
   2303     /* Limit the size of the chunk storage cache used for sPLT, text,
   2304      * and unknown chunks.
   2305      */
   2306     png_set_chunk_cache_max(ping, 32767);
   2307 #  endif
   2308 #endif
   2309 
   2310 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
   2311     /* Disable new libpng-1.5.10 feature */
   2312     png_set_check_for_invalid_index (ping, 0);
   2313 #endif
   2314 
   2315 #if (PNG_LIBPNG_VER < 10400)
   2316 #  if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
   2317    (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
   2318   /* Disable thread-unsafe features of pnggccrd */
   2319   if (png_access_version_number() >= 10200)
   2320   {
   2321     png_uint_32 mmx_disable_mask=0;
   2322     png_uint_32 asm_flags;
   2323 
   2324     mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
   2325                         | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
   2326                         | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
   2327                         | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
   2328     asm_flags=png_get_asm_flags(ping);
   2329     png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
   2330   }
   2331 #  endif
   2332 #endif
   2333 
   2334   png_read_info(ping,ping_info);
   2335 
   2336   png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
   2337                &ping_bit_depth,&ping_color_type,
   2338                &ping_interlace_method,&ping_compression_method,
   2339                &ping_filter_method);
   2340 
   2341   ping_file_depth = ping_bit_depth;
   2342 
   2343   /* Swap bytes if requested */
   2344   if (ping_file_depth == 16)
   2345   {
   2346      const char
   2347        *value;
   2348 
   2349      value=GetImageOption(image_info,"png:swap-bytes");
   2350 
   2351      if (value == NULL)
   2352         value=GetImageArtifact(image,"png:swap-bytes");
   2353 
   2354      if (value != NULL)
   2355         png_set_swap(ping);
   2356   }
   2357 
   2358   /* Save bit-depth and color-type in case we later want to write a PNG00 */
   2359   {
   2360       char
   2361         msg[MagickPathExtent];
   2362 
   2363       (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_color_type);
   2364       (void) SetImageProperty(image,"png:IHDR.color-type-orig",msg,exception);
   2365 
   2366       (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_bit_depth);
   2367       (void) SetImageProperty(image,"png:IHDR.bit-depth-orig",msg,exception);
   2368   }
   2369 
   2370   (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
   2371                       &ping_trans_color);
   2372 
   2373   (void) png_get_bKGD(ping, ping_info, &ping_background);
   2374 
   2375   if (ping_bit_depth < 8)
   2376     {
   2377        png_set_packing(ping);
   2378        ping_bit_depth = 8;
   2379     }
   2380 
   2381   image->depth=ping_bit_depth;
   2382   image->depth=GetImageQuantumDepth(image,MagickFalse);
   2383   image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
   2384 
   2385   if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
   2386       ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
   2387     {
   2388       image->rendering_intent=UndefinedIntent;
   2389       intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
   2390       (void) ResetMagickMemory(&image->chromaticity,0,
   2391         sizeof(image->chromaticity));
   2392     }
   2393 
   2394   if (logging != MagickFalse)
   2395     {
   2396       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2397         "    PNG width: %.20g, height: %.20g\n"
   2398         "    PNG color_type: %d, bit_depth: %d\n"
   2399         "    PNG compression_method: %d\n"
   2400         "    PNG interlace_method: %d, filter_method: %d",
   2401         (double) ping_width, (double) ping_height,
   2402         ping_color_type, ping_bit_depth,
   2403         ping_compression_method,
   2404         ping_interlace_method,ping_filter_method);
   2405 
   2406     }
   2407 
   2408   if (png_get_valid(ping,ping_info, PNG_INFO_iCCP))
   2409     {
   2410       ping_found_iCCP=MagickTrue;
   2411       if (logging != MagickFalse)
   2412         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2413           "    Found PNG iCCP chunk.");
   2414     }
   2415 
   2416   if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
   2417     {
   2418       ping_found_gAMA=MagickTrue;
   2419       if (logging != MagickFalse)
   2420         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2421           "    Found PNG gAMA chunk.");
   2422     }
   2423 
   2424   if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
   2425     {
   2426       ping_found_cHRM=MagickTrue;
   2427       if (logging != MagickFalse)
   2428         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2429           "    Found PNG cHRM chunk.");
   2430     }
   2431 
   2432   if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info,
   2433       PNG_INFO_sRGB))
   2434     {
   2435       ping_found_sRGB=MagickTrue;
   2436       if (logging != MagickFalse)
   2437         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2438           "    Found PNG sRGB chunk.");
   2439     }
   2440 
   2441 #ifdef PNG_READ_iCCP_SUPPORTED
   2442     if (ping_found_iCCP !=MagickTrue &&
   2443       ping_found_sRGB != MagickTrue &&
   2444       png_get_valid(ping,ping_info, PNG_INFO_iCCP))
   2445     {
   2446       ping_found_iCCP=MagickTrue;
   2447       if (logging != MagickFalse)
   2448         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2449           "    Found PNG iCCP chunk.");
   2450     }
   2451 
   2452   if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
   2453     {
   2454       int
   2455         compression;
   2456 
   2457 #if (PNG_LIBPNG_VER < 10500)
   2458       png_charp
   2459         info;
   2460 #else
   2461       png_bytep
   2462         info;
   2463 #endif
   2464 
   2465       png_charp
   2466         name;
   2467 
   2468       png_uint_32
   2469         profile_length;
   2470 
   2471       (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
   2472         &profile_length);
   2473 
   2474       if (profile_length != 0)
   2475         {
   2476           StringInfo
   2477             *profile;
   2478 
   2479           if (logging != MagickFalse)
   2480             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2481               "    Reading PNG iCCP chunk.");
   2482 
   2483           profile=BlobToStringInfo(info,profile_length);
   2484 
   2485           if (profile == (StringInfo *) NULL)
   2486           {
   2487             png_warning(ping, "ICC profile is NULL");
   2488             profile=DestroyStringInfo(profile);
   2489           }
   2490           else
   2491           {
   2492             if (ping_preserve_iCCP == MagickFalse)
   2493             {
   2494                  int
   2495                    icheck,
   2496                    got_crc=0;
   2497 
   2498 
   2499                  png_uint_32
   2500                    length,
   2501                    profile_crc=0;
   2502 
   2503                  unsigned char
   2504                    *data;
   2505 
   2506                  length=(png_uint_32) GetStringInfoLength(profile);
   2507 
   2508                  for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
   2509                  {
   2510                    if (length == sRGB_info[icheck].len)
   2511                    {
   2512                      if (got_crc == 0)
   2513                      {
   2514                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2515                          "    Got a %lu-byte ICC profile (potentially sRGB)",
   2516                          (unsigned long) length);
   2517 
   2518                        data=GetStringInfoDatum(profile);
   2519                        profile_crc=crc32(0,data,length);
   2520 
   2521                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2522                            "      with crc=%8x",(unsigned int) profile_crc);
   2523                        got_crc++;
   2524                      }
   2525 
   2526                      if (profile_crc == sRGB_info[icheck].crc)
   2527                      {
   2528                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2529                             "      It is sRGB with rendering intent = %s",
   2530                         Magick_RenderingIntentString_from_PNG_RenderingIntent(
   2531                              sRGB_info[icheck].intent));
   2532                         if (image->rendering_intent==UndefinedIntent)
   2533                         {
   2534                           image->rendering_intent=
   2535                           Magick_RenderingIntent_from_PNG_RenderingIntent(
   2536                              sRGB_info[icheck].intent);
   2537                         }
   2538                         break;
   2539                      }
   2540                    }
   2541                  }
   2542                  if (sRGB_info[icheck].len == 0)
   2543                  {
   2544                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2545                         "    Got a %lu-byte ICC profile not recognized as sRGB",
   2546                         (unsigned long) length);
   2547                     (void) SetImageProfile(image,"icc",profile,exception);
   2548                  }
   2549             }
   2550             else /* Preserve-iCCP */
   2551             {
   2552                     (void) SetImageProfile(image,"icc",profile,exception);
   2553             }
   2554 
   2555             profile=DestroyStringInfo(profile);
   2556           }
   2557       }
   2558     }
   2559 #endif
   2560 
   2561 #if defined(PNG_READ_sRGB_SUPPORTED)
   2562   {
   2563     if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info,
   2564         PNG_INFO_sRGB))
   2565     {
   2566       if (png_get_sRGB(ping,ping_info,&intent))
   2567       {
   2568         if (image->rendering_intent == UndefinedIntent)
   2569           image->rendering_intent=
   2570              Magick_RenderingIntent_from_PNG_RenderingIntent (intent);
   2571 
   2572         if (logging != MagickFalse)
   2573           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2574             "    Reading PNG sRGB chunk: rendering_intent: %d",intent);
   2575       }
   2576     }
   2577 
   2578     else if (mng_info->have_global_srgb)
   2579       {
   2580         if (image->rendering_intent == UndefinedIntent)
   2581           image->rendering_intent=
   2582             Magick_RenderingIntent_from_PNG_RenderingIntent
   2583             (mng_info->global_srgb_intent);
   2584       }
   2585   }
   2586 #endif
   2587 
   2588 
   2589   {
   2590      if (!png_get_gAMA(ping,ping_info,&file_gamma))
   2591        if (mng_info->have_global_gama)
   2592          png_set_gAMA(ping,ping_info,mng_info->global_gamma);
   2593 
   2594      if (png_get_gAMA(ping,ping_info,&file_gamma))
   2595        {
   2596          image->gamma=(float) file_gamma;
   2597          if (logging != MagickFalse)
   2598            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2599              "    Reading PNG gAMA chunk: gamma: %f",file_gamma);
   2600        }
   2601   }
   2602 
   2603   if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
   2604     {
   2605       if (mng_info->have_global_chrm != MagickFalse)
   2606         {
   2607           (void) png_set_cHRM(ping,ping_info,
   2608             mng_info->global_chrm.white_point.x,
   2609             mng_info->global_chrm.white_point.y,
   2610             mng_info->global_chrm.red_primary.x,
   2611             mng_info->global_chrm.red_primary.y,
   2612             mng_info->global_chrm.green_primary.x,
   2613             mng_info->global_chrm.green_primary.y,
   2614             mng_info->global_chrm.blue_primary.x,
   2615             mng_info->global_chrm.blue_primary.y);
   2616         }
   2617     }
   2618 
   2619   if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
   2620     {
   2621       (void) png_get_cHRM(ping,ping_info,
   2622         &image->chromaticity.white_point.x,
   2623         &image->chromaticity.white_point.y,
   2624         &image->chromaticity.red_primary.x,
   2625         &image->chromaticity.red_primary.y,
   2626         &image->chromaticity.green_primary.x,
   2627         &image->chromaticity.green_primary.y,
   2628         &image->chromaticity.blue_primary.x,
   2629         &image->chromaticity.blue_primary.y);
   2630 
   2631        ping_found_cHRM=MagickTrue;
   2632 
   2633        if (image->chromaticity.red_primary.x>0.6399f &&
   2634            image->chromaticity.red_primary.x<0.6401f &&
   2635            image->chromaticity.red_primary.y>0.3299f &&
   2636            image->chromaticity.red_primary.y<0.3301f &&
   2637            image->chromaticity.green_primary.x>0.2999f &&
   2638            image->chromaticity.green_primary.x<0.3001f &&
   2639            image->chromaticity.green_primary.y>0.5999f &&
   2640            image->chromaticity.green_primary.y<0.6001f &&
   2641            image->chromaticity.blue_primary.x>0.1499f &&
   2642            image->chromaticity.blue_primary.x<0.1501f &&
   2643            image->chromaticity.blue_primary.y>0.0599f &&
   2644            image->chromaticity.blue_primary.y<0.0601f &&
   2645            image->chromaticity.white_point.x>0.3126f &&
   2646            image->chromaticity.white_point.x<0.3128f &&
   2647            image->chromaticity.white_point.y>0.3289f &&
   2648            image->chromaticity.white_point.y<0.3291f)
   2649           ping_found_sRGB_cHRM=MagickTrue;
   2650     }
   2651 
   2652   if (image->rendering_intent != UndefinedIntent)
   2653     {
   2654       if (ping_found_sRGB != MagickTrue &&
   2655           (ping_found_gAMA != MagickTrue ||
   2656           (image->gamma > .45 && image->gamma < .46)) &&
   2657           (ping_found_cHRM != MagickTrue ||
   2658           ping_found_sRGB_cHRM != MagickFalse) &&
   2659           ping_found_iCCP != MagickTrue)
   2660       {
   2661          png_set_sRGB(ping,ping_info,
   2662             Magick_RenderingIntent_to_PNG_RenderingIntent
   2663             (image->rendering_intent));
   2664          file_gamma=1.000f/2.200f;
   2665          ping_found_sRGB=MagickTrue;
   2666          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2667            "    Setting sRGB as if in input");
   2668       }
   2669     }
   2670 
   2671 #if defined(PNG_oFFs_SUPPORTED)
   2672   if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
   2673     {
   2674       image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
   2675       image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
   2676 
   2677       if (logging != MagickFalse)
   2678         if (image->page.x || image->page.y)
   2679           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2680             "    Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
   2681             image->page.x,(double) image->page.y);
   2682     }
   2683 #endif
   2684 #if defined(PNG_pHYs_SUPPORTED)
   2685   if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
   2686     {
   2687       if (mng_info->have_global_phys)
   2688         {
   2689           png_set_pHYs(ping,ping_info,
   2690                        mng_info->global_x_pixels_per_unit,
   2691                        mng_info->global_y_pixels_per_unit,
   2692                        mng_info->global_phys_unit_type);
   2693         }
   2694     }
   2695 
   2696   x_resolution=0;
   2697   y_resolution=0;
   2698   unit_type=0;
   2699   if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
   2700     {
   2701       /*
   2702         Set image resolution.
   2703       */
   2704       (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
   2705         &unit_type);
   2706       image->resolution.x=(double) x_resolution;
   2707       image->resolution.y=(double) y_resolution;
   2708 
   2709       if (unit_type == PNG_RESOLUTION_METER)
   2710         {
   2711           image->units=PixelsPerCentimeterResolution;
   2712           image->resolution.x=(double) x_resolution/100.0;
   2713           image->resolution.y=(double) y_resolution/100.0;
   2714         }
   2715 
   2716       if (logging != MagickFalse)
   2717         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2718           "    Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
   2719           (double) x_resolution,(double) y_resolution,unit_type);
   2720     }
   2721 #endif
   2722 
   2723   if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
   2724     {
   2725       png_colorp
   2726         palette;
   2727 
   2728       (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
   2729 
   2730       if ((number_colors == 0) &&
   2731           ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
   2732         {
   2733           if (mng_info->global_plte_length)
   2734             {
   2735               png_set_PLTE(ping,ping_info,mng_info->global_plte,
   2736                 (int) mng_info->global_plte_length);
   2737 
   2738               if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
   2739               {
   2740                 if (mng_info->global_trns_length)
   2741                   {
   2742                     png_warning(ping,
   2743                       "global tRNS has more entries than global PLTE");
   2744                   }
   2745                 else
   2746                   {
   2747                      png_set_tRNS(ping,ping_info,mng_info->global_trns,
   2748                        (int) mng_info->global_trns_length,NULL);
   2749                   }
   2750                }
   2751 #ifdef PNG_READ_bKGD_SUPPORTED
   2752               if (
   2753 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
   2754                    mng_info->have_saved_bkgd_index ||
   2755 #endif
   2756                    png_get_valid(ping,ping_info,PNG_INFO_bKGD))
   2757                     {
   2758                       png_color_16
   2759                          background;
   2760 
   2761 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
   2762                       if (mng_info->have_saved_bkgd_index)
   2763                         background.index=mng_info->saved_bkgd_index;
   2764 #endif
   2765                       if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
   2766                         background.index=ping_background->index;
   2767 
   2768                       background.red=(png_uint_16)
   2769                         mng_info->global_plte[background.index].red;
   2770 
   2771                       background.green=(png_uint_16)
   2772                         mng_info->global_plte[background.index].green;
   2773 
   2774                       background.blue=(png_uint_16)
   2775                         mng_info->global_plte[background.index].blue;
   2776 
   2777                       background.gray=(png_uint_16)
   2778                         mng_info->global_plte[background.index].green;
   2779 
   2780                       png_set_bKGD(ping,ping_info,&background);
   2781                     }
   2782 #endif
   2783                 }
   2784               else
   2785                 png_error(ping,"No global PLTE in file");
   2786             }
   2787         }
   2788 
   2789 #ifdef PNG_READ_bKGD_SUPPORTED
   2790   if (mng_info->have_global_bkgd &&
   2791           (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
   2792       image->background_color=mng_info->mng_global_bkgd;
   2793 
   2794   if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
   2795     {
   2796       unsigned int
   2797         bkgd_scale;
   2798 
   2799       /* Set image background color.
   2800        * Scale background components to 16-bit, then scale
   2801        * to quantum depth
   2802        */
   2803 
   2804         bkgd_scale = 1;
   2805 
   2806         if (ping_file_depth == 1)
   2807            bkgd_scale = 255;
   2808 
   2809         else if (ping_file_depth == 2)
   2810            bkgd_scale = 85;
   2811 
   2812         else if (ping_file_depth == 4)
   2813            bkgd_scale = 17;
   2814 
   2815         if (ping_file_depth <= 8)
   2816            bkgd_scale *= 257;
   2817 
   2818         ping_background->red *= bkgd_scale;
   2819         ping_background->green *= bkgd_scale;
   2820         ping_background->blue *= bkgd_scale;
   2821 
   2822         if (logging != MagickFalse)
   2823           {
   2824             if (logging != MagickFalse)
   2825               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2826                  "    Reading PNG bKGD chunk, raw ping_background=(%d,%d,%d).\n"
   2827                  "    bkgd_scale=%d.  ping_background=(%d,%d,%d).",
   2828                  ping_background->red,ping_background->green,
   2829                  ping_background->blue,
   2830                  bkgd_scale,ping_background->red,
   2831                  ping_background->green,ping_background->blue);
   2832           }
   2833 
   2834         image->background_color.red=
   2835             ScaleShortToQuantum(ping_background->red);
   2836 
   2837         image->background_color.green=
   2838             ScaleShortToQuantum(ping_background->green);
   2839 
   2840         image->background_color.blue=
   2841           ScaleShortToQuantum(ping_background->blue);
   2842 
   2843         image->background_color.alpha=OpaqueAlpha;
   2844 
   2845         if (logging != MagickFalse)
   2846           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2847             "    image->background_color=(%.20g,%.20g,%.20g).",
   2848             (double) image->background_color.red,
   2849             (double) image->background_color.green,
   2850             (double) image->background_color.blue);
   2851     }
   2852 #endif /* PNG_READ_bKGD_SUPPORTED */
   2853 
   2854   if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
   2855     {
   2856       /*
   2857         Image has a tRNS chunk.
   2858       */
   2859       int
   2860         max_sample;
   2861 
   2862       size_t
   2863         one=1;
   2864 
   2865       if (logging != MagickFalse)
   2866         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2867           "    Reading PNG tRNS chunk.");
   2868 
   2869       max_sample = (int) ((one << ping_file_depth) - 1);
   2870 
   2871       if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
   2872           (int)ping_trans_color->gray > max_sample) ||
   2873           (ping_color_type == PNG_COLOR_TYPE_RGB &&
   2874           ((int)ping_trans_color->red > max_sample ||
   2875           (int)ping_trans_color->green > max_sample ||
   2876           (int)ping_trans_color->blue > max_sample)))
   2877         {
   2878           if (logging != MagickFalse)
   2879             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2880               "    Ignoring PNG tRNS chunk with out-of-range sample.");
   2881           png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
   2882           png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
   2883           image->alpha_trait=UndefinedPixelTrait;
   2884         }
   2885       else
   2886         {
   2887           int
   2888             scale_to_short;
   2889 
   2890           scale_to_short = 65535L/((1UL << ping_file_depth)-1);
   2891 
   2892           /* Scale transparent_color to short */
   2893           transparent_color.red= scale_to_short*ping_trans_color->red;
   2894           transparent_color.green= scale_to_short*ping_trans_color->green;
   2895           transparent_color.blue= scale_to_short*ping_trans_color->blue;
   2896           transparent_color.alpha= scale_to_short*ping_trans_color->gray;
   2897 
   2898           if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   2899             {
   2900               if (logging != MagickFalse)
   2901               {
   2902                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   2903                   "    Raw tRNS graylevel = %d, scaled graylevel = %d.",
   2904                   (int) ping_trans_color->gray,(int) transparent_color.alpha);
   2905 
   2906               }
   2907               transparent_color.red=transparent_color.alpha;
   2908               transparent_color.green=transparent_color.alpha;
   2909               transparent_color.blue=transparent_color.alpha;
   2910             }
   2911         }
   2912     }
   2913 #if defined(PNG_READ_sBIT_SUPPORTED)
   2914   if (mng_info->have_global_sbit)
   2915     {
   2916       if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
   2917         png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
   2918     }
   2919 #endif
   2920   num_passes=png_set_interlace_handling(ping);
   2921 
   2922   png_read_update_info(ping,ping_info);
   2923 
   2924   ping_rowbytes=png_get_rowbytes(ping,ping_info);
   2925 
   2926   /*
   2927     Initialize image structure.
   2928   */
   2929   mng_info->image_box.left=0;
   2930   mng_info->image_box.right=(ssize_t) ping_width;
   2931   mng_info->image_box.top=0;
   2932   mng_info->image_box.bottom=(ssize_t) ping_height;
   2933   if (mng_info->mng_type == 0)
   2934     {
   2935       mng_info->mng_width=ping_width;
   2936       mng_info->mng_height=ping_height;
   2937       mng_info->frame=mng_info->image_box;
   2938       mng_info->clip=mng_info->image_box;
   2939     }
   2940 
   2941   else
   2942     {
   2943       image->page.y=mng_info->y_off[mng_info->object_id];
   2944     }
   2945 
   2946   image->compression=ZipCompression;
   2947   image->columns=ping_width;
   2948   image->rows=ping_height;
   2949 
   2950   if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
   2951       ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
   2952     {
   2953       double
   2954         image_gamma = image->gamma;
   2955 
   2956       (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   2957          "    image->gamma=%f",(float) image_gamma);
   2958 
   2959       if (image_gamma > 0.75)
   2960         {
   2961           /* Set image->rendering_intent to Undefined,
   2962            * image->colorspace to GRAY, and reset image->chromaticity.
   2963            */
   2964           image->intensity = Rec709LuminancePixelIntensityMethod;
   2965           SetImageColorspace(image,GRAYColorspace,exception);
   2966         }
   2967       else
   2968         {
   2969           RenderingIntent
   2970             save_rendering_intent = image->rendering_intent;
   2971           ChromaticityInfo
   2972             save_chromaticity = image->chromaticity;
   2973 
   2974           SetImageColorspace(image,GRAYColorspace,exception);
   2975           image->rendering_intent = save_rendering_intent;
   2976           image->chromaticity = save_chromaticity;
   2977         }
   2978 
   2979       image->gamma = image_gamma;
   2980     }
   2981 
   2982   (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   2983       "    image->colorspace=%d",(int) image->colorspace);
   2984 
   2985   if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
   2986       ((int) ping_bit_depth < 16 &&
   2987       (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
   2988     {
   2989       size_t
   2990         one;
   2991 
   2992       image->storage_class=PseudoClass;
   2993       one=1;
   2994       image->colors=one << ping_file_depth;
   2995 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
   2996       if (image->colors > 256)
   2997         image->colors=256;
   2998 #else
   2999       if (image->colors > 65536L)
   3000         image->colors=65536L;
   3001 #endif
   3002       if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3003         {
   3004           png_colorp
   3005             palette;
   3006 
   3007           (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
   3008           image->colors=(size_t) number_colors;
   3009 
   3010           if (logging != MagickFalse)
   3011             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3012               "    Reading PNG PLTE chunk: number_colors: %d.",number_colors);
   3013         }
   3014     }
   3015 
   3016   if (image->storage_class == PseudoClass)
   3017     {
   3018       /*
   3019         Initialize image colormap.
   3020       */
   3021       if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
   3022         png_error(ping,"Memory allocation failed");
   3023 
   3024       if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3025         {
   3026           png_colorp
   3027             palette;
   3028 
   3029           (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
   3030 
   3031           for (i=0; i < (ssize_t) number_colors; i++)
   3032           {
   3033             image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
   3034             image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
   3035             image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
   3036           }
   3037 
   3038           for ( ; i < (ssize_t) image->colors; i++)
   3039           {
   3040             image->colormap[i].red=0;
   3041             image->colormap[i].green=0;
   3042             image->colormap[i].blue=0;
   3043           }
   3044         }
   3045 
   3046       else
   3047         {
   3048           Quantum
   3049             scale;
   3050 
   3051           scale = (Quantum) ((65535UL)/((1UL << ping_file_depth)-1));
   3052 
   3053 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   3054           scale = ScaleShortToQuantum(scale);
   3055 #endif
   3056 
   3057           for (i=0; i < (ssize_t) image->colors; i++)
   3058           {
   3059             image->colormap[i].red=(Quantum) (i*scale);
   3060             image->colormap[i].green=(Quantum) (i*scale);
   3061             image->colormap[i].blue=(Quantum) (i*scale);
   3062           }
   3063        }
   3064     }
   3065 
   3066    /* Set some properties for reporting by "identify" */
   3067     {
   3068       char
   3069         msg[MagickPathExtent];
   3070 
   3071      /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
   3072         ping_interlace_method in value */
   3073 
   3074      (void) FormatLocaleString(msg,MagickPathExtent,
   3075          "%d, %d",(int) ping_width, (int) ping_height);
   3076      (void) SetImageProperty(image,"png:IHDR.width,height",msg,exception);
   3077 
   3078      (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_file_depth);
   3079      (void) SetImageProperty(image,"png:IHDR.bit_depth",msg,exception);
   3080 
   3081      (void) FormatLocaleString(msg,MagickPathExtent,"%d (%s)",
   3082          (int) ping_color_type,
   3083          Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
   3084      (void) SetImageProperty(image,"png:IHDR.color_type",msg,exception);
   3085 
   3086      if (ping_interlace_method == 0)
   3087        {
   3088          (void) FormatLocaleString(msg,MagickPathExtent,"%d (Not interlaced)",
   3089             (int) ping_interlace_method);
   3090        }
   3091      else if (ping_interlace_method == 1)
   3092        {
   3093          (void) FormatLocaleString(msg,MagickPathExtent,"%d (Adam7 method)",
   3094             (int) ping_interlace_method);
   3095        }
   3096      else
   3097        {
   3098          (void) FormatLocaleString(msg,MagickPathExtent,"%d (Unknown method)",
   3099             (int) ping_interlace_method);
   3100        }
   3101        (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
   3102 
   3103      if (number_colors != 0)
   3104        {
   3105          (void) FormatLocaleString(msg,MagickPathExtent,"%d",
   3106             (int) number_colors);
   3107          (void) SetImageProperty(image,"png:PLTE.number_colors",msg,
   3108             exception);
   3109        }
   3110    }
   3111 #if defined(PNG_tIME_SUPPORTED)
   3112    read_tIME_chunk(image,ping,ping_info,exception);
   3113 #endif
   3114 
   3115 
   3116   /*
   3117     Read image scanlines.
   3118   */
   3119   if (image->delay != 0)
   3120     mng_info->scenes_found++;
   3121 
   3122   if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
   3123       (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
   3124       (image_info->first_scene+image_info->number_scenes))))
   3125     {
   3126       /* This happens later in non-ping decodes */
   3127       if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
   3128         image->storage_class=DirectClass;
   3129       image->alpha_trait=
   3130         (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
   3131          ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
   3132          (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
   3133         BlendPixelTrait : UndefinedPixelTrait;
   3134 
   3135       if (logging != MagickFalse)
   3136         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3137           "    Skipping PNG image data for scene %.20g",(double)
   3138           mng_info->scenes_found-1);
   3139       png_destroy_read_struct(&ping,&ping_info,&end_info);
   3140 
   3141 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   3142       UnlockSemaphoreInfo(ping_semaphore);
   3143 #endif
   3144 
   3145       if (logging != MagickFalse)
   3146         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3147           "  exit ReadOnePNGImage().");
   3148 
   3149       return(image);
   3150     }
   3151 
   3152   if (logging != MagickFalse)
   3153     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3154       "    Reading PNG IDAT chunk(s)");
   3155 
   3156   status=SetImageExtent(image,image->columns,image->rows,exception);
   3157   if (status == MagickFalse)
   3158     return(DestroyImageList(image));
   3159 
   3160   if (num_passes > 1)
   3161     pixel_info=AcquireVirtualMemory(image->rows,ping_rowbytes*
   3162       sizeof(*ping_pixels));
   3163   else
   3164     pixel_info=AcquireVirtualMemory(ping_rowbytes,sizeof(*ping_pixels));
   3165 
   3166   if (pixel_info == (MemoryInfo *) NULL)
   3167     png_error(ping,"Memory allocation failed");
   3168   ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   3169 
   3170   if (logging != MagickFalse)
   3171     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3172       "    Converting PNG pixels to pixel packets");
   3173   /*
   3174     Convert PNG pixels to pixel packets.
   3175   */
   3176   quantum_info=AcquireQuantumInfo(image_info,image);
   3177 
   3178   if (quantum_info == (QuantumInfo *) NULL)
   3179      png_error(ping,"Failed to allocate quantum_info");
   3180 
   3181   (void) SetQuantumEndian(image,quantum_info,MSBEndian);
   3182 
   3183   {
   3184 
   3185    MagickBooleanType
   3186      found_transparent_pixel;
   3187 
   3188   found_transparent_pixel=MagickFalse;
   3189 
   3190   if (image->storage_class == DirectClass)
   3191     {
   3192       for (pass=0; pass < num_passes; pass++)
   3193       {
   3194         /*
   3195           Convert image to DirectClass pixel packets.
   3196         */
   3197         image->alpha_trait=
   3198             (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
   3199             ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
   3200             (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
   3201             BlendPixelTrait : UndefinedPixelTrait;
   3202 
   3203         for (y=0; y < (ssize_t) image->rows; y++)
   3204         {
   3205           if (num_passes > 1)
   3206             row_offset=ping_rowbytes*y;
   3207 
   3208           else
   3209             row_offset=0;
   3210 
   3211           png_read_row(ping,ping_pixels+row_offset,NULL);
   3212 
   3213           if (pass < num_passes-1)
   3214             continue;
   3215 
   3216           q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   3217 
   3218           if (q == (Quantum *) NULL)
   3219             break;
   3220 
   3221           if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
   3222             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   3223               GrayQuantum,ping_pixels+row_offset,exception);
   3224 
   3225           else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
   3226             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   3227               GrayAlphaQuantum,ping_pixels+row_offset,exception);
   3228 
   3229           else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
   3230             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   3231               RGBAQuantum,ping_pixels+row_offset,exception);
   3232 
   3233           else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3234             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   3235               IndexQuantum,ping_pixels+row_offset,exception);
   3236 
   3237           else /* ping_color_type == PNG_COLOR_TYPE_RGB */
   3238             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   3239               RGBQuantum,ping_pixels+row_offset,exception);
   3240 
   3241           if (found_transparent_pixel == MagickFalse)
   3242             {
   3243               /* Is there a transparent pixel in the row? */
   3244               if (y== 0 && logging != MagickFalse)
   3245                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3246                    "    Looking for cheap transparent pixel");
   3247 
   3248               for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3249               {
   3250                 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
   3251                     ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
   3252                    (GetPixelAlpha(image,q) != OpaqueAlpha))
   3253                   {
   3254                     if (logging != MagickFalse)
   3255                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3256                         "    ...got one.");
   3257 
   3258                     found_transparent_pixel = MagickTrue;
   3259                     break;
   3260                   }
   3261                 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
   3262                     ping_color_type == PNG_COLOR_TYPE_GRAY) &&
   3263                     (ScaleQuantumToShort(GetPixelRed(image,q)) ==
   3264                     transparent_color.red &&
   3265                     ScaleQuantumToShort(GetPixelGreen(image,q)) ==
   3266                     transparent_color.green &&
   3267                     ScaleQuantumToShort(GetPixelBlue(image,q)) ==
   3268                     transparent_color.blue))
   3269                   {
   3270                     if (logging != MagickFalse)
   3271                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3272                         "    ...got one.");
   3273                     found_transparent_pixel = MagickTrue;
   3274                     break;
   3275                   }
   3276                 q+=GetPixelChannels(image);
   3277               }
   3278             }
   3279 
   3280           if (num_passes == 1)
   3281             {
   3282               status=SetImageProgress(image,LoadImageTag,
   3283                   (MagickOffsetType) y, image->rows);
   3284 
   3285               if (status == MagickFalse)
   3286                 break;
   3287             }
   3288           if (SyncAuthenticPixels(image,exception) == MagickFalse)
   3289             break;
   3290         }
   3291 
   3292         if (num_passes != 1)
   3293           {
   3294             status=SetImageProgress(image,LoadImageTag,pass,num_passes);
   3295             if (status == MagickFalse)
   3296               break;
   3297           }
   3298       }
   3299     }
   3300 
   3301   else /* image->storage_class != DirectClass */
   3302 
   3303     for (pass=0; pass < num_passes; pass++)
   3304     {
   3305       Quantum
   3306         *quantum_scanline;
   3307 
   3308       register Quantum
   3309         *r;
   3310 
   3311       /*
   3312         Convert grayscale image to PseudoClass pixel packets.
   3313       */
   3314       if (logging != MagickFalse)
   3315         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3316           "    Converting grayscale pixels to pixel packets");
   3317 
   3318       image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
   3319         BlendPixelTrait : UndefinedPixelTrait;
   3320 
   3321       quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
   3322         (image->alpha_trait  == BlendPixelTrait?  2 : 1)*
   3323         sizeof(*quantum_scanline));
   3324 
   3325       if (quantum_scanline == (Quantum *) NULL)
   3326         png_error(ping,"Memory allocation failed");
   3327 
   3328       for (y=0; y < (ssize_t) image->rows; y++)
   3329       {
   3330         Quantum
   3331            alpha;
   3332 
   3333         if (num_passes > 1)
   3334           row_offset=ping_rowbytes*y;
   3335 
   3336         else
   3337           row_offset=0;
   3338 
   3339         png_read_row(ping,ping_pixels+row_offset,NULL);
   3340 
   3341         if (pass < num_passes-1)
   3342           continue;
   3343 
   3344         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
   3345 
   3346         if (q == (Quantum *) NULL)
   3347           break;
   3348 
   3349         p=ping_pixels+row_offset;
   3350         r=quantum_scanline;
   3351 
   3352         switch (ping_bit_depth)
   3353         {
   3354           case 8:
   3355           {
   3356 
   3357             if (ping_color_type == 4)
   3358               for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3359               {
   3360                 *r++=*p++;
   3361 
   3362                 alpha=ScaleCharToQuantum((unsigned char)*p++);
   3363 
   3364                 SetPixelAlpha(image,alpha,q);
   3365 
   3366                 if (alpha != OpaqueAlpha)
   3367                   found_transparent_pixel = MagickTrue;
   3368 
   3369                 q+=GetPixelChannels(image);
   3370               }
   3371 
   3372             else
   3373               for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3374                 *r++=*p++;
   3375 
   3376             break;
   3377           }
   3378 
   3379           case 16:
   3380           {
   3381             for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3382             {
   3383 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
   3384               unsigned short
   3385                 quantum;
   3386 
   3387               if (image->colors > 256)
   3388                 quantum=((*p++) << 8);
   3389 
   3390               else
   3391                 quantum=0;
   3392 
   3393               quantum|=(*p++);
   3394               *r=ScaleShortToQuantum(quantum);
   3395               r++;
   3396 
   3397               if (ping_color_type == 4)
   3398                 {
   3399                   if (image->colors > 256)
   3400                     quantum=((*p++) << 8);
   3401                   else
   3402                     quantum=0;
   3403 
   3404                   quantum|=(*p++);
   3405 
   3406                   alpha=ScaleShortToQuantum(quantum);
   3407                   SetPixelAlpha(image,alpha,q);
   3408 
   3409                   if (alpha != OpaqueAlpha)
   3410                     found_transparent_pixel = MagickTrue;
   3411 
   3412                   q+=GetPixelChannels(image);
   3413                 }
   3414 
   3415 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
   3416               *r++=(*p++);
   3417               p++; /* strip low byte */
   3418 
   3419               if (ping_color_type == 4)
   3420                 {
   3421                   SetPixelAlpha(image,*p++,q);
   3422 
   3423                   if (GetPixelAlpha(image,q) != OpaqueAlpha)
   3424                     found_transparent_pixel = MagickTrue;
   3425 
   3426                   p++;
   3427                   q+=GetPixelChannels(image);
   3428                 }
   3429 #endif
   3430             }
   3431 
   3432             break;
   3433           }
   3434 
   3435           default:
   3436             break;
   3437         }
   3438 
   3439         /*
   3440           Transfer image scanline.
   3441         */
   3442         r=quantum_scanline;
   3443 
   3444         q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   3445 
   3446         if (q == (Quantum *) NULL)
   3447           break;
   3448         for (x=0; x < (ssize_t) image->columns; x++)
   3449         {
   3450           SetPixelIndex(image,*r++,q);
   3451           q+=GetPixelChannels(image);
   3452         }
   3453 
   3454         if (SyncAuthenticPixels(image,exception) == MagickFalse)
   3455           break;
   3456 
   3457         if (num_passes == 1)
   3458           {
   3459             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
   3460               image->rows);
   3461 
   3462             if (status == MagickFalse)
   3463               break;
   3464           }
   3465       }
   3466 
   3467       if (num_passes != 1)
   3468         {
   3469           status=SetImageProgress(image,LoadImageTag,pass,num_passes);
   3470 
   3471           if (status == MagickFalse)
   3472             break;
   3473         }
   3474 
   3475       quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
   3476     }
   3477 
   3478     image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
   3479       UndefinedPixelTrait;
   3480 
   3481     if (logging != MagickFalse)
   3482       {
   3483         if (found_transparent_pixel != MagickFalse)
   3484           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3485             "    Found transparent pixel");
   3486         else
   3487           {
   3488             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3489               "    No transparent pixel was found");
   3490 
   3491             ping_color_type&=0x03;
   3492           }
   3493       }
   3494     }
   3495 
   3496   if (quantum_info != (QuantumInfo *) NULL)
   3497     quantum_info=DestroyQuantumInfo(quantum_info);
   3498 
   3499   if (image->storage_class == PseudoClass)
   3500     {
   3501       PixelTrait
   3502         alpha_trait;
   3503 
   3504       alpha_trait=image->alpha_trait;
   3505       image->alpha_trait=UndefinedPixelTrait;
   3506       (void) SyncImage(image,exception);
   3507       image->alpha_trait=alpha_trait;
   3508     }
   3509 
   3510   png_read_end(ping,end_info);
   3511 
   3512   if (logging != MagickFalse)
   3513   {
   3514     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3515        "  image->storage_class=%d\n",(int) image->storage_class);
   3516   }
   3517 
   3518   if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
   3519       (ssize_t) image_info->first_scene && image->delay != 0)
   3520     {
   3521       png_destroy_read_struct(&ping,&ping_info,&end_info);
   3522       pixel_info=RelinquishVirtualMemory(pixel_info);
   3523       image->colors=2;
   3524       (void) SetImageBackgroundColor(image,exception);
   3525 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   3526       UnlockSemaphoreInfo(ping_semaphore);
   3527 #endif
   3528       if (logging != MagickFalse)
   3529         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3530           "  exit ReadOnePNGImage() early.");
   3531       return(image);
   3532     }
   3533 
   3534   if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
   3535     {
   3536       ClassType
   3537         storage_class;
   3538 
   3539       /*
   3540         Image has a transparent background.
   3541       */
   3542       storage_class=image->storage_class;
   3543       image->alpha_trait=BlendPixelTrait;
   3544 
   3545 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
   3546 
   3547       if (storage_class == PseudoClass)
   3548         {
   3549           if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3550             {
   3551               for (x=0; x < ping_num_trans; x++)
   3552               {
   3553                  image->colormap[x].alpha_trait=BlendPixelTrait;
   3554                  image->colormap[x].alpha =
   3555                    ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
   3556               }
   3557             }
   3558 
   3559           else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   3560             {
   3561               for (x=0; x < (int) image->colors; x++)
   3562               {
   3563                  if (ScaleQuantumToShort(image->colormap[x].red) ==
   3564                      transparent_color.alpha)
   3565                  {
   3566                     image->colormap[x].alpha_trait=BlendPixelTrait;
   3567                     image->colormap[x].alpha = (Quantum) TransparentAlpha;
   3568                  }
   3569               }
   3570             }
   3571           (void) SyncImage(image,exception);
   3572         }
   3573 
   3574 #if 1 /* Should have already been done above, but glennrp problem P10
   3575        * needs this.
   3576        */
   3577       else
   3578         {
   3579           for (y=0; y < (ssize_t) image->rows; y++)
   3580           {
   3581             image->storage_class=storage_class;
   3582             q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   3583 
   3584             if (q == (Quantum *) NULL)
   3585               break;
   3586 
   3587 
   3588             /* Caution: on a Q8 build, this does not distinguish between
   3589              * 16-bit colors that differ only in the low byte
   3590              */
   3591             for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3592             {
   3593               if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
   3594                   transparent_color.red &&
   3595                   ScaleQuantumToShort(GetPixelGreen(image,q)) ==
   3596                   transparent_color.green &&
   3597                   ScaleQuantumToShort(GetPixelBlue(image,q)) ==
   3598                   transparent_color.blue)
   3599                 {
   3600                   SetPixelAlpha(image,TransparentAlpha,q);
   3601                 }
   3602 
   3603 #if 0 /* I have not found a case where this is needed. */
   3604               else
   3605                 {
   3606                   SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
   3607                 }
   3608 #endif
   3609 
   3610               q+=GetPixelChannels(image);
   3611             }
   3612 
   3613             if (SyncAuthenticPixels(image,exception) == MagickFalse)
   3614                break;
   3615           }
   3616         }
   3617 #endif
   3618 
   3619       image->storage_class=DirectClass;
   3620     }
   3621 
   3622   for (j = 0; j < 2; j++)
   3623   {
   3624     if (j == 0)
   3625       status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
   3626           MagickTrue : MagickFalse;
   3627     else
   3628       status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
   3629           MagickTrue : MagickFalse;
   3630 
   3631     if (status != MagickFalse)
   3632       for (i=0; i < (ssize_t) num_text; i++)
   3633       {
   3634         /* Check for a profile */
   3635 
   3636         if (logging != MagickFalse)
   3637           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3638             "    Reading PNG text chunk");
   3639 
   3640         if (strlen(text[i].key) > 16 &&
   3641             memcmp(text[i].key, "Raw profile type ",17) == 0)
   3642           {
   3643             const char
   3644               *value;
   3645 
   3646             value=GetImageOption(image_info,"profile:skip");
   3647 
   3648             if (IsOptionMember(text[i].key+17,value) == MagickFalse)
   3649             {
   3650                (void) Magick_png_read_raw_profile(ping,image,image_info,text,
   3651                   (int) i,exception);
   3652                num_raw_profiles++;
   3653                if (logging != MagickFalse)
   3654                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3655                    "    Read raw profile %s",text[i].key+17);
   3656             }
   3657             else
   3658             {
   3659                if (logging != MagickFalse)
   3660                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3661                    "    Skipping raw profile %s",text[i].key+17);
   3662             }
   3663           }
   3664 
   3665         else
   3666           {
   3667             char
   3668               *value;
   3669 
   3670             length=text[i].text_length;
   3671             value=(char *) AcquireQuantumMemory(length+MagickPathExtent,
   3672               sizeof(*value));
   3673             if (value == (char *) NULL)
   3674               {
   3675                 png_error(ping,"Memory allocation failed");
   3676                 break;
   3677               }
   3678             *value='\0';
   3679             (void) ConcatenateMagickString(value,text[i].text,length+2);
   3680 
   3681             /* Don't save "density" or "units" property if we have a pHYs
   3682              * chunk
   3683              */
   3684             if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
   3685                 (LocaleCompare(text[i].key,"density") != 0 &&
   3686                 LocaleCompare(text[i].key,"units") != 0))
   3687                (void) SetImageProperty(image,text[i].key,value,exception);
   3688 
   3689             if (logging != MagickFalse)
   3690             {
   3691               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3692                 "      length: %lu\n"
   3693                 "      Keyword: %s",
   3694                 (unsigned long) length,
   3695                 text[i].key);
   3696             }
   3697 
   3698             value=DestroyString(value);
   3699           }
   3700       }
   3701     num_text_total += num_text;
   3702   }
   3703 
   3704 #ifdef MNG_OBJECT_BUFFERS
   3705   /*
   3706     Store the object if necessary.
   3707   */
   3708   if (object_id && !mng_info->frozen[object_id])
   3709     {
   3710       if (mng_info->ob[object_id] == (MngBuffer *) NULL)
   3711         {
   3712           /*
   3713             create a new object buffer.
   3714           */
   3715           mng_info->ob[object_id]=(MngBuffer *)
   3716             AcquireMagickMemory(sizeof(MngBuffer));
   3717 
   3718           if (mng_info->ob[object_id] != (MngBuffer *) NULL)
   3719             {
   3720               mng_info->ob[object_id]->image=(Image *) NULL;
   3721               mng_info->ob[object_id]->reference_count=1;
   3722             }
   3723         }
   3724 
   3725       if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
   3726           mng_info->ob[object_id]->frozen)
   3727         {
   3728           if (mng_info->ob[object_id] == (MngBuffer *) NULL)
   3729              png_error(ping,"Memory allocation failed");
   3730 
   3731           if (mng_info->ob[object_id]->frozen)
   3732             png_error(ping,"Cannot overwrite frozen MNG object buffer");
   3733         }
   3734 
   3735       else
   3736         {
   3737 
   3738           if (mng_info->ob[object_id]->image != (Image *) NULL)
   3739             mng_info->ob[object_id]->image=DestroyImage
   3740                 (mng_info->ob[object_id]->image);
   3741 
   3742           mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
   3743             exception);
   3744 
   3745           if (mng_info->ob[object_id]->image != (Image *) NULL)
   3746             mng_info->ob[object_id]->image->file=(FILE *) NULL;
   3747 
   3748           else
   3749             png_error(ping, "Cloning image for object buffer failed");
   3750 
   3751           if (ping_width > 250000L || ping_height > 250000L)
   3752              png_error(ping,"PNG Image dimensions are too large.");
   3753 
   3754           mng_info->ob[object_id]->width=ping_width;
   3755           mng_info->ob[object_id]->height=ping_height;
   3756           mng_info->ob[object_id]->color_type=ping_color_type;
   3757           mng_info->ob[object_id]->sample_depth=ping_bit_depth;
   3758           mng_info->ob[object_id]->interlace_method=ping_interlace_method;
   3759           mng_info->ob[object_id]->compression_method=
   3760              ping_compression_method;
   3761           mng_info->ob[object_id]->filter_method=ping_filter_method;
   3762 
   3763           if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
   3764             {
   3765               png_colorp
   3766                 plte;
   3767 
   3768               /*
   3769                 Copy the PLTE to the object buffer.
   3770               */
   3771               png_get_PLTE(ping,ping_info,&plte,&number_colors);
   3772               mng_info->ob[object_id]->plte_length=number_colors;
   3773 
   3774               for (i=0; i < number_colors; i++)
   3775               {
   3776                 mng_info->ob[object_id]->plte[i]=plte[i];
   3777               }
   3778             }
   3779 
   3780           else
   3781               mng_info->ob[object_id]->plte_length=0;
   3782         }
   3783     }
   3784 #endif
   3785 
   3786    /* Set image->alpha_trait to MagickTrue if the input colortype supports
   3787     * alpha or if a valid tRNS chunk is present, no matter whether there
   3788     * is actual transparency present.
   3789     */
   3790     image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
   3791         ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
   3792         (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
   3793         BlendPixelTrait : UndefinedPixelTrait;
   3794 
   3795 #if 0  /* I'm not sure what's wrong here but it does not work. */
   3796     if (image->alpha_trait != UndefinedPixelTrait)
   3797     {
   3798       if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
   3799         (void) SetImageType(image,GrayscaleAlphaType,exception);
   3800 
   3801       else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3802         (void) SetImageType(image,PaletteAlphaType,exception);
   3803 
   3804       else
   3805         (void) SetImageType(image,TrueColorAlphaType,exception);
   3806     }
   3807 
   3808     else
   3809     {
   3810       if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   3811         (void) SetImageType(image,GrayscaleType,exception);
   3812 
   3813       else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
   3814         (void) SetImageType(image,PaletteType,exception);
   3815 
   3816       else
   3817         (void) SetImageType(image,TrueColorType,exception);
   3818     }
   3819 #endif
   3820 
   3821    /* Set more properties for identify to retrieve */
   3822    {
   3823      char
   3824        msg[MagickPathExtent];
   3825 
   3826      if (num_text_total != 0)
   3827        {
   3828          /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
   3829          (void) FormatLocaleString(msg,MagickPathExtent,
   3830             "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
   3831          (void) SetImageProperty(image,"png:text",msg,
   3832                 exception);
   3833        }
   3834 
   3835      if (num_raw_profiles != 0)
   3836        {
   3837          (void) FormatLocaleString(msg,MagickPathExtent,
   3838             "%d were found", num_raw_profiles);
   3839          (void) SetImageProperty(image,"png:text-encoded profiles",msg,
   3840                 exception);
   3841        }
   3842 
   3843      if (ping_found_cHRM != MagickFalse)
   3844        {
   3845          (void) FormatLocaleString(msg,MagickPathExtent,"%s",
   3846             "chunk was found (see Chromaticity, above)");
   3847          (void) SetImageProperty(image,"png:cHRM",msg,
   3848                 exception);
   3849        }
   3850 
   3851      if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
   3852        {
   3853          (void) FormatLocaleString(msg,MagickPathExtent,"%s",
   3854             "chunk was found (see Background color, above)");
   3855          (void) SetImageProperty(image,"png:bKGD",msg,
   3856                 exception);
   3857        }
   3858 
   3859      (void) FormatLocaleString(msg,MagickPathExtent,"%s",
   3860         "chunk was found");
   3861 
   3862 #if defined(PNG_iCCP_SUPPORTED)
   3863      if (ping_found_iCCP != MagickFalse)
   3864         (void) SetImageProperty(image,"png:iCCP",msg,
   3865                 exception);
   3866 #endif
   3867 
   3868      if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
   3869         (void) SetImageProperty(image,"png:tRNS",msg,
   3870                 exception);
   3871 
   3872 #if defined(PNG_sRGB_SUPPORTED)
   3873      if (ping_found_sRGB != MagickFalse)
   3874        {
   3875          (void) FormatLocaleString(msg,MagickPathExtent,
   3876             "intent=%d (%s)",
   3877             (int) intent,
   3878             Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
   3879          (void) SetImageProperty(image,"png:sRGB",msg,
   3880                  exception);
   3881        }
   3882 #endif
   3883 
   3884      if (ping_found_gAMA != MagickFalse)
   3885        {
   3886          (void) FormatLocaleString(msg,MagickPathExtent,
   3887             "gamma=%.8g (See Gamma, above)",
   3888             file_gamma);
   3889          (void) SetImageProperty(image,"png:gAMA",msg,
   3890                 exception);
   3891        }
   3892 
   3893 #if defined(PNG_pHYs_SUPPORTED)
   3894      if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
   3895        {
   3896          (void) FormatLocaleString(msg,MagickPathExtent,
   3897             "x_res=%.10g, y_res=%.10g, units=%d",
   3898             (double) x_resolution,(double) y_resolution, unit_type);
   3899          (void) SetImageProperty(image,"png:pHYs",msg,
   3900                 exception);
   3901        }
   3902 #endif
   3903 
   3904 #if defined(PNG_oFFs_SUPPORTED)
   3905      if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
   3906        {
   3907          (void) FormatLocaleString(msg,MagickPathExtent,"x_off=%.20g, y_off=%.20g",
   3908             (double) image->page.x,(double) image->page.y);
   3909          (void) SetImageProperty(image,"png:oFFs",msg,
   3910                 exception);
   3911        }
   3912 #endif
   3913 
   3914 #if defined(PNG_tIME_SUPPORTED)
   3915      read_tIME_chunk(image,ping,end_info,exception);
   3916 #endif
   3917 
   3918      if ((image->page.width != 0 && image->page.width != image->columns) ||
   3919          (image->page.height != 0 && image->page.height != image->rows))
   3920        {
   3921          (void) FormatLocaleString(msg,MagickPathExtent,
   3922             "width=%.20g, height=%.20g",
   3923             (double) image->page.width,(double) image->page.height);
   3924          (void) SetImageProperty(image,"png:vpAg",msg,
   3925                 exception);
   3926        }
   3927    }
   3928 
   3929   /*
   3930     Relinquish resources.
   3931   */
   3932   png_destroy_read_struct(&ping,&ping_info,&end_info);
   3933 
   3934   pixel_info=RelinquishVirtualMemory(pixel_info);
   3935 
   3936   if (logging != MagickFalse)
   3937     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   3938       "  exit ReadOnePNGImage()");
   3939 
   3940 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   3941   UnlockSemaphoreInfo(ping_semaphore);
   3942 #endif
   3943 
   3944   /* }  for navigation to beginning of SETJMP-protected block, revert to
   3945    *    Throwing an Exception when an error occurs.
   3946    */
   3947 
   3948   return(image);
   3949 
   3950 /* end of reading one PNG image */
   3951 }
   3952 
   3953 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   3954 {
   3955   Image
   3956     *image;
   3957 
   3958   MagickBooleanType
   3959     have_mng_structure,
   3960     logging,
   3961     status;
   3962 
   3963   MngInfo
   3964     *mng_info;
   3965 
   3966   char
   3967     magic_number[MagickPathExtent];
   3968 
   3969   ssize_t
   3970     count;
   3971 
   3972   /*
   3973     Open image file.
   3974   */
   3975   assert(image_info != (const ImageInfo *) NULL);
   3976   assert(image_info->signature == MagickCoreSignature);
   3977 
   3978   if (image_info->debug != MagickFalse)
   3979     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
   3980       image_info->filename);
   3981 
   3982   assert(exception != (ExceptionInfo *) NULL);
   3983   assert(exception->signature == MagickCoreSignature);
   3984   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
   3985   image=AcquireImage(image_info,exception);
   3986   mng_info=(MngInfo *) NULL;
   3987   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   3988 
   3989   if (status == MagickFalse)
   3990     ThrowReaderException(FileOpenError,"UnableToOpenFile");
   3991 
   3992   /*
   3993     Verify PNG signature.
   3994   */
   3995   count=ReadBlob(image,8,(unsigned char *) magic_number);
   3996 
   3997   if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
   3998     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   3999 
   4000   /*
   4001     Allocate a MngInfo structure.
   4002   */
   4003   have_mng_structure=MagickFalse;
   4004   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
   4005 
   4006   if (mng_info == (MngInfo *) NULL)
   4007     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4008 
   4009   /*
   4010     Initialize members of the MngInfo structure.
   4011   */
   4012   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   4013   mng_info->image=image;
   4014   have_mng_structure=MagickTrue;
   4015 
   4016   image=ReadOnePNGImage(mng_info,image_info,exception);
   4017   MngInfoFreeStruct(mng_info,&have_mng_structure);
   4018 
   4019   if (image == (Image *) NULL)
   4020     {
   4021       if (logging != MagickFalse)
   4022         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4023           "exit ReadPNGImage() with error");
   4024 
   4025       return((Image *) NULL);
   4026     }
   4027 
   4028   (void) CloseBlob(image);
   4029 
   4030   if ((image->columns == 0) || (image->rows == 0))
   4031     {
   4032       if (logging != MagickFalse)
   4033         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4034           "exit ReadPNGImage() with error.");
   4035 
   4036       ThrowReaderException(CorruptImageError,"CorruptImage");
   4037     }
   4038 
   4039   if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
   4040       ((image->gamma < .45) || (image->gamma > .46)) &&
   4041            !(image->chromaticity.red_primary.x>0.6399f &&
   4042            image->chromaticity.red_primary.x<0.6401f &&
   4043            image->chromaticity.red_primary.y>0.3299f &&
   4044            image->chromaticity.red_primary.y<0.3301f &&
   4045            image->chromaticity.green_primary.x>0.2999f &&
   4046            image->chromaticity.green_primary.x<0.3001f &&
   4047            image->chromaticity.green_primary.y>0.5999f &&
   4048            image->chromaticity.green_primary.y<0.6001f &&
   4049            image->chromaticity.blue_primary.x>0.1499f &&
   4050            image->chromaticity.blue_primary.x<0.1501f &&
   4051            image->chromaticity.blue_primary.y>0.0599f &&
   4052            image->chromaticity.blue_primary.y<0.0601f &&
   4053            image->chromaticity.white_point.x>0.3126f &&
   4054            image->chromaticity.white_point.x<0.3128f &&
   4055            image->chromaticity.white_point.y>0.3289f &&
   4056            image->chromaticity.white_point.y<0.3291f))
   4057     {
   4058        SetImageColorspace(image,RGBColorspace,exception);
   4059     }
   4060 
   4061   if (logging != MagickFalse)
   4062     {
   4063        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4064            "  page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
   4065                (double) image->page.width,(double) image->page.height,
   4066                (double) image->page.x,(double) image->page.y);
   4067        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4068            "  image->colorspace: %d", (int) image->colorspace);
   4069     }
   4070 
   4071   if (logging != MagickFalse)
   4072     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
   4073 
   4074   return(image);
   4075 }
   4076 
   4077 
   4078 
   4079 #if defined(JNG_SUPPORTED)
   4080 /*
   4081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4082 %                                                                             %
   4083 %                                                                             %
   4084 %                                                                             %
   4085 %   R e a d O n e J N G I m a g e                                             %
   4086 %                                                                             %
   4087 %                                                                             %
   4088 %                                                                             %
   4089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4090 %
   4091 %  ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
   4092 %  (minus the 8-byte signature)  and returns it.  It allocates the memory
   4093 %  necessary for the new Image structure and returns a pointer to the new
   4094 %  image.
   4095 %
   4096 %  JNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   4097 %
   4098 %  The format of the ReadOneJNGImage method is:
   4099 %
   4100 %      Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
   4101 %         ExceptionInfo *exception)
   4102 %
   4103 %  A description of each parameter follows:
   4104 %
   4105 %    o mng_info: Specifies a pointer to a MngInfo structure.
   4106 %
   4107 %    o image_info: the image info.
   4108 %
   4109 %    o exception: return any errors or warnings in this structure.
   4110 %
   4111 */
   4112 static Image *ReadOneJNGImage(MngInfo *mng_info,
   4113     const ImageInfo *image_info, ExceptionInfo *exception)
   4114 {
   4115   Image
   4116     *alpha_image,
   4117     *color_image,
   4118     *image,
   4119     *jng_image;
   4120 
   4121   ImageInfo
   4122     *alpha_image_info,
   4123     *color_image_info;
   4124 
   4125   MagickBooleanType
   4126     logging;
   4127 
   4128   ssize_t
   4129     y;
   4130 
   4131   MagickBooleanType
   4132     status;
   4133 
   4134   png_uint_32
   4135     jng_height,
   4136     jng_width;
   4137 
   4138   png_byte
   4139     jng_color_type,
   4140     jng_image_sample_depth,
   4141     jng_image_compression_method,
   4142     jng_image_interlace_method,
   4143     jng_alpha_sample_depth,
   4144     jng_alpha_compression_method,
   4145     jng_alpha_filter_method,
   4146     jng_alpha_interlace_method;
   4147 
   4148   register const Quantum
   4149     *s;
   4150 
   4151   register ssize_t
   4152     i,
   4153     x;
   4154 
   4155   register Quantum
   4156     *q;
   4157 
   4158   register unsigned char
   4159     *p;
   4160 
   4161   unsigned int
   4162     read_JSEP,
   4163     reading_idat;
   4164 
   4165   size_t
   4166     length;
   4167 
   4168   jng_alpha_compression_method=0;
   4169   jng_alpha_sample_depth=8;
   4170   jng_color_type=0;
   4171   jng_height=0;
   4172   jng_width=0;
   4173   alpha_image=(Image *) NULL;
   4174   color_image=(Image *) NULL;
   4175   alpha_image_info=(ImageInfo *) NULL;
   4176   color_image_info=(ImageInfo *) NULL;
   4177 
   4178   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
   4179     "  Enter ReadOneJNGImage()");
   4180 
   4181   image=mng_info->image;
   4182 
   4183   if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   4184     {
   4185       /*
   4186         Allocate next image structure.
   4187       */
   4188       if (logging != MagickFalse)
   4189         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4190            "  AcquireNextImage()");
   4191 
   4192       AcquireNextImage(image_info,image,exception);
   4193 
   4194       if (GetNextImageInList(image) == (Image *) NULL)
   4195         return((Image *) NULL);
   4196 
   4197       image=SyncNextImageInList(image);
   4198     }
   4199   mng_info->image=image;
   4200 
   4201   /*
   4202     Signature bytes have already been read.
   4203   */
   4204 
   4205   read_JSEP=MagickFalse;
   4206   reading_idat=MagickFalse;
   4207   for (;;)
   4208   {
   4209     char
   4210       type[MagickPathExtent];
   4211 
   4212     unsigned char
   4213       *chunk;
   4214 
   4215     unsigned int
   4216       count;
   4217 
   4218     /*
   4219       Read a new JNG chunk.
   4220     */
   4221     status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
   4222       2*GetBlobSize(image));
   4223 
   4224     if (status == MagickFalse)
   4225       break;
   4226 
   4227     type[0]='\0';
   4228     (void) ConcatenateMagickString(type,"errr",MagickPathExtent);
   4229     length=ReadBlobMSBLong(image);
   4230     count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
   4231 
   4232     if (logging != MagickFalse)
   4233       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4234         "  Reading JNG chunk type %c%c%c%c, length: %.20g",
   4235         type[0],type[1],type[2],type[3],(double) length);
   4236 
   4237     if (length > PNG_UINT_31_MAX || count == 0)
   4238       ThrowReaderException(CorruptImageError,"CorruptImage");
   4239 
   4240     p=NULL;
   4241     chunk=(unsigned char *) NULL;
   4242 
   4243     if (length != 0)
   4244       {
   4245         chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
   4246 
   4247         if (chunk == (unsigned char *) NULL)
   4248           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4249 
   4250         for (i=0; i < (ssize_t) length; i++)
   4251           chunk[i]=(unsigned char) ReadBlobByte(image);
   4252 
   4253         p=chunk;
   4254       }
   4255 
   4256     (void) ReadBlobMSBLong(image);  /* read crc word */
   4257 
   4258     if (memcmp(type,mng_JHDR,4) == 0)
   4259       {
   4260         if (length == 16)
   4261           {
   4262             jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
   4263               (p[2] << 8) | p[3]);
   4264             jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
   4265               (p[6] << 8) | p[7]);
   4266             if ((jng_width == 0) || (jng_height == 0))
   4267               ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
   4268             jng_color_type=p[8];
   4269             jng_image_sample_depth=p[9];
   4270             jng_image_compression_method=p[10];
   4271             jng_image_interlace_method=p[11];
   4272 
   4273             image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
   4274               NoInterlace;
   4275 
   4276             jng_alpha_sample_depth=p[12];
   4277             jng_alpha_compression_method=p[13];
   4278             jng_alpha_filter_method=p[14];
   4279             jng_alpha_interlace_method=p[15];
   4280 
   4281             if (logging != MagickFalse)
   4282               {
   4283                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4284                   "    jng_width:      %16lu,    jng_height:     %16lu\n"
   4285                   "    jng_color_type: %16d,     jng_image_sample_depth: %3d\n"
   4286                   "    jng_image_compression_method:%3d",
   4287                   (unsigned long) jng_width, (unsigned long) jng_height,
   4288                   jng_color_type, jng_image_sample_depth,
   4289                   jng_image_compression_method);
   4290 
   4291                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4292                   "    jng_image_interlace_method:  %3d"
   4293                   "    jng_alpha_sample_depth:      %3d",
   4294                   jng_image_interlace_method,
   4295                   jng_alpha_sample_depth);
   4296 
   4297                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4298                   "    jng_alpha_compression_method:%3d\n"
   4299                   "    jng_alpha_filter_method:     %3d\n"
   4300                   "    jng_alpha_interlace_method:  %3d",
   4301                   jng_alpha_compression_method,
   4302                   jng_alpha_filter_method,
   4303                   jng_alpha_interlace_method);
   4304               }
   4305           }
   4306 
   4307         if (length != 0)
   4308           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4309 
   4310         continue;
   4311       }
   4312 
   4313 
   4314     if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
   4315         ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
   4316          (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
   4317       {
   4318         /*
   4319            o create color_image
   4320            o open color_blob, attached to color_image
   4321            o if (color type has alpha)
   4322                open alpha_blob, attached to alpha_image
   4323         */
   4324 
   4325         color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
   4326 
   4327         if (color_image_info == (ImageInfo *) NULL)
   4328           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4329 
   4330         GetImageInfo(color_image_info);
   4331         color_image=AcquireImage(color_image_info,exception);
   4332 
   4333         if (color_image == (Image *) NULL)
   4334           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4335 
   4336         if (logging != MagickFalse)
   4337           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4338             "    Creating color_blob.");
   4339 
   4340         (void) AcquireUniqueFilename(color_image->filename);
   4341         status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
   4342           exception);
   4343 
   4344         if (status == MagickFalse)
   4345           return((Image *) NULL);
   4346 
   4347         if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
   4348           {
   4349             alpha_image_info=(ImageInfo *)
   4350               AcquireMagickMemory(sizeof(ImageInfo));
   4351 
   4352             if (alpha_image_info == (ImageInfo *) NULL)
   4353               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4354 
   4355             GetImageInfo(alpha_image_info);
   4356             alpha_image=AcquireImage(alpha_image_info,exception);
   4357 
   4358             if (alpha_image == (Image *) NULL)
   4359               {
   4360                 alpha_image=DestroyImage(alpha_image);
   4361                 ThrowReaderException(ResourceLimitError,
   4362                   "MemoryAllocationFailed");
   4363               }
   4364 
   4365             if (logging != MagickFalse)
   4366               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4367                 "    Creating alpha_blob.");
   4368 
   4369             (void) AcquireUniqueFilename(alpha_image->filename);
   4370             status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
   4371               exception);
   4372 
   4373             if (status == MagickFalse)
   4374               return((Image *) NULL);
   4375 
   4376             if (jng_alpha_compression_method == 0)
   4377               {
   4378                 unsigned char
   4379                   data[18];
   4380 
   4381                 if (logging != MagickFalse)
   4382                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4383                     "    Writing IHDR chunk to alpha_blob.");
   4384 
   4385                 (void) WriteBlob(alpha_image,8,(const unsigned char *)
   4386                   "\211PNG\r\n\032\n");
   4387 
   4388                 (void) WriteBlobMSBULong(alpha_image,13L);
   4389                 PNGType(data,mng_IHDR);
   4390                 LogPNGChunk(logging,mng_IHDR,13L);
   4391                 PNGLong(data+4,jng_width);
   4392                 PNGLong(data+8,jng_height);
   4393                 data[12]=jng_alpha_sample_depth;
   4394                 data[13]=0; /* color_type gray */
   4395                 data[14]=0; /* compression method 0 */
   4396                 data[15]=0; /* filter_method 0 */
   4397                 data[16]=0; /* interlace_method 0 */
   4398                 (void) WriteBlob(alpha_image,17,data);
   4399                 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
   4400               }
   4401           }
   4402         reading_idat=MagickTrue;
   4403       }
   4404 
   4405     if (memcmp(type,mng_JDAT,4) == 0)
   4406       {
   4407         /* Copy chunk to color_image->blob */
   4408 
   4409         if (logging != MagickFalse)
   4410           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4411             "    Copying JDAT chunk data to color_blob.");
   4412 
   4413         (void) WriteBlob(color_image,length,chunk);
   4414 
   4415         if (length != 0)
   4416           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4417 
   4418         continue;
   4419       }
   4420 
   4421     if (memcmp(type,mng_IDAT,4) == 0)
   4422       {
   4423         png_byte
   4424            data[5];
   4425 
   4426         /* Copy IDAT header and chunk data to alpha_image->blob */
   4427 
   4428         if (alpha_image != NULL && image_info->ping == MagickFalse)
   4429           {
   4430             if (logging != MagickFalse)
   4431               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4432                 "    Copying IDAT chunk data to alpha_blob.");
   4433 
   4434             (void) WriteBlobMSBULong(alpha_image,(size_t) length);
   4435             PNGType(data,mng_IDAT);
   4436             LogPNGChunk(logging,mng_IDAT,length);
   4437             (void) WriteBlob(alpha_image,4,data);
   4438             (void) WriteBlob(alpha_image,length,chunk);
   4439             (void) WriteBlobMSBULong(alpha_image,
   4440               crc32(crc32(0,data,4),chunk,(uInt) length));
   4441           }
   4442 
   4443         if (length != 0)
   4444           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4445 
   4446         continue;
   4447       }
   4448 
   4449     if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
   4450       {
   4451         /* Copy chunk data to alpha_image->blob */
   4452 
   4453         if (alpha_image != NULL && image_info->ping == MagickFalse)
   4454           {
   4455             if (logging != MagickFalse)
   4456               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4457                 "    Copying JDAA chunk data to alpha_blob.");
   4458 
   4459             (void) WriteBlob(alpha_image,length,chunk);
   4460           }
   4461 
   4462         if (length != 0)
   4463           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4464 
   4465         continue;
   4466       }
   4467 
   4468     if (memcmp(type,mng_JSEP,4) == 0)
   4469       {
   4470         read_JSEP=MagickTrue;
   4471 
   4472         if (length != 0)
   4473           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4474 
   4475         continue;
   4476       }
   4477 
   4478     if (memcmp(type,mng_bKGD,4) == 0)
   4479       {
   4480         if (length == 2)
   4481           {
   4482             image->background_color.red=ScaleCharToQuantum(p[1]);
   4483             image->background_color.green=image->background_color.red;
   4484             image->background_color.blue=image->background_color.red;
   4485           }
   4486 
   4487         if (length == 6)
   4488           {
   4489             image->background_color.red=ScaleCharToQuantum(p[1]);
   4490             image->background_color.green=ScaleCharToQuantum(p[3]);
   4491             image->background_color.blue=ScaleCharToQuantum(p[5]);
   4492           }
   4493 
   4494         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4495         continue;
   4496       }
   4497 
   4498     if (memcmp(type,mng_gAMA,4) == 0)
   4499       {
   4500         if (length == 4)
   4501           image->gamma=((float) mng_get_long(p))*0.00001;
   4502 
   4503         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4504         continue;
   4505       }
   4506 
   4507     if (memcmp(type,mng_cHRM,4) == 0)
   4508       {
   4509         if (length == 32)
   4510           {
   4511             image->chromaticity.white_point.x=0.00001*mng_get_long(p);
   4512             image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
   4513             image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
   4514             image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
   4515             image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
   4516             image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
   4517             image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
   4518             image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
   4519           }
   4520 
   4521         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4522         continue;
   4523       }
   4524 
   4525     if (memcmp(type,mng_sRGB,4) == 0)
   4526       {
   4527         if (length == 1)
   4528           {
   4529             image->rendering_intent=
   4530               Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
   4531             image->gamma=1.000f/2.200f;
   4532             image->chromaticity.red_primary.x=0.6400f;
   4533             image->chromaticity.red_primary.y=0.3300f;
   4534             image->chromaticity.green_primary.x=0.3000f;
   4535             image->chromaticity.green_primary.y=0.6000f;
   4536             image->chromaticity.blue_primary.x=0.1500f;
   4537             image->chromaticity.blue_primary.y=0.0600f;
   4538             image->chromaticity.white_point.x=0.3127f;
   4539             image->chromaticity.white_point.y=0.3290f;
   4540           }
   4541 
   4542         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4543         continue;
   4544       }
   4545 
   4546     if (memcmp(type,mng_oFFs,4) == 0)
   4547       {
   4548         if (length > 8)
   4549           {
   4550             image->page.x=(ssize_t) mng_get_long(p);
   4551             image->page.y=(ssize_t) mng_get_long(&p[4]);
   4552 
   4553             if ((int) p[8] != 0)
   4554               {
   4555                 image->page.x/=10000;
   4556                 image->page.y/=10000;
   4557               }
   4558           }
   4559 
   4560         if (length != 0)
   4561           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4562 
   4563         continue;
   4564       }
   4565 
   4566     if (memcmp(type,mng_pHYs,4) == 0)
   4567       {
   4568         if (length > 8)
   4569           {
   4570             image->resolution.x=(double) mng_get_long(p);
   4571             image->resolution.y=(double) mng_get_long(&p[4]);
   4572             if ((int) p[8] == PNG_RESOLUTION_METER)
   4573               {
   4574                 image->units=PixelsPerCentimeterResolution;
   4575                 image->resolution.x=image->resolution.x/100.0f;
   4576                 image->resolution.y=image->resolution.y/100.0f;
   4577               }
   4578           }
   4579 
   4580         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4581         continue;
   4582       }
   4583 
   4584 #if 0
   4585     if (memcmp(type,mng_iCCP,4) == 0)
   4586       {
   4587         /* To do: */
   4588         if (length != 0)
   4589           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4590 
   4591         continue;
   4592       }
   4593 #endif
   4594 
   4595     if (length != 0)
   4596       chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   4597 
   4598     if (memcmp(type,mng_IEND,4))
   4599       continue;
   4600 
   4601     break;
   4602   }
   4603 
   4604 
   4605   /* IEND found */
   4606 
   4607   /*
   4608     Finish up reading image data:
   4609 
   4610        o read main image from color_blob.
   4611 
   4612        o close color_blob.
   4613 
   4614        o if (color_type has alpha)
   4615             if alpha_encoding is PNG
   4616                read secondary image from alpha_blob via ReadPNG
   4617             if alpha_encoding is JPEG
   4618                read secondary image from alpha_blob via ReadJPEG
   4619 
   4620        o close alpha_blob.
   4621 
   4622        o copy intensity of secondary image into
   4623          alpha samples of main image.
   4624 
   4625        o destroy the secondary image.
   4626   */
   4627 
   4628   if (color_image_info == (ImageInfo *) NULL)
   4629     {
   4630       assert(color_image == (Image *) NULL);
   4631       assert(alpha_image == (Image *) NULL);
   4632       return((Image *) NULL);
   4633     }
   4634 
   4635   if (color_image == (Image *) NULL)
   4636     {
   4637       assert(alpha_image == (Image *) NULL);
   4638       return((Image *) NULL);
   4639     }
   4640 
   4641   (void) SeekBlob(color_image,0,SEEK_SET);
   4642 
   4643   if (logging != MagickFalse)
   4644     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4645       "    Reading jng_image from color_blob.");
   4646 
   4647   assert(color_image_info != (ImageInfo *) NULL);
   4648   (void) FormatLocaleString(color_image_info->filename,MagickPathExtent,"%s",
   4649     color_image->filename);
   4650 
   4651   color_image_info->ping=MagickFalse;   /* To do: avoid this */
   4652   jng_image=ReadImage(color_image_info,exception);
   4653 
   4654   (void) RelinquishUniqueFileResource(color_image->filename);
   4655   color_image=DestroyImage(color_image);
   4656   color_image_info=DestroyImageInfo(color_image_info);
   4657 
   4658   if (jng_image == (Image *) NULL)
   4659     return((Image *) NULL);
   4660 
   4661   if (logging != MagickFalse)
   4662     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4663       "    Copying jng_image pixels to main image.");
   4664 
   4665   image->rows=jng_height;
   4666   image->columns=jng_width;
   4667 
   4668   status=SetImageExtent(image,image->columns,image->rows,exception);
   4669   if (status == MagickFalse)
   4670     return(DestroyImageList(image));
   4671 
   4672   for (y=0; y < (ssize_t) image->rows; y++)
   4673   {
   4674     s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
   4675     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   4676     for (x=(ssize_t) image->columns; x != 0; x--)
   4677     {
   4678       SetPixelRed(image,GetPixelRed(jng_image,s),q);
   4679       SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
   4680       SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
   4681       q+=GetPixelChannels(image);
   4682       s+=GetPixelChannels(jng_image);
   4683     }
   4684 
   4685     if (SyncAuthenticPixels(image,exception) == MagickFalse)
   4686       break;
   4687   }
   4688 
   4689   jng_image=DestroyImage(jng_image);
   4690 
   4691   if (image_info->ping == MagickFalse)
   4692     {
   4693      if (jng_color_type >= 12)
   4694        {
   4695          if (jng_alpha_compression_method == 0)
   4696            {
   4697              png_byte
   4698                data[5];
   4699              (void) WriteBlobMSBULong(alpha_image,0x00000000L);
   4700              PNGType(data,mng_IEND);
   4701              LogPNGChunk(logging,mng_IEND,0L);
   4702              (void) WriteBlob(alpha_image,4,data);
   4703              (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
   4704            }
   4705 
   4706          (void) CloseBlob(alpha_image);
   4707 
   4708          if (logging != MagickFalse)
   4709            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4710              "    Reading alpha from alpha_blob.");
   4711 
   4712          (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent,
   4713            "%s",alpha_image->filename);
   4714 
   4715          jng_image=ReadImage(alpha_image_info,exception);
   4716 
   4717          if (jng_image != (Image *) NULL)
   4718            for (y=0; y < (ssize_t) image->rows; y++)
   4719            {
   4720              s=GetVirtualPixels(jng_image,0,y,image->columns,1,
   4721                exception);
   4722              q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   4723 
   4724              if (image->alpha_trait != UndefinedPixelTrait)
   4725                for (x=(ssize_t) image->columns; x != 0; x--)
   4726                {
   4727                   SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
   4728                   q+=GetPixelChannels(image);
   4729                   s+=GetPixelChannels(jng_image);
   4730                }
   4731 
   4732              else
   4733                for (x=(ssize_t) image->columns; x != 0; x--)
   4734                {
   4735                   SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
   4736                   if (GetPixelAlpha(image,q) != OpaqueAlpha)
   4737                     image->alpha_trait=BlendPixelTrait;
   4738                   q+=GetPixelChannels(image);
   4739                   s+=GetPixelChannels(jng_image);
   4740                }
   4741 
   4742              if (SyncAuthenticPixels(image,exception) == MagickFalse)
   4743                break;
   4744            }
   4745          (void) RelinquishUniqueFileResource(alpha_image->filename);
   4746          alpha_image=DestroyImage(alpha_image);
   4747          alpha_image_info=DestroyImageInfo(alpha_image_info);
   4748          if (jng_image != (Image *) NULL)
   4749            jng_image=DestroyImage(jng_image);
   4750        }
   4751     }
   4752 
   4753   /* Read the JNG image.  */
   4754 
   4755   if (mng_info->mng_type == 0)
   4756     {
   4757       mng_info->mng_width=jng_width;
   4758       mng_info->mng_height=jng_height;
   4759     }
   4760 
   4761   if (image->page.width == 0 && image->page.height == 0)
   4762     {
   4763       image->page.width=jng_width;
   4764       image->page.height=jng_height;
   4765     }
   4766 
   4767   if (image->page.x == 0 && image->page.y == 0)
   4768     {
   4769       image->page.x=mng_info->x_off[mng_info->object_id];
   4770       image->page.y=mng_info->y_off[mng_info->object_id];
   4771     }
   4772 
   4773   else
   4774     {
   4775       image->page.y=mng_info->y_off[mng_info->object_id];
   4776     }
   4777 
   4778   mng_info->image_found++;
   4779   status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
   4780     2*GetBlobSize(image));
   4781 
   4782   if (status == MagickFalse)
   4783     return((Image *) NULL);
   4784 
   4785   if (logging != MagickFalse)
   4786     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4787       "  exit ReadOneJNGImage()");
   4788 
   4789   return(image);
   4790 }
   4791 
   4792 /*
   4793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4794 %                                                                             %
   4795 %                                                                             %
   4796 %                                                                             %
   4797 %   R e a d J N G I m a g e                                                   %
   4798 %                                                                             %
   4799 %                                                                             %
   4800 %                                                                             %
   4801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4802 %
   4803 %  ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
   4804 %  (including the 8-byte signature)  and returns it.  It allocates the memory
   4805 %  necessary for the new Image structure and returns a pointer to the new
   4806 %  image.
   4807 %
   4808 %  JNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   4809 %
   4810 %  The format of the ReadJNGImage method is:
   4811 %
   4812 %      Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
   4813 %         *exception)
   4814 %
   4815 %  A description of each parameter follows:
   4816 %
   4817 %    o image_info: the image info.
   4818 %
   4819 %    o exception: return any errors or warnings in this structure.
   4820 %
   4821 */
   4822 
   4823 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   4824 {
   4825   Image
   4826     *image;
   4827 
   4828   MagickBooleanType
   4829     have_mng_structure,
   4830     logging,
   4831     status;
   4832 
   4833   MngInfo
   4834     *mng_info;
   4835 
   4836   char
   4837     magic_number[MagickPathExtent];
   4838 
   4839   size_t
   4840     count;
   4841 
   4842   /*
   4843     Open image file.
   4844   */
   4845   assert(image_info != (const ImageInfo *) NULL);
   4846   assert(image_info->signature == MagickCoreSignature);
   4847   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
   4848   assert(exception != (ExceptionInfo *) NULL);
   4849   assert(exception->signature == MagickCoreSignature);
   4850   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
   4851   image=AcquireImage(image_info,exception);
   4852   mng_info=(MngInfo *) NULL;
   4853   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   4854 
   4855   if (status == MagickFalse)
   4856     return((Image *) NULL);
   4857 
   4858   if (LocaleCompare(image_info->magick,"JNG") != 0)
   4859     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   4860 
   4861   /* Verify JNG signature.  */
   4862 
   4863   count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
   4864 
   4865   if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
   4866     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   4867 
   4868   /* Allocate a MngInfo structure.  */
   4869 
   4870   have_mng_structure=MagickFalse;
   4871   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
   4872 
   4873   if (mng_info == (MngInfo *) NULL)
   4874     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   4875 
   4876   /* Initialize members of the MngInfo structure.  */
   4877 
   4878   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   4879   have_mng_structure=MagickTrue;
   4880 
   4881   mng_info->image=image;
   4882   image=ReadOneJNGImage(mng_info,image_info,exception);
   4883   MngInfoFreeStruct(mng_info,&have_mng_structure);
   4884 
   4885   if (image == (Image *) NULL)
   4886     {
   4887       if (logging != MagickFalse)
   4888         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4889           "exit ReadJNGImage() with error");
   4890 
   4891       return((Image *) NULL);
   4892     }
   4893   (void) CloseBlob(image);
   4894 
   4895   if (image->columns == 0 || image->rows == 0)
   4896     {
   4897       if (logging != MagickFalse)
   4898         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   4899           "exit ReadJNGImage() with error");
   4900 
   4901       ThrowReaderException(CorruptImageError,"CorruptImage");
   4902     }
   4903 
   4904   if (logging != MagickFalse)
   4905     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
   4906 
   4907   return(image);
   4908 }
   4909 #endif
   4910 
   4911 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   4912 {
   4913   char
   4914     page_geometry[MagickPathExtent];
   4915 
   4916   Image
   4917     *image;
   4918 
   4919   MagickBooleanType
   4920     logging,
   4921     have_mng_structure;
   4922 
   4923   volatile int
   4924     first_mng_object,
   4925     object_id,
   4926     term_chunk_found,
   4927     skip_to_iend;
   4928 
   4929   volatile ssize_t
   4930     image_count=0;
   4931 
   4932   MagickBooleanType
   4933     status;
   4934 
   4935   MagickOffsetType
   4936     offset;
   4937 
   4938   MngInfo
   4939     *mng_info;
   4940 
   4941   MngBox
   4942     default_fb,
   4943     fb,
   4944     previous_fb;
   4945 
   4946 #if defined(MNG_INSERT_LAYERS)
   4947   PixelInfo
   4948     mng_background_color;
   4949 #endif
   4950 
   4951   register unsigned char
   4952     *p;
   4953 
   4954   register ssize_t
   4955     i;
   4956 
   4957   size_t
   4958     count;
   4959 
   4960   ssize_t
   4961     loop_level;
   4962 
   4963   volatile short
   4964     skipping_loop;
   4965 
   4966 #if defined(MNG_INSERT_LAYERS)
   4967   unsigned int
   4968     mandatory_back=0;
   4969 #endif
   4970 
   4971   volatile unsigned int
   4972 #ifdef MNG_OBJECT_BUFFERS
   4973     mng_background_object=0,
   4974 #endif
   4975     mng_type=0;   /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
   4976 
   4977   size_t
   4978     default_frame_timeout,
   4979     frame_timeout,
   4980 #if defined(MNG_INSERT_LAYERS)
   4981     image_height,
   4982     image_width,
   4983 #endif
   4984     length;
   4985 
   4986   /* These delays are all measured in image ticks_per_second,
   4987    * not in MNG ticks_per_second
   4988    */
   4989   volatile size_t
   4990     default_frame_delay,
   4991     final_delay,
   4992     final_image_delay,
   4993     frame_delay,
   4994 #if defined(MNG_INSERT_LAYERS)
   4995     insert_layers,
   4996 #endif
   4997     mng_iterations=1,
   4998     simplicity=0,
   4999     subframe_height=0,
   5000     subframe_width=0;
   5001 
   5002   previous_fb.top=0;
   5003   previous_fb.bottom=0;
   5004   previous_fb.left=0;
   5005   previous_fb.right=0;
   5006   default_fb.top=0;
   5007   default_fb.bottom=0;
   5008   default_fb.left=0;
   5009   default_fb.right=0;
   5010 
   5011   /* Open image file.  */
   5012 
   5013   assert(image_info != (const ImageInfo *) NULL);
   5014   assert(image_info->signature == MagickCoreSignature);
   5015   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
   5016   assert(exception != (ExceptionInfo *) NULL);
   5017   assert(exception->signature == MagickCoreSignature);
   5018   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
   5019   image=AcquireImage(image_info,exception);
   5020   mng_info=(MngInfo *) NULL;
   5021   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   5022 
   5023   if (status == MagickFalse)
   5024     return((Image *) NULL);
   5025 
   5026   first_mng_object=MagickFalse;
   5027   skipping_loop=(-1);
   5028   have_mng_structure=MagickFalse;
   5029 
   5030   /* Allocate a MngInfo structure.  */
   5031 
   5032   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
   5033 
   5034   if (mng_info == (MngInfo *) NULL)
   5035     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   5036 
   5037   /* Initialize members of the MngInfo structure.  */
   5038 
   5039   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   5040   mng_info->image=image;
   5041   have_mng_structure=MagickTrue;
   5042 
   5043   if (LocaleCompare(image_info->magick,"MNG") == 0)
   5044     {
   5045       char
   5046         magic_number[MagickPathExtent];
   5047 
   5048       /* Verify MNG signature.  */
   5049       count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
   5050       if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
   5051         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   5052 
   5053       /* Initialize some nonzero members of the MngInfo structure.  */
   5054       for (i=0; i < MNG_MAX_OBJECTS; i++)
   5055       {
   5056         mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
   5057         mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
   5058       }
   5059       mng_info->exists[0]=MagickTrue;
   5060     }
   5061 
   5062   first_mng_object=MagickTrue;
   5063   mng_type=0;
   5064 #if defined(MNG_INSERT_LAYERS)
   5065   insert_layers=MagickFalse; /* should be False when converting or mogrifying */
   5066 #endif
   5067   default_frame_delay=0;
   5068   default_frame_timeout=0;
   5069   frame_delay=0;
   5070   final_delay=1;
   5071   mng_info->ticks_per_second=1UL*image->ticks_per_second;
   5072   object_id=0;
   5073   skip_to_iend=MagickFalse;
   5074   term_chunk_found=MagickFalse;
   5075   mng_info->framing_mode=1;
   5076 #if defined(MNG_INSERT_LAYERS)
   5077   mandatory_back=MagickFalse;
   5078 #endif
   5079 #if defined(MNG_INSERT_LAYERS)
   5080   mng_background_color=image->background_color;
   5081 #endif
   5082   default_fb=mng_info->frame;
   5083   previous_fb=mng_info->frame;
   5084   do
   5085   {
   5086     char
   5087       type[MagickPathExtent];
   5088 
   5089     if (LocaleCompare(image_info->magick,"MNG") == 0)
   5090       {
   5091         unsigned char
   5092           *chunk;
   5093 
   5094         /*
   5095           Read a new chunk.
   5096         */
   5097         type[0]='\0';
   5098         (void) ConcatenateMagickString(type,"errr",MagickPathExtent);
   5099         length=ReadBlobMSBLong(image);
   5100         count=(size_t) ReadBlob(image,4,(unsigned char *) type);
   5101 
   5102         if (logging != MagickFalse)
   5103           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5104            "  Reading MNG chunk type %c%c%c%c, length: %.20g",
   5105            type[0],type[1],type[2],type[3],(double) length);
   5106 
   5107         if (length > PNG_UINT_31_MAX)
   5108           {
   5109             status=MagickFalse;
   5110             break;
   5111           }
   5112 
   5113         if (count == 0)
   5114           ThrowReaderException(CorruptImageError,"CorruptImage");
   5115 
   5116         p=NULL;
   5117         chunk=(unsigned char *) NULL;
   5118 
   5119         if (length != 0)
   5120           {
   5121             chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
   5122 
   5123             if (chunk == (unsigned char *) NULL)
   5124               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   5125 
   5126             for (i=0; i < (ssize_t) length; i++)
   5127               chunk[i]=(unsigned char) ReadBlobByte(image);
   5128 
   5129             p=chunk;
   5130           }
   5131 
   5132         (void) ReadBlobMSBLong(image);  /* read crc word */
   5133 
   5134 #if !defined(JNG_SUPPORTED)
   5135         if (memcmp(type,mng_JHDR,4) == 0)
   5136           {
   5137             skip_to_iend=MagickTrue;
   5138 
   5139             if (mng_info->jhdr_warning == 0)
   5140               (void) ThrowMagickException(exception,GetMagickModule(),
   5141                 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
   5142 
   5143             mng_info->jhdr_warning++;
   5144           }
   5145 #endif
   5146         if (memcmp(type,mng_DHDR,4) == 0)
   5147           {
   5148             skip_to_iend=MagickTrue;
   5149 
   5150             if (mng_info->dhdr_warning == 0)
   5151               (void) ThrowMagickException(exception,GetMagickModule(),
   5152                 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
   5153 
   5154             mng_info->dhdr_warning++;
   5155           }
   5156         if (memcmp(type,mng_MEND,4) == 0)
   5157           break;
   5158 
   5159         if (skip_to_iend)
   5160           {
   5161             if (memcmp(type,mng_IEND,4) == 0)
   5162               skip_to_iend=MagickFalse;
   5163 
   5164             if (length != 0)
   5165               chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5166 
   5167             if (logging != MagickFalse)
   5168               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5169                 "  Skip to IEND.");
   5170 
   5171             continue;
   5172           }
   5173 
   5174         if (memcmp(type,mng_MHDR,4) == 0)
   5175           {
   5176             if (length != 28)
   5177               {
   5178                 if (chunk)
   5179                   chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5180                 ThrowReaderException(CorruptImageError,"CorruptImage");
   5181               }
   5182 
   5183             mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
   5184                 (p[2] << 8) | p[3]);
   5185 
   5186             mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
   5187                 (p[6] << 8) | p[7]);
   5188 
   5189             if (logging != MagickFalse)
   5190               {
   5191                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5192                   "  MNG width: %.20g",(double) mng_info->mng_width);
   5193                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5194                   "  MNG height: %.20g",(double) mng_info->mng_height);
   5195               }
   5196 
   5197             p+=8;
   5198             mng_info->ticks_per_second=(size_t) mng_get_long(p);
   5199 
   5200             if (mng_info->ticks_per_second == 0)
   5201               default_frame_delay=0;
   5202 
   5203             else
   5204               default_frame_delay=1UL*image->ticks_per_second/
   5205                 mng_info->ticks_per_second;
   5206 
   5207             frame_delay=default_frame_delay;
   5208             simplicity=0;
   5209 
   5210             p+=16;
   5211             simplicity=(size_t) mng_get_long(p);
   5212 
   5213             mng_type=1;    /* Full MNG */
   5214 
   5215             if ((simplicity != 0) && ((simplicity | 11) == 11))
   5216               mng_type=2; /* LC */
   5217 
   5218             if ((simplicity != 0) && ((simplicity | 9) == 9))
   5219               mng_type=3; /* VLC */
   5220 
   5221 #if defined(MNG_INSERT_LAYERS)
   5222             if (mng_type != 3)
   5223               insert_layers=MagickTrue;
   5224 #endif
   5225             if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   5226               {
   5227                 /* Allocate next image structure.  */
   5228                 AcquireNextImage(image_info,image,exception);
   5229 
   5230                 if (GetNextImageInList(image) == (Image *) NULL)
   5231                   return((Image *) NULL);
   5232 
   5233                 image=SyncNextImageInList(image);
   5234                 mng_info->image=image;
   5235               }
   5236 
   5237             if ((mng_info->mng_width > 65535L) ||
   5238                 (mng_info->mng_height > 65535L))
   5239               ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
   5240 
   5241             (void) FormatLocaleString(page_geometry,MagickPathExtent,
   5242               "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
   5243               mng_info->mng_height);
   5244 
   5245             mng_info->frame.left=0;
   5246             mng_info->frame.right=(ssize_t) mng_info->mng_width;
   5247             mng_info->frame.top=0;
   5248             mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
   5249             mng_info->clip=default_fb=previous_fb=mng_info->frame;
   5250 
   5251             for (i=0; i < MNG_MAX_OBJECTS; i++)
   5252               mng_info->object_clip[i]=mng_info->frame;
   5253 
   5254             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5255             continue;
   5256           }
   5257 
   5258         if (memcmp(type,mng_TERM,4) == 0)
   5259           {
   5260             int
   5261               repeat=0;
   5262 
   5263             if (length != 0)
   5264               repeat=p[0];
   5265 
   5266             if (repeat == 3)
   5267               {
   5268                 final_delay=(png_uint_32) mng_get_long(&p[2]);
   5269                 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
   5270 
   5271                 if (mng_iterations == PNG_UINT_31_MAX)
   5272                   mng_iterations=0;
   5273 
   5274                 image->iterations=mng_iterations;
   5275                 term_chunk_found=MagickTrue;
   5276               }
   5277 
   5278             if (logging != MagickFalse)
   5279               {
   5280                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5281                   "    repeat=%d,  final_delay=%.20g,  iterations=%.20g",
   5282                   repeat,(double) final_delay, (double) image->iterations);
   5283               }
   5284 
   5285             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5286             continue;
   5287           }
   5288         if (memcmp(type,mng_DEFI,4) == 0)
   5289           {
   5290             if (mng_type == 3)
   5291               (void) ThrowMagickException(exception,GetMagickModule(),
   5292                 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
   5293                 image->filename);
   5294 
   5295             if (length < 2)
   5296               {
   5297                 if (chunk)
   5298                   chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5299                 ThrowReaderException(CorruptImageError,"CorruptImage");
   5300               }
   5301 
   5302             object_id=(p[0] << 8) | p[1];
   5303 
   5304             if (mng_type == 2 && object_id != 0)
   5305               (void) ThrowMagickException(exception,GetMagickModule(),
   5306                 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
   5307                 image->filename);
   5308 
   5309             if (object_id > MNG_MAX_OBJECTS)
   5310               {
   5311                 /*
   5312                   Instead of using a warning we should allocate a larger
   5313                   MngInfo structure and continue.
   5314                 */
   5315                 (void) ThrowMagickException(exception,GetMagickModule(),
   5316                   CoderError,"object id too large","`%s'",image->filename);
   5317                 object_id=MNG_MAX_OBJECTS;
   5318               }
   5319 
   5320             if (mng_info->exists[object_id])
   5321               if (mng_info->frozen[object_id])
   5322                 {
   5323                   chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5324                   (void) ThrowMagickException(exception,
   5325                     GetMagickModule(),CoderError,
   5326                     "DEFI cannot redefine a frozen MNG object","`%s'",
   5327                     image->filename);
   5328                   continue;
   5329                 }
   5330 
   5331             mng_info->exists[object_id]=MagickTrue;
   5332 
   5333             if (length > 2)
   5334               mng_info->invisible[object_id]=p[2];
   5335 
   5336             /*
   5337               Extract object offset info.
   5338             */
   5339             if (length > 11)
   5340               {
   5341                 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
   5342                     (p[5] << 16) | (p[6] << 8) | p[7]);
   5343 
   5344                 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
   5345                     (p[9] << 16) | (p[10] << 8) | p[11]);
   5346 
   5347                 if (logging != MagickFalse)
   5348                   {
   5349                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5350                       "  x_off[%d]: %.20g,  y_off[%d]: %.20g",
   5351                       object_id,(double) mng_info->x_off[object_id],
   5352                       object_id,(double) mng_info->y_off[object_id]);
   5353                   }
   5354               }
   5355 
   5356             /*
   5357               Extract object clipping info.
   5358             */
   5359             if (length > 27)
   5360               mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
   5361                 &p[12]);
   5362 
   5363             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5364             continue;
   5365           }
   5366         if (memcmp(type,mng_bKGD,4) == 0)
   5367           {
   5368             mng_info->have_global_bkgd=MagickFalse;
   5369 
   5370             if (length > 5)
   5371               {
   5372                 mng_info->mng_global_bkgd.red=
   5373                   ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
   5374 
   5375                 mng_info->mng_global_bkgd.green=
   5376                   ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
   5377 
   5378                 mng_info->mng_global_bkgd.blue=
   5379                   ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
   5380 
   5381                 mng_info->have_global_bkgd=MagickTrue;
   5382               }
   5383 
   5384             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5385             continue;
   5386           }
   5387         if (memcmp(type,mng_BACK,4) == 0)
   5388           {
   5389 #if defined(MNG_INSERT_LAYERS)
   5390             if (length > 6)
   5391               mandatory_back=p[6];
   5392 
   5393             else
   5394               mandatory_back=0;
   5395 
   5396             if (mandatory_back && length > 5)
   5397               {
   5398                 mng_background_color.red=
   5399                     ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
   5400 
   5401                 mng_background_color.green=
   5402                     ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
   5403 
   5404                 mng_background_color.blue=
   5405                     ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
   5406 
   5407                 mng_background_color.alpha=OpaqueAlpha;
   5408               }
   5409 
   5410 #ifdef MNG_OBJECT_BUFFERS
   5411             if (length > 8)
   5412               mng_background_object=(p[7] << 8) | p[8];
   5413 #endif
   5414 #endif
   5415             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5416             continue;
   5417           }
   5418 
   5419         if (memcmp(type,mng_PLTE,4) == 0)
   5420           {
   5421             /* Read global PLTE.  */
   5422 
   5423             if (length && (length < 769))
   5424               {
   5425                 if (mng_info->global_plte == (png_colorp) NULL)
   5426                   mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
   5427                     sizeof(*mng_info->global_plte));
   5428 
   5429                 for (i=0; i < (ssize_t) (length/3); i++)
   5430                 {
   5431                   mng_info->global_plte[i].red=p[3*i];
   5432                   mng_info->global_plte[i].green=p[3*i+1];
   5433                   mng_info->global_plte[i].blue=p[3*i+2];
   5434                 }
   5435 
   5436                 mng_info->global_plte_length=(unsigned int) (length/3);
   5437               }
   5438 #ifdef MNG_LOOSE
   5439             for ( ; i < 256; i++)
   5440             {
   5441               mng_info->global_plte[i].red=i;
   5442               mng_info->global_plte[i].green=i;
   5443               mng_info->global_plte[i].blue=i;
   5444             }
   5445 
   5446             if (length != 0)
   5447               mng_info->global_plte_length=256;
   5448 #endif
   5449             else
   5450               mng_info->global_plte_length=0;
   5451 
   5452             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5453             continue;
   5454           }
   5455 
   5456         if (memcmp(type,mng_tRNS,4) == 0)
   5457           {
   5458             /* read global tRNS */
   5459 
   5460             if (length > 0 && length < 257)
   5461               for (i=0; i < (ssize_t) length; i++)
   5462                 mng_info->global_trns[i]=p[i];
   5463 
   5464 #ifdef MNG_LOOSE
   5465             for ( ; i < 256; i++)
   5466               mng_info->global_trns[i]=255;
   5467 #endif
   5468             mng_info->global_trns_length=(unsigned int) length;
   5469             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5470             continue;
   5471           }
   5472         if (memcmp(type,mng_gAMA,4) == 0)
   5473           {
   5474             if (length == 4)
   5475               {
   5476                 ssize_t
   5477                   igamma;
   5478 
   5479                 igamma=mng_get_long(p);
   5480                 mng_info->global_gamma=((float) igamma)*0.00001;
   5481                 mng_info->have_global_gama=MagickTrue;
   5482               }
   5483 
   5484             else
   5485               mng_info->have_global_gama=MagickFalse;
   5486 
   5487             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5488             continue;
   5489           }
   5490 
   5491         if (memcmp(type,mng_cHRM,4) == 0)
   5492           {
   5493             /* Read global cHRM */
   5494 
   5495             if (length == 32)
   5496               {
   5497                 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
   5498                 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
   5499                 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
   5500                 mng_info->global_chrm.red_primary.y=0.00001*
   5501                   mng_get_long(&p[12]);
   5502                 mng_info->global_chrm.green_primary.x=0.00001*
   5503                   mng_get_long(&p[16]);
   5504                 mng_info->global_chrm.green_primary.y=0.00001*
   5505                   mng_get_long(&p[20]);
   5506                 mng_info->global_chrm.blue_primary.x=0.00001*
   5507                   mng_get_long(&p[24]);
   5508                 mng_info->global_chrm.blue_primary.y=0.00001*
   5509                   mng_get_long(&p[28]);
   5510                 mng_info->have_global_chrm=MagickTrue;
   5511               }
   5512             else
   5513               mng_info->have_global_chrm=MagickFalse;
   5514 
   5515             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5516             continue;
   5517           }
   5518 
   5519         if (memcmp(type,mng_sRGB,4) == 0)
   5520           {
   5521             /*
   5522               Read global sRGB.
   5523             */
   5524             if (length != 0)
   5525               {
   5526                 mng_info->global_srgb_intent=
   5527                   Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
   5528                 mng_info->have_global_srgb=MagickTrue;
   5529               }
   5530             else
   5531               mng_info->have_global_srgb=MagickFalse;
   5532 
   5533             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5534             continue;
   5535           }
   5536 
   5537         if (memcmp(type,mng_iCCP,4) == 0)
   5538           {
   5539             /* To do: */
   5540 
   5541             /*
   5542               Read global iCCP.
   5543             */
   5544             if (length != 0)
   5545               chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5546 
   5547             continue;
   5548           }
   5549 
   5550         if (memcmp(type,mng_FRAM,4) == 0)
   5551           {
   5552             if (mng_type == 3)
   5553               (void) ThrowMagickException(exception,GetMagickModule(),
   5554                 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
   5555                 image->filename);
   5556 
   5557             if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
   5558               image->delay=frame_delay;
   5559 
   5560             frame_delay=default_frame_delay;
   5561             frame_timeout=default_frame_timeout;
   5562             fb=default_fb;
   5563 
   5564             if (length != 0)
   5565               if (p[0])
   5566                 mng_info->framing_mode=p[0];
   5567 
   5568             if (logging != MagickFalse)
   5569               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5570                 "    Framing_mode=%d",mng_info->framing_mode);
   5571 
   5572             if (length > 6)
   5573               {
   5574                 /* Note the delay and frame clipping boundaries.  */
   5575 
   5576                 p++; /* framing mode */
   5577 
   5578                 while (*p && ((p-chunk) < (ssize_t) length))
   5579                   p++;  /* frame name */
   5580 
   5581                 p++;  /* frame name terminator */
   5582 
   5583                 if ((p-chunk) < (ssize_t) (length-4))
   5584                   {
   5585                     int
   5586                       change_delay,
   5587                       change_timeout,
   5588                       change_clipping;
   5589 
   5590                     change_delay=(*p++);
   5591                     change_timeout=(*p++);
   5592                     change_clipping=(*p++);
   5593                     p++; /* change_sync */
   5594 
   5595                     if (change_delay)
   5596                       {
   5597                         frame_delay=1UL*image->ticks_per_second*
   5598                           mng_get_long(p);
   5599 
   5600                         if (mng_info->ticks_per_second != 0)
   5601                           frame_delay/=mng_info->ticks_per_second;
   5602 
   5603                         else
   5604                           frame_delay=PNG_UINT_31_MAX;
   5605 
   5606                         if (change_delay == 2)
   5607                           default_frame_delay=frame_delay;
   5608 
   5609                         p+=4;
   5610 
   5611                         if (logging != MagickFalse)
   5612                           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5613                             "    Framing_delay=%.20g",(double) frame_delay);
   5614                       }
   5615 
   5616                     if (change_timeout)
   5617                       {
   5618                         frame_timeout=1UL*image->ticks_per_second*
   5619                           mng_get_long(p);
   5620 
   5621                         if (mng_info->ticks_per_second != 0)
   5622                           frame_timeout/=mng_info->ticks_per_second;
   5623 
   5624                         else
   5625                           frame_timeout=PNG_UINT_31_MAX;
   5626 
   5627                         if (change_timeout == 2)
   5628                           default_frame_timeout=frame_timeout;
   5629 
   5630                         p+=4;
   5631 
   5632                         if (logging != MagickFalse)
   5633                           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5634                             "    Framing_timeout=%.20g",(double) frame_timeout);
   5635                       }
   5636 
   5637                     if (change_clipping)
   5638                       {
   5639                         fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
   5640                         p+=17;
   5641                         previous_fb=fb;
   5642 
   5643                         if (logging != MagickFalse)
   5644                           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5645                             "    Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
   5646                             (double) fb.left,(double) fb.right,(double) fb.top,
   5647                             (double) fb.bottom);
   5648 
   5649                         if (change_clipping == 2)
   5650                           default_fb=fb;
   5651                       }
   5652                   }
   5653               }
   5654             mng_info->clip=fb;
   5655             mng_info->clip=mng_minimum_box(fb,mng_info->frame);
   5656 
   5657             subframe_width=(size_t) (mng_info->clip.right
   5658                -mng_info->clip.left);
   5659 
   5660             subframe_height=(size_t) (mng_info->clip.bottom
   5661                -mng_info->clip.top);
   5662             /*
   5663               Insert a background layer behind the frame if framing_mode is 4.
   5664             */
   5665 #if defined(MNG_INSERT_LAYERS)
   5666             if (logging != MagickFalse)
   5667               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5668                 "   subframe_width=%.20g, subframe_height=%.20g",(double)
   5669                 subframe_width,(double) subframe_height);
   5670 
   5671             if (insert_layers && (mng_info->framing_mode == 4) &&
   5672                 (subframe_width) && (subframe_height))
   5673               {
   5674                 /* Allocate next image structure.  */
   5675                 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   5676                   {
   5677                     AcquireNextImage(image_info,image,exception);
   5678 
   5679                     if (GetNextImageInList(image) == (Image *) NULL)
   5680                       {
   5681                         image=DestroyImageList(image);
   5682                         MngInfoFreeStruct(mng_info,&have_mng_structure);
   5683                         return((Image *) NULL);
   5684                       }
   5685 
   5686                     image=SyncNextImageInList(image);
   5687                   }
   5688 
   5689                 mng_info->image=image;
   5690 
   5691                 if (term_chunk_found)
   5692                   {
   5693                     image->start_loop=MagickTrue;
   5694                     image->iterations=mng_iterations;
   5695                     term_chunk_found=MagickFalse;
   5696                   }
   5697 
   5698                 else
   5699                     image->start_loop=MagickFalse;
   5700 
   5701                 image->columns=subframe_width;
   5702                 image->rows=subframe_height;
   5703                 image->page.width=subframe_width;
   5704                 image->page.height=subframe_height;
   5705                 image->page.x=mng_info->clip.left;
   5706                 image->page.y=mng_info->clip.top;
   5707                 image->background_color=mng_background_color;
   5708                 image->alpha_trait=UndefinedPixelTrait;
   5709                 image->delay=0;
   5710                 (void) SetImageBackgroundColor(image,exception);
   5711 
   5712                 if (logging != MagickFalse)
   5713                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5714                     "  Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
   5715                     (double) mng_info->clip.left,(double) mng_info->clip.right,
   5716                     (double) mng_info->clip.top,(double) mng_info->clip.bottom);
   5717               }
   5718 #endif
   5719             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5720             continue;
   5721           }
   5722 
   5723         if (memcmp(type,mng_CLIP,4) == 0)
   5724           {
   5725             unsigned int
   5726               first_object,
   5727               last_object;
   5728 
   5729             /*
   5730               Read CLIP.
   5731             */
   5732             if (length > 3)
   5733               {
   5734                 first_object=(p[0] << 8) | p[1];
   5735                 last_object=(p[2] << 8) | p[3];
   5736                 p+=4;
   5737 
   5738                 for (i=(int) first_object; i <= (int) last_object; i++)
   5739                 {
   5740                   if (mng_info->exists[i] && !mng_info->frozen[i])
   5741                     {
   5742                       MngBox
   5743                         box;
   5744 
   5745                       box=mng_info->object_clip[i];
   5746                       if ((p-chunk) < (ssize_t) (length-17))
   5747                         mng_info->object_clip[i]=
   5748                            mng_read_box(box,(char) p[0],&p[1]);
   5749                     }
   5750                 }
   5751 
   5752               }
   5753             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5754             continue;
   5755           }
   5756 
   5757         if (memcmp(type,mng_SAVE,4) == 0)
   5758           {
   5759             for (i=1; i < MNG_MAX_OBJECTS; i++)
   5760               if (mng_info->exists[i])
   5761                 {
   5762                  mng_info->frozen[i]=MagickTrue;
   5763 #ifdef MNG_OBJECT_BUFFERS
   5764                  if (mng_info->ob[i] != (MngBuffer *) NULL)
   5765                     mng_info->ob[i]->frozen=MagickTrue;
   5766 #endif
   5767                 }
   5768 
   5769             if (length != 0)
   5770               chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5771 
   5772             continue;
   5773           }
   5774 
   5775         if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
   5776           {
   5777             /* Read DISC or SEEK.  */
   5778 
   5779             if ((length == 0) || !memcmp(type,mng_SEEK,4))
   5780               {
   5781                 for (i=1; i < MNG_MAX_OBJECTS; i++)
   5782                   MngInfoDiscardObject(mng_info,i);
   5783               }
   5784 
   5785             else
   5786               {
   5787                 register ssize_t
   5788                   j;
   5789 
   5790                 for (j=1; j < (ssize_t) length; j+=2)
   5791                 {
   5792                   i=p[j-1] << 8 | p[j];
   5793                   MngInfoDiscardObject(mng_info,i);
   5794                 }
   5795               }
   5796 
   5797             if (length != 0)
   5798               chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5799 
   5800             continue;
   5801           }
   5802 
   5803         if (memcmp(type,mng_MOVE,4) == 0)
   5804           {
   5805             size_t
   5806               first_object,
   5807               last_object;
   5808 
   5809             /* read MOVE */
   5810 
   5811             if (length > 3)
   5812             {
   5813               first_object=(p[0] << 8) | p[1];
   5814               last_object=(p[2] << 8) | p[3];
   5815               p+=4;
   5816 
   5817               for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
   5818               {
   5819                 if (mng_info->exists[i] && !mng_info->frozen[i] &&
   5820                     (p-chunk) < (ssize_t) (length-8))
   5821                   {
   5822                     MngPair
   5823                       new_pair;
   5824 
   5825                     MngPair
   5826                       old_pair;
   5827 
   5828                     old_pair.a=mng_info->x_off[i];
   5829                     old_pair.b=mng_info->y_off[i];
   5830                     new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]);
   5831                     mng_info->x_off[i]=new_pair.a;
   5832                     mng_info->y_off[i]=new_pair.b;
   5833                   }
   5834               }
   5835             }
   5836 
   5837             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5838             continue;
   5839           }
   5840 
   5841         if (memcmp(type,mng_LOOP,4) == 0)
   5842           {
   5843             ssize_t loop_iters=1;
   5844             if (length > 4)
   5845               {
   5846                 loop_level=chunk[0];
   5847                 mng_info->loop_active[loop_level]=1;  /* mark loop active */
   5848 
   5849                 /* Record starting point.  */
   5850                 loop_iters=mng_get_long(&chunk[1]);
   5851 
   5852                 if (logging != MagickFalse)
   5853                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5854                     "  LOOP level %.20g has %.20g iterations ",
   5855                     (double) loop_level, (double) loop_iters);
   5856 
   5857                 if (loop_iters == 0)
   5858                   skipping_loop=loop_level;
   5859 
   5860                 else
   5861                   {
   5862                     mng_info->loop_jump[loop_level]=TellBlob(image);
   5863                     mng_info->loop_count[loop_level]=loop_iters;
   5864                   }
   5865 
   5866                 mng_info->loop_iteration[loop_level]=0;
   5867               }
   5868             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5869             continue;
   5870           }
   5871 
   5872         if (memcmp(type,mng_ENDL,4) == 0)
   5873           {
   5874             if (length > 0)
   5875               {
   5876                 loop_level=chunk[0];
   5877 
   5878                 if (skipping_loop > 0)
   5879                   {
   5880                     if (skipping_loop == loop_level)
   5881                       {
   5882                         /*
   5883                           Found end of zero-iteration loop.
   5884                         */
   5885                         skipping_loop=(-1);
   5886                         mng_info->loop_active[loop_level]=0;
   5887                       }
   5888                   }
   5889 
   5890                 else
   5891                   {
   5892                     if (mng_info->loop_active[loop_level] == 1)
   5893                       {
   5894                         mng_info->loop_count[loop_level]--;
   5895                         mng_info->loop_iteration[loop_level]++;
   5896 
   5897                         if (logging != MagickFalse)
   5898                           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   5899                           "  ENDL: LOOP level %.20g has %.20g remaining iters ",
   5900                             (double) loop_level,(double)
   5901                             mng_info->loop_count[loop_level]);
   5902 
   5903                         if (mng_info->loop_count[loop_level] != 0)
   5904                           {
   5905                             offset=
   5906                               SeekBlob(image,mng_info->loop_jump[loop_level],
   5907                               SEEK_SET);
   5908 
   5909                             if (offset < 0)
   5910                               ThrowReaderException(CorruptImageError,
   5911                                 "ImproperImageHeader");
   5912                           }
   5913 
   5914                         else
   5915                           {
   5916                             short
   5917                               last_level;
   5918 
   5919                             /*
   5920                               Finished loop.
   5921                             */
   5922                             mng_info->loop_active[loop_level]=0;
   5923                             last_level=(-1);
   5924                             for (i=0; i < loop_level; i++)
   5925                               if (mng_info->loop_active[i] == 1)
   5926                                 last_level=(short) i;
   5927                             loop_level=last_level;
   5928                           }
   5929                       }
   5930                   }
   5931               }
   5932 
   5933             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   5934             continue;
   5935           }
   5936 
   5937         if (memcmp(type,mng_CLON,4) == 0)
   5938           {
   5939             if (mng_info->clon_warning == 0)
   5940               (void) ThrowMagickException(exception,GetMagickModule(),
   5941                 CoderError,"CLON is not implemented yet","`%s'",
   5942                 image->filename);
   5943 
   5944             mng_info->clon_warning++;
   5945           }
   5946 
   5947         if (memcmp(type,mng_MAGN,4) == 0)
   5948           {
   5949             png_uint_16
   5950               magn_first,
   5951               magn_last,
   5952               magn_mb,
   5953               magn_ml,
   5954               magn_mr,
   5955               magn_mt,
   5956               magn_mx,
   5957               magn_my,
   5958               magn_methx,
   5959               magn_methy;
   5960 
   5961             if (length > 1)
   5962               magn_first=(p[0] << 8) | p[1];
   5963 
   5964             else
   5965               magn_first=0;
   5966 
   5967             if (length > 3)
   5968               magn_last=(p[2] << 8) | p[3];
   5969 
   5970             else
   5971               magn_last=magn_first;
   5972 #ifndef MNG_OBJECT_BUFFERS
   5973             if (magn_first || magn_last)
   5974               if (mng_info->magn_warning == 0)
   5975                 {
   5976                   (void) ThrowMagickException(exception,
   5977                      GetMagickModule(),CoderError,
   5978                      "MAGN is not implemented yet for nonzero objects",
   5979                      "`%s'",image->filename);
   5980 
   5981                    mng_info->magn_warning++;
   5982                 }
   5983 #endif
   5984             if (length > 4)
   5985               magn_methx=p[4];
   5986 
   5987             else
   5988               magn_methx=0;
   5989 
   5990             if (length > 6)
   5991               magn_mx=(p[5] << 8) | p[6];
   5992 
   5993             else
   5994               magn_mx=1;
   5995 
   5996             if (magn_mx == 0)
   5997               magn_mx=1;
   5998 
   5999             if (length > 8)
   6000               magn_my=(p[7] << 8) | p[8];
   6001 
   6002             else
   6003               magn_my=magn_mx;
   6004 
   6005             if (magn_my == 0)
   6006               magn_my=1;
   6007 
   6008             if (length > 10)
   6009               magn_ml=(p[9] << 8) | p[10];
   6010 
   6011             else
   6012               magn_ml=magn_mx;
   6013 
   6014             if (magn_ml == 0)
   6015               magn_ml=1;
   6016 
   6017             if (length > 12)
   6018               magn_mr=(p[11] << 8) | p[12];
   6019 
   6020             else
   6021               magn_mr=magn_mx;
   6022 
   6023             if (magn_mr == 0)
   6024               magn_mr=1;
   6025 
   6026             if (length > 14)
   6027               magn_mt=(p[13] << 8) | p[14];
   6028 
   6029             else
   6030               magn_mt=magn_my;
   6031 
   6032             if (magn_mt == 0)
   6033               magn_mt=1;
   6034 
   6035             if (length > 16)
   6036               magn_mb=(p[15] << 8) | p[16];
   6037 
   6038             else
   6039               magn_mb=magn_my;
   6040 
   6041             if (magn_mb == 0)
   6042               magn_mb=1;
   6043 
   6044             if (length > 17)
   6045               magn_methy=p[17];
   6046 
   6047             else
   6048               magn_methy=magn_methx;
   6049 
   6050 
   6051             if (magn_methx > 5 || magn_methy > 5)
   6052               if (mng_info->magn_warning == 0)
   6053                 {
   6054                   (void) ThrowMagickException(exception,
   6055                      GetMagickModule(),CoderError,
   6056                      "Unknown MAGN method in MNG datastream","`%s'",
   6057                      image->filename);
   6058 
   6059                    mng_info->magn_warning++;
   6060                 }
   6061 #ifdef MNG_OBJECT_BUFFERS
   6062           /* Magnify existing objects in the range magn_first to magn_last */
   6063 #endif
   6064             if (magn_first == 0 || magn_last == 0)
   6065               {
   6066                 /* Save the magnification factors for object 0 */
   6067                 mng_info->magn_mb=magn_mb;
   6068                 mng_info->magn_ml=magn_ml;
   6069                 mng_info->magn_mr=magn_mr;
   6070                 mng_info->magn_mt=magn_mt;
   6071                 mng_info->magn_mx=magn_mx;
   6072                 mng_info->magn_my=magn_my;
   6073                 mng_info->magn_methx=magn_methx;
   6074                 mng_info->magn_methy=magn_methy;
   6075               }
   6076           }
   6077 
   6078         if (memcmp(type,mng_PAST,4) == 0)
   6079           {
   6080             if (mng_info->past_warning == 0)
   6081               (void) ThrowMagickException(exception,GetMagickModule(),
   6082                 CoderError,"PAST is not implemented yet","`%s'",
   6083                 image->filename);
   6084 
   6085             mng_info->past_warning++;
   6086           }
   6087 
   6088         if (memcmp(type,mng_SHOW,4) == 0)
   6089           {
   6090             if (mng_info->show_warning == 0)
   6091               (void) ThrowMagickException(exception,GetMagickModule(),
   6092                 CoderError,"SHOW is not implemented yet","`%s'",
   6093                 image->filename);
   6094 
   6095             mng_info->show_warning++;
   6096           }
   6097 
   6098         if (memcmp(type,mng_sBIT,4) == 0)
   6099           {
   6100             if (length < 4)
   6101               mng_info->have_global_sbit=MagickFalse;
   6102 
   6103             else
   6104               {
   6105                 mng_info->global_sbit.gray=p[0];
   6106                 mng_info->global_sbit.red=p[0];
   6107                 mng_info->global_sbit.green=p[1];
   6108                 mng_info->global_sbit.blue=p[2];
   6109                 mng_info->global_sbit.alpha=p[3];
   6110                 mng_info->have_global_sbit=MagickTrue;
   6111              }
   6112           }
   6113         if (memcmp(type,mng_pHYs,4) == 0)
   6114           {
   6115             if (length > 8)
   6116               {
   6117                 mng_info->global_x_pixels_per_unit=
   6118                     (size_t) mng_get_long(p);
   6119                 mng_info->global_y_pixels_per_unit=
   6120                     (size_t) mng_get_long(&p[4]);
   6121                 mng_info->global_phys_unit_type=p[8];
   6122                 mng_info->have_global_phys=MagickTrue;
   6123               }
   6124 
   6125             else
   6126               mng_info->have_global_phys=MagickFalse;
   6127           }
   6128         if (memcmp(type,mng_pHYg,4) == 0)
   6129           {
   6130             if (mng_info->phyg_warning == 0)
   6131               (void) ThrowMagickException(exception,GetMagickModule(),
   6132                 CoderError,"pHYg is not implemented.","`%s'",image->filename);
   6133 
   6134             mng_info->phyg_warning++;
   6135           }
   6136         if (memcmp(type,mng_BASI,4) == 0)
   6137           {
   6138             skip_to_iend=MagickTrue;
   6139 
   6140             if (mng_info->basi_warning == 0)
   6141               (void) ThrowMagickException(exception,GetMagickModule(),
   6142                 CoderError,"BASI is not implemented yet","`%s'",
   6143                 image->filename);
   6144 
   6145             mng_info->basi_warning++;
   6146 #ifdef MNG_BASI_SUPPORTED
   6147             basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
   6148                (p[2] << 8) | p[3]);
   6149             basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
   6150                (p[6] << 8) | p[7]);
   6151             basi_color_type=p[8];
   6152             basi_compression_method=p[9];
   6153             basi_filter_type=p[10];
   6154             basi_interlace_method=p[11];
   6155             if (length > 11)
   6156               basi_red=(p[12] << 8) & p[13];
   6157 
   6158             else
   6159               basi_red=0;
   6160 
   6161             if (length > 13)
   6162               basi_green=(p[14] << 8) & p[15];
   6163 
   6164             else
   6165               basi_green=0;
   6166 
   6167             if (length > 15)
   6168               basi_blue=(p[16] << 8) & p[17];
   6169 
   6170             else
   6171               basi_blue=0;
   6172 
   6173             if (length > 17)
   6174               basi_alpha=(p[18] << 8) & p[19];
   6175 
   6176             else
   6177               {
   6178                 if (basi_sample_depth == 16)
   6179                   basi_alpha=65535L;
   6180                 else
   6181                   basi_alpha=255;
   6182               }
   6183 
   6184             if (length > 19)
   6185               basi_viewable=p[20];
   6186 
   6187             else
   6188               basi_viewable=0;
   6189 
   6190 #endif
   6191             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   6192             continue;
   6193           }
   6194 
   6195         if (memcmp(type,mng_IHDR,4)
   6196 #if defined(JNG_SUPPORTED)
   6197             && memcmp(type,mng_JHDR,4)
   6198 #endif
   6199             )
   6200           {
   6201             /* Not an IHDR or JHDR chunk */
   6202             if (length != 0)
   6203               chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   6204 
   6205             continue;
   6206           }
   6207 /* Process IHDR */
   6208         if (logging != MagickFalse)
   6209           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6210             "  Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
   6211 
   6212         mng_info->exists[object_id]=MagickTrue;
   6213         mng_info->viewable[object_id]=MagickTrue;
   6214 
   6215         if (mng_info->invisible[object_id])
   6216           {
   6217             if (logging != MagickFalse)
   6218               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6219                 "  Skipping invisible object");
   6220 
   6221             skip_to_iend=MagickTrue;
   6222             chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   6223             continue;
   6224           }
   6225 #if defined(MNG_INSERT_LAYERS)
   6226         if (length < 8)
   6227           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   6228 
   6229         image_width=(size_t) mng_get_long(p);
   6230         image_height=(size_t) mng_get_long(&p[4]);
   6231 #endif
   6232         chunk=(unsigned char *) RelinquishMagickMemory(chunk);
   6233 
   6234         /*
   6235           Insert a transparent background layer behind the entire animation
   6236           if it is not full screen.
   6237         */
   6238 #if defined(MNG_INSERT_LAYERS)
   6239         if (insert_layers && mng_type && first_mng_object)
   6240           {
   6241             if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
   6242                 (image_width < mng_info->mng_width) ||
   6243                 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
   6244                 (image_height < mng_info->mng_height) ||
   6245                 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
   6246               {
   6247                 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   6248                   {
   6249                     /*
   6250                       Allocate next image structure.
   6251                     */
   6252                     AcquireNextImage(image_info,image,exception);
   6253 
   6254                     if (GetNextImageInList(image) == (Image *) NULL)
   6255                       {
   6256                         image=DestroyImageList(image);
   6257                         MngInfoFreeStruct(mng_info,&have_mng_structure);
   6258                         return((Image *) NULL);
   6259                       }
   6260 
   6261                     image=SyncNextImageInList(image);
   6262                   }
   6263                 mng_info->image=image;
   6264 
   6265                 if (term_chunk_found)
   6266                   {
   6267                     image->start_loop=MagickTrue;
   6268                     image->iterations=mng_iterations;
   6269                     term_chunk_found=MagickFalse;
   6270                   }
   6271 
   6272                 else
   6273                     image->start_loop=MagickFalse;
   6274 
   6275                 /* Make a background rectangle.  */
   6276 
   6277                 image->delay=0;
   6278                 image->columns=mng_info->mng_width;
   6279                 image->rows=mng_info->mng_height;
   6280                 image->page.width=mng_info->mng_width;
   6281                 image->page.height=mng_info->mng_height;
   6282                 image->page.x=0;
   6283                 image->page.y=0;
   6284                 image->background_color=mng_background_color;
   6285                 (void) SetImageBackgroundColor(image,exception);
   6286                 if (logging != MagickFalse)
   6287                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6288                     "  Inserted transparent background layer, W=%.20g, H=%.20g",
   6289                     (double) mng_info->mng_width,(double) mng_info->mng_height);
   6290               }
   6291           }
   6292         /*
   6293           Insert a background layer behind the upcoming image if
   6294           framing_mode is 3, and we haven't already inserted one.
   6295         */
   6296         if (insert_layers && (mng_info->framing_mode == 3) &&
   6297                 (subframe_width) && (subframe_height) && (simplicity == 0 ||
   6298                 (simplicity & 0x08)))
   6299           {
   6300             if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   6301             {
   6302               /*
   6303                 Allocate next image structure.
   6304               */
   6305               AcquireNextImage(image_info,image,exception);
   6306 
   6307               if (GetNextImageInList(image) == (Image *) NULL)
   6308                 {
   6309                   image=DestroyImageList(image);
   6310                   MngInfoFreeStruct(mng_info,&have_mng_structure);
   6311                   return((Image *) NULL);
   6312                 }
   6313 
   6314               image=SyncNextImageInList(image);
   6315             }
   6316 
   6317             mng_info->image=image;
   6318 
   6319             if (term_chunk_found)
   6320               {
   6321                 image->start_loop=MagickTrue;
   6322                 image->iterations=mng_iterations;
   6323                 term_chunk_found=MagickFalse;
   6324               }
   6325 
   6326             else
   6327                 image->start_loop=MagickFalse;
   6328 
   6329             image->delay=0;
   6330             image->columns=subframe_width;
   6331             image->rows=subframe_height;
   6332             image->page.width=subframe_width;
   6333             image->page.height=subframe_height;
   6334             image->page.x=mng_info->clip.left;
   6335             image->page.y=mng_info->clip.top;
   6336             image->background_color=mng_background_color;
   6337             image->alpha_trait=UndefinedPixelTrait;
   6338             (void) SetImageBackgroundColor(image,exception);
   6339 
   6340             if (logging != MagickFalse)
   6341               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6342                 "  Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
   6343                 (double) mng_info->clip.left,(double) mng_info->clip.right,
   6344                 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
   6345           }
   6346 #endif /* MNG_INSERT_LAYERS */
   6347         first_mng_object=MagickFalse;
   6348 
   6349         if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   6350           {
   6351             /*
   6352               Allocate next image structure.
   6353             */
   6354             AcquireNextImage(image_info,image,exception);
   6355 
   6356             if (GetNextImageInList(image) == (Image *) NULL)
   6357               {
   6358                 image=DestroyImageList(image);
   6359                 MngInfoFreeStruct(mng_info,&have_mng_structure);
   6360                 return((Image *) NULL);
   6361               }
   6362 
   6363             image=SyncNextImageInList(image);
   6364           }
   6365         mng_info->image=image;
   6366         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
   6367           GetBlobSize(image));
   6368 
   6369         if (status == MagickFalse)
   6370           break;
   6371 
   6372         if (term_chunk_found)
   6373           {
   6374             image->start_loop=MagickTrue;
   6375             term_chunk_found=MagickFalse;
   6376           }
   6377 
   6378         else
   6379             image->start_loop=MagickFalse;
   6380 
   6381         if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
   6382           {
   6383             image->delay=frame_delay;
   6384             frame_delay=default_frame_delay;
   6385           }
   6386 
   6387         else
   6388           image->delay=0;
   6389 
   6390         image->page.width=mng_info->mng_width;
   6391         image->page.height=mng_info->mng_height;
   6392         image->page.x=mng_info->x_off[object_id];
   6393         image->page.y=mng_info->y_off[object_id];
   6394         image->iterations=mng_iterations;
   6395 
   6396         /*
   6397           Seek back to the beginning of the IHDR or JHDR chunk's length field.
   6398         */
   6399 
   6400         if (logging != MagickFalse)
   6401           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6402             "  Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
   6403             type[2],type[3]);
   6404 
   6405         offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
   6406 
   6407         if (offset < 0)
   6408           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   6409       }
   6410 
   6411     mng_info->image=image;
   6412     mng_info->mng_type=mng_type;
   6413     mng_info->object_id=object_id;
   6414 
   6415     if (memcmp(type,mng_IHDR,4) == 0)
   6416       image=ReadOnePNGImage(mng_info,image_info,exception);
   6417 
   6418 #if defined(JNG_SUPPORTED)
   6419     else
   6420       image=ReadOneJNGImage(mng_info,image_info,exception);
   6421 #endif
   6422 
   6423     if (image == (Image *) NULL)
   6424       {
   6425         if (logging != MagickFalse)
   6426           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6427             "exit ReadJNGImage() with error");
   6428 
   6429         MngInfoFreeStruct(mng_info,&have_mng_structure);
   6430         return((Image *) NULL);
   6431       }
   6432 
   6433     if (image->columns == 0 || image->rows == 0)
   6434       {
   6435         (void) CloseBlob(image);
   6436         image=DestroyImageList(image);
   6437         MngInfoFreeStruct(mng_info,&have_mng_structure);
   6438         return((Image *) NULL);
   6439       }
   6440 
   6441     mng_info->image=image;
   6442 
   6443     if (mng_type)
   6444       {
   6445         MngBox
   6446           crop_box;
   6447 
   6448         if (mng_info->magn_methx || mng_info->magn_methy)
   6449           {
   6450             png_uint_32
   6451                magnified_height,
   6452                magnified_width;
   6453 
   6454             if (logging != MagickFalse)
   6455               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6456                 "  Processing MNG MAGN chunk");
   6457 
   6458             if (mng_info->magn_methx == 1)
   6459               {
   6460                 magnified_width=mng_info->magn_ml;
   6461 
   6462                 if (image->columns > 1)
   6463                    magnified_width += mng_info->magn_mr;
   6464 
   6465                 if (image->columns > 2)
   6466                    magnified_width += (png_uint_32)
   6467                       ((image->columns-2)*(mng_info->magn_mx));
   6468               }
   6469 
   6470             else
   6471               {
   6472                 magnified_width=(png_uint_32) image->columns;
   6473 
   6474                 if (image->columns > 1)
   6475                    magnified_width += mng_info->magn_ml-1;
   6476 
   6477                 if (image->columns > 2)
   6478                    magnified_width += mng_info->magn_mr-1;
   6479 
   6480                 if (image->columns > 3)
   6481                    magnified_width += (png_uint_32)
   6482                       ((image->columns-3)*(mng_info->magn_mx-1));
   6483               }
   6484 
   6485             if (mng_info->magn_methy == 1)
   6486               {
   6487                 magnified_height=mng_info->magn_mt;
   6488 
   6489                 if (image->rows > 1)
   6490                    magnified_height += mng_info->magn_mb;
   6491 
   6492                 if (image->rows > 2)
   6493                    magnified_height += (png_uint_32)
   6494                       ((image->rows-2)*(mng_info->magn_my));
   6495               }
   6496 
   6497             else
   6498               {
   6499                 magnified_height=(png_uint_32) image->rows;
   6500 
   6501                 if (image->rows > 1)
   6502                    magnified_height += mng_info->magn_mt-1;
   6503 
   6504                 if (image->rows > 2)
   6505                    magnified_height += mng_info->magn_mb-1;
   6506 
   6507                 if (image->rows > 3)
   6508                    magnified_height += (png_uint_32)
   6509                       ((image->rows-3)*(mng_info->magn_my-1));
   6510               }
   6511 
   6512             if (magnified_height > image->rows ||
   6513                 magnified_width > image->columns)
   6514               {
   6515                 Image
   6516                   *large_image;
   6517 
   6518                 int
   6519                   yy;
   6520 
   6521                 Quantum
   6522                   *next,
   6523                   *prev;
   6524 
   6525                 png_uint_16
   6526                   magn_methx,
   6527                   magn_methy;
   6528 
   6529                 ssize_t
   6530                   m,
   6531                   y;
   6532 
   6533                 register Quantum
   6534                   *n,
   6535                   *q;
   6536 
   6537                 register ssize_t
   6538                   x;
   6539 
   6540                 /* Allocate next image structure.  */
   6541 
   6542                 if (logging != MagickFalse)
   6543                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6544                     "    Allocate magnified image");
   6545 
   6546                 AcquireNextImage(image_info,image,exception);
   6547 
   6548                 if (GetNextImageInList(image) == (Image *) NULL)
   6549                   {
   6550                     image=DestroyImageList(image);
   6551                     MngInfoFreeStruct(mng_info,&have_mng_structure);
   6552                     return((Image *) NULL);
   6553                   }
   6554 
   6555                 large_image=SyncNextImageInList(image);
   6556 
   6557                 large_image->columns=magnified_width;
   6558                 large_image->rows=magnified_height;
   6559 
   6560                 magn_methx=mng_info->magn_methx;
   6561                 magn_methy=mng_info->magn_methy;
   6562 
   6563 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   6564 #define QM unsigned short
   6565                 if (magn_methx != 1 || magn_methy != 1)
   6566                   {
   6567                   /*
   6568                      Scale pixels to unsigned shorts to prevent
   6569                      overflow of intermediate values of interpolations
   6570                   */
   6571                      for (y=0; y < (ssize_t) image->rows; y++)
   6572                      {
   6573                        q=GetAuthenticPixels(image,0,y,image->columns,1,
   6574                           exception);
   6575 
   6576                        for (x=(ssize_t) image->columns-1; x >= 0; x--)
   6577                        {
   6578                           SetPixelRed(image,ScaleQuantumToShort(
   6579                             GetPixelRed(image,q)),q);
   6580                           SetPixelGreen(image,ScaleQuantumToShort(
   6581                             GetPixelGreen(image,q)),q);
   6582                           SetPixelBlue(image,ScaleQuantumToShort(
   6583                             GetPixelBlue(image,q)),q);
   6584                           SetPixelAlpha(image,ScaleQuantumToShort(
   6585                             GetPixelAlpha(image,q)),q);
   6586                           q+=GetPixelChannels(image);
   6587                        }
   6588 
   6589                        if (SyncAuthenticPixels(image,exception) == MagickFalse)
   6590                          break;
   6591                      }
   6592                   }
   6593 #else
   6594 #define QM Quantum
   6595 #endif
   6596 
   6597                 if (image->alpha_trait != UndefinedPixelTrait)
   6598                    (void) SetImageBackgroundColor(large_image,exception);
   6599 
   6600                 else
   6601                   {
   6602                     large_image->background_color.alpha=OpaqueAlpha;
   6603                     (void) SetImageBackgroundColor(large_image,exception);
   6604 
   6605                     if (magn_methx == 4)
   6606                       magn_methx=2;
   6607 
   6608                     if (magn_methx == 5)
   6609                       magn_methx=3;
   6610 
   6611                     if (magn_methy == 4)
   6612                       magn_methy=2;
   6613 
   6614                     if (magn_methy == 5)
   6615                       magn_methy=3;
   6616                   }
   6617 
   6618                 /* magnify the rows into the right side of the large image */
   6619 
   6620                 if (logging != MagickFalse)
   6621                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6622                     "    Magnify the rows to %.20g",(double) large_image->rows);
   6623                 m=(ssize_t) mng_info->magn_mt;
   6624                 yy=0;
   6625                 length=(size_t) GetPixelChannels(image)*image->columns;
   6626                 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
   6627                 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
   6628 
   6629                 if ((prev == (Quantum *) NULL) ||
   6630                     (next == (Quantum *) NULL))
   6631                   {
   6632                      image=DestroyImageList(image);
   6633                      MngInfoFreeStruct(mng_info,&have_mng_structure);
   6634                      ThrowReaderException(ResourceLimitError,
   6635                        "MemoryAllocationFailed");
   6636                   }
   6637 
   6638                 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
   6639                 (void) CopyMagickMemory(next,n,length);
   6640 
   6641                 for (y=0; y < (ssize_t) image->rows; y++)
   6642                 {
   6643                   if (y == 0)
   6644                     m=(ssize_t) mng_info->magn_mt;
   6645 
   6646                   else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
   6647                     m=(ssize_t) mng_info->magn_mb;
   6648 
   6649                   else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
   6650                     m=(ssize_t) mng_info->magn_mb;
   6651 
   6652                   else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
   6653                     m=1;
   6654 
   6655                   else
   6656                     m=(ssize_t) mng_info->magn_my;
   6657 
   6658                   n=prev;
   6659                   prev=next;
   6660                   next=n;
   6661 
   6662                   if (y < (ssize_t) image->rows-1)
   6663                     {
   6664                       n=GetAuthenticPixels(image,0,y+1,image->columns,1,
   6665                           exception);
   6666                       (void) CopyMagickMemory(next,n,length);
   6667                     }
   6668 
   6669                   for (i=0; i < m; i++, yy++)
   6670                   {
   6671                     register Quantum
   6672                       *pixels;
   6673 
   6674                     assert(yy < (ssize_t) large_image->rows);
   6675                     pixels=prev;
   6676                     n=next;
   6677                     q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
   6678                       1,exception);
   6679                     q+=(large_image->columns-image->columns)*
   6680                       GetPixelChannels(large_image);
   6681 
   6682                     for (x=(ssize_t) image->columns-1; x >= 0; x--)
   6683                     {
   6684                       /* To do: get color as function of indexes[x] */
   6685                       /*
   6686                       if (image->storage_class == PseudoClass)
   6687                         {
   6688                         }
   6689                       */
   6690 
   6691                       if (magn_methy <= 1)
   6692                         {
   6693                           /* replicate previous */
   6694                           SetPixelRed(large_image,GetPixelRed(image,pixels),q);
   6695                           SetPixelGreen(large_image,GetPixelGreen(image,
   6696                              pixels),q);
   6697                           SetPixelBlue(large_image,GetPixelBlue(image,
   6698                              pixels),q);
   6699                           SetPixelAlpha(large_image,GetPixelAlpha(image,
   6700                              pixels),q);
   6701                         }
   6702 
   6703                       else if (magn_methy == 2 || magn_methy == 4)
   6704                         {
   6705                           if (i == 0)
   6706                             {
   6707                               SetPixelRed(large_image,GetPixelRed(image,
   6708                                  pixels),q);
   6709                               SetPixelGreen(large_image,GetPixelGreen(image,
   6710                                  pixels),q);
   6711                               SetPixelBlue(large_image,GetPixelBlue(image,
   6712                                  pixels),q);
   6713                               SetPixelAlpha(large_image,GetPixelAlpha(image,
   6714                                  pixels),q);
   6715                             }
   6716 
   6717                           else
   6718                             {
   6719                               /* Interpolate */
   6720                               SetPixelRed(large_image,((QM) (((ssize_t)
   6721                                  (2*i*(GetPixelRed(image,n)
   6722                                  -GetPixelRed(image,pixels)+m))/
   6723                                  ((ssize_t) (m*2))
   6724                                  +GetPixelRed(image,pixels)))),q);
   6725                               SetPixelGreen(large_image,((QM) (((ssize_t)
   6726                                  (2*i*(GetPixelGreen(image,n)
   6727                                  -GetPixelGreen(image,pixels)+m))/
   6728                                  ((ssize_t) (m*2))
   6729                                  +GetPixelGreen(image,pixels)))),q);
   6730                               SetPixelBlue(large_image,((QM) (((ssize_t)
   6731                                  (2*i*(GetPixelBlue(image,n)
   6732                                  -GetPixelBlue(image,pixels)+m))/
   6733                                  ((ssize_t) (m*2))
   6734                                  +GetPixelBlue(image,pixels)))),q);
   6735 
   6736                               if (image->alpha_trait != UndefinedPixelTrait)
   6737                                  SetPixelAlpha(large_image, ((QM) (((ssize_t)
   6738                                     (2*i*(GetPixelAlpha(image,n)
   6739                                     -GetPixelAlpha(image,pixels)+m))
   6740                                     /((ssize_t) (m*2))+
   6741                                    GetPixelAlpha(image,pixels)))),q);
   6742                             }
   6743 
   6744                           if (magn_methy == 4)
   6745                             {
   6746                               /* Replicate nearest */
   6747                               if (i <= ((m+1) << 1))
   6748                                  SetPixelAlpha(large_image,GetPixelAlpha(image,
   6749                                     pixels),q);
   6750                               else
   6751                                  SetPixelAlpha(large_image,GetPixelAlpha(image,
   6752                                     n),q);
   6753                             }
   6754                         }
   6755 
   6756                       else /* if (magn_methy == 3 || magn_methy == 5) */
   6757                         {
   6758                           /* Replicate nearest */
   6759                           if (i <= ((m+1) << 1))
   6760                           {
   6761                              SetPixelRed(large_image,GetPixelRed(image,
   6762                                     pixels),q);
   6763                              SetPixelGreen(large_image,GetPixelGreen(image,
   6764                                     pixels),q);
   6765                              SetPixelBlue(large_image,GetPixelBlue(image,
   6766                                     pixels),q);
   6767                              SetPixelAlpha(large_image,GetPixelAlpha(image,
   6768                                     pixels),q);
   6769                           }
   6770 
   6771                           else
   6772                           {
   6773                              SetPixelRed(large_image,GetPixelRed(image,n),q);
   6774                              SetPixelGreen(large_image,GetPixelGreen(image,n),
   6775                                     q);
   6776                              SetPixelBlue(large_image,GetPixelBlue(image,n),
   6777                                     q);
   6778                              SetPixelAlpha(large_image,GetPixelAlpha(image,n),
   6779                                     q);
   6780                           }
   6781 
   6782                           if (magn_methy == 5)
   6783                             {
   6784                               SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
   6785                                  (GetPixelAlpha(image,n)
   6786                                  -GetPixelAlpha(image,pixels))
   6787                                  +m))/((ssize_t) (m*2))
   6788                                  +GetPixelAlpha(image,pixels)),q);
   6789                             }
   6790                         }
   6791                       n+=GetPixelChannels(image);
   6792                       q+=GetPixelChannels(large_image);
   6793                       pixels+=GetPixelChannels(image);
   6794                     } /* x */
   6795 
   6796                     if (SyncAuthenticPixels(large_image,exception) == 0)
   6797                       break;
   6798 
   6799                   } /* i */
   6800                 } /* y */
   6801 
   6802                 prev=(Quantum *) RelinquishMagickMemory(prev);
   6803                 next=(Quantum *) RelinquishMagickMemory(next);
   6804 
   6805                 length=image->columns;
   6806 
   6807                 if (logging != MagickFalse)
   6808                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6809                     "    Delete original image");
   6810 
   6811                 DeleteImageFromList(&image);
   6812 
   6813                 image=large_image;
   6814 
   6815                 mng_info->image=image;
   6816 
   6817                 /* magnify the columns */
   6818                 if (logging != MagickFalse)
   6819                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6820                     "    Magnify the columns to %.20g",(double) image->columns);
   6821 
   6822                 for (y=0; y < (ssize_t) image->rows; y++)
   6823                 {
   6824                   register Quantum
   6825                     *pixels;
   6826 
   6827                   q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   6828                   pixels=q+(image->columns-length)*GetPixelChannels(image);
   6829                   n=pixels+GetPixelChannels(image);
   6830 
   6831                   for (x=(ssize_t) (image->columns-length);
   6832                     x < (ssize_t) image->columns; x++)
   6833                   {
   6834                     /* To do: Rewrite using Get/Set***PixelChannel() */
   6835 
   6836                     if (x == (ssize_t) (image->columns-length))
   6837                       m=(ssize_t) mng_info->magn_ml;
   6838 
   6839                     else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
   6840                       m=(ssize_t) mng_info->magn_mr;
   6841 
   6842                     else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
   6843                       m=(ssize_t) mng_info->magn_mr;
   6844 
   6845                     else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
   6846                       m=1;
   6847 
   6848                     else
   6849                       m=(ssize_t) mng_info->magn_mx;
   6850 
   6851                     for (i=0; i < m; i++)
   6852                     {
   6853                       if (magn_methx <= 1)
   6854                         {
   6855                           /* replicate previous */
   6856                           SetPixelRed(image,GetPixelRed(image,pixels),q);
   6857                           SetPixelGreen(image,GetPixelGreen(image,pixels),q);
   6858                           SetPixelBlue(image,GetPixelBlue(image,pixels),q);
   6859                           SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
   6860                         }
   6861 
   6862                       else if (magn_methx == 2 || magn_methx == 4)
   6863                         {
   6864                           if (i == 0)
   6865                           {
   6866                             SetPixelRed(image,GetPixelRed(image,pixels),q);
   6867                             SetPixelGreen(image,GetPixelGreen(image,pixels),q);
   6868                             SetPixelBlue(image,GetPixelBlue(image,pixels),q);
   6869                             SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
   6870                           }
   6871 
   6872                           /* To do: Rewrite using Get/Set***PixelChannel() */
   6873                           else
   6874                             {
   6875                               /* Interpolate */
   6876                               SetPixelRed(image,(QM) ((2*i*(
   6877                                  GetPixelRed(image,n)
   6878                                  -GetPixelRed(image,pixels))+m)
   6879                                  /((ssize_t) (m*2))+
   6880                                  GetPixelRed(image,pixels)),q);
   6881 
   6882                               SetPixelGreen(image,(QM) ((2*i*(
   6883                                  GetPixelGreen(image,n)
   6884                                  -GetPixelGreen(image,pixels))+m)
   6885                                  /((ssize_t) (m*2))+
   6886                                  GetPixelGreen(image,pixels)),q);
   6887 
   6888                               SetPixelBlue(image,(QM) ((2*i*(
   6889                                  GetPixelBlue(image,n)
   6890                                  -GetPixelBlue(image,pixels))+m)
   6891                                  /((ssize_t) (m*2))+
   6892                                  GetPixelBlue(image,pixels)),q);
   6893                               if (image->alpha_trait != UndefinedPixelTrait)
   6894                                  SetPixelAlpha(image,(QM) ((2*i*(
   6895                                    GetPixelAlpha(image,n)
   6896                                    -GetPixelAlpha(image,pixels))+m)
   6897                                    /((ssize_t) (m*2))+
   6898                                    GetPixelAlpha(image,pixels)),q);
   6899                             }
   6900 
   6901                           if (magn_methx == 4)
   6902                             {
   6903                               /* Replicate nearest */
   6904                               if (i <= ((m+1) << 1))
   6905                               {
   6906                                  SetPixelAlpha(image,
   6907                                    GetPixelAlpha(image,pixels)+0,q);
   6908                               }
   6909                               else
   6910                               {
   6911                                  SetPixelAlpha(image,
   6912                                    GetPixelAlpha(image,n)+0,q);
   6913                               }
   6914                             }
   6915                         }
   6916 
   6917                       else /* if (magn_methx == 3 || magn_methx == 5) */
   6918                         {
   6919                           /* Replicate nearest */
   6920                           if (i <= ((m+1) << 1))
   6921                           {
   6922                              SetPixelRed(image,GetPixelRed(image,pixels),q);
   6923                              SetPixelGreen(image,GetPixelGreen(image,pixels),q);
   6924                              SetPixelBlue(image,GetPixelBlue(image,pixels),q);
   6925                              SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
   6926                           }
   6927 
   6928                           else
   6929                           {
   6930                              SetPixelRed(image,GetPixelRed(image,n),q);
   6931                              SetPixelGreen(image,GetPixelGreen(image,n),q);
   6932                              SetPixelBlue(image,GetPixelBlue(image,n),q);
   6933                              SetPixelAlpha(image,GetPixelAlpha(image,n),q);
   6934                           }
   6935 
   6936                           if (magn_methx == 5)
   6937                             {
   6938                               /* Interpolate */
   6939                               SetPixelAlpha(image,
   6940                                  (QM) ((2*i*( GetPixelAlpha(image,n)
   6941                                  -GetPixelAlpha(image,pixels))+m)/
   6942                                  ((ssize_t) (m*2))
   6943                                  +GetPixelAlpha(image,pixels)),q);
   6944                             }
   6945                         }
   6946                       q+=GetPixelChannels(image);
   6947                     }
   6948                     n+=GetPixelChannels(image);
   6949                   }
   6950 
   6951                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
   6952                     break;
   6953                 }
   6954 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   6955               if (magn_methx != 1 || magn_methy != 1)
   6956                 {
   6957                 /*
   6958                    Rescale pixels to Quantum
   6959                 */
   6960                    for (y=0; y < (ssize_t) image->rows; y++)
   6961                    {
   6962                      q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   6963 
   6964                      for (x=(ssize_t) image->columns-1; x >= 0; x--)
   6965                      {
   6966                         SetPixelRed(image,ScaleShortToQuantum(
   6967                           GetPixelRed(image,q)),q);
   6968                         SetPixelGreen(image,ScaleShortToQuantum(
   6969                           GetPixelGreen(image,q)),q);
   6970                         SetPixelBlue(image,ScaleShortToQuantum(
   6971                           GetPixelBlue(image,q)),q);
   6972                         SetPixelAlpha(image,ScaleShortToQuantum(
   6973                           GetPixelAlpha(image,q)),q);
   6974                         q+=GetPixelChannels(image);
   6975                      }
   6976 
   6977                      if (SyncAuthenticPixels(image,exception) == MagickFalse)
   6978                        break;
   6979                    }
   6980                 }
   6981 #endif
   6982                 if (logging != MagickFalse)
   6983                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   6984                     "  Finished MAGN processing");
   6985               }
   6986           }
   6987 
   6988         /*
   6989           Crop_box is with respect to the upper left corner of the MNG.
   6990         */
   6991         crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
   6992         crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
   6993         crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
   6994         crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
   6995         crop_box=mng_minimum_box(crop_box,mng_info->clip);
   6996         crop_box=mng_minimum_box(crop_box,mng_info->frame);
   6997         crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
   6998         if ((crop_box.left != (mng_info->image_box.left
   6999             +mng_info->x_off[object_id])) ||
   7000             (crop_box.right != (mng_info->image_box.right
   7001             +mng_info->x_off[object_id])) ||
   7002             (crop_box.top != (mng_info->image_box.top
   7003             +mng_info->y_off[object_id])) ||
   7004             (crop_box.bottom != (mng_info->image_box.bottom
   7005             +mng_info->y_off[object_id])))
   7006           {
   7007             if (logging != MagickFalse)
   7008               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7009                 "  Crop the PNG image");
   7010 
   7011             if ((crop_box.left < crop_box.right) &&
   7012                 (crop_box.top < crop_box.bottom))
   7013               {
   7014                 Image
   7015                   *im;
   7016 
   7017                 RectangleInfo
   7018                   crop_info;
   7019 
   7020                 /*
   7021                   Crop_info is with respect to the upper left corner of
   7022                   the image.
   7023                 */
   7024                 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
   7025                 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
   7026                 crop_info.width=(size_t) (crop_box.right-crop_box.left);
   7027                 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
   7028                 image->page.width=image->columns;
   7029                 image->page.height=image->rows;
   7030                 image->page.x=0;
   7031                 image->page.y=0;
   7032                 im=CropImage(image,&crop_info,exception);
   7033 
   7034                 if (im != (Image *) NULL)
   7035                   {
   7036                     image->columns=im->columns;
   7037                     image->rows=im->rows;
   7038                     im=DestroyImage(im);
   7039                     image->page.width=image->columns;
   7040                     image->page.height=image->rows;
   7041                     image->page.x=crop_box.left;
   7042                     image->page.y=crop_box.top;
   7043                   }
   7044               }
   7045 
   7046             else
   7047               {
   7048                 /*
   7049                   No pixels in crop area.  The MNG spec still requires
   7050                   a layer, though, so make a single transparent pixel in
   7051                   the top left corner.
   7052                 */
   7053                 image->columns=1;
   7054                 image->rows=1;
   7055                 image->colors=2;
   7056                 (void) SetImageBackgroundColor(image,exception);
   7057                 image->page.width=1;
   7058                 image->page.height=1;
   7059                 image->page.x=0;
   7060                 image->page.y=0;
   7061               }
   7062           }
   7063 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
   7064         image=mng_info->image;
   7065 #endif
   7066       }
   7067 
   7068 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   7069       /* PNG does not handle depths greater than 16 so reduce it even
   7070        * if lossy.
   7071        */
   7072       if (image->depth > 16)
   7073          image->depth=16;
   7074 #endif
   7075 
   7076 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
   7077       if (image->depth > 8)
   7078         {
   7079           /* To do: fill low byte properly */
   7080           image->depth=16;
   7081         }
   7082 
   7083       if (LosslessReduceDepthOK(image,exception) != MagickFalse)
   7084          image->depth = 8;
   7085 #endif
   7086 
   7087       if (image_info->number_scenes != 0)
   7088         {
   7089           if (mng_info->scenes_found >
   7090              (ssize_t) (image_info->first_scene+image_info->number_scenes))
   7091             break;
   7092         }
   7093 
   7094       if (logging != MagickFalse)
   7095         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7096           "  Finished reading image datastream.");
   7097 
   7098   } while (LocaleCompare(image_info->magick,"MNG") == 0);
   7099 
   7100   (void) CloseBlob(image);
   7101 
   7102   if (logging != MagickFalse)
   7103     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7104       "  Finished reading all image datastreams.");
   7105 
   7106 #if defined(MNG_INSERT_LAYERS)
   7107   if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
   7108        (mng_info->mng_height))
   7109     {
   7110       /*
   7111         Insert a background layer if nothing else was found.
   7112       */
   7113       if (logging != MagickFalse)
   7114         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7115           "  No images found.  Inserting a background layer.");
   7116 
   7117       if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
   7118         {
   7119           /*
   7120             Allocate next image structure.
   7121           */
   7122           AcquireNextImage(image_info,image,exception);
   7123           if (GetNextImageInList(image) == (Image *) NULL)
   7124             {
   7125               image=DestroyImageList(image);
   7126               MngInfoFreeStruct(mng_info,&have_mng_structure);
   7127 
   7128               if (logging != MagickFalse)
   7129                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7130                   "  Allocation failed, returning NULL.");
   7131 
   7132               return((Image *) NULL);
   7133             }
   7134           image=SyncNextImageInList(image);
   7135         }
   7136       image->columns=mng_info->mng_width;
   7137       image->rows=mng_info->mng_height;
   7138       image->page.width=mng_info->mng_width;
   7139       image->page.height=mng_info->mng_height;
   7140       image->page.x=0;
   7141       image->page.y=0;
   7142       image->background_color=mng_background_color;
   7143       image->alpha_trait=UndefinedPixelTrait;
   7144 
   7145       if (image_info->ping == MagickFalse)
   7146         (void) SetImageBackgroundColor(image,exception);
   7147 
   7148       mng_info->image_found++;
   7149     }
   7150 #endif
   7151   image->iterations=mng_iterations;
   7152 
   7153   if (mng_iterations == 1)
   7154     image->start_loop=MagickTrue;
   7155 
   7156   while (GetPreviousImageInList(image) != (Image *) NULL)
   7157   {
   7158     image_count++;
   7159     if (image_count > 10*mng_info->image_found)
   7160       {
   7161         if (logging != MagickFalse)
   7162           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  No beginning");
   7163 
   7164         (void) ThrowMagickException(exception,GetMagickModule(),
   7165           CoderError,"Linked list is corrupted, beginning of list not found",
   7166           "`%s'",image_info->filename);
   7167 
   7168         return((Image *) NULL);
   7169       }
   7170 
   7171     image=GetPreviousImageInList(image);
   7172 
   7173     if (GetNextImageInList(image) == (Image *) NULL)
   7174       {
   7175         if (logging != MagickFalse)
   7176           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Corrupt list");
   7177 
   7178         (void) ThrowMagickException(exception,GetMagickModule(),
   7179           CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
   7180           image_info->filename);
   7181       }
   7182   }
   7183 
   7184   if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
   7185              GetNextImageInList(image) ==
   7186      (Image *) NULL)
   7187     {
   7188       if (logging != MagickFalse)
   7189         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7190             "  First image null");
   7191 
   7192       (void) ThrowMagickException(exception,GetMagickModule(),
   7193         CoderError,"image->next for first image is NULL but shouldn't be.",
   7194         "`%s'",image_info->filename);
   7195     }
   7196 
   7197   if (mng_info->image_found == 0)
   7198     {
   7199       if (logging != MagickFalse)
   7200         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7201           "  No visible images found.");
   7202 
   7203       (void) ThrowMagickException(exception,GetMagickModule(),
   7204         CoderError,"No visible images in file","`%s'",image_info->filename);
   7205 
   7206       if (image != (Image *) NULL)
   7207         image=DestroyImageList(image);
   7208 
   7209       MngInfoFreeStruct(mng_info,&have_mng_structure);
   7210       return((Image *) NULL);
   7211     }
   7212 
   7213   if (mng_info->ticks_per_second)
   7214     final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
   7215             final_delay/mng_info->ticks_per_second;
   7216 
   7217   else
   7218     image->start_loop=MagickTrue;
   7219 
   7220   /* Find final nonzero image delay */
   7221   final_image_delay=0;
   7222 
   7223   while (GetNextImageInList(image) != (Image *) NULL)
   7224     {
   7225       if (image->delay)
   7226         final_image_delay=image->delay;
   7227 
   7228       image=GetNextImageInList(image);
   7229     }
   7230 
   7231   if (final_delay < final_image_delay)
   7232     final_delay=final_image_delay;
   7233 
   7234   image->delay=final_delay;
   7235 
   7236   if (logging != MagickFalse)
   7237       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7238         "  image->delay=%.20g, final_delay=%.20g",(double) image->delay,
   7239         (double) final_delay);
   7240 
   7241   if (logging != MagickFalse)
   7242     {
   7243       int
   7244         scene;
   7245 
   7246       scene=0;
   7247       image=GetFirstImageInList(image);
   7248 
   7249       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7250         "  Before coalesce:");
   7251 
   7252       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7253         "    scene 0 delay=%.20g",(double) image->delay);
   7254 
   7255       while (GetNextImageInList(image) != (Image *) NULL)
   7256       {
   7257         image=GetNextImageInList(image);
   7258         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7259           "    scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
   7260       }
   7261     }
   7262 
   7263   image=GetFirstImageInList(image);
   7264 #ifdef MNG_COALESCE_LAYERS
   7265   if (insert_layers)
   7266     {
   7267       Image
   7268         *next_image,
   7269         *next;
   7270 
   7271       size_t
   7272         scene;
   7273 
   7274       if (logging != MagickFalse)
   7275         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Coalesce Images");
   7276 
   7277       scene=image->scene;
   7278       next_image=CoalesceImages(image,exception);
   7279 
   7280       if (next_image == (Image *) NULL)
   7281         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   7282 
   7283       image=DestroyImageList(image);
   7284       image=next_image;
   7285 
   7286       for (next=image; next != (Image *) NULL; next=next_image)
   7287       {
   7288          next->page.width=mng_info->mng_width;
   7289          next->page.height=mng_info->mng_height;
   7290          next->page.x=0;
   7291          next->page.y=0;
   7292          next->scene=scene++;
   7293          next_image=GetNextImageInList(next);
   7294 
   7295          if (next_image == (Image *) NULL)
   7296            break;
   7297 
   7298          if (next->delay == 0)
   7299            {
   7300              scene--;
   7301              next_image->previous=GetPreviousImageInList(next);
   7302              if (GetPreviousImageInList(next) == (Image *) NULL)
   7303                image=next_image;
   7304              else
   7305                next->previous->next=next_image;
   7306              next=DestroyImage(next);
   7307            }
   7308       }
   7309     }
   7310 #endif
   7311 
   7312   while (GetNextImageInList(image) != (Image *) NULL)
   7313       image=GetNextImageInList(image);
   7314 
   7315   image->dispose=BackgroundDispose;
   7316 
   7317   if (logging != MagickFalse)
   7318     {
   7319       int
   7320         scene;
   7321 
   7322       scene=0;
   7323       image=GetFirstImageInList(image);
   7324 
   7325       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7326         "  After coalesce:");
   7327 
   7328       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7329         "    scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
   7330         (double) image->dispose);
   7331 
   7332       while (GetNextImageInList(image) != (Image *) NULL)
   7333       {
   7334         image=GetNextImageInList(image);
   7335 
   7336         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7337           "    scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
   7338           (double) image->delay,(double) image->dispose);
   7339       }
   7340    }
   7341 
   7342   image=GetFirstImageInList(image);
   7343   MngInfoFreeStruct(mng_info,&have_mng_structure);
   7344   have_mng_structure=MagickFalse;
   7345 
   7346   if (logging != MagickFalse)
   7347     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
   7348 
   7349   return(GetFirstImageInList(image));
   7350 }
   7351 #else /* PNG_LIBPNG_VER > 10011 */
   7352 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   7353 {
   7354   printf("Your PNG library is too old: You have libpng-%s\n",
   7355      PNG_LIBPNG_VER_STRING);
   7356 
   7357   (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
   7358     "PNG library is too old","`%s'",image_info->filename);
   7359 
   7360   return(Image *) NULL;
   7361 }
   7362 
   7363 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   7364 {
   7365   return(ReadPNGImage(image_info,exception));
   7366 }
   7367 #endif /* PNG_LIBPNG_VER > 10011 */
   7368 #endif
   7369 
   7370 /*
   7372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7373 %                                                                             %
   7374 %                                                                             %
   7375 %                                                                             %
   7376 %   R e g i s t e r P N G I m a g e                                           %
   7377 %                                                                             %
   7378 %                                                                             %
   7379 %                                                                             %
   7380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7381 %
   7382 %  RegisterPNGImage() adds properties for the PNG image format to
   7383 %  the list of supported formats.  The properties include the image format
   7384 %  tag, a method to read and/or write the format, whether the format
   7385 %  supports the saving of more than one frame to the same file or blob,
   7386 %  whether the format supports native in-memory I/O, and a brief
   7387 %  description of the format.
   7388 %
   7389 %  The format of the RegisterPNGImage method is:
   7390 %
   7391 %      size_t RegisterPNGImage(void)
   7392 %
   7393 */
   7394 ModuleExport size_t RegisterPNGImage(void)
   7395 {
   7396   char
   7397     version[MagickPathExtent];
   7398 
   7399   MagickInfo
   7400     *entry;
   7401 
   7402   static const char
   7403     *PNGNote=
   7404     {
   7405       "See http://www.libpng.org/ for details about the PNG format."
   7406     },
   7407 
   7408     *JNGNote=
   7409     {
   7410       "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
   7411       "format."
   7412     },
   7413 
   7414     *MNGNote=
   7415     {
   7416       "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
   7417       "format."
   7418     };
   7419 
   7420   *version='\0';
   7421 
   7422 #if defined(PNG_LIBPNG_VER_STRING)
   7423   (void) ConcatenateMagickString(version,"libpng ",MagickPathExtent);
   7424   (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MagickPathExtent);
   7425 
   7426   if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
   7427     {
   7428       (void) ConcatenateMagickString(version,",",MagickPathExtent);
   7429       (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
   7430             MagickPathExtent);
   7431     }
   7432 #endif
   7433 
   7434   entry=AcquireMagickInfo("PNG","MNG","Multiple-image Network Graphics");
   7435   entry->flags|=CoderSeekableStreamFlag;  /* To do: eliminate this. */
   7436 
   7437 #if defined(MAGICKCORE_PNG_DELEGATE)
   7438   entry->decoder=(DecodeImageHandler *) ReadMNGImage;
   7439   entry->encoder=(EncodeImageHandler *) WriteMNGImage;
   7440 #endif
   7441 
   7442   entry->magick=(IsImageFormatHandler *) IsMNG;
   7443 
   7444   if (*version != '\0')
   7445     entry->version=ConstantString(version);
   7446 
   7447   entry->mime_type=ConstantString("video/x-mng");
   7448   entry->note=ConstantString(MNGNote);
   7449   (void) RegisterMagickInfo(entry);
   7450 
   7451   entry=AcquireMagickInfo("PNG","PNG","Portable Network Graphics");
   7452 
   7453 #if defined(MAGICKCORE_PNG_DELEGATE)
   7454   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7455   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7456 #endif
   7457 
   7458   entry->magick=(IsImageFormatHandler *) IsPNG;
   7459   entry->flags^=CoderAdjoinFlag;
   7460   entry->mime_type=ConstantString("image/png");
   7461 
   7462   if (*version != '\0')
   7463     entry->version=ConstantString(version);
   7464 
   7465   entry->note=ConstantString(PNGNote);
   7466   (void) RegisterMagickInfo(entry);
   7467 
   7468   entry=AcquireMagickInfo("PNG","PNG8",
   7469     "8-bit indexed with optional binary transparency");
   7470 
   7471 #if defined(MAGICKCORE_PNG_DELEGATE)
   7472   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7473   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7474 #endif
   7475 
   7476   entry->magick=(IsImageFormatHandler *) IsPNG;
   7477   entry->flags^=CoderAdjoinFlag;
   7478   entry->mime_type=ConstantString("image/png");
   7479   (void) RegisterMagickInfo(entry);
   7480 
   7481   entry=AcquireMagickInfo("PNG","PNG24",
   7482     "opaque or binary transparent 24-bit RGB");
   7483   *version='\0';
   7484 
   7485 #if defined(ZLIB_VERSION)
   7486   (void) ConcatenateMagickString(version,"zlib ",MagickPathExtent);
   7487   (void) ConcatenateMagickString(version,ZLIB_VERSION,MagickPathExtent);
   7488 
   7489   if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
   7490     {
   7491       (void) ConcatenateMagickString(version,",",MagickPathExtent);
   7492       (void) ConcatenateMagickString(version,zlib_version,MagickPathExtent);
   7493     }
   7494 #endif
   7495 
   7496   if (*version != '\0')
   7497     entry->version=ConstantString(version);
   7498 
   7499 #if defined(MAGICKCORE_PNG_DELEGATE)
   7500   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7501   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7502 #endif
   7503 
   7504   entry->magick=(IsImageFormatHandler *) IsPNG;
   7505   entry->flags^=CoderAdjoinFlag;
   7506   entry->mime_type=ConstantString("image/png");
   7507   (void) RegisterMagickInfo(entry);
   7508 
   7509   entry=AcquireMagickInfo("PNG","PNG32","opaque or transparent 32-bit RGBA");
   7510 
   7511 #if defined(MAGICKCORE_PNG_DELEGATE)
   7512   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7513   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7514 #endif
   7515 
   7516   entry->magick=(IsImageFormatHandler *) IsPNG;
   7517   entry->flags^=CoderAdjoinFlag;
   7518   entry->mime_type=ConstantString("image/png");
   7519   (void) RegisterMagickInfo(entry);
   7520 
   7521   entry=AcquireMagickInfo("PNG","PNG48",
   7522     "opaque or binary transparent 48-bit RGB");
   7523 
   7524 #if defined(MAGICKCORE_PNG_DELEGATE)
   7525   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7526   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7527 #endif
   7528 
   7529   entry->magick=(IsImageFormatHandler *) IsPNG;
   7530   entry->flags^=CoderAdjoinFlag;
   7531   entry->mime_type=ConstantString("image/png");
   7532   (void) RegisterMagickInfo(entry);
   7533 
   7534   entry=AcquireMagickInfo("PNG","PNG64","opaque or transparent 64-bit RGBA");
   7535 
   7536 #if defined(MAGICKCORE_PNG_DELEGATE)
   7537   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7538   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7539 #endif
   7540 
   7541   entry->magick=(IsImageFormatHandler *) IsPNG;
   7542   entry->flags^=CoderAdjoinFlag;
   7543   entry->mime_type=ConstantString("image/png");
   7544   (void) RegisterMagickInfo(entry);
   7545 
   7546   entry=AcquireMagickInfo("PNG","PNG00",
   7547     "PNG inheriting bit-depth, color-type from original, if possible");
   7548 
   7549 #if defined(MAGICKCORE_PNG_DELEGATE)
   7550   entry->decoder=(DecodeImageHandler *) ReadPNGImage;
   7551   entry->encoder=(EncodeImageHandler *) WritePNGImage;
   7552 #endif
   7553 
   7554   entry->magick=(IsImageFormatHandler *) IsPNG;
   7555   entry->flags^=CoderAdjoinFlag;
   7556   entry->mime_type=ConstantString("image/png");
   7557   (void) RegisterMagickInfo(entry);
   7558 
   7559   entry=AcquireMagickInfo("PNG","JNG","JPEG Network Graphics");
   7560 
   7561 #if defined(JNG_SUPPORTED)
   7562 #if defined(MAGICKCORE_PNG_DELEGATE)
   7563   entry->decoder=(DecodeImageHandler *) ReadJNGImage;
   7564   entry->encoder=(EncodeImageHandler *) WriteJNGImage;
   7565 #endif
   7566 #endif
   7567 
   7568   entry->magick=(IsImageFormatHandler *) IsJNG;
   7569   entry->flags^=CoderAdjoinFlag;
   7570   entry->mime_type=ConstantString("image/x-jng");
   7571   entry->note=ConstantString(JNGNote);
   7572   (void) RegisterMagickInfo(entry);
   7573 
   7574 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   7575   ping_semaphore=AcquireSemaphoreInfo();
   7576 #endif
   7577 
   7578   return(MagickImageCoderSignature);
   7579 }
   7580 
   7581 /*
   7583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7584 %                                                                             %
   7585 %                                                                             %
   7586 %                                                                             %
   7587 %   U n r e g i s t e r P N G I m a g e                                       %
   7588 %                                                                             %
   7589 %                                                                             %
   7590 %                                                                             %
   7591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7592 %
   7593 %  UnregisterPNGImage() removes format registrations made by the
   7594 %  PNG module from the list of supported formats.
   7595 %
   7596 %  The format of the UnregisterPNGImage method is:
   7597 %
   7598 %      UnregisterPNGImage(void)
   7599 %
   7600 */
   7601 ModuleExport void UnregisterPNGImage(void)
   7602 {
   7603   (void) UnregisterMagickInfo("MNG");
   7604   (void) UnregisterMagickInfo("PNG");
   7605   (void) UnregisterMagickInfo("PNG8");
   7606   (void) UnregisterMagickInfo("PNG24");
   7607   (void) UnregisterMagickInfo("PNG32");
   7608   (void) UnregisterMagickInfo("PNG48");
   7609   (void) UnregisterMagickInfo("PNG64");
   7610   (void) UnregisterMagickInfo("PNG00");
   7611   (void) UnregisterMagickInfo("JNG");
   7612 
   7613 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   7614   if (ping_semaphore != (SemaphoreInfo *) NULL)
   7615     RelinquishSemaphoreInfo(&ping_semaphore);
   7616 #endif
   7617 }
   7618 
   7619 #if defined(MAGICKCORE_PNG_DELEGATE)
   7621 #if PNG_LIBPNG_VER > 10011
   7622 /*
   7623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7624 %                                                                             %
   7625 %                                                                             %
   7626 %                                                                             %
   7627 %   W r i t e M N G I m a g e                                                 %
   7628 %                                                                             %
   7629 %                                                                             %
   7630 %                                                                             %
   7631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   7632 %
   7633 %  WriteMNGImage() writes an image in the Portable Network Graphics
   7634 %  Group's "Multiple-image Network Graphics" encoded image format.
   7635 %
   7636 %  MNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   7637 %
   7638 %  The format of the WriteMNGImage method is:
   7639 %
   7640 %      MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
   7641 %        Image *image,ExceptionInfo *exception)
   7642 %
   7643 %  A description of each parameter follows.
   7644 %
   7645 %    o image_info: the image info.
   7646 %
   7647 %    o image:  The image.
   7648 %
   7649 %    o exception: return any errors or warnings in this structure.
   7650 %
   7651 %  To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
   7652 %    "To do" under ReadPNGImage):
   7653 %
   7654 %    Preserve all unknown and not-yet-handled known chunks found in input
   7655 %    PNG file and copy them  into output PNG files according to the PNG
   7656 %    copying rules.
   7657 %
   7658 %    Write the iCCP chunk at MNG level when (icc profile length > 0)
   7659 %
   7660 %    Improve selection of color type (use indexed-colour or indexed-colour
   7661 %    with tRNS when 256 or fewer unique RGBA values are present).
   7662 %
   7663 %    Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
   7664 %    This will be complicated if we limit ourselves to generating MNG-LC
   7665 %    files.  For now we ignore disposal method 3 and simply overlay the next
   7666 %    image on it.
   7667 %
   7668 %    Check for identical PLTE's or PLTE/tRNS combinations and use a
   7669 %    global MNG PLTE or PLTE/tRNS combination when appropriate.
   7670 %    [mostly done 15 June 1999 but still need to take care of tRNS]
   7671 %
   7672 %    Check for identical sRGB and replace with a global sRGB (and remove
   7673 %    gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
   7674 %    replace with global gAMA/cHRM (or with sRGB if appropriate; replace
   7675 %    local gAMA/cHRM with local sRGB if appropriate).
   7676 %
   7677 %    Check for identical sBIT chunks and write global ones.
   7678 %
   7679 %    Provide option to skip writing the signature tEXt chunks.
   7680 %
   7681 %    Use signatures to detect identical objects and reuse the first
   7682 %    instance of such objects instead of writing duplicate objects.
   7683 %
   7684 %    Use a smaller-than-32k value of compression window size when
   7685 %    appropriate.
   7686 %
   7687 %    Encode JNG datastreams.  Mostly done as of 5.5.2; need to write
   7688 %    ancillary text chunks and save profiles.
   7689 %
   7690 %    Provide an option to force LC files (to ensure exact framing rate)
   7691 %    instead of VLC.
   7692 %
   7693 %    Provide an option to force VLC files instead of LC, even when offsets
   7694 %    are present.  This will involve expanding the embedded images with a
   7695 %    transparent region at the top and/or left.
   7696 */
   7697 
   7698 static void
   7699 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
   7700    png_info *ping_info, unsigned char *profile_type, unsigned char
   7701    *profile_description, unsigned char *profile_data, png_uint_32 length)
   7702 {
   7703    png_textp
   7704      text;
   7705 
   7706    register ssize_t
   7707      i;
   7708 
   7709    unsigned char
   7710      *sp;
   7711 
   7712    png_charp
   7713      dp;
   7714 
   7715    png_uint_32
   7716      allocated_length,
   7717      description_length;
   7718 
   7719    unsigned char
   7720      hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
   7721 
   7722    if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
   7723       return;
   7724 
   7725    if (image_info->verbose)
   7726      {
   7727        (void) printf("writing raw profile: type=%s, length=%.20g\n",
   7728          (char *) profile_type, (double) length);
   7729      }
   7730 
   7731 #if PNG_LIBPNG_VER >= 10400
   7732    text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
   7733 #else
   7734    text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
   7735 #endif
   7736    description_length=(png_uint_32) strlen((const char *) profile_description);
   7737    allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
   7738       + description_length);
   7739 #if PNG_LIBPNG_VER >= 10400
   7740    text[0].text=(png_charp) png_malloc(ping,
   7741       (png_alloc_size_t) allocated_length);
   7742    text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
   7743 #else
   7744    text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
   7745    text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
   7746 #endif
   7747    text[0].key[0]='\0';
   7748    (void) ConcatenateMagickString(text[0].key,
   7749       "Raw profile type ",MagickPathExtent);
   7750    (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
   7751    sp=profile_data;
   7752    dp=text[0].text;
   7753    *dp++='\n';
   7754    (void) CopyMagickString(dp,(const char *) profile_description,
   7755      allocated_length);
   7756    dp+=description_length;
   7757    *dp++='\n';
   7758    (void) FormatLocaleString(dp,allocated_length-
   7759      (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
   7760    dp+=8;
   7761 
   7762    for (i=0; i < (ssize_t) length; i++)
   7763    {
   7764      if (i%36 == 0)
   7765        *dp++='\n';
   7766      *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
   7767      *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
   7768    }
   7769 
   7770    *dp++='\n';
   7771    *dp='\0';
   7772    text[0].text_length=(png_size_t) (dp-text[0].text);
   7773    text[0].compression=image_info->compression == NoCompression ||
   7774      (image_info->compression == UndefinedCompression &&
   7775      text[0].text_length < 128) ? -1 : 0;
   7776 
   7777    if (text[0].text_length <= allocated_length)
   7778      png_set_text(ping,ping_info,text,1);
   7779 
   7780    png_free(ping,text[0].text);
   7781    png_free(ping,text[0].key);
   7782    png_free(ping,text);
   7783 }
   7784 
   7785 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
   7786   const char *string, MagickBooleanType logging)
   7787 {
   7788   char
   7789     *name;
   7790 
   7791   const StringInfo
   7792     *profile;
   7793 
   7794   unsigned char
   7795     *data;
   7796 
   7797   png_uint_32 length;
   7798 
   7799   ResetImageProfileIterator(image);
   7800 
   7801   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
   7802   {
   7803     profile=GetImageProfile(image,name);
   7804 
   7805     if (profile != (const StringInfo *) NULL)
   7806       {
   7807         StringInfo
   7808           *ping_profile;
   7809 
   7810         if (LocaleNCompare(name,string,11) == 0)
   7811           {
   7812             if (logging != MagickFalse)
   7813                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   7814                    "  Found %s profile",name);
   7815 
   7816             ping_profile=CloneStringInfo(profile);
   7817             data=GetStringInfoDatum(ping_profile),
   7818             length=(png_uint_32) GetStringInfoLength(ping_profile);
   7819             data[4]=data[3];
   7820             data[3]=data[2];
   7821             data[2]=data[1];
   7822             data[1]=data[0];
   7823             (void) WriteBlobMSBULong(image,length-5);  /* data length */
   7824             (void) WriteBlob(image,length-1,data+1);
   7825             (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
   7826             ping_profile=DestroyStringInfo(ping_profile);
   7827           }
   7828       }
   7829 
   7830       name=GetNextImageProfile(image);
   7831    }
   7832 
   7833    return(MagickTrue);
   7834 }
   7835 
   7836 static inline MagickBooleanType Magick_png_color_equal(const Image *image,
   7837   const Quantum *p, const PixelInfo *q)
   7838 {
   7839   MagickRealType
   7840     value;
   7841 
   7842   value=(MagickRealType) p[image->channel_map[RedPixelChannel].offset];
   7843   if (AbsolutePixelValue(value-q->red) >= MagickEpsilon)
   7844     return(MagickFalse);
   7845   value=(MagickRealType) p[image->channel_map[GreenPixelChannel].offset];
   7846   if (AbsolutePixelValue(value-q->green) >= MagickEpsilon)
   7847     return(MagickFalse);
   7848   value=(MagickRealType) p[image->channel_map[BluePixelChannel].offset];
   7849   if (AbsolutePixelValue(value-q->blue) >= MagickEpsilon)
   7850     return(MagickFalse);
   7851 
   7852   return(MagickTrue);
   7853 }
   7854 
   7855 #if defined(PNG_tIME_SUPPORTED)
   7856 static void write_tIME_chunk(Image *image,png_struct *ping,png_info *info,
   7857   const char *date,ExceptionInfo *exception)
   7858 {
   7859   unsigned int
   7860     day,
   7861     hour,
   7862     minute,
   7863     month,
   7864     second,
   7865     year;
   7866 
   7867   png_time
   7868     ptime;
   7869 
   7870   time_t
   7871     ttime;
   7872 
   7873   if (date != (const char *) NULL)
   7874     {
   7875       if (sscanf(date,"%d-%d-%dT%d:%d:%dZ",&year,&month,&day,&hour,&minute,
   7876           &second) != 6)
   7877         {
   7878           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
   7879             "Invalid date format specified for png:tIME","`%s'",
   7880             image->filename);
   7881           return;
   7882         }
   7883       ptime.year=(png_uint_16) year;
   7884       ptime.month=(png_byte) month;
   7885       ptime.day=(png_byte) day;
   7886       ptime.hour=(png_byte) hour;
   7887       ptime.minute=(png_byte) minute;
   7888       ptime.second=(png_byte) second;
   7889     }
   7890   else
   7891   {
   7892     time(&ttime);
   7893     png_convert_from_time_t(&ptime,ttime);
   7894   }
   7895   png_set_tIME(ping,info,&ptime);
   7896 }
   7897 #endif
   7898 
   7899 /* Write one PNG image */
   7900 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   7901   const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
   7902 {
   7903   char
   7904     im_vers[32],
   7905     libpng_runv[32],
   7906     libpng_vers[32],
   7907     zlib_runv[32],
   7908     zlib_vers[32];
   7909 
   7910   Image
   7911     *image;
   7912 
   7913   ImageInfo
   7914     *image_info;
   7915 
   7916   char
   7917     s[2];
   7918 
   7919   const char
   7920     *name,
   7921     *property,
   7922     *value;
   7923 
   7924   const StringInfo
   7925     *profile;
   7926 
   7927   int
   7928     num_passes,
   7929     pass;
   7930 
   7931   png_byte
   7932      ping_trans_alpha[256];
   7933 
   7934   png_color
   7935      palette[257];
   7936 
   7937   png_color_16
   7938     ping_background,
   7939     ping_trans_color;
   7940 
   7941   png_info
   7942     *ping_info;
   7943 
   7944   png_struct
   7945     *ping;
   7946 
   7947   png_uint_32
   7948     ping_height,
   7949     ping_width;
   7950 
   7951   ssize_t
   7952     y;
   7953 
   7954   MagickBooleanType
   7955     image_matte,
   7956     logging,
   7957     matte,
   7958 
   7959     ping_have_blob,
   7960     ping_have_cheap_transparency,
   7961     ping_have_color,
   7962     ping_have_non_bw,
   7963     ping_have_PLTE,
   7964     ping_have_bKGD,
   7965     ping_have_iCCP,
   7966     ping_have_pHYs,
   7967     ping_have_sRGB,
   7968     ping_have_tRNS,
   7969 
   7970     ping_exclude_bKGD,
   7971     ping_exclude_cHRM,
   7972     ping_exclude_date,
   7973     /* ping_exclude_EXIF, */
   7974     ping_exclude_gAMA,
   7975     ping_exclude_iCCP,
   7976     /* ping_exclude_iTXt, */
   7977     ping_exclude_oFFs,
   7978     ping_exclude_pHYs,
   7979     ping_exclude_sRGB,
   7980     ping_exclude_tEXt,
   7981     ping_exclude_tIME,
   7982     /* ping_exclude_tRNS, */
   7983     ping_exclude_vpAg,
   7984     ping_exclude_zCCP, /* hex-encoded iCCP */
   7985     ping_exclude_zTXt,
   7986 
   7987     ping_preserve_colormap,
   7988     ping_preserve_iCCP,
   7989     ping_need_colortype_warning,
   7990 
   7991     status,
   7992     tried_332,
   7993     tried_333,
   7994     tried_444;
   7995 
   7996   MemoryInfo
   7997     *volatile pixel_info;
   7998 
   7999   QuantumInfo
   8000     *quantum_info;
   8001 
   8002   PNGErrorInfo
   8003     error_info;
   8004 
   8005   register ssize_t
   8006     i,
   8007     x;
   8008 
   8009   unsigned char
   8010     *ping_pixels;
   8011 
   8012   volatile int
   8013     image_colors,
   8014     ping_bit_depth,
   8015     ping_color_type,
   8016     ping_interlace_method,
   8017     ping_compression_method,
   8018     ping_filter_method,
   8019     ping_num_trans;
   8020 
   8021   volatile size_t
   8022     image_depth,
   8023     old_bit_depth;
   8024 
   8025   size_t
   8026     quality,
   8027     rowbytes,
   8028     save_image_depth;
   8029 
   8030   int
   8031     j,
   8032     number_colors,
   8033     number_opaque,
   8034     number_semitransparent,
   8035     number_transparent,
   8036     ping_pHYs_unit_type;
   8037 
   8038   png_uint_32
   8039     ping_pHYs_x_resolution,
   8040     ping_pHYs_y_resolution;
   8041 
   8042   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
   8043     "  Enter WriteOnePNGImage()");
   8044 
   8045   image = CloneImage(IMimage,0,0,MagickFalse,exception);
   8046   image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
   8047   if (image_info == (ImageInfo *) NULL)
   8048      ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
   8049 
   8050   /* Define these outside of the following "if logging()" block so they will
   8051    * show in debuggers.
   8052    */
   8053   *im_vers='\0';
   8054   (void) ConcatenateMagickString(im_vers,
   8055          MagickLibVersionText,MagickPathExtent);
   8056   (void) ConcatenateMagickString(im_vers,
   8057          MagickLibAddendum,MagickPathExtent);
   8058 
   8059   *libpng_vers='\0';
   8060   (void) ConcatenateMagickString(libpng_vers,
   8061          PNG_LIBPNG_VER_STRING,32);
   8062   *libpng_runv='\0';
   8063   (void) ConcatenateMagickString(libpng_runv,
   8064          png_get_libpng_ver(NULL),32);
   8065 
   8066   *zlib_vers='\0';
   8067   (void) ConcatenateMagickString(zlib_vers,
   8068          ZLIB_VERSION,32);
   8069   *zlib_runv='\0';
   8070   (void) ConcatenateMagickString(zlib_runv,
   8071          zlib_version,32);
   8072 
   8073   if (logging != MagickFalse)
   8074     {
   8075        LogMagickEvent(CoderEvent,GetMagickModule(),"    IM version     = %s",
   8076            im_vers);
   8077        LogMagickEvent(CoderEvent,GetMagickModule(),"    Libpng version = %s",
   8078            libpng_vers);
   8079        if (LocaleCompare(libpng_vers,libpng_runv) != 0)
   8080        {
   8081        LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
   8082            libpng_runv);
   8083        }
   8084        LogMagickEvent(CoderEvent,GetMagickModule(),"    Zlib version   = %s",
   8085            zlib_vers);
   8086        if (LocaleCompare(zlib_vers,zlib_runv) != 0)
   8087        {
   8088        LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
   8089            zlib_runv);
   8090        }
   8091     }
   8092 
   8093   /* Initialize some stuff */
   8094   ping_bit_depth=0,
   8095   ping_color_type=0,
   8096   ping_interlace_method=0,
   8097   ping_compression_method=0,
   8098   ping_filter_method=0,
   8099   ping_num_trans = 0;
   8100 
   8101   ping_background.red = 0;
   8102   ping_background.green = 0;
   8103   ping_background.blue = 0;
   8104   ping_background.gray = 0;
   8105   ping_background.index = 0;
   8106 
   8107   ping_trans_color.red=0;
   8108   ping_trans_color.green=0;
   8109   ping_trans_color.blue=0;
   8110   ping_trans_color.gray=0;
   8111 
   8112   ping_pHYs_unit_type = 0;
   8113   ping_pHYs_x_resolution = 0;
   8114   ping_pHYs_y_resolution = 0;
   8115 
   8116   ping_have_blob=MagickFalse;
   8117   ping_have_cheap_transparency=MagickFalse;
   8118   ping_have_color=MagickTrue;
   8119   ping_have_non_bw=MagickTrue;
   8120   ping_have_PLTE=MagickFalse;
   8121   ping_have_bKGD=MagickFalse;
   8122   ping_have_iCCP=MagickFalse;
   8123   ping_have_pHYs=MagickFalse;
   8124   ping_have_sRGB=MagickFalse;
   8125   ping_have_tRNS=MagickFalse;
   8126 
   8127   ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
   8128   ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
   8129   ping_exclude_date=mng_info->ping_exclude_date;
   8130   /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
   8131   ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
   8132   ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
   8133   /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
   8134   ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
   8135   ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
   8136   ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
   8137   ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
   8138   ping_exclude_tIME=mng_info->ping_exclude_tIME;
   8139   /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
   8140   ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
   8141   ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
   8142   ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
   8143 
   8144   ping_preserve_colormap = mng_info->ping_preserve_colormap;
   8145   ping_preserve_iCCP = mng_info->ping_preserve_iCCP;
   8146   ping_need_colortype_warning = MagickFalse;
   8147 
   8148   /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
   8149    * i.e., eliminate the ICC profile and set image->rendering_intent.
   8150    * Note that this will not involve any changes to the actual pixels
   8151    * but merely passes information to applications that read the resulting
   8152    * PNG image.
   8153    *
   8154    * To do: recognize other variants of the sRGB profile, using the CRC to
   8155    * verify all recognized variants including the 7 already known.
   8156    *
   8157    * Work around libpng16+ rejecting some "known invalid sRGB profiles".
   8158    *
   8159    * Use something other than image->rendering_intent to record the fact
   8160    * that the sRGB profile was found.
   8161    *
   8162    * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC
   8163    * profile.  Record the Blackpoint Compensation, if any.
   8164    */
   8165    if (ping_exclude_sRGB == MagickFalse && ping_preserve_iCCP == MagickFalse)
   8166    {
   8167       char
   8168         *name;
   8169 
   8170       const StringInfo
   8171         *profile;
   8172 
   8173       ResetImageProfileIterator(image);
   8174       for (name=GetNextImageProfile(image); name != (const char *) NULL; )
   8175       {
   8176         profile=GetImageProfile(image,name);
   8177 
   8178         if (profile != (StringInfo *) NULL)
   8179           {
   8180             if ((LocaleCompare(name,"ICC") == 0) ||
   8181                 (LocaleCompare(name,"ICM") == 0))
   8182 
   8183              {
   8184                  int
   8185                    icheck,
   8186                    got_crc=0;
   8187 
   8188 
   8189                  png_uint_32
   8190                    length,
   8191                    profile_crc=0;
   8192 
   8193                  unsigned char
   8194                    *data;
   8195 
   8196                  length=(png_uint_32) GetStringInfoLength(profile);
   8197 
   8198                  for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
   8199                  {
   8200                    if (length == sRGB_info[icheck].len)
   8201                    {
   8202                      if (got_crc == 0)
   8203                      {
   8204                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8205                          "    Got a %lu-byte ICC profile (potentially sRGB)",
   8206                          (unsigned long) length);
   8207 
   8208                        data=GetStringInfoDatum(profile);
   8209                        profile_crc=crc32(0,data,length);
   8210 
   8211                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8212                            "      with crc=%8x",(unsigned int) profile_crc);
   8213                        got_crc++;
   8214                      }
   8215 
   8216                      if (profile_crc == sRGB_info[icheck].crc)
   8217                      {
   8218                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8219                             "      It is sRGB with rendering intent = %s",
   8220                         Magick_RenderingIntentString_from_PNG_RenderingIntent(
   8221                              sRGB_info[icheck].intent));
   8222                         if (image->rendering_intent==UndefinedIntent)
   8223                         {
   8224                           image->rendering_intent=
   8225                           Magick_RenderingIntent_from_PNG_RenderingIntent(
   8226                              sRGB_info[icheck].intent);
   8227                         }
   8228                         ping_exclude_iCCP = MagickTrue;
   8229                         ping_exclude_zCCP = MagickTrue;
   8230                         ping_have_sRGB = MagickTrue;
   8231                         break;
   8232                      }
   8233                    }
   8234                  }
   8235                  if (sRGB_info[icheck].len == 0)
   8236                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8237                         "    Got a %lu-byte ICC profile not recognized as sRGB",
   8238                         (unsigned long) length);
   8239               }
   8240           }
   8241         name=GetNextImageProfile(image);
   8242       }
   8243   }
   8244 
   8245   number_opaque = 0;
   8246   number_semitransparent = 0;
   8247   number_transparent = 0;
   8248 
   8249   if (logging != MagickFalse)
   8250     {
   8251       if (image->storage_class == UndefinedClass)
   8252           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8253           "    image->storage_class=UndefinedClass");
   8254       if (image->storage_class == DirectClass)
   8255           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8256           "    image->storage_class=DirectClass");
   8257       if (image->storage_class == PseudoClass)
   8258           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8259           "    image->storage_class=PseudoClass");
   8260       (void) LogMagickEvent(CoderEvent,GetMagickModule(), image->taint ?
   8261           "    image->taint=MagickTrue":
   8262           "    image->taint=MagickFalse");
   8263     }
   8264 
   8265   if (image->storage_class == PseudoClass &&
   8266      (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
   8267      mng_info->write_png48 || mng_info->write_png64 ||
   8268      (mng_info->write_png_colortype != 1 &&
   8269      mng_info->write_png_colortype != 5)))
   8270     {
   8271       (void) SyncImage(image,exception);
   8272       image->storage_class = DirectClass;
   8273     }
   8274 
   8275   if (ping_preserve_colormap == MagickFalse)
   8276     {
   8277       if (image->storage_class != PseudoClass && image->colormap != NULL)
   8278         {
   8279           /* Free the bogus colormap; it can cause trouble later */
   8280            if (logging != MagickFalse)
   8281               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8282               "    Freeing bogus colormap");
   8283            (void) RelinquishMagickMemory(image->colormap);
   8284            image->colormap=NULL;
   8285         }
   8286     }
   8287 
   8288   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   8289     (void) TransformImageColorspace(image,sRGBColorspace,exception);
   8290 
   8291   /*
   8292     Sometimes we get PseudoClass images whose RGB values don't match
   8293     the colors in the colormap.  This code syncs the RGB values.
   8294   */
   8295   if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
   8296      (void) SyncImage(image,exception);
   8297 
   8298 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
   8299   if (image->depth > 8)
   8300     {
   8301       if (logging != MagickFalse)
   8302         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8303           "    Reducing PNG bit depth to 8 since this is a Q8 build.");
   8304 
   8305       image->depth=8;
   8306     }
   8307 #endif
   8308 
   8309   /* Respect the -depth option */
   8310   if (image->depth < 4)
   8311     {
   8312        register Quantum
   8313          *r;
   8314 
   8315        if (image->depth > 2)
   8316          {
   8317            /* Scale to 4-bit */
   8318            LBR04PacketRGBO(image->background_color);
   8319 
   8320            for (y=0; y < (ssize_t) image->rows; y++)
   8321            {
   8322              r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8323 
   8324              if (r == (Quantum *) NULL)
   8325                break;
   8326 
   8327              for (x=0; x < (ssize_t) image->columns; x++)
   8328              {
   8329                 LBR04PixelRGBA(r);
   8330                 r+=GetPixelChannels(image);
   8331              }
   8332 
   8333              if (SyncAuthenticPixels(image,exception) == MagickFalse)
   8334                 break;
   8335            }
   8336 
   8337            if (image->storage_class == PseudoClass && image->colormap != NULL)
   8338            {
   8339              for (i=0; i < (ssize_t) image->colors; i++)
   8340              {
   8341                LBR04PacketRGBO(image->colormap[i]);
   8342              }
   8343            }
   8344          }
   8345        else if (image->depth > 1)
   8346          {
   8347            /* Scale to 2-bit */
   8348            LBR02PacketRGBO(image->background_color);
   8349 
   8350            for (y=0; y < (ssize_t) image->rows; y++)
   8351            {
   8352              r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8353 
   8354              if (r == (Quantum *) NULL)
   8355                break;
   8356 
   8357              for (x=0; x < (ssize_t) image->columns; x++)
   8358              {
   8359                 LBR02PixelRGBA(r);
   8360                 r+=GetPixelChannels(image);
   8361              }
   8362 
   8363              if (SyncAuthenticPixels(image,exception) == MagickFalse)
   8364                 break;
   8365            }
   8366 
   8367            if (image->storage_class == PseudoClass && image->colormap != NULL)
   8368            {
   8369              for (i=0; i < (ssize_t) image->colors; i++)
   8370              {
   8371                LBR02PacketRGBO(image->colormap[i]);
   8372              }
   8373            }
   8374          }
   8375        else
   8376          {
   8377            /* Scale to 1-bit */
   8378            LBR01PacketRGBO(image->background_color);
   8379 
   8380            for (y=0; y < (ssize_t) image->rows; y++)
   8381            {
   8382              r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8383 
   8384              if (r == (Quantum *) NULL)
   8385                break;
   8386 
   8387              for (x=0; x < (ssize_t) image->columns; x++)
   8388              {
   8389                 LBR01PixelRGBA(r);
   8390                 r+=GetPixelChannels(image);
   8391              }
   8392 
   8393              if (SyncAuthenticPixels(image,exception) == MagickFalse)
   8394                 break;
   8395            }
   8396 
   8397            if (image->storage_class == PseudoClass && image->colormap != NULL)
   8398            {
   8399              for (i=0; i < (ssize_t) image->colors; i++)
   8400              {
   8401                LBR01PacketRGBO(image->colormap[i]);
   8402              }
   8403            }
   8404          }
   8405     }
   8406 
   8407   /* To do: set to next higher multiple of 8 */
   8408   if (image->depth < 8)
   8409      image->depth=8;
   8410 
   8411 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   8412   /* PNG does not handle depths greater than 16 so reduce it even
   8413    * if lossy
   8414    */
   8415   if (image->depth > 8)
   8416       image->depth=16;
   8417 #endif
   8418 
   8419 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
   8420   if (image->depth > 8)
   8421     {
   8422       /* To do: fill low byte properly */
   8423       image->depth=16;
   8424     }
   8425 
   8426   if (image->depth == 16 && mng_info->write_png_depth != 16)
   8427     if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
   8428       image->depth = 8;
   8429 #endif
   8430 
   8431   image_colors = (int) image->colors;
   8432   number_opaque = (int) image->colors;
   8433   number_transparent = 0;
   8434   number_semitransparent = 0;
   8435 
   8436   if (mng_info->write_png_colortype &&
   8437      (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
   8438      mng_info->write_png_colortype < 4 &&
   8439      image->alpha_trait == UndefinedPixelTrait)))
   8440   {
   8441      /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
   8442       * are not going to need the result.
   8443       */
   8444      if (mng_info->write_png_colortype == 1 ||
   8445         mng_info->write_png_colortype == 5)
   8446        ping_have_color=MagickFalse;
   8447 
   8448      if (image->alpha_trait != UndefinedPixelTrait)
   8449        {
   8450          number_transparent = 2;
   8451          number_semitransparent = 1;
   8452        }
   8453   }
   8454 
   8455   if (mng_info->write_png_colortype < 7)
   8456   {
   8457   /* BUILD_PALETTE
   8458    *
   8459    * Normally we run this just once, but in the case of writing PNG8
   8460    * we reduce the transparency to binary and run again, then if there
   8461    * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
   8462    * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
   8463    * palette.  Then (To do) we take care of a final reduction that is only
   8464    * needed if there are still 256 colors present and one of them has both
   8465    * transparent and opaque instances.
   8466    */
   8467 
   8468   tried_332 = MagickFalse;
   8469   tried_333 = MagickFalse;
   8470   tried_444 = MagickFalse;
   8471 
   8472   for (j=0; j<6; j++)
   8473   {
   8474     /*
   8475      * Sometimes we get DirectClass images that have 256 colors or fewer.
   8476      * This code will build a colormap.
   8477      *
   8478      * Also, sometimes we get PseudoClass images with an out-of-date
   8479      * colormap.  This code will replace the colormap with a new one.
   8480      * Sometimes we get PseudoClass images that have more than 256 colors.
   8481      * This code will delete the colormap and change the image to
   8482      * DirectClass.
   8483      *
   8484      * If image->alpha_trait is MagickFalse, we ignore the alpha channel
   8485      * even though it sometimes contains left-over non-opaque values.
   8486      *
   8487      * Also we gather some information (number of opaque, transparent,
   8488      * and semitransparent pixels, and whether the image has any non-gray
   8489      * pixels or only black-and-white pixels) that we might need later.
   8490      *
   8491      * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
   8492      * we need to check for bogus non-opaque values, at least.
   8493      */
   8494 
   8495    int
   8496      n;
   8497 
   8498    PixelInfo
   8499      opaque[260],
   8500      semitransparent[260],
   8501      transparent[260];
   8502 
   8503    register const Quantum
   8504      *s;
   8505 
   8506    register Quantum
   8507      *q,
   8508      *r;
   8509 
   8510    if (logging != MagickFalse)
   8511      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8512          "    Enter BUILD_PALETTE:");
   8513 
   8514    if (logging != MagickFalse)
   8515      {
   8516        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8517              "      image->columns=%.20g",(double) image->columns);
   8518        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8519              "      image->rows=%.20g",(double) image->rows);
   8520        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8521              "      image->alpha_trait=%.20g",(double) image->alpha_trait);
   8522        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8523              "      image->depth=%.20g",(double) image->depth);
   8524 
   8525        if (image->storage_class == PseudoClass && image->colormap != NULL)
   8526        {
   8527          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8528              "      Original colormap:");
   8529          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8530              "        i    (red,green,blue,alpha)");
   8531 
   8532          for (i=0; i < 256; i++)
   8533          {
   8534                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8535                    "        %d    (%d,%d,%d,%d)",
   8536                     (int) i,
   8537                     (int) image->colormap[i].red,
   8538                     (int) image->colormap[i].green,
   8539                     (int) image->colormap[i].blue,
   8540                     (int) image->colormap[i].alpha);
   8541          }
   8542 
   8543          for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
   8544          {
   8545            if (i > 255)
   8546              {
   8547                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8548                    "        %d    (%d,%d,%d,%d)",
   8549                     (int) i,
   8550                     (int) image->colormap[i].red,
   8551                     (int) image->colormap[i].green,
   8552                     (int) image->colormap[i].blue,
   8553                     (int) image->colormap[i].alpha);
   8554              }
   8555          }
   8556        }
   8557 
   8558        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8559            "      image->colors=%d",(int) image->colors);
   8560 
   8561        if (image->colors == 0)
   8562          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8563              "        (zero means unknown)");
   8564 
   8565        if (ping_preserve_colormap == MagickFalse)
   8566          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8567               "      Regenerate the colormap");
   8568      }
   8569 
   8570      image_colors=0;
   8571      number_opaque = 0;
   8572      number_semitransparent = 0;
   8573      number_transparent = 0;
   8574 
   8575      for (y=0; y < (ssize_t) image->rows; y++)
   8576      {
   8577        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8578 
   8579        if (q == (Quantum *) NULL)
   8580          break;
   8581 
   8582        for (x=0; x < (ssize_t) image->columns; x++)
   8583        {
   8584            if (image->alpha_trait == UndefinedPixelTrait ||
   8585               GetPixelAlpha(image,q) == OpaqueAlpha)
   8586              {
   8587                if (number_opaque < 259)
   8588                  {
   8589                    if (number_opaque == 0)
   8590                      {
   8591                        GetPixelInfoPixel(image, q, opaque);
   8592                        opaque[0].alpha=OpaqueAlpha;
   8593                        number_opaque=1;
   8594                      }
   8595 
   8596                    for (i=0; i< (ssize_t) number_opaque; i++)
   8597                      {
   8598                        if (Magick_png_color_equal(image,q,opaque+i))
   8599                          break;
   8600                      }
   8601 
   8602                    if (i ==  (ssize_t) number_opaque && number_opaque < 259)
   8603                      {
   8604                        number_opaque++;
   8605                        GetPixelInfoPixel(image, q, opaque+i);
   8606                        opaque[i].alpha=OpaqueAlpha;
   8607                      }
   8608                  }
   8609              }
   8610            else if (GetPixelAlpha(image,q) == TransparentAlpha)
   8611              {
   8612                if (number_transparent < 259)
   8613                  {
   8614                    if (number_transparent == 0)
   8615                      {
   8616                        GetPixelInfoPixel(image, q, transparent);
   8617                        ping_trans_color.red=(unsigned short)
   8618                          GetPixelRed(image,q);
   8619                        ping_trans_color.green=(unsigned short)
   8620                          GetPixelGreen(image,q);
   8621                        ping_trans_color.blue=(unsigned short)
   8622                          GetPixelBlue(image,q);
   8623                        ping_trans_color.gray=(unsigned short)
   8624                          GetPixelGray(image,q);
   8625                        number_transparent = 1;
   8626                      }
   8627 
   8628                    for (i=0; i< (ssize_t) number_transparent; i++)
   8629                      {
   8630                        if (Magick_png_color_equal(image,q,transparent+i))
   8631                          break;
   8632                      }
   8633 
   8634                    if (i ==  (ssize_t) number_transparent &&
   8635                        number_transparent < 259)
   8636                      {
   8637                        number_transparent++;
   8638                        GetPixelInfoPixel(image,q,transparent+i);
   8639                      }
   8640                  }
   8641              }
   8642            else
   8643              {
   8644                if (number_semitransparent < 259)
   8645                  {
   8646                    if (number_semitransparent == 0)
   8647                      {
   8648                        GetPixelInfoPixel(image,q,semitransparent);
   8649                        number_semitransparent = 1;
   8650                      }
   8651 
   8652                    for (i=0; i< (ssize_t) number_semitransparent; i++)
   8653                      {
   8654                        if (Magick_png_color_equal(image,q,semitransparent+i)
   8655                            && GetPixelAlpha(image,q) ==
   8656                            semitransparent[i].alpha)
   8657                          break;
   8658                      }
   8659 
   8660                    if (i ==  (ssize_t) number_semitransparent &&
   8661                        number_semitransparent < 259)
   8662                      {
   8663                        number_semitransparent++;
   8664                        GetPixelInfoPixel(image, q, semitransparent+i);
   8665                      }
   8666                  }
   8667              }
   8668            q+=GetPixelChannels(image);
   8669         }
   8670      }
   8671 
   8672      if (mng_info->write_png8 == MagickFalse &&
   8673          ping_exclude_bKGD == MagickFalse)
   8674        {
   8675          /* Add the background color to the palette, if it
   8676           * isn't already there.
   8677           */
   8678           if (logging != MagickFalse)
   8679             {
   8680               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8681                   "      Check colormap for background (%d,%d,%d)",
   8682                   (int) image->background_color.red,
   8683                   (int) image->background_color.green,
   8684                   (int) image->background_color.blue);
   8685             }
   8686           for (i=0; i<number_opaque; i++)
   8687           {
   8688              if (opaque[i].red == image->background_color.red &&
   8689                  opaque[i].green == image->background_color.green &&
   8690                  opaque[i].blue == image->background_color.blue)
   8691                break;
   8692           }
   8693           if (number_opaque < 259 && i == number_opaque)
   8694             {
   8695                opaque[i] = image->background_color;
   8696                ping_background.index = i;
   8697                number_opaque++;
   8698                if (logging != MagickFalse)
   8699                  {
   8700                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8701                        "      background_color index is %d",(int) i);
   8702                  }
   8703 
   8704             }
   8705           else if (logging != MagickFalse)
   8706               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8707                   "      No room in the colormap to add background color");
   8708        }
   8709 
   8710      image_colors=number_opaque+number_transparent+number_semitransparent;
   8711 
   8712      if (logging != MagickFalse)
   8713        {
   8714          if (image_colors > 256)
   8715             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8716                   "      image has more than 256 colors");
   8717 
   8718          else
   8719             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8720                   "      image has %d colors",image_colors);
   8721        }
   8722 
   8723      if (ping_preserve_colormap != MagickFalse)
   8724        break;
   8725 
   8726      if (mng_info->write_png_colortype != 7) /* We won't need this info */
   8727        {
   8728          ping_have_color=MagickFalse;
   8729          ping_have_non_bw=MagickFalse;
   8730 
   8731          if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   8732          {
   8733            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8734               "incompatible colorspace");
   8735            ping_have_color=MagickTrue;
   8736            ping_have_non_bw=MagickTrue;
   8737          }
   8738 
   8739          if(image_colors > 256)
   8740            {
   8741              for (y=0; y < (ssize_t) image->rows; y++)
   8742              {
   8743                q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8744 
   8745                if (q == (Quantum *) NULL)
   8746                  break;
   8747 
   8748                s=q;
   8749                for (x=0; x < (ssize_t) image->columns; x++)
   8750                {
   8751                  if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
   8752                      GetPixelRed(image,s) != GetPixelBlue(image,s))
   8753                    {
   8754                       ping_have_color=MagickTrue;
   8755                       ping_have_non_bw=MagickTrue;
   8756                       break;
   8757                    }
   8758                  s+=GetPixelChannels(image);
   8759                }
   8760 
   8761                if (ping_have_color != MagickFalse)
   8762                  break;
   8763 
   8764                /* Worst case is black-and-white; we are looking at every
   8765                 * pixel twice.
   8766                 */
   8767 
   8768                if (ping_have_non_bw == MagickFalse)
   8769                  {
   8770                    s=q;
   8771                    for (x=0; x < (ssize_t) image->columns; x++)
   8772                    {
   8773                      if (GetPixelRed(image,s) != 0 &&
   8774                          GetPixelRed(image,s) != QuantumRange)
   8775                        {
   8776                          ping_have_non_bw=MagickTrue;
   8777                          break;
   8778                        }
   8779                      s+=GetPixelChannels(image);
   8780                    }
   8781                }
   8782              }
   8783            }
   8784        }
   8785 
   8786      if (image_colors < 257)
   8787        {
   8788          PixelInfo
   8789            colormap[260];
   8790 
   8791          /*
   8792           * Initialize image colormap.
   8793           */
   8794 
   8795          if (logging != MagickFalse)
   8796             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8797                   "      Sort the new colormap");
   8798 
   8799         /* Sort palette, transparent first */;
   8800 
   8801          n = 0;
   8802 
   8803          for (i=0; i<number_transparent; i++)
   8804             colormap[n++] = transparent[i];
   8805 
   8806          for (i=0; i<number_semitransparent; i++)
   8807             colormap[n++] = semitransparent[i];
   8808 
   8809          for (i=0; i<number_opaque; i++)
   8810             colormap[n++] = opaque[i];
   8811 
   8812          ping_background.index +=
   8813            (number_transparent + number_semitransparent);
   8814 
   8815          /* image_colors < 257; search the colormap instead of the pixels
   8816           * to get ping_have_color and ping_have_non_bw
   8817           */
   8818          for (i=0; i<n; i++)
   8819          {
   8820            if (ping_have_color == MagickFalse)
   8821              {
   8822                 if (colormap[i].red != colormap[i].green ||
   8823                     colormap[i].red != colormap[i].blue)
   8824                   {
   8825                      ping_have_color=MagickTrue;
   8826                      ping_have_non_bw=MagickTrue;
   8827                      break;
   8828                   }
   8829               }
   8830 
   8831            if (ping_have_non_bw == MagickFalse)
   8832              {
   8833                if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
   8834                    ping_have_non_bw=MagickTrue;
   8835              }
   8836           }
   8837 
   8838         if ((mng_info->ping_exclude_tRNS == MagickFalse ||
   8839             (number_transparent == 0 && number_semitransparent == 0)) &&
   8840             (((mng_info->write_png_colortype-1) ==
   8841             PNG_COLOR_TYPE_PALETTE) ||
   8842             (mng_info->write_png_colortype == 0)))
   8843           {
   8844             if (logging != MagickFalse)
   8845               {
   8846                 if (n !=  (ssize_t) image_colors)
   8847                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8848                    "   image_colors (%d) and n (%d)  don't match",
   8849                    image_colors, n);
   8850 
   8851                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8852                    "      AcquireImageColormap");
   8853               }
   8854 
   8855             image->colors = image_colors;
   8856 
   8857             if (AcquireImageColormap(image,image_colors,exception) ==
   8858                 MagickFalse)
   8859                ThrowWriterException(ResourceLimitError,
   8860                    "MemoryAllocationFailed");
   8861 
   8862             for (i=0; i< (ssize_t) image_colors; i++)
   8863                image->colormap[i] = colormap[i];
   8864 
   8865             if (logging != MagickFalse)
   8866               {
   8867                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8868                       "      image->colors=%d (%d)",
   8869                       (int) image->colors, image_colors);
   8870 
   8871                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8872                       "      Update the pixel indexes");
   8873               }
   8874 
   8875             /* Sync the pixel indices with the new colormap */
   8876 
   8877             for (y=0; y < (ssize_t) image->rows; y++)
   8878             {
   8879               q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8880 
   8881               if (q == (Quantum *) NULL)
   8882                 break;
   8883 
   8884               for (x=0; x < (ssize_t) image->columns; x++)
   8885               {
   8886                 for (i=0; i< (ssize_t) image_colors; i++)
   8887                 {
   8888                   if ((image->alpha_trait == UndefinedPixelTrait ||
   8889                       image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
   8890                       image->colormap[i].red == GetPixelRed(image,q) &&
   8891                       image->colormap[i].green == GetPixelGreen(image,q) &&
   8892                       image->colormap[i].blue == GetPixelBlue(image,q))
   8893                   {
   8894                     SetPixelIndex(image,i,q);
   8895                     break;
   8896                   }
   8897                 }
   8898                 q+=GetPixelChannels(image);
   8899               }
   8900 
   8901               if (SyncAuthenticPixels(image,exception) == MagickFalse)
   8902                  break;
   8903             }
   8904           }
   8905        }
   8906 
   8907      if (logging != MagickFalse)
   8908        {
   8909          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8910             "      image->colors=%d", (int) image->colors);
   8911 
   8912          if (image->colormap != NULL)
   8913            {
   8914              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8915                  "       i     (red,green,blue,alpha)");
   8916 
   8917              for (i=0; i < (ssize_t) image->colors; i++)
   8918              {
   8919                if (i < 300 || i >= (ssize_t) image->colors - 10)
   8920                  {
   8921                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8922                        "       %d     (%d,%d,%d,%d)",
   8923                         (int) i,
   8924                         (int) image->colormap[i].red,
   8925                         (int) image->colormap[i].green,
   8926                         (int) image->colormap[i].blue,
   8927                         (int) image->colormap[i].alpha);
   8928                  }
   8929              }
   8930            }
   8931 
   8932            if (number_transparent < 257)
   8933              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8934                    "      number_transparent     = %d",
   8935                    number_transparent);
   8936            else
   8937 
   8938              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8939                    "      number_transparent     > 256");
   8940 
   8941            if (number_opaque < 257)
   8942              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8943                    "      number_opaque          = %d",
   8944                    number_opaque);
   8945 
   8946            else
   8947              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8948                    "      number_opaque          > 256");
   8949 
   8950            if (number_semitransparent < 257)
   8951              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8952                    "      number_semitransparent = %d",
   8953                    number_semitransparent);
   8954 
   8955            else
   8956              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8957                    "      number_semitransparent > 256");
   8958 
   8959            if (ping_have_non_bw == MagickFalse)
   8960               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8961                     "      All pixels and the background are black or white");
   8962 
   8963            else if (ping_have_color == MagickFalse)
   8964               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8965                     "      All pixels and the background are gray");
   8966 
   8967            else
   8968               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8969                     "      At least one pixel or the background is non-gray");
   8970 
   8971            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8972                "    Exit BUILD_PALETTE:");
   8973        }
   8974 
   8975    if (mng_info->write_png8 == MagickFalse)
   8976       break;
   8977 
   8978    /* Make any reductions necessary for the PNG8 format */
   8979     if (image_colors <= 256 &&
   8980         image_colors != 0 && image->colormap != NULL &&
   8981         number_semitransparent == 0 &&
   8982         number_transparent <= 1)
   8983       break;
   8984 
   8985     /* PNG8 can't have semitransparent colors so we threshold the
   8986      * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
   8987      * transparent color so if more than one is transparent we merge
   8988      * them into image->background_color.
   8989      */
   8990     if (number_semitransparent != 0 || number_transparent > 1)
   8991       {
   8992         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   8993             "    Thresholding the alpha channel to binary");
   8994 
   8995         for (y=0; y < (ssize_t) image->rows; y++)
   8996         {
   8997           r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   8998 
   8999           if (r == (Quantum *) NULL)
   9000             break;
   9001 
   9002           for (x=0; x < (ssize_t) image->columns; x++)
   9003           {
   9004               if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
   9005                 {
   9006                   SetPixelViaPixelInfo(image,&image->background_color,r);
   9007                   SetPixelAlpha(image,TransparentAlpha,r);
   9008                 }
   9009               else
   9010                   SetPixelAlpha(image,OpaqueAlpha,r);
   9011               r+=GetPixelChannels(image);
   9012           }
   9013 
   9014           if (SyncAuthenticPixels(image,exception) == MagickFalse)
   9015              break;
   9016 
   9017           if (image_colors != 0 && image_colors <= 256 &&
   9018              image->colormap != NULL)
   9019             for (i=0; i<image_colors; i++)
   9020                 image->colormap[i].alpha =
   9021                     (image->colormap[i].alpha > TransparentAlpha/2 ?
   9022                     TransparentAlpha : OpaqueAlpha);
   9023         }
   9024       continue;
   9025     }
   9026 
   9027     /* PNG8 can't have more than 256 colors so we quantize the pixels and
   9028      * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette.  If the
   9029      * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
   9030      * colors or less.
   9031      */
   9032     if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
   9033       {
   9034         if (logging != MagickFalse)
   9035            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9036                "    Quantizing the background color to 4-4-4");
   9037 
   9038         tried_444 = MagickTrue;
   9039 
   9040         LBR04PacketRGB(image->background_color);
   9041 
   9042         if (logging != MagickFalse)
   9043           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9044               "    Quantizing the pixel colors to 4-4-4");
   9045 
   9046         if (image->colormap == NULL)
   9047         {
   9048           for (y=0; y < (ssize_t) image->rows; y++)
   9049           {
   9050             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   9051 
   9052             if (r == (Quantum *) NULL)
   9053               break;
   9054 
   9055             for (x=0; x < (ssize_t) image->columns; x++)
   9056             {
   9057               if (GetPixelAlpha(image,r) == OpaqueAlpha)
   9058                   LBR04PixelRGB(r);
   9059               r+=GetPixelChannels(image);
   9060             }
   9061 
   9062             if (SyncAuthenticPixels(image,exception) == MagickFalse)
   9063                break;
   9064           }
   9065         }
   9066 
   9067         else /* Should not reach this; colormap already exists and
   9068                 must be <= 256 */
   9069         {
   9070           if (logging != MagickFalse)
   9071               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9072               "    Quantizing the colormap to 4-4-4");
   9073 
   9074           for (i=0; i<image_colors; i++)
   9075           {
   9076             LBR04PacketRGB(image->colormap[i]);
   9077           }
   9078         }
   9079         continue;
   9080       }
   9081 
   9082     if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
   9083       {
   9084         if (logging != MagickFalse)
   9085            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9086                "    Quantizing the background color to 3-3-3");
   9087 
   9088         tried_333 = MagickTrue;
   9089 
   9090         LBR03PacketRGB(image->background_color);
   9091 
   9092         if (logging != MagickFalse)
   9093           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9094               "    Quantizing the pixel colors to 3-3-3-1");
   9095 
   9096         if (image->colormap == NULL)
   9097         {
   9098           for (y=0; y < (ssize_t) image->rows; y++)
   9099           {
   9100             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   9101 
   9102             if (r == (Quantum *) NULL)
   9103               break;
   9104 
   9105             for (x=0; x < (ssize_t) image->columns; x++)
   9106             {
   9107               if (GetPixelAlpha(image,r) == OpaqueAlpha)
   9108                   LBR03RGB(r);
   9109               r+=GetPixelChannels(image);
   9110             }
   9111 
   9112             if (SyncAuthenticPixels(image,exception) == MagickFalse)
   9113                break;
   9114           }
   9115         }
   9116 
   9117         else /* Should not reach this; colormap already exists and
   9118                 must be <= 256 */
   9119         {
   9120           if (logging != MagickFalse)
   9121               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9122               "    Quantizing the colormap to 3-3-3-1");
   9123           for (i=0; i<image_colors; i++)
   9124           {
   9125               LBR03PacketRGB(image->colormap[i]);
   9126           }
   9127         }
   9128         continue;
   9129       }
   9130 
   9131     if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
   9132       {
   9133         if (logging != MagickFalse)
   9134            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9135                "    Quantizing the background color to 3-3-2");
   9136 
   9137         tried_332 = MagickTrue;
   9138 
   9139         /* Red and green were already done so we only quantize the blue
   9140          * channel
   9141          */
   9142 
   9143         LBR02PacketBlue(image->background_color);
   9144 
   9145         if (logging != MagickFalse)
   9146           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9147               "    Quantizing the pixel colors to 3-3-2-1");
   9148 
   9149         if (image->colormap == NULL)
   9150         {
   9151           for (y=0; y < (ssize_t) image->rows; y++)
   9152           {
   9153             r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   9154 
   9155             if (r == (Quantum *) NULL)
   9156               break;
   9157 
   9158             for (x=0; x < (ssize_t) image->columns; x++)
   9159             {
   9160               if (GetPixelAlpha(image,r) == OpaqueAlpha)
   9161                   LBR02PixelBlue(r);
   9162               r+=GetPixelChannels(image);
   9163             }
   9164 
   9165             if (SyncAuthenticPixels(image,exception) == MagickFalse)
   9166                break;
   9167           }
   9168         }
   9169 
   9170         else /* Should not reach this; colormap already exists and
   9171                 must be <= 256 */
   9172         {
   9173           if (logging != MagickFalse)
   9174               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9175               "    Quantizing the colormap to 3-3-2-1");
   9176           for (i=0; i<image_colors; i++)
   9177           {
   9178               LBR02PacketBlue(image->colormap[i]);
   9179           }
   9180       }
   9181       continue;
   9182     }
   9183 
   9184     if (image_colors == 0 || image_colors > 256)
   9185     {
   9186       /* Take care of special case with 256 opaque colors + 1 transparent
   9187        * color.  We don't need to quantize to 2-3-2-1; we only need to
   9188        * eliminate one color, so we'll merge the two darkest red
   9189        * colors (0x49, 0, 0) -> (0x24, 0, 0).
   9190        */
   9191       if (logging != MagickFalse)
   9192         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9193             "    Merging two dark red background colors to 3-3-2-1");
   9194 
   9195       if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
   9196           ScaleQuantumToChar(image->background_color.green) == 0x00 &&
   9197           ScaleQuantumToChar(image->background_color.blue) == 0x00)
   9198       {
   9199          image->background_color.red=ScaleCharToQuantum(0x24);
   9200       }
   9201 
   9202       if (logging != MagickFalse)
   9203         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9204             "    Merging two dark red pixel colors to 3-3-2-1");
   9205 
   9206       if (image->colormap == NULL)
   9207       {
   9208         for (y=0; y < (ssize_t) image->rows; y++)
   9209         {
   9210           r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
   9211 
   9212           if (r == (Quantum *) NULL)
   9213             break;
   9214 
   9215           for (x=0; x < (ssize_t) image->columns; x++)
   9216           {
   9217             if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
   9218                 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
   9219                 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
   9220                 GetPixelAlpha(image,r) == OpaqueAlpha)
   9221               {
   9222                 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
   9223               }
   9224             r+=GetPixelChannels(image);
   9225           }
   9226 
   9227           if (SyncAuthenticPixels(image,exception) == MagickFalse)
   9228              break;
   9229 
   9230         }
   9231       }
   9232 
   9233       else
   9234       {
   9235          for (i=0; i<image_colors; i++)
   9236          {
   9237             if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
   9238                 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
   9239                 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
   9240             {
   9241                image->colormap[i].red=ScaleCharToQuantum(0x24);
   9242             }
   9243          }
   9244       }
   9245     }
   9246   }
   9247   }
   9248   /* END OF BUILD_PALETTE */
   9249 
   9250   /* If we are excluding the tRNS chunk and there is transparency,
   9251    * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
   9252    * PNG.
   9253    */
   9254   if (mng_info->ping_exclude_tRNS != MagickFalse &&
   9255      (number_transparent != 0 || number_semitransparent != 0))
   9256     {
   9257       unsigned int colortype=mng_info->write_png_colortype;
   9258 
   9259       if (ping_have_color == MagickFalse)
   9260         mng_info->write_png_colortype = 5;
   9261 
   9262       else
   9263         mng_info->write_png_colortype = 7;
   9264 
   9265       if (colortype != 0 &&
   9266          mng_info->write_png_colortype != colortype)
   9267         ping_need_colortype_warning=MagickTrue;
   9268 
   9269     }
   9270 
   9271   /* See if cheap transparency is possible.  It is only possible
   9272    * when there is a single transparent color, no semitransparent
   9273    * color, and no opaque color that has the same RGB components
   9274    * as the transparent color.  We only need this information if
   9275    * we are writing a PNG with colortype 0 or 2, and we have not
   9276    * excluded the tRNS chunk.
   9277    */
   9278   if (number_transparent == 1 &&
   9279       mng_info->write_png_colortype < 4)
   9280     {
   9281        ping_have_cheap_transparency = MagickTrue;
   9282 
   9283        if (number_semitransparent != 0)
   9284          ping_have_cheap_transparency = MagickFalse;
   9285 
   9286        else if (image_colors == 0 || image_colors > 256 ||
   9287            image->colormap == NULL)
   9288          {
   9289            register const Quantum
   9290              *q;
   9291 
   9292            for (y=0; y < (ssize_t) image->rows; y++)
   9293            {
   9294              q=GetVirtualPixels(image,0,y,image->columns,1, exception);
   9295 
   9296              if (q == (Quantum *) NULL)
   9297                break;
   9298 
   9299              for (x=0; x < (ssize_t) image->columns; x++)
   9300              {
   9301                  if (GetPixelAlpha(image,q) != TransparentAlpha &&
   9302                      (unsigned short) GetPixelRed(image,q) ==
   9303                                      ping_trans_color.red &&
   9304                      (unsigned short) GetPixelGreen(image,q) ==
   9305                                      ping_trans_color.green &&
   9306                      (unsigned short) GetPixelBlue(image,q) ==
   9307                                      ping_trans_color.blue)
   9308                    {
   9309                      ping_have_cheap_transparency = MagickFalse;
   9310                      break;
   9311                    }
   9312 
   9313                  q+=GetPixelChannels(image);
   9314              }
   9315 
   9316              if (ping_have_cheap_transparency == MagickFalse)
   9317                 break;
   9318            }
   9319          }
   9320        else
   9321          {
   9322             /* Assuming that image->colormap[0] is the one transparent color
   9323              * and that all others are opaque.
   9324              */
   9325             if (image_colors > 1)
   9326               for (i=1; i<image_colors; i++)
   9327                 if (image->colormap[i].red == image->colormap[0].red &&
   9328                     image->colormap[i].green == image->colormap[0].green &&
   9329                     image->colormap[i].blue == image->colormap[0].blue)
   9330                   {
   9331                      ping_have_cheap_transparency = MagickFalse;
   9332                      break;
   9333                   }
   9334          }
   9335 
   9336        if (logging != MagickFalse)
   9337          {
   9338            if (ping_have_cheap_transparency == MagickFalse)
   9339              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9340                  "   Cheap transparency is not possible.");
   9341 
   9342            else
   9343              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9344                  "   Cheap transparency is possible.");
   9345          }
   9346      }
   9347   else
   9348     ping_have_cheap_transparency = MagickFalse;
   9349 
   9350   image_depth=image->depth;
   9351 
   9352   quantum_info = (QuantumInfo *) NULL;
   9353   number_colors=0;
   9354   image_colors=(int) image->colors;
   9355   image_matte=image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse;
   9356 
   9357   if (mng_info->write_png_colortype < 5)
   9358     mng_info->IsPalette=image->storage_class == PseudoClass &&
   9359       image_colors <= 256 && image->colormap != NULL;
   9360   else
   9361     mng_info->IsPalette = MagickFalse;
   9362 
   9363   if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
   9364      (image->colors == 0 || image->colormap == NULL))
   9365     {
   9366       image_info=DestroyImageInfo(image_info);
   9367       image=DestroyImage(image);
   9368       (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
   9369           "Cannot write PNG8 or color-type 3; colormap is NULL",
   9370           "`%s'",IMimage->filename);
   9371       return(MagickFalse);
   9372     }
   9373 
   9374   /*
   9375     Allocate the PNG structures
   9376   */
   9377 #ifdef PNG_USER_MEM_SUPPORTED
   9378  error_info.image=image;
   9379  error_info.exception=exception;
   9380   ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
   9381     MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
   9382     (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
   9383 
   9384 #else
   9385   ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
   9386     MagickPNGErrorHandler,MagickPNGWarningHandler);
   9387 
   9388 #endif
   9389   if (ping == (png_struct *) NULL)
   9390     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   9391 
   9392   ping_info=png_create_info_struct(ping);
   9393 
   9394   if (ping_info == (png_info *) NULL)
   9395     {
   9396       png_destroy_write_struct(&ping,(png_info **) NULL);
   9397       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   9398     }
   9399 
   9400   png_set_write_fn(ping,image,png_put_data,png_flush_data);
   9401   pixel_info=(MemoryInfo *) NULL;
   9402 
   9403   if (setjmp(png_jmpbuf(ping)))
   9404     {
   9405       /*
   9406         PNG write failed.
   9407       */
   9408 #ifdef PNG_DEBUG
   9409      if (image_info->verbose)
   9410         (void) printf("PNG write has failed.\n");
   9411 #endif
   9412       png_destroy_write_struct(&ping,&ping_info);
   9413 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   9414       UnlockSemaphoreInfo(ping_semaphore);
   9415 #endif
   9416 
   9417       if (pixel_info != (MemoryInfo *) NULL)
   9418         pixel_info=RelinquishVirtualMemory(pixel_info);
   9419 
   9420       if (quantum_info != (QuantumInfo *) NULL)
   9421         quantum_info=DestroyQuantumInfo(quantum_info);
   9422 
   9423       if (ping_have_blob != MagickFalse)
   9424           (void) CloseBlob(image);
   9425       image_info=DestroyImageInfo(image_info);
   9426       image=DestroyImage(image);
   9427       return(MagickFalse);
   9428     }
   9429 
   9430   /* {  For navigation to end of SETJMP-protected block.  Within this
   9431    *    block, use png_error() instead of Throwing an Exception, to ensure
   9432    *    that libpng is able to clean up, and that the semaphore is unlocked.
   9433    */
   9434 
   9435 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   9436   LockSemaphoreInfo(ping_semaphore);
   9437 #endif
   9438 
   9439 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
   9440   /* Allow benign errors */
   9441   png_set_benign_errors(ping, 1);
   9442 #endif
   9443 
   9444 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
   9445   /* Reject images with too many rows or columns */
   9446   png_set_user_limits(ping,
   9447     (png_uint_32) MagickMin(0x7fffffffL,
   9448         GetMagickResourceLimit(WidthResource)),
   9449     (png_uint_32) MagickMin(0x7fffffffL,
   9450         GetMagickResourceLimit(HeightResource)));
   9451 #endif /* PNG_SET_USER_LIMITS_SUPPORTED */
   9452 
   9453   /*
   9454     Prepare PNG for writing.
   9455   */
   9456 
   9457 #if defined(PNG_MNG_FEATURES_SUPPORTED)
   9458   if (mng_info->write_mng)
   9459   {
   9460      (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
   9461 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
   9462      /* Disable new libpng-1.5.10 feature when writing a MNG because
   9463       * zero-length PLTE is OK
   9464       */
   9465      png_set_check_for_invalid_index (ping, 0);
   9466 # endif
   9467   }
   9468 
   9469 #else
   9470 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
   9471   if (mng_info->write_mng)
   9472      png_permit_empty_plte(ping,MagickTrue);
   9473 
   9474 # endif
   9475 #endif
   9476 
   9477   x=0;
   9478 
   9479   ping_width=(png_uint_32) image->columns;
   9480   ping_height=(png_uint_32) image->rows;
   9481 
   9482   if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
   9483      image_depth=8;
   9484 
   9485   if (mng_info->write_png48 || mng_info->write_png64)
   9486      image_depth=16;
   9487 
   9488   if (mng_info->write_png_depth != 0)
   9489      image_depth=mng_info->write_png_depth;
   9490 
   9491   /* Adjust requested depth to next higher valid depth if necessary */
   9492   if (image_depth > 8)
   9493      image_depth=16;
   9494 
   9495   if ((image_depth > 4) && (image_depth < 8))
   9496      image_depth=8;
   9497 
   9498   if (image_depth == 3)
   9499      image_depth=4;
   9500 
   9501   if (logging != MagickFalse)
   9502     {
   9503      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9504         "    width=%.20g",(double) ping_width);
   9505      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9506         "    height=%.20g",(double) ping_height);
   9507      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9508         "    image_matte=%.20g",(double) image->alpha_trait);
   9509      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9510         "    image->depth=%.20g",(double) image->depth);
   9511      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9512         "    Tentative ping_bit_depth=%.20g",(double) image_depth);
   9513     }
   9514 
   9515   save_image_depth=image_depth;
   9516   ping_bit_depth=(png_byte) save_image_depth;
   9517 
   9518 
   9519 #if defined(PNG_pHYs_SUPPORTED)
   9520   if (ping_exclude_pHYs == MagickFalse)
   9521   {
   9522   if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
   9523       (!mng_info->write_mng || !mng_info->equal_physs))
   9524     {
   9525       if (logging != MagickFalse)
   9526         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9527             "    Setting up pHYs chunk");
   9528 
   9529       if (image->units == PixelsPerInchResolution)
   9530         {
   9531           ping_pHYs_unit_type=PNG_RESOLUTION_METER;
   9532           ping_pHYs_x_resolution=
   9533              (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
   9534           ping_pHYs_y_resolution=
   9535              (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
   9536         }
   9537 
   9538       else if (image->units == PixelsPerCentimeterResolution)
   9539         {
   9540           ping_pHYs_unit_type=PNG_RESOLUTION_METER;
   9541           ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
   9542           ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
   9543         }
   9544 
   9545       else
   9546         {
   9547           ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
   9548           ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
   9549           ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
   9550         }
   9551 
   9552       if (logging != MagickFalse)
   9553         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9554           "    Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
   9555           (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
   9556           (int) ping_pHYs_unit_type);
   9557        ping_have_pHYs = MagickTrue;
   9558     }
   9559   }
   9560 #endif
   9561 
   9562   if (ping_exclude_bKGD == MagickFalse)
   9563   {
   9564   if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
   9565     {
   9566        unsigned int
   9567          mask;
   9568 
   9569        mask=0xffff;
   9570        if (ping_bit_depth == 8)
   9571           mask=0x00ff;
   9572 
   9573        if (ping_bit_depth == 4)
   9574           mask=0x000f;
   9575 
   9576        if (ping_bit_depth == 2)
   9577           mask=0x0003;
   9578 
   9579        if (ping_bit_depth == 1)
   9580           mask=0x0001;
   9581 
   9582        ping_background.red=(png_uint_16)
   9583          (ScaleQuantumToShort(image->background_color.red) & mask);
   9584 
   9585        ping_background.green=(png_uint_16)
   9586          (ScaleQuantumToShort(image->background_color.green) & mask);
   9587 
   9588        ping_background.blue=(png_uint_16)
   9589          (ScaleQuantumToShort(image->background_color.blue) & mask);
   9590 
   9591        ping_background.gray=(png_uint_16) ping_background.green;
   9592     }
   9593 
   9594   if (logging != MagickFalse)
   9595     {
   9596       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9597           "    Setting up bKGD chunk (1)");
   9598       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9599           "      background_color index is %d",
   9600           (int) ping_background.index);
   9601 
   9602       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9603           "    ping_bit_depth=%d",ping_bit_depth);
   9604     }
   9605 
   9606   ping_have_bKGD = MagickTrue;
   9607   }
   9608 
   9609   /*
   9610     Select the color type.
   9611   */
   9612   matte=image_matte;
   9613   old_bit_depth=0;
   9614 
   9615   if (mng_info->IsPalette && mng_info->write_png8)
   9616     {
   9617       /* To do: make this a function cause it's used twice, except
   9618          for reducing the sample depth from 8. */
   9619 
   9620       number_colors=image_colors;
   9621 
   9622       ping_have_tRNS=MagickFalse;
   9623 
   9624       /*
   9625         Set image palette.
   9626       */
   9627       ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
   9628 
   9629       if (logging != MagickFalse)
   9630         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9631             "  Setting up PLTE chunk with %d colors (%d)",
   9632             number_colors, image_colors);
   9633 
   9634       for (i=0; i < (ssize_t) number_colors; i++)
   9635       {
   9636         palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
   9637         palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
   9638         palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
   9639         if (logging != MagickFalse)
   9640           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9641 #if MAGICKCORE_QUANTUM_DEPTH == 8
   9642             "    %3ld (%3d,%3d,%3d)",
   9643 #else
   9644             "    %5ld (%5d,%5d,%5d)",
   9645 #endif
   9646             (long) i,palette[i].red,palette[i].green,palette[i].blue);
   9647 
   9648       }
   9649 
   9650       ping_have_PLTE=MagickTrue;
   9651       image_depth=ping_bit_depth;
   9652       ping_num_trans=0;
   9653 
   9654       if (matte != MagickFalse)
   9655       {
   9656           /*
   9657             Identify which colormap entry is transparent.
   9658           */
   9659           assert(number_colors <= 256);
   9660           assert(image->colormap != NULL);
   9661 
   9662           for (i=0; i < (ssize_t) number_transparent; i++)
   9663              ping_trans_alpha[i]=0;
   9664 
   9665 
   9666           ping_num_trans=(unsigned short) (number_transparent +
   9667              number_semitransparent);
   9668 
   9669           if (ping_num_trans == 0)
   9670              ping_have_tRNS=MagickFalse;
   9671 
   9672           else
   9673              ping_have_tRNS=MagickTrue;
   9674       }
   9675 
   9676       if (ping_exclude_bKGD == MagickFalse)
   9677       {
   9678        /*
   9679         * Identify which colormap entry is the background color.
   9680         */
   9681 
   9682         for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
   9683           if (IsPNGColorEqual(ping_background,image->colormap[i]))
   9684             break;
   9685 
   9686         ping_background.index=(png_byte) i;
   9687 
   9688         if (logging != MagickFalse)
   9689           {
   9690             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9691                  "      background_color index is %d",
   9692                  (int) ping_background.index);
   9693           }
   9694       }
   9695     } /* end of write_png8 */
   9696 
   9697   else if (mng_info->write_png_colortype == 1)
   9698     {
   9699       image_matte=MagickFalse;
   9700       ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
   9701     }
   9702 
   9703   else if (mng_info->write_png24 || mng_info->write_png48 ||
   9704       mng_info->write_png_colortype == 3)
   9705     {
   9706       image_matte=MagickFalse;
   9707       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
   9708     }
   9709 
   9710   else if (mng_info->write_png32 || mng_info->write_png64 ||
   9711       mng_info->write_png_colortype == 7)
   9712     {
   9713       image_matte=MagickTrue;
   9714       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
   9715     }
   9716 
   9717   else /* mng_info->write_pngNN not specified */
   9718     {
   9719       image_depth=ping_bit_depth;
   9720 
   9721       if (mng_info->write_png_colortype != 0)
   9722         {
   9723           ping_color_type=(png_byte) mng_info->write_png_colortype-1;
   9724 
   9725           if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
   9726               ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
   9727             image_matte=MagickTrue;
   9728 
   9729           else
   9730             image_matte=MagickFalse;
   9731 
   9732           if (logging != MagickFalse)
   9733              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9734              "   PNG colortype %d was specified:",(int) ping_color_type);
   9735         }
   9736 
   9737       else /* write_png_colortype not specified */
   9738         {
   9739           if (logging != MagickFalse)
   9740              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9741              "  Selecting PNG colortype:");
   9742 
   9743           ping_color_type=(png_byte) ((matte != MagickFalse)?
   9744             PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
   9745 
   9746           if (image_info->type == TrueColorType)
   9747             {
   9748               ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
   9749               image_matte=MagickFalse;
   9750             }
   9751 
   9752           if (image_info->type == TrueColorAlphaType)
   9753             {
   9754               ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
   9755               image_matte=MagickTrue;
   9756             }
   9757 
   9758           if (image_info->type == PaletteType ||
   9759               image_info->type == PaletteAlphaType)
   9760             ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
   9761 
   9762           if (mng_info->write_png_colortype == 0 &&
   9763              image_info->type == UndefinedType)
   9764             {
   9765               if (ping_have_color == MagickFalse)
   9766                 {
   9767                   if (image_matte == MagickFalse)
   9768                     {
   9769                       ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
   9770                       image_matte=MagickFalse;
   9771                     }
   9772 
   9773                   else
   9774                     {
   9775                       ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
   9776                       image_matte=MagickTrue;
   9777                     }
   9778                 }
   9779               else
   9780                 {
   9781                   if (image_matte == MagickFalse)
   9782                     {
   9783                       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
   9784                       image_matte=MagickFalse;
   9785                     }
   9786 
   9787                   else
   9788                     {
   9789                       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
   9790                       image_matte=MagickTrue;
   9791                     }
   9792                  }
   9793             }
   9794 
   9795         }
   9796 
   9797       if (logging != MagickFalse)
   9798          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9799          "    Selected PNG colortype=%d",ping_color_type);
   9800 
   9801       if (ping_bit_depth < 8)
   9802         {
   9803           if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
   9804               ping_color_type == PNG_COLOR_TYPE_RGB ||
   9805               ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
   9806             ping_bit_depth=8;
   9807         }
   9808 
   9809       old_bit_depth=ping_bit_depth;
   9810 
   9811       if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   9812         {
   9813           if (image->alpha_trait == UndefinedPixelTrait && ping_have_non_bw == MagickFalse)
   9814              ping_bit_depth=1;
   9815         }
   9816 
   9817       if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
   9818         {
   9819            size_t one = 1;
   9820            ping_bit_depth=1;
   9821 
   9822            if (image->colors == 0)
   9823            {
   9824               /* DO SOMETHING */
   9825                 png_error(ping,"image has 0 colors");
   9826            }
   9827 
   9828            while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
   9829              ping_bit_depth <<= 1;
   9830         }
   9831 
   9832       if (logging != MagickFalse)
   9833          {
   9834            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9835             "    Number of colors: %.20g",(double) image_colors);
   9836 
   9837            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9838             "    Tentative PNG bit depth: %d",ping_bit_depth);
   9839          }
   9840 
   9841       if (ping_bit_depth < (int) mng_info->write_png_depth)
   9842          ping_bit_depth = mng_info->write_png_depth;
   9843     }
   9844 
   9845   image_depth=ping_bit_depth;
   9846 
   9847   if (logging != MagickFalse)
   9848     {
   9849       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9850         "    Tentative PNG color type: %s (%.20g)",
   9851         PngColorTypeToString(ping_color_type),
   9852         (double) ping_color_type);
   9853 
   9854       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9855         "    image_info->type: %.20g",(double) image_info->type);
   9856 
   9857       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9858         "    image_depth: %.20g",(double) image_depth);
   9859 
   9860       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9861 
   9862         "    image->depth: %.20g",(double) image->depth);
   9863 
   9864       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9865         "    ping_bit_depth: %.20g",(double) ping_bit_depth);
   9866     }
   9867 
   9868   if (matte != MagickFalse)
   9869     {
   9870       if (mng_info->IsPalette)
   9871         {
   9872           if (mng_info->write_png_colortype == 0)
   9873             {
   9874               ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
   9875 
   9876               if (ping_have_color != MagickFalse)
   9877                  ping_color_type=PNG_COLOR_TYPE_RGBA;
   9878             }
   9879 
   9880           /*
   9881            * Determine if there is any transparent color.
   9882           */
   9883           if (number_transparent + number_semitransparent == 0)
   9884             {
   9885               /*
   9886                 No transparent pixels are present.  Change 4 or 6 to 0 or 2.
   9887               */
   9888 
   9889               image_matte=MagickFalse;
   9890 
   9891               if (mng_info->write_png_colortype == 0)
   9892                 ping_color_type&=0x03;
   9893             }
   9894 
   9895           else
   9896             {
   9897               unsigned int
   9898                 mask;
   9899 
   9900               mask=0xffff;
   9901 
   9902               if (ping_bit_depth == 8)
   9903                  mask=0x00ff;
   9904 
   9905               if (ping_bit_depth == 4)
   9906                  mask=0x000f;
   9907 
   9908               if (ping_bit_depth == 2)
   9909                  mask=0x0003;
   9910 
   9911               if (ping_bit_depth == 1)
   9912                  mask=0x0001;
   9913 
   9914               ping_trans_color.red=(png_uint_16)
   9915                 (ScaleQuantumToShort(image->colormap[0].red) & mask);
   9916 
   9917               ping_trans_color.green=(png_uint_16)
   9918                 (ScaleQuantumToShort(image->colormap[0].green) & mask);
   9919 
   9920               ping_trans_color.blue=(png_uint_16)
   9921                 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
   9922 
   9923               ping_trans_color.gray=(png_uint_16)
   9924                 (ScaleQuantumToShort(GetPixelInfoIntensity(image,
   9925                    image->colormap)) & mask);
   9926 
   9927               ping_trans_color.index=(png_byte) 0;
   9928 
   9929               ping_have_tRNS=MagickTrue;
   9930             }
   9931 
   9932           if (ping_have_tRNS != MagickFalse)
   9933             {
   9934               /*
   9935                * Determine if there is one and only one transparent color
   9936                * and if so if it is fully transparent.
   9937                */
   9938               if (ping_have_cheap_transparency == MagickFalse)
   9939                 ping_have_tRNS=MagickFalse;
   9940             }
   9941 
   9942           if (ping_have_tRNS != MagickFalse)
   9943             {
   9944               if (mng_info->write_png_colortype == 0)
   9945                 ping_color_type &= 0x03;  /* changes 4 or 6 to 0 or 2 */
   9946 
   9947               if (image_depth == 8)
   9948                 {
   9949                   ping_trans_color.red&=0xff;
   9950                   ping_trans_color.green&=0xff;
   9951                   ping_trans_color.blue&=0xff;
   9952                   ping_trans_color.gray&=0xff;
   9953                 }
   9954             }
   9955         }
   9956       else
   9957         {
   9958           if (image_depth == 8)
   9959             {
   9960               ping_trans_color.red&=0xff;
   9961               ping_trans_color.green&=0xff;
   9962               ping_trans_color.blue&=0xff;
   9963               ping_trans_color.gray&=0xff;
   9964             }
   9965         }
   9966     }
   9967 
   9968     matte=image_matte;
   9969 
   9970     if (ping_have_tRNS != MagickFalse)
   9971       image_matte=MagickFalse;
   9972 
   9973     if ((mng_info->IsPalette) &&
   9974         mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
   9975         ping_have_color == MagickFalse &&
   9976         (image_matte == MagickFalse || image_depth >= 8))
   9977       {
   9978         size_t one=1;
   9979 
   9980         if (image_matte != MagickFalse)
   9981           ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
   9982 
   9983         else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
   9984           {
   9985             ping_color_type=PNG_COLOR_TYPE_GRAY;
   9986 
   9987             if (save_image_depth == 16 && image_depth == 8)
   9988               {
   9989                 if (logging != MagickFalse)
   9990                   {
   9991                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   9992                         "  Scaling ping_trans_color (0)");
   9993                   }
   9994                     ping_trans_color.gray*=0x0101;
   9995               }
   9996           }
   9997 
   9998         if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
   9999           image_depth=MAGICKCORE_QUANTUM_DEPTH;
   10000 
   10001         if ((image_colors == 0) ||
   10002              ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
   10003           image_colors=(int) (one << image_depth);
   10004 
   10005         if (image_depth > 8)
   10006           ping_bit_depth=16;
   10007 
   10008         else
   10009           {
   10010             ping_bit_depth=8;
   10011             if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   10012               {
   10013                 if(!mng_info->write_png_depth)
   10014                   {
   10015                     ping_bit_depth=1;
   10016 
   10017                     while ((int) (one << ping_bit_depth)
   10018                         < (ssize_t) image_colors)
   10019                       ping_bit_depth <<= 1;
   10020                   }
   10021               }
   10022 
   10023             else if (ping_color_type ==
   10024                 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
   10025                 mng_info->IsPalette)
   10026               {
   10027               /* Check if grayscale is reducible */
   10028 
   10029                 int
   10030                   depth_4_ok=MagickTrue,
   10031                   depth_2_ok=MagickTrue,
   10032                   depth_1_ok=MagickTrue;
   10033 
   10034                 for (i=0; i < (ssize_t) image_colors; i++)
   10035                 {
   10036                    unsigned char
   10037                      intensity;
   10038 
   10039                    intensity=ScaleQuantumToChar(image->colormap[i].red);
   10040 
   10041                    if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
   10042                      depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
   10043                    else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
   10044                      depth_2_ok=depth_1_ok=MagickFalse;
   10045                    else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
   10046                      depth_1_ok=MagickFalse;
   10047                 }
   10048 
   10049                 if (depth_1_ok && mng_info->write_png_depth <= 1)
   10050                   ping_bit_depth=1;
   10051 
   10052                 else if (depth_2_ok && mng_info->write_png_depth <= 2)
   10053                   ping_bit_depth=2;
   10054 
   10055                 else if (depth_4_ok && mng_info->write_png_depth <= 4)
   10056                   ping_bit_depth=4;
   10057               }
   10058           }
   10059 
   10060           image_depth=ping_bit_depth;
   10061       }
   10062 
   10063     else
   10064 
   10065       if (mng_info->IsPalette)
   10066       {
   10067         number_colors=image_colors;
   10068 
   10069         if (image_depth <= 8)
   10070           {
   10071             /*
   10072               Set image palette.
   10073             */
   10074             ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
   10075 
   10076             if (!(mng_info->have_write_global_plte && matte == MagickFalse))
   10077               {
   10078                 for (i=0; i < (ssize_t) number_colors; i++)
   10079                 {
   10080                   palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
   10081                   palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
   10082                   palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
   10083                 }
   10084 
   10085                 if (logging != MagickFalse)
   10086                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10087                     "  Setting up PLTE chunk with %d colors",
   10088                     number_colors);
   10089 
   10090                 ping_have_PLTE=MagickTrue;
   10091               }
   10092 
   10093             /* color_type is PNG_COLOR_TYPE_PALETTE */
   10094             if (mng_info->write_png_depth == 0)
   10095               {
   10096                 size_t
   10097                   one;
   10098 
   10099                 ping_bit_depth=1;
   10100                 one=1;
   10101 
   10102                 while ((one << ping_bit_depth) < (size_t) number_colors)
   10103                   ping_bit_depth <<= 1;
   10104               }
   10105 
   10106             ping_num_trans=0;
   10107 
   10108             if (matte != MagickFalse)
   10109               {
   10110                 /*
   10111                  * Set up trans_colors array.
   10112                  */
   10113                 assert(number_colors <= 256);
   10114 
   10115                 ping_num_trans=(unsigned short) (number_transparent +
   10116                   number_semitransparent);
   10117 
   10118                 if (ping_num_trans == 0)
   10119                   ping_have_tRNS=MagickFalse;
   10120 
   10121                 else
   10122                   {
   10123                     if (logging != MagickFalse)
   10124                       {
   10125                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10126                           "  Scaling ping_trans_color (1)");
   10127                       }
   10128                     ping_have_tRNS=MagickTrue;
   10129 
   10130                     for (i=0; i < ping_num_trans; i++)
   10131                     {
   10132                        ping_trans_alpha[i]= (png_byte)
   10133                          ScaleQuantumToChar(image->colormap[i].alpha);
   10134                     }
   10135                   }
   10136               }
   10137           }
   10138       }
   10139 
   10140     else
   10141       {
   10142 
   10143         if (image_depth < 8)
   10144           image_depth=8;
   10145 
   10146         if ((save_image_depth == 16) && (image_depth == 8))
   10147           {
   10148             if (logging != MagickFalse)
   10149               {
   10150                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10151                   "    Scaling ping_trans_color from (%d,%d,%d)",
   10152                   (int) ping_trans_color.red,
   10153                   (int) ping_trans_color.green,
   10154                   (int) ping_trans_color.blue);
   10155               }
   10156 
   10157             ping_trans_color.red*=0x0101;
   10158             ping_trans_color.green*=0x0101;
   10159             ping_trans_color.blue*=0x0101;
   10160             ping_trans_color.gray*=0x0101;
   10161 
   10162             if (logging != MagickFalse)
   10163               {
   10164                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10165                   "    to (%d,%d,%d)",
   10166                   (int) ping_trans_color.red,
   10167                   (int) ping_trans_color.green,
   10168                   (int) ping_trans_color.blue);
   10169               }
   10170           }
   10171       }
   10172 
   10173     if (ping_bit_depth <  (ssize_t) mng_info->write_png_depth)
   10174          ping_bit_depth =  (ssize_t) mng_info->write_png_depth;
   10175 
   10176     /*
   10177       Adjust background and transparency samples in sub-8-bit grayscale files.
   10178     */
   10179     if (ping_bit_depth < 8 && ping_color_type ==
   10180         PNG_COLOR_TYPE_GRAY)
   10181       {
   10182          png_uint_16
   10183            maxval;
   10184 
   10185          size_t
   10186            one=1;
   10187 
   10188          maxval=(png_uint_16) ((one << ping_bit_depth)-1);
   10189 
   10190          if (ping_exclude_bKGD == MagickFalse)
   10191          {
   10192 
   10193          ping_background.gray=(png_uint_16) ((maxval/65535.)*
   10194            (ScaleQuantumToShort(((GetPixelInfoIntensity(image,
   10195            &image->background_color))) +.5)));
   10196 
   10197          if (logging != MagickFalse)
   10198            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10199              "  Setting up bKGD chunk (2)");
   10200          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10201              "      background_color index is %d",
   10202              (int) ping_background.index);
   10203 
   10204          ping_have_bKGD = MagickTrue;
   10205          }
   10206 
   10207          if (logging != MagickFalse)
   10208            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10209              "  Scaling ping_trans_color.gray from %d",
   10210              (int)ping_trans_color.gray);
   10211 
   10212          ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
   10213            ping_trans_color.gray)+.5);
   10214 
   10215          if (logging != MagickFalse)
   10216            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10217              "      to %d", (int)ping_trans_color.gray);
   10218       }
   10219 
   10220   if (ping_exclude_bKGD == MagickFalse)
   10221   {
   10222     if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
   10223       {
   10224         /*
   10225            Identify which colormap entry is the background color.
   10226         */
   10227 
   10228         number_colors=image_colors;
   10229 
   10230         for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
   10231           if (IsPNGColorEqual(image->background_color,image->colormap[i]))
   10232             break;
   10233 
   10234         ping_background.index=(png_byte) i;
   10235 
   10236         if (logging != MagickFalse)
   10237           {
   10238             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10239               "  Setting up bKGD chunk with index=%d",(int) i);
   10240           }
   10241 
   10242         if (i < (ssize_t) number_colors)
   10243           {
   10244             ping_have_bKGD = MagickTrue;
   10245 
   10246             if (logging != MagickFalse)
   10247               {
   10248                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10249                   "     background   =(%d,%d,%d)",
   10250                         (int) ping_background.red,
   10251                         (int) ping_background.green,
   10252                         (int) ping_background.blue);
   10253               }
   10254           }
   10255 
   10256         else  /* Can't happen */
   10257           {
   10258             if (logging != MagickFalse)
   10259               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10260                   "      No room in PLTE to add bKGD color");
   10261             ping_have_bKGD = MagickFalse;
   10262           }
   10263       }
   10264   }
   10265 
   10266   if (logging != MagickFalse)
   10267     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10268       "    PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
   10269       ping_color_type);
   10270   /*
   10271     Initialize compression level and filtering.
   10272   */
   10273   if (logging != MagickFalse)
   10274     {
   10275       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10276         "  Setting up deflate compression");
   10277 
   10278       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10279         "    Compression buffer size: 32768");
   10280     }
   10281 
   10282   png_set_compression_buffer_size(ping,32768L);
   10283 
   10284   if (logging != MagickFalse)
   10285     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10286       "    Compression mem level: 9");
   10287 
   10288   png_set_compression_mem_level(ping, 9);
   10289 
   10290   /* Untangle the "-quality" setting:
   10291 
   10292      Undefined is 0; the default is used.
   10293      Default is 75
   10294 
   10295      10's digit:
   10296 
   10297         0 or omitted: Use Z_HUFFMAN_ONLY strategy with the
   10298            zlib default compression level
   10299 
   10300         1-9: the zlib compression level
   10301 
   10302      1's digit:
   10303 
   10304         0-4: the PNG filter method
   10305 
   10306         5:   libpng adaptive filtering if compression level > 5
   10307              libpng filter type "none" if compression level <= 5
   10308                 or if image is grayscale or palette
   10309 
   10310         6:   libpng adaptive filtering
   10311 
   10312         7:   "LOCO" filtering (intrapixel differing) if writing
   10313              a MNG, otherwise "none".  Did not work in IM-6.7.0-9
   10314              and earlier because of a missing "else".
   10315 
   10316         8:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive
   10317              filtering. Unused prior to IM-6.7.0-10, was same as 6
   10318 
   10319         9:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters
   10320              Unused prior to IM-6.7.0-10, was same as 6
   10321 
   10322     Note that using the -quality option, not all combinations of
   10323     PNG filter type, zlib compression level, and zlib compression
   10324     strategy are possible.  This will be addressed soon in a
   10325     release that accomodates "-define png:compression-strategy", etc.
   10326 
   10327    */
   10328 
   10329   quality=image_info->quality == UndefinedCompressionQuality ? 75UL :
   10330      image_info->quality;
   10331 
   10332   if (quality <= 9)
   10333     {
   10334       if (mng_info->write_png_compression_strategy == 0)
   10335         mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
   10336     }
   10337 
   10338   else if (mng_info->write_png_compression_level == 0)
   10339     {
   10340       int
   10341         level;
   10342 
   10343       level=(int) MagickMin((ssize_t) quality/10,9);
   10344 
   10345       mng_info->write_png_compression_level = level+1;
   10346     }
   10347 
   10348   if (mng_info->write_png_compression_strategy == 0)
   10349     {
   10350         if ((quality %10) == 8 || (quality %10) == 9)
   10351 #ifdef Z_RLE  /* Z_RLE was added to zlib-1.2.0 */
   10352           mng_info->write_png_compression_strategy=Z_RLE+1;
   10353 #else
   10354           mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
   10355 #endif
   10356     }
   10357 
   10358   if (mng_info->write_png_compression_filter == 0)
   10359         mng_info->write_png_compression_filter=((int) quality % 10) + 1;
   10360 
   10361   if (logging != MagickFalse)
   10362     {
   10363      if (mng_info->write_png_compression_level)
   10364         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10365           "    Compression level:    %d",
   10366             (int) mng_info->write_png_compression_level-1);
   10367 
   10368      if (mng_info->write_png_compression_strategy)
   10369         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10370           "    Compression strategy: %d",
   10371             (int) mng_info->write_png_compression_strategy-1);
   10372 
   10373         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10374           "  Setting up filtering");
   10375 
   10376         if (mng_info->write_png_compression_filter == 6)
   10377           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10378             "    Base filter method: ADAPTIVE");
   10379         else if (mng_info->write_png_compression_filter == 0 ||
   10380                  mng_info->write_png_compression_filter == 1)
   10381           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10382             "    Base filter method: NONE");
   10383         else
   10384           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10385             "    Base filter method: %d",
   10386             (int) mng_info->write_png_compression_filter-1);
   10387     }
   10388 
   10389   if (mng_info->write_png_compression_level != 0)
   10390     png_set_compression_level(ping,mng_info->write_png_compression_level-1);
   10391 
   10392   if (mng_info->write_png_compression_filter == 6)
   10393     {
   10394       if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
   10395          ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
   10396          (quality < 50))
   10397         png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
   10398       else
   10399         png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
   10400      }
   10401   else if (mng_info->write_png_compression_filter == 7 ||
   10402       mng_info->write_png_compression_filter == 10)
   10403     png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
   10404 
   10405   else if (mng_info->write_png_compression_filter == 8)
   10406     {
   10407 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
   10408       if (mng_info->write_mng)
   10409       {
   10410          if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
   10411              ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
   10412         ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
   10413       }
   10414 #endif
   10415       png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
   10416     }
   10417 
   10418   else if (mng_info->write_png_compression_filter == 9)
   10419     png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
   10420 
   10421   else if (mng_info->write_png_compression_filter != 0)
   10422     png_set_filter(ping,PNG_FILTER_TYPE_BASE,
   10423        mng_info->write_png_compression_filter-1);
   10424 
   10425   if (mng_info->write_png_compression_strategy != 0)
   10426     png_set_compression_strategy(ping,
   10427        mng_info->write_png_compression_strategy-1);
   10428 
   10429   ping_interlace_method=image_info->interlace != NoInterlace;
   10430 
   10431   if (mng_info->write_mng)
   10432     png_set_sig_bytes(ping,8);
   10433 
   10434   /* Bail out if cannot meet defined png:bit-depth or png:color-type */
   10435 
   10436   if (mng_info->write_png_colortype != 0)
   10437     {
   10438      if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
   10439        if (ping_have_color != MagickFalse)
   10440          {
   10441            ping_color_type = PNG_COLOR_TYPE_RGB;
   10442 
   10443            if (ping_bit_depth < 8)
   10444              ping_bit_depth=8;
   10445          }
   10446 
   10447      if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
   10448        if (ping_have_color != MagickFalse)
   10449          ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
   10450     }
   10451 
   10452   if (ping_need_colortype_warning != MagickFalse ||
   10453      ((mng_info->write_png_depth &&
   10454      (int) mng_info->write_png_depth != ping_bit_depth) ||
   10455      (mng_info->write_png_colortype &&
   10456      ((int) mng_info->write_png_colortype-1 != ping_color_type &&
   10457       mng_info->write_png_colortype != 7 &&
   10458       !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
   10459     {
   10460       if (logging != MagickFalse)
   10461         {
   10462           if (ping_need_colortype_warning != MagickFalse)
   10463             {
   10464               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10465                  "  Image has transparency but tRNS chunk was excluded");
   10466             }
   10467 
   10468           if (mng_info->write_png_depth)
   10469             {
   10470               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10471                   "  Defined png:bit-depth=%u, Computed depth=%u",
   10472                   mng_info->write_png_depth,
   10473                   ping_bit_depth);
   10474             }
   10475 
   10476           if (mng_info->write_png_colortype)
   10477             {
   10478               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10479                   "  Defined png:color-type=%u, Computed color type=%u",
   10480                   mng_info->write_png_colortype-1,
   10481                   ping_color_type);
   10482             }
   10483         }
   10484 
   10485       png_warning(ping,
   10486         "Cannot write image with defined png:bit-depth or png:color-type.");
   10487     }
   10488 
   10489   if (image_matte != MagickFalse && image->alpha_trait == UndefinedPixelTrait)
   10490     {
   10491       /* Add an opaque matte channel */
   10492       image->alpha_trait = BlendPixelTrait;
   10493       (void) SetImageAlpha(image,OpaqueAlpha,exception);
   10494 
   10495       if (logging != MagickFalse)
   10496         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10497           "  Added an opaque matte channel");
   10498     }
   10499 
   10500   if (number_transparent != 0 || number_semitransparent != 0)
   10501     {
   10502       if (ping_color_type < 4)
   10503         {
   10504            ping_have_tRNS=MagickTrue;
   10505            if (logging != MagickFalse)
   10506              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10507                "  Setting ping_have_tRNS=MagickTrue.");
   10508         }
   10509     }
   10510 
   10511   if (logging != MagickFalse)
   10512     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10513       "  Writing PNG header chunks");
   10514 
   10515   png_set_IHDR(ping,ping_info,ping_width,ping_height,
   10516                ping_bit_depth,ping_color_type,
   10517                ping_interlace_method,ping_compression_method,
   10518                ping_filter_method);
   10519 
   10520   if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
   10521     {
   10522       png_set_PLTE(ping,ping_info,palette,number_colors);
   10523 
   10524       if (logging != MagickFalse)
   10525         {
   10526           for (i=0; i< (ssize_t) number_colors; i++)
   10527           {
   10528             if (i < ping_num_trans)
   10529               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10530                 "     PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
   10531                       (int) i,
   10532                       (int) palette[i].red,
   10533                       (int) palette[i].green,
   10534                       (int) palette[i].blue,
   10535                       (int) i,
   10536                       (int) ping_trans_alpha[i]);
   10537              else
   10538               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10539                 "     PLTE[%d] = (%d,%d,%d)",
   10540                       (int) i,
   10541                       (int) palette[i].red,
   10542                       (int) palette[i].green,
   10543                       (int) palette[i].blue);
   10544            }
   10545          }
   10546     }
   10547 
   10548   /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
   10549   if (ping_exclude_sRGB != MagickFalse ||
   10550      (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
   10551   {
   10552     if ((ping_exclude_tEXt == MagickFalse ||
   10553        ping_exclude_zTXt == MagickFalse) &&
   10554        (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
   10555     {
   10556       ResetImageProfileIterator(image);
   10557       for (name=GetNextImageProfile(image); name != (const char *) NULL; )
   10558       {
   10559         profile=GetImageProfile(image,name);
   10560 
   10561         if (profile != (StringInfo *) NULL)
   10562           {
   10563 #ifdef PNG_WRITE_iCCP_SUPPORTED
   10564             if ((LocaleCompare(name,"ICC") == 0) ||
   10565                 (LocaleCompare(name,"ICM") == 0))
   10566              {
   10567 
   10568                if (ping_exclude_iCCP == MagickFalse)
   10569                  {
   10570                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10571                           "  Setting up iCCP chunk");
   10572 
   10573                        png_set_iCCP(ping,ping_info,(png_charp) name,0,
   10574 #if (PNG_LIBPNG_VER < 10500)
   10575                          (png_charp) GetStringInfoDatum(profile),
   10576 #else
   10577                          (const png_byte *) GetStringInfoDatum(profile),
   10578 #endif
   10579                          (png_uint_32) GetStringInfoLength(profile));
   10580                        ping_have_iCCP = MagickTrue;
   10581                  }
   10582              }
   10583 
   10584             else
   10585 #endif
   10586               if (ping_exclude_zCCP == MagickFalse)
   10587                 {
   10588                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10589                       "  Setting up zTXT chunk with uuencoded ICC");
   10590                   Magick_png_write_raw_profile(image_info,ping,ping_info,
   10591                     (unsigned char *) name,(unsigned char *) name,
   10592                     GetStringInfoDatum(profile),
   10593                     (png_uint_32) GetStringInfoLength(profile));
   10594                   ping_have_iCCP = MagickTrue;
   10595                 }
   10596           }
   10597 
   10598           if (logging != MagickFalse)
   10599             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10600               "  Setting up text chunk with %s profile",name);
   10601 
   10602         name=GetNextImageProfile(image);
   10603       }
   10604     }
   10605   }
   10606 
   10607 #if defined(PNG_WRITE_sRGB_SUPPORTED)
   10608   if ((mng_info->have_write_global_srgb == 0) &&
   10609       ping_have_iCCP != MagickTrue &&
   10610       (ping_have_sRGB != MagickFalse ||
   10611       png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
   10612     {
   10613       if (ping_exclude_sRGB == MagickFalse)
   10614         {
   10615           /*
   10616             Note image rendering intent.
   10617           */
   10618           if (logging != MagickFalse)
   10619             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10620                 "  Setting up sRGB chunk");
   10621 
   10622           (void) png_set_sRGB(ping,ping_info,(
   10623             Magick_RenderingIntent_to_PNG_RenderingIntent(
   10624               image->rendering_intent)));
   10625 
   10626           ping_have_sRGB = MagickTrue;
   10627         }
   10628     }
   10629 
   10630   if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
   10631 #endif
   10632     {
   10633       if (ping_exclude_gAMA == MagickFalse &&
   10634           ping_have_iCCP == MagickFalse &&
   10635           ping_have_sRGB == MagickFalse &&
   10636           (ping_exclude_sRGB == MagickFalse ||
   10637           (image->gamma < .45 || image->gamma > .46)))
   10638       {
   10639       if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
   10640         {
   10641           /*
   10642             Note image gamma.
   10643             To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
   10644           */
   10645           if (logging != MagickFalse)
   10646             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10647               "  Setting up gAMA chunk");
   10648 
   10649           png_set_gAMA(ping,ping_info,image->gamma);
   10650         }
   10651       }
   10652 
   10653       if (ping_exclude_cHRM == MagickFalse && ping_have_sRGB == MagickFalse)
   10654         {
   10655           if ((mng_info->have_write_global_chrm == 0) &&
   10656               (image->chromaticity.red_primary.x != 0.0))
   10657             {
   10658               /*
   10659                 Note image chromaticity.
   10660                 Note: if cHRM+gAMA == sRGB write sRGB instead.
   10661               */
   10662                PrimaryInfo
   10663                  bp,
   10664                  gp,
   10665                  rp,
   10666                  wp;
   10667 
   10668                wp=image->chromaticity.white_point;
   10669                rp=image->chromaticity.red_primary;
   10670                gp=image->chromaticity.green_primary;
   10671                bp=image->chromaticity.blue_primary;
   10672 
   10673                if (logging != MagickFalse)
   10674                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10675                    "  Setting up cHRM chunk");
   10676 
   10677                png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
   10678                    bp.x,bp.y);
   10679            }
   10680         }
   10681     }
   10682 
   10683   if (ping_exclude_bKGD == MagickFalse)
   10684     {
   10685       if (ping_have_bKGD != MagickFalse)
   10686         {
   10687           png_set_bKGD(ping,ping_info,&ping_background);
   10688           if (logging != MagickFalse)
   10689             {
   10690               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10691                    "    Setting up bKGD chunk");
   10692               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10693                    "      background color = (%d,%d,%d)",
   10694                         (int) ping_background.red,
   10695                         (int) ping_background.green,
   10696                         (int) ping_background.blue);
   10697               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10698                    "      index = %d, gray=%d",
   10699                         (int) ping_background.index,
   10700                         (int) ping_background.gray);
   10701             }
   10702          }
   10703     }
   10704 
   10705   if (ping_exclude_pHYs == MagickFalse)
   10706     {
   10707       if (ping_have_pHYs != MagickFalse)
   10708         {
   10709           png_set_pHYs(ping,ping_info,
   10710              ping_pHYs_x_resolution,
   10711              ping_pHYs_y_resolution,
   10712              ping_pHYs_unit_type);
   10713 
   10714           if (logging != MagickFalse)
   10715             {
   10716               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10717                    "    Setting up pHYs chunk");
   10718               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10719                    "      x_resolution=%lu",
   10720                    (unsigned long) ping_pHYs_x_resolution);
   10721               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10722                    "      y_resolution=%lu",
   10723                    (unsigned long) ping_pHYs_y_resolution);
   10724               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10725                    "      unit_type=%lu",
   10726                    (unsigned long) ping_pHYs_unit_type);
   10727             }
   10728         }
   10729     }
   10730 
   10731 #if defined(PNG_oFFs_SUPPORTED)
   10732   if (ping_exclude_oFFs == MagickFalse)
   10733     {
   10734       if (image->page.x || image->page.y)
   10735         {
   10736            png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
   10737               (png_int_32) image->page.y, 0);
   10738 
   10739            if (logging != MagickFalse)
   10740              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10741                  "    Setting up oFFs chunk with x=%d, y=%d, units=0",
   10742                  (int) image->page.x, (int) image->page.y);
   10743         }
   10744     }
   10745 #endif
   10746 
   10747 #if defined(PNG_tIME_SUPPORTED)
   10748   if (ping_exclude_tIME == MagickFalse)
   10749     {
   10750       const char
   10751         *timestamp;
   10752 
   10753       if (image->taint == MagickFalse)
   10754         {
   10755           timestamp=GetImageOption(image_info,"png:tIME");
   10756 
   10757           if (timestamp == (const char *) NULL)
   10758             timestamp=GetImageProperty(image,"png:tIME",exception);
   10759         }
   10760 
   10761       else
   10762         {
   10763           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10764              "  Reset tIME in tainted image");
   10765 
   10766           timestamp=GetImageProperty(image,"date:modify",exception);
   10767         }
   10768 
   10769       if (timestamp != (const char *) NULL)
   10770           write_tIME_chunk(image,ping,ping_info,timestamp,exception);
   10771     }
   10772 #endif
   10773 
   10774   if (mng_info->need_blob != MagickFalse)
   10775   {
   10776     if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
   10777        MagickFalse)
   10778        png_error(ping,"WriteBlob Failed");
   10779 
   10780      ping_have_blob=MagickTrue;
   10781   }
   10782 
   10783   png_write_info_before_PLTE(ping, ping_info);
   10784 
   10785   if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
   10786     {
   10787       if (logging != MagickFalse)
   10788         {
   10789           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10790               "  Calling png_set_tRNS with num_trans=%d",ping_num_trans);
   10791         }
   10792 
   10793       if (ping_color_type == 3)
   10794          (void) png_set_tRNS(ping, ping_info,
   10795                 ping_trans_alpha,
   10796                 ping_num_trans,
   10797                 NULL);
   10798 
   10799       else
   10800         {
   10801            (void) png_set_tRNS(ping, ping_info,
   10802                   NULL,
   10803                   0,
   10804                   &ping_trans_color);
   10805 
   10806            if (logging != MagickFalse)
   10807              {
   10808                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10809                  "     tRNS color   =(%d,%d,%d)",
   10810                        (int) ping_trans_color.red,
   10811                        (int) ping_trans_color.green,
   10812                        (int) ping_trans_color.blue);
   10813              }
   10814          }
   10815     }
   10816 
   10817   /* write any png-chunk-b profiles */
   10818   (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
   10819 
   10820   png_write_info(ping,ping_info);
   10821 
   10822   /* write any PNG-chunk-m profiles */
   10823   (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
   10824 
   10825   if (ping_exclude_vpAg == MagickFalse)
   10826     {
   10827       if ((image->page.width != 0 && image->page.width != image->columns) ||
   10828           (image->page.height != 0 && image->page.height != image->rows))
   10829         {
   10830           unsigned char
   10831             chunk[14];
   10832 
   10833           (void) WriteBlobMSBULong(image,9L);  /* data length=8 */
   10834           PNGType(chunk,mng_vpAg);
   10835           LogPNGChunk(logging,mng_vpAg,9L);
   10836           PNGLong(chunk+4,(png_uint_32) image->page.width);
   10837           PNGLong(chunk+8,(png_uint_32) image->page.height);
   10838           chunk[12]=0;   /* unit = pixels */
   10839           (void) WriteBlob(image,13,chunk);
   10840           (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
   10841         }
   10842     }
   10843 
   10844 #if (PNG_LIBPNG_VER == 10206)
   10845     /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
   10846 #define PNG_HAVE_IDAT               0x04
   10847     ping->mode |= PNG_HAVE_IDAT;
   10848 #undef PNG_HAVE_IDAT
   10849 #endif
   10850 
   10851   png_set_packing(ping);
   10852   /*
   10853     Allocate memory.
   10854   */
   10855   rowbytes=image->columns;
   10856   if (image_depth > 8)
   10857     rowbytes*=2;
   10858   switch (ping_color_type)
   10859     {
   10860       case PNG_COLOR_TYPE_RGB:
   10861         rowbytes*=3;
   10862         break;
   10863 
   10864       case PNG_COLOR_TYPE_GRAY_ALPHA:
   10865         rowbytes*=2;
   10866         break;
   10867 
   10868       case PNG_COLOR_TYPE_RGBA:
   10869         rowbytes*=4;
   10870         break;
   10871 
   10872       default:
   10873         break;
   10874     }
   10875 
   10876   if (logging != MagickFalse)
   10877     {
   10878       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10879         "  Writing PNG image data");
   10880 
   10881       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10882         "    Allocating %.20g bytes of memory for pixels",(double) rowbytes);
   10883     }
   10884   pixel_info=AcquireVirtualMemory(rowbytes,sizeof(*ping_pixels));
   10885   if (pixel_info == (MemoryInfo *) NULL)
   10886     png_error(ping,"Allocation of memory for pixels failed");
   10887   ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   10888 
   10889   /*
   10890     Initialize image scanlines.
   10891   */
   10892   quantum_info=AcquireQuantumInfo(image_info,image);
   10893   if (quantum_info == (QuantumInfo *) NULL)
   10894     png_error(ping,"Memory allocation for quantum_info failed");
   10895   quantum_info->format=UndefinedQuantumFormat;
   10896   SetQuantumDepth(image,quantum_info,image_depth);
   10897   (void) SetQuantumEndian(image,quantum_info,MSBEndian);
   10898   num_passes=png_set_interlace_handling(ping);
   10899 
   10900   if ((!mng_info->write_png8 && !mng_info->write_png24 &&
   10901        !mng_info->write_png48 && !mng_info->write_png64 &&
   10902        !mng_info->write_png32) &&
   10903        (mng_info->IsPalette ||
   10904        (image_info->type == BilevelType)) &&
   10905        image_matte == MagickFalse &&
   10906        ping_have_non_bw == MagickFalse)
   10907     {
   10908       /* Palette, Bilevel, or Opaque Monochrome */
   10909       register const Quantum
   10910         *p;
   10911 
   10912       SetQuantumDepth(image,quantum_info,8);
   10913       for (pass=0; pass < num_passes; pass++)
   10914       {
   10915         /*
   10916           Convert PseudoClass image to a PNG monochrome image.
   10917         */
   10918         for (y=0; y < (ssize_t) image->rows; y++)
   10919         {
   10920           if (logging != MagickFalse && y == 0)
   10921              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10922                  "    Writing row of pixels (0)");
   10923 
   10924           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   10925 
   10926           if (p == (const Quantum *) NULL)
   10927             break;
   10928 
   10929           if (mng_info->IsPalette)
   10930             {
   10931               (void) ExportQuantumPixels(image,(CacheView *) NULL,
   10932                 quantum_info,GrayQuantum,ping_pixels,exception);
   10933               if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
   10934                   mng_info->write_png_depth &&
   10935                   mng_info->write_png_depth != old_bit_depth)
   10936                 {
   10937                   /* Undo pixel scaling */
   10938                   for (i=0; i < (ssize_t) image->columns; i++)
   10939                      *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
   10940                      >> (8-old_bit_depth));
   10941                 }
   10942             }
   10943 
   10944           else
   10945             {
   10946               (void) ExportQuantumPixels(image,(CacheView *) NULL,
   10947                 quantum_info,RedQuantum,ping_pixels,exception);
   10948             }
   10949 
   10950           if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
   10951             for (i=0; i < (ssize_t) image->columns; i++)
   10952                *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
   10953                       255 : 0);
   10954 
   10955           if (logging != MagickFalse && y == 0)
   10956             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   10957                 "    Writing row of pixels (1)");
   10958 
   10959           png_write_row(ping,ping_pixels);
   10960 
   10961           status=SetImageProgress(image,SaveImageTag,
   10962               (MagickOffsetType) (pass * image->rows + y),
   10963               num_passes * image->rows);
   10964 
   10965           if (status == MagickFalse)
   10966             break;
   10967         }
   10968       }
   10969     }
   10970 
   10971   else   /* Not Palette, Bilevel, or Opaque Monochrome */
   10972     {
   10973       if ((!mng_info->write_png8 && !mng_info->write_png24 &&
   10974           !mng_info->write_png48 && !mng_info->write_png64 &&
   10975           !mng_info->write_png32) && (image_matte != MagickFalse ||
   10976           (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
   10977           (mng_info->IsPalette) && ping_have_color == MagickFalse)
   10978         {
   10979           register const Quantum
   10980             *p;
   10981 
   10982           for (pass=0; pass < num_passes; pass++)
   10983           {
   10984 
   10985           for (y=0; y < (ssize_t) image->rows; y++)
   10986           {
   10987             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   10988 
   10989             if (p == (const Quantum *) NULL)
   10990               break;
   10991 
   10992             if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   10993               {
   10994                 if (mng_info->IsPalette)
   10995                   (void) ExportQuantumPixels(image,(CacheView *) NULL,
   10996                     quantum_info,GrayQuantum,ping_pixels,exception);
   10997 
   10998                 else
   10999                   (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11000                     quantum_info,RedQuantum,ping_pixels,exception);
   11001 
   11002                 if (logging != MagickFalse && y == 0)
   11003                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11004                        "    Writing GRAY PNG pixels (2)");
   11005               }
   11006 
   11007             else /* PNG_COLOR_TYPE_GRAY_ALPHA */
   11008               {
   11009                 if (logging != MagickFalse && y == 0)
   11010                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11011                          "    Writing GRAY_ALPHA PNG pixels (2)");
   11012 
   11013                 (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11014                   quantum_info,GrayAlphaQuantum,ping_pixels,exception);
   11015               }
   11016 
   11017             if (logging != MagickFalse && y == 0)
   11018               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11019                   "    Writing row of pixels (2)");
   11020 
   11021             png_write_row(ping,ping_pixels);
   11022 
   11023             status=SetImageProgress(image,SaveImageTag,
   11024               (MagickOffsetType) (pass * image->rows + y),
   11025               num_passes * image->rows);
   11026 
   11027             if (status == MagickFalse)
   11028               break;
   11029             }
   11030           }
   11031         }
   11032 
   11033       else
   11034         {
   11035           register const Quantum
   11036             *p;
   11037 
   11038           for (pass=0; pass < num_passes; pass++)
   11039           {
   11040             if ((image_depth > 8) ||
   11041                 mng_info->write_png24 ||
   11042                 mng_info->write_png32 ||
   11043                 mng_info->write_png48 ||
   11044                 mng_info->write_png64 ||
   11045                 (!mng_info->write_png8 && !mng_info->IsPalette))
   11046             {
   11047               for (y=0; y < (ssize_t) image->rows; y++)
   11048               {
   11049                 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
   11050 
   11051                 if (p == (const Quantum *) NULL)
   11052                   break;
   11053 
   11054                 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   11055                   {
   11056                     if (image->storage_class == DirectClass)
   11057                       (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11058                         quantum_info,RedQuantum,ping_pixels,exception);
   11059 
   11060                     else
   11061                       (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11062                         quantum_info,GrayQuantum,ping_pixels,exception);
   11063                   }
   11064 
   11065                 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
   11066                   {
   11067                     (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11068                       quantum_info,GrayAlphaQuantum,ping_pixels,
   11069                       exception);
   11070 
   11071                     if (logging != MagickFalse && y == 0)
   11072                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11073                            "    Writing GRAY_ALPHA PNG pixels (3)");
   11074                   }
   11075 
   11076                 else if (image_matte != MagickFalse)
   11077                   (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11078                     quantum_info,RGBAQuantum,ping_pixels,exception);
   11079 
   11080                 else
   11081                   (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11082                     quantum_info,RGBQuantum,ping_pixels,exception);
   11083 
   11084                 if (logging != MagickFalse && y == 0)
   11085                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11086                       "    Writing row of pixels (3)");
   11087 
   11088                 png_write_row(ping,ping_pixels);
   11089 
   11090                 status=SetImageProgress(image,SaveImageTag,
   11091                   (MagickOffsetType) (pass * image->rows + y),
   11092                   num_passes * image->rows);
   11093 
   11094                 if (status == MagickFalse)
   11095                   break;
   11096               }
   11097             }
   11098 
   11099           else
   11100             /* not ((image_depth > 8) ||
   11101                 mng_info->write_png24 || mng_info->write_png32 ||
   11102                 mng_info->write_png48 || mng_info->write_png64 ||
   11103                 (!mng_info->write_png8 && !mng_info->IsPalette))
   11104              */
   11105             {
   11106               if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
   11107                   (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
   11108                 {
   11109                   if (logging != MagickFalse)
   11110                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11111                       "  pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
   11112 
   11113                   SetQuantumDepth(image,quantum_info,8);
   11114                   image_depth=8;
   11115                 }
   11116 
   11117               for (y=0; y < (ssize_t) image->rows; y++)
   11118               {
   11119                 if (logging != MagickFalse && y == 0)
   11120                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11121                     "  pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
   11122 
   11123                 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
   11124 
   11125                 if (p == (const Quantum *) NULL)
   11126                   break;
   11127 
   11128                 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
   11129                   {
   11130                     SetQuantumDepth(image,quantum_info,image->depth);
   11131 
   11132                     (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11133                        quantum_info,GrayQuantum,ping_pixels,exception);
   11134                   }
   11135 
   11136                 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
   11137                   {
   11138                     if (logging != MagickFalse && y == 0)
   11139                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11140                            "  Writing GRAY_ALPHA PNG pixels (4)");
   11141 
   11142                     (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11143                          quantum_info,GrayAlphaQuantum,ping_pixels,
   11144                          exception);
   11145                   }
   11146 
   11147                 else
   11148                   {
   11149                     (void) ExportQuantumPixels(image,(CacheView *) NULL,
   11150                       quantum_info,IndexQuantum,ping_pixels,exception);
   11151 
   11152                     if (logging != MagickFalse && y <= 2)
   11153                     {
   11154                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11155                           "  Writing row of non-gray pixels (4)");
   11156 
   11157                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11158                           "  ping_pixels[0]=%d,ping_pixels[1]=%d",
   11159                           (int)ping_pixels[0],(int)ping_pixels[1]);
   11160                     }
   11161                   }
   11162                 png_write_row(ping,ping_pixels);
   11163 
   11164                 status=SetImageProgress(image,SaveImageTag,
   11165                   (MagickOffsetType) (pass * image->rows + y),
   11166                   num_passes * image->rows);
   11167 
   11168                 if (status == MagickFalse)
   11169                   break;
   11170               }
   11171             }
   11172           }
   11173         }
   11174     }
   11175 
   11176   if (quantum_info != (QuantumInfo *) NULL)
   11177     quantum_info=DestroyQuantumInfo(quantum_info);
   11178 
   11179   if (logging != MagickFalse)
   11180     {
   11181       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11182         "  Wrote PNG image data");
   11183 
   11184       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11185         "    Width: %.20g",(double) ping_width);
   11186 
   11187       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11188         "    Height: %.20g",(double) ping_height);
   11189 
   11190       if (mng_info->write_png_depth)
   11191         {
   11192           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11193             "    Defined png:bit-depth: %d",mng_info->write_png_depth);
   11194         }
   11195 
   11196       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11197         "    PNG bit-depth written: %d",ping_bit_depth);
   11198 
   11199       if (mng_info->write_png_colortype)
   11200         {
   11201           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11202             "    Defined png:color-type: %d",mng_info->write_png_colortype-1);
   11203         }
   11204 
   11205       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11206         "    PNG color-type written: %d",ping_color_type);
   11207 
   11208       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11209         "    PNG Interlace method: %d",ping_interlace_method);
   11210     }
   11211   /*
   11212     Generate text chunks after IDAT.
   11213   */
   11214   if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
   11215   {
   11216     ResetImagePropertyIterator(image);
   11217     property=GetNextImageProperty(image);
   11218     while (property != (const char *) NULL)
   11219     {
   11220       png_textp
   11221         text;
   11222 
   11223       value=GetImageProperty(image,property,exception);
   11224 
   11225       /* Don't write any "png:" or "jpeg:" properties; those are just for
   11226        * "identify" or for passing through to another JPEG
   11227        */
   11228       if ((LocaleNCompare(property,"png:",4) != 0 &&
   11229            LocaleNCompare(property,"jpeg:",5) != 0) &&
   11230 
   11231 
   11232           /* Suppress density and units if we wrote a pHYs chunk */
   11233           (ping_exclude_pHYs != MagickFalse      ||
   11234           LocaleCompare(property,"density") != 0 ||
   11235           LocaleCompare(property,"units") != 0) &&
   11236 
   11237           /* Suppress the IM-generated Date:create and Date:modify */
   11238           (ping_exclude_date == MagickFalse      ||
   11239           LocaleNCompare(property, "Date:",5) != 0))
   11240         {
   11241         if (value != (const char *) NULL)
   11242           {
   11243 
   11244 #if PNG_LIBPNG_VER >= 10400
   11245             text=(png_textp) png_malloc(ping,
   11246                  (png_alloc_size_t) sizeof(png_text));
   11247 #else
   11248             text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
   11249 #endif
   11250             text[0].key=(char *) property;
   11251             text[0].text=(char *) value;
   11252             text[0].text_length=strlen(value);
   11253 
   11254             if (ping_exclude_tEXt != MagickFalse)
   11255                text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
   11256 
   11257             else if (ping_exclude_zTXt != MagickFalse)
   11258                text[0].compression=PNG_TEXT_COMPRESSION_NONE;
   11259 
   11260             else
   11261             {
   11262                text[0].compression=image_info->compression == NoCompression ||
   11263                  (image_info->compression == UndefinedCompression &&
   11264                  text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
   11265                  PNG_TEXT_COMPRESSION_zTXt ;
   11266             }
   11267 
   11268             if (logging != MagickFalse)
   11269               {
   11270                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11271                   "  Setting up text chunk");
   11272 
   11273                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11274                   "    keyword: '%s'",text[0].key);
   11275               }
   11276 
   11277             png_set_text(ping,ping_info,text,1);
   11278             png_free(ping,text);
   11279           }
   11280         }
   11281       property=GetNextImageProperty(image);
   11282     }
   11283   }
   11284 
   11285   /* write any PNG-chunk-e profiles */
   11286   (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
   11287 
   11288   if (logging != MagickFalse)
   11289     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11290       "  Writing PNG end info");
   11291 
   11292   png_write_end(ping,ping_info);
   11293 
   11294   if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
   11295     {
   11296       if (mng_info->page.x || mng_info->page.y ||
   11297           (ping_width != mng_info->page.width) ||
   11298           (ping_height != mng_info->page.height))
   11299         {
   11300           unsigned char
   11301             chunk[32];
   11302 
   11303           /*
   11304             Write FRAM 4 with clipping boundaries followed by FRAM 1.
   11305           */
   11306           (void) WriteBlobMSBULong(image,27L);  /* data length=27 */
   11307           PNGType(chunk,mng_FRAM);
   11308           LogPNGChunk(logging,mng_FRAM,27L);
   11309           chunk[4]=4;
   11310           chunk[5]=0;  /* frame name separator (no name) */
   11311           chunk[6]=1;  /* flag for changing delay, for next frame only */
   11312           chunk[7]=0;  /* flag for changing frame timeout */
   11313           chunk[8]=1;  /* flag for changing frame clipping for next frame */
   11314           chunk[9]=0;  /* flag for changing frame sync_id */
   11315           PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
   11316           chunk[14]=0; /* clipping boundaries delta type */
   11317           PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
   11318           PNGLong(chunk+19,
   11319              (png_uint_32) (mng_info->page.x + ping_width));
   11320           PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
   11321           PNGLong(chunk+27,
   11322              (png_uint_32) (mng_info->page.y + ping_height));
   11323           (void) WriteBlob(image,31,chunk);
   11324           (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
   11325           mng_info->old_framing_mode=4;
   11326           mng_info->framing_mode=1;
   11327         }
   11328 
   11329       else
   11330         mng_info->framing_mode=3;
   11331     }
   11332   if (mng_info->write_mng && !mng_info->need_fram &&
   11333       ((int) image->dispose == 3))
   11334      png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
   11335 
   11336   /*
   11337     Free PNG resources.
   11338   */
   11339 
   11340   png_destroy_write_struct(&ping,&ping_info);
   11341 
   11342   pixel_info=RelinquishVirtualMemory(pixel_info);
   11343 
   11344   if (ping_have_blob != MagickFalse)
   11345      (void) CloseBlob(image);
   11346 
   11347   image_info=DestroyImageInfo(image_info);
   11348   image=DestroyImage(image);
   11349 
   11350   /* Store bit depth actually written */
   11351   s[0]=(char) ping_bit_depth;
   11352   s[1]='\0';
   11353 
   11354   (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
   11355 
   11356   if (logging != MagickFalse)
   11357     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11358       "  exit WriteOnePNGImage()");
   11359 
   11360 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
   11361   UnlockSemaphoreInfo(ping_semaphore);
   11362 #endif
   11363 
   11364    /* }  for navigation to beginning of SETJMP-protected block. Revert to
   11365     *    Throwing an Exception when an error occurs.
   11366     */
   11367 
   11368   return(MagickTrue);
   11369 /*  End write one PNG image */
   11370 
   11371 }
   11372 
   11373 /*
   11374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   11375 %                                                                             %
   11376 %                                                                             %
   11377 %                                                                             %
   11378 %   W r i t e P N G I m a g e                                                 %
   11379 %                                                                             %
   11380 %                                                                             %
   11381 %                                                                             %
   11382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   11383 %
   11384 %  WritePNGImage() writes a Portable Network Graphics (PNG) or
   11385 %  Multiple-image Network Graphics (MNG) image file.
   11386 %
   11387 %  MNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   11388 %
   11389 %  The format of the WritePNGImage method is:
   11390 %
   11391 %      MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   11392 %        Image *image,ExceptionInfo *exception)
   11393 %
   11394 %  A description of each parameter follows:
   11395 %
   11396 %    o image_info: the image info.
   11397 %
   11398 %    o image:  The image.
   11399 %
   11400 %    o exception: return any errors or warnings in this structure.
   11401 %
   11402 %  Returns MagickTrue on success, MagickFalse on failure.
   11403 %
   11404 %  Communicating with the PNG encoder:
   11405 %
   11406 %  While the datastream written is always in PNG format and normally would
   11407 %  be given the "png" file extension, this method also writes the following
   11408 %  pseudo-formats which are subsets of png:
   11409 %
   11410 %    o PNG8:    An 8-bit indexed PNG datastream is written.  If the image has
   11411 %               a depth greater than 8, the depth is reduced. If transparency
   11412 %               is present, the tRNS chunk must only have values 0 and 255
   11413 %               (i.e., transparency is binary: fully opaque or fully
   11414 %               transparent).  If other values are present they will be
   11415 %               50%-thresholded to binary transparency.  If more than 256
   11416 %               colors are present, they will be quantized to the 4-4-4-1,
   11417 %               3-3-3-1, or 3-3-2-1 palette.  The underlying RGB color
   11418 %               of any resulting fully-transparent pixels is changed to
   11419 %               the image's background color.
   11420 %
   11421 %               If you want better quantization or dithering of the colors
   11422 %               or alpha than that, you need to do it before calling the
   11423 %               PNG encoder. The pixels contain 8-bit indices even if
   11424 %               they could be represented with 1, 2, or 4 bits.  Grayscale
   11425 %               images will be written as indexed PNG files even though the
   11426 %               PNG grayscale type might be slightly more efficient.  Please
   11427 %               note that writing to the PNG8 format may result in loss
   11428 %               of color and alpha data.
   11429 %
   11430 %    o PNG24:   An 8-bit per sample RGB PNG datastream is written.  The tRNS
   11431 %               chunk can be present to convey binary transparency by naming
   11432 %               one of the colors as transparent.  The only loss incurred
   11433 %               is reduction of sample depth to 8.  If the image has more
   11434 %               than one transparent color, has semitransparent pixels, or
   11435 %               has an opaque pixel with the same RGB components as the
   11436 %               transparent color, an image is not written.
   11437 %
   11438 %    o PNG32:   An 8-bit per sample RGBA PNG is written.  Partial
   11439 %               transparency is permitted, i.e., the alpha sample for
   11440 %               each pixel can have any value from 0 to 255. The alpha
   11441 %               channel is present even if the image is fully opaque.
   11442 %               The only loss in data is the reduction of the sample depth
   11443 %               to 8.
   11444 %
   11445 %    o PNG48:   A 16-bit per sample RGB PNG datastream is written.  The tRNS
   11446 %               chunk can be present to convey binary transparency by naming
   11447 %               one of the colors as transparent.  If the image has more
   11448 %               than one transparent color, has semitransparent pixels, or
   11449 %               has an opaque pixel with the same RGB components as the
   11450 %               transparent color, an image is not written.
   11451 %
   11452 %    o PNG64:   A 16-bit per sample RGBA PNG is written.  Partial
   11453 %               transparency is permitted, i.e., the alpha sample for
   11454 %               each pixel can have any value from 0 to 65535. The alpha
   11455 %               channel is present even if the image is fully opaque.
   11456 %
   11457 %    o PNG00:   A PNG that inherits its colortype and bit-depth from the input
   11458 %               image, if the input was a PNG, is written.  If these values
   11459 %               cannot be found, or if the pixels have been changed in a way
   11460 %               that makes this impossible, then "PNG00" falls back to the
   11461 %               regular "PNG" format.
   11462 %
   11463 %    o -define: For more precise control of the PNG output, you can use the
   11464 %               Image options "png:bit-depth" and "png:color-type".  These
   11465 %               can be set from the commandline with "-define" and also
   11466 %               from the application programming interfaces.  The options
   11467 %               are case-independent and are converted to lowercase before
   11468 %               being passed to this encoder.
   11469 %
   11470 %               png:color-type can be 0, 2, 3, 4, or 6.
   11471 %
   11472 %               When png:color-type is 0 (Grayscale), png:bit-depth can
   11473 %               be 1, 2, 4, 8, or 16.
   11474 %
   11475 %               When png:color-type is 2 (RGB), png:bit-depth can
   11476 %               be 8 or 16.
   11477 %
   11478 %               When png:color-type is 3 (Indexed), png:bit-depth can
   11479 %               be 1, 2, 4, or 8.  This refers to the number of bits
   11480 %               used to store the index.  The color samples always have
   11481 %               bit-depth 8 in indexed PNG files.
   11482 %
   11483 %               When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
   11484 %               png:bit-depth can be 8 or 16.
   11485 %
   11486 %               If the image cannot be written without loss with the
   11487 %               requested bit-depth and color-type, a PNG file will not
   11488 %               be written, a warning will be issued, and the encoder will
   11489 %               return MagickFalse.
   11490 %
   11491 %  Since image encoders should not be responsible for the "heavy lifting",
   11492 %  the user should make sure that ImageMagick has already reduced the
   11493 %  image depth and number of colors and limit transparency to binary
   11494 %  transparency prior to attempting to write the image with depth, color,
   11495 %  or transparency limitations.
   11496 %
   11497 %  Note that another definition, "png:bit-depth-written" exists, but it
   11498 %  is not intended for external use.  It is only used internally by the
   11499 %  PNG encoder to inform the JNG encoder of the depth of the alpha channel.
   11500 %
   11501 %  It is possible to request that the PNG encoder write previously-formatted
   11502 %  ancillary chunks in the output PNG file, using the "-profile" commandline
   11503 %  option as shown below or by setting the profile via a programming
   11504 %  interface:
   11505 %
   11506 %     -profile PNG-chunk-x:<file>
   11507 %
   11508 %  where x is a location flag and <file> is a file containing the chunk
   11509 %  name in the first 4 bytes, then a colon (":"), followed by the chunk data.
   11510 %  This encoder will compute the chunk length and CRC, so those must not
   11511 %  be included in the file.
   11512 %
   11513 %  "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
   11514 %  or "e" (end, i.e., after IDAT).  If you want to write multiple chunks
   11515 %  of the same type, then add a short unique string after the "x" to prevent
   11516 %  subsequent profiles from overwriting the preceding ones, e.g.,
   11517 %
   11518 %     -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
   11519 %
   11520 %  As of version 6.6.6 the following optimizations are always done:
   11521 %
   11522 %   o  32-bit depth is reduced to 16.
   11523 %   o  16-bit depth is reduced to 8 if all pixels contain samples whose
   11524 %      high byte and low byte are identical.
   11525 %   o  Palette is sorted to remove unused entries and to put a
   11526 %      transparent color first, if BUILD_PNG_PALETTE is defined.
   11527 %   o  Opaque matte channel is removed when writing an indexed PNG.
   11528 %   o  Grayscale images are reduced to 1, 2, or 4 bit depth if
   11529 %      this can be done without loss and a larger bit depth N was not
   11530 %      requested via the "-define png:bit-depth=N" option.
   11531 %   o  If matte channel is present but only one transparent color is
   11532 %      present, RGB+tRNS is written instead of RGBA
   11533 %   o  Opaque matte channel is removed (or added, if color-type 4 or 6
   11534 %      was requested when converting an opaque image).
   11535 %
   11536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   11537 */
   11538 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   11539   Image *image,ExceptionInfo *exception)
   11540 {
   11541   MagickBooleanType
   11542     excluding,
   11543     logging,
   11544     have_mng_structure,
   11545     status;
   11546 
   11547   MngInfo
   11548     *mng_info;
   11549 
   11550   const char
   11551     *value;
   11552 
   11553   int
   11554     source;
   11555 
   11556   /*
   11557     Open image file.
   11558   */
   11559   assert(image_info != (const ImageInfo *) NULL);
   11560   assert(image_info->signature == MagickCoreSignature);
   11561   assert(image != (Image *) NULL);
   11562   assert(image->signature == MagickCoreSignature);
   11563   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   11564   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
   11565   /*
   11566     Allocate a MngInfo structure.
   11567   */
   11568   have_mng_structure=MagickFalse;
   11569   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
   11570 
   11571   if (mng_info == (MngInfo *) NULL)
   11572     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   11573 
   11574   /*
   11575     Initialize members of the MngInfo structure.
   11576   */
   11577   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   11578   mng_info->image=image;
   11579   mng_info->equal_backgrounds=MagickTrue;
   11580   have_mng_structure=MagickTrue;
   11581 
   11582   /* See if user has requested a specific PNG subformat */
   11583 
   11584   mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
   11585   mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
   11586   mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
   11587   mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
   11588   mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
   11589 
   11590   value=GetImageOption(image_info,"png:format");
   11591 
   11592   if (value != (char *) NULL || LocaleCompare(image_info->magick,"PNG00") == 0)
   11593     {
   11594       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11595          "  Format=%s",value);
   11596 
   11597       mng_info->write_png8 = MagickFalse;
   11598       mng_info->write_png24 = MagickFalse;
   11599       mng_info->write_png32 = MagickFalse;
   11600       mng_info->write_png48 = MagickFalse;
   11601       mng_info->write_png64 = MagickFalse;
   11602 
   11603       if (LocaleCompare(value,"png8") == 0)
   11604         mng_info->write_png8 = MagickTrue;
   11605 
   11606       else if (LocaleCompare(value,"png24") == 0)
   11607         mng_info->write_png24 = MagickTrue;
   11608 
   11609       else if (LocaleCompare(value,"png32") == 0)
   11610         mng_info->write_png32 = MagickTrue;
   11611 
   11612       else if (LocaleCompare(value,"png48") == 0)
   11613         mng_info->write_png48 = MagickTrue;
   11614 
   11615       else if (LocaleCompare(value,"png64") == 0)
   11616         mng_info->write_png64 = MagickTrue;
   11617 
   11618       else if ((LocaleCompare(value,"png00") == 0) ||
   11619          LocaleCompare(image_info->magick,"PNG00") == 0)
   11620         {
   11621           /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig. */
   11622           value=GetImageProperty(image,"png:IHDR.bit-depth-orig",exception);
   11623 
   11624           if (value != (char *) NULL)
   11625             {
   11626               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11627                  "  png00 inherited bit depth=%s",value);
   11628 
   11629               if (LocaleCompare(value,"1") == 0)
   11630                 mng_info->write_png_depth = 1;
   11631 
   11632               else if (LocaleCompare(value,"2") == 0)
   11633                 mng_info->write_png_depth = 2;
   11634 
   11635               else if (LocaleCompare(value,"4") == 0)
   11636                 mng_info->write_png_depth = 4;
   11637 
   11638               else if (LocaleCompare(value,"8") == 0)
   11639                 mng_info->write_png_depth = 8;
   11640 
   11641               else if (LocaleCompare(value,"16") == 0)
   11642                 mng_info->write_png_depth = 16;
   11643             }
   11644 
   11645           value=GetImageProperty(image,"png:IHDR.color-type-orig",exception);
   11646 
   11647           if (value != (char *) NULL)
   11648             {
   11649               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11650                  "  png00 inherited color type=%s",value);
   11651 
   11652               if (LocaleCompare(value,"0") == 0)
   11653                 mng_info->write_png_colortype = 1;
   11654 
   11655               else if (LocaleCompare(value,"2") == 0)
   11656                 mng_info->write_png_colortype = 3;
   11657 
   11658               else if (LocaleCompare(value,"3") == 0)
   11659                 mng_info->write_png_colortype = 4;
   11660 
   11661               else if (LocaleCompare(value,"4") == 0)
   11662                 mng_info->write_png_colortype = 5;
   11663 
   11664               else if (LocaleCompare(value,"6") == 0)
   11665                 mng_info->write_png_colortype = 7;
   11666             }
   11667         }
   11668     }
   11669 
   11670   if (mng_info->write_png8)
   11671     {
   11672       mng_info->write_png_colortype = /* 3 */ 4;
   11673       mng_info->write_png_depth = 8;
   11674       image->depth = 8;
   11675     }
   11676 
   11677   if (mng_info->write_png24)
   11678     {
   11679       mng_info->write_png_colortype = /* 2 */ 3;
   11680       mng_info->write_png_depth = 8;
   11681       image->depth = 8;
   11682 
   11683       if (image->alpha_trait != UndefinedPixelTrait)
   11684         (void) SetImageType(image,TrueColorAlphaType,exception);
   11685 
   11686       else
   11687         (void) SetImageType(image,TrueColorType,exception);
   11688 
   11689       (void) SyncImage(image,exception);
   11690     }
   11691 
   11692   if (mng_info->write_png32)
   11693     {
   11694       mng_info->write_png_colortype = /* 6 */  7;
   11695       mng_info->write_png_depth = 8;
   11696       image->depth = 8;
   11697       image->alpha_trait = BlendPixelTrait;
   11698 
   11699       (void) SetImageType(image,TrueColorAlphaType,exception);
   11700       (void) SyncImage(image,exception);
   11701     }
   11702 
   11703   if (mng_info->write_png48)
   11704     {
   11705       mng_info->write_png_colortype = /* 2 */ 3;
   11706       mng_info->write_png_depth = 16;
   11707       image->depth = 16;
   11708 
   11709       if (image->alpha_trait != UndefinedPixelTrait)
   11710         (void) SetImageType(image,TrueColorAlphaType,exception);
   11711 
   11712       else
   11713         (void) SetImageType(image,TrueColorType,exception);
   11714 
   11715       (void) SyncImage(image,exception);
   11716     }
   11717 
   11718   if (mng_info->write_png64)
   11719     {
   11720       mng_info->write_png_colortype = /* 6 */  7;
   11721       mng_info->write_png_depth = 16;
   11722       image->depth = 16;
   11723       image->alpha_trait = BlendPixelTrait;
   11724 
   11725       (void) SetImageType(image,TrueColorAlphaType,exception);
   11726       (void) SyncImage(image,exception);
   11727     }
   11728 
   11729   value=GetImageOption(image_info,"png:bit-depth");
   11730 
   11731   if (value != (char *) NULL)
   11732     {
   11733       if (LocaleCompare(value,"1") == 0)
   11734         mng_info->write_png_depth = 1;
   11735 
   11736       else if (LocaleCompare(value,"2") == 0)
   11737         mng_info->write_png_depth = 2;
   11738 
   11739       else if (LocaleCompare(value,"4") == 0)
   11740         mng_info->write_png_depth = 4;
   11741 
   11742       else if (LocaleCompare(value,"8") == 0)
   11743         mng_info->write_png_depth = 8;
   11744 
   11745       else if (LocaleCompare(value,"16") == 0)
   11746         mng_info->write_png_depth = 16;
   11747 
   11748       else
   11749         (void) ThrowMagickException(exception,
   11750              GetMagickModule(),CoderWarning,
   11751              "ignoring invalid defined png:bit-depth",
   11752              "=%s",value);
   11753 
   11754       if (logging != MagickFalse)
   11755         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11756           "  png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
   11757     }
   11758 
   11759   value=GetImageOption(image_info,"png:color-type");
   11760 
   11761   if (value != (char *) NULL)
   11762     {
   11763       /* We must store colortype+1 because 0 is a valid colortype */
   11764       if (LocaleCompare(value,"0") == 0)
   11765         mng_info->write_png_colortype = 1;
   11766 
   11767       else if (LocaleCompare(value,"1") == 0)
   11768         mng_info->write_png_colortype = 2;
   11769 
   11770       else if (LocaleCompare(value,"2") == 0)
   11771         mng_info->write_png_colortype = 3;
   11772 
   11773       else if (LocaleCompare(value,"3") == 0)
   11774         mng_info->write_png_colortype = 4;
   11775 
   11776       else if (LocaleCompare(value,"4") == 0)
   11777         mng_info->write_png_colortype = 5;
   11778 
   11779       else if (LocaleCompare(value,"6") == 0)
   11780         mng_info->write_png_colortype = 7;
   11781 
   11782       else
   11783         (void) ThrowMagickException(exception,
   11784              GetMagickModule(),CoderWarning,
   11785              "ignoring invalid defined png:color-type",
   11786              "=%s",value);
   11787 
   11788       if (logging != MagickFalse)
   11789         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   11790           "  png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
   11791     }
   11792 
   11793   /* Check for chunks to be excluded:
   11794    *
   11795    * The default is to not exclude any known chunks except for any
   11796    * listed in the "unused_chunks" array, above.
   11797    *
   11798    * Chunks can be listed for exclusion via a "png:exclude-chunk"
   11799    * define (in the image properties or in the image artifacts)
   11800    * or via a mng_info member.  For convenience, in addition
   11801    * to or instead of a comma-separated list of chunks, the
   11802    * "exclude-chunk" string can be simply "all" or "none".
   11803    *
   11804    * The exclude-chunk define takes priority over the mng_info.
   11805    *
   11806    * A "png:include-chunk" define takes  priority over both the
   11807    * mng_info and the "png:exclude-chunk" define.  Like the
   11808    * "exclude-chunk" string, it can define "all" or "none" as
   11809    * well as a comma-separated list.  Chunks that are unknown to
   11810    * ImageMagick are always excluded, regardless of their "copy-safe"
   11811    * status according to the PNG specification, and even if they
   11812    * appear in the "include-chunk" list. Such defines appearing among
   11813    * the image options take priority over those found among the image
   11814    * artifacts.
   11815    *
   11816    * Finally, all chunks listed in the "unused_chunks" array are
   11817    * automatically excluded, regardless of the other instructions
   11818    * or lack thereof.
   11819    *
   11820    * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
   11821    * will not be written and the gAMA chunk will only be written if it
   11822    * is not between .45 and .46, or approximately (1.0/2.2).
   11823    *
   11824    * If you exclude tRNS and the image has transparency, the colortype
   11825    * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
   11826    *
   11827    * The -strip option causes StripImage() to set the png:include-chunk
   11828    * artifact to "none,trns,gama".
   11829    */
   11830 
   11831   mng_info->ping_exclude_bKGD=MagickFalse;
   11832   mng_info->ping_exclude_cHRM=MagickFalse;
   11833   mng_info->ping_exclude_date=MagickFalse;
   11834   mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
   11835   mng_info->ping_exclude_gAMA=MagickFalse;
   11836   mng_info->ping_exclude_iCCP=MagickFalse;
   11837   /* mng_info->ping_exclude_iTXt=MagickFalse; */
   11838   mng_info->ping_exclude_oFFs=MagickFalse;
   11839   mng_info->ping_exclude_pHYs=MagickFalse;
   11840   mng_info->ping_exclude_sRGB=MagickFalse;
   11841   mng_info->ping_exclude_tEXt=MagickFalse;
   11842   mng_info->ping_exclude_tIME=MagickFalse;
   11843   mng_info->ping_exclude_tRNS=MagickFalse;
   11844   mng_info->ping_exclude_vpAg=MagickFalse;
   11845   mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
   11846   mng_info->ping_exclude_zTXt=MagickFalse;
   11847 
   11848   mng_info->ping_preserve_colormap=MagickFalse;
   11849 
   11850   value=GetImageOption(image_info,"png:preserve-colormap");
   11851   if (value == NULL)
   11852      value=GetImageArtifact(image,"png:preserve-colormap");
   11853   if (value != NULL)
   11854      mng_info->ping_preserve_colormap=MagickTrue;
   11855 
   11856   mng_info->ping_preserve_iCCP=MagickFalse;
   11857 
   11858   value=GetImageOption(image_info,"png:preserve-iCCP");
   11859   if (value == NULL)
   11860      value=GetImageArtifact(image,"png:preserve-iCCP");
   11861   if (value != NULL)
   11862      mng_info->ping_preserve_iCCP=MagickTrue;
   11863 
   11864   /* These compression-level, compression-strategy, and compression-filter
   11865    * defines take precedence over values from the -quality option.
   11866    */
   11867   value=GetImageOption(image_info,"png:compression-level");
   11868   if (value == NULL)
   11869      value=GetImageArtifact(image,"png:compression-level");
   11870   if (value != NULL)
   11871   {
   11872       /* We have to add 1 to everything because 0 is a valid input,
   11873        * and we want to use 0 (the default) to mean undefined.
   11874        */
   11875       if (LocaleCompare(value,"0") == 0)
   11876         mng_info->write_png_compression_level = 1;
   11877 
   11878       else if (LocaleCompare(value,"1") == 0)
   11879         mng_info->write_png_compression_level = 2;
   11880 
   11881       else if (LocaleCompare(value,"2") == 0)
   11882         mng_info->write_png_compression_level = 3;
   11883 
   11884       else if (LocaleCompare(value,"3") == 0)
   11885         mng_info->write_png_compression_level = 4;
   11886 
   11887       else if (LocaleCompare(value,"4") == 0)
   11888         mng_info->write_png_compression_level = 5;
   11889 
   11890       else if (LocaleCompare(value,"5") == 0)
   11891         mng_info->write_png_compression_level = 6;
   11892 
   11893       else if (LocaleCompare(value,"6") == 0)
   11894         mng_info->write_png_compression_level = 7;
   11895 
   11896       else if (LocaleCompare(value,"7") == 0)
   11897         mng_info->write_png_compression_level = 8;
   11898 
   11899       else if (LocaleCompare(value,"8") == 0)
   11900         mng_info->write_png_compression_level = 9;
   11901 
   11902       else if (LocaleCompare(value,"9") == 0)
   11903         mng_info->write_png_compression_level = 10;
   11904 
   11905       else
   11906         (void) ThrowMagickException(exception,
   11907              GetMagickModule(),CoderWarning,
   11908              "ignoring invalid defined png:compression-level",
   11909              "=%s",value);
   11910     }
   11911 
   11912   value=GetImageOption(image_info,"png:compression-strategy");
   11913   if (value == NULL)
   11914      value=GetImageArtifact(image,"png:compression-strategy");
   11915   if (value != NULL)
   11916   {
   11917       if (LocaleCompare(value,"0") == 0)
   11918         mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
   11919 
   11920       else if (LocaleCompare(value,"1") == 0)
   11921         mng_info->write_png_compression_strategy = Z_FILTERED+1;
   11922 
   11923       else if (LocaleCompare(value,"2") == 0)
   11924         mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
   11925 
   11926       else if (LocaleCompare(value,"3") == 0)
   11927 #ifdef Z_RLE  /* Z_RLE was added to zlib-1.2.0 */
   11928         mng_info->write_png_compression_strategy = Z_RLE+1;
   11929 #else
   11930         mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
   11931 #endif
   11932 
   11933       else if (LocaleCompare(value,"4") == 0)
   11934 #ifdef Z_FIXED  /* Z_FIXED was added to zlib-1.2.2.2 */
   11935         mng_info->write_png_compression_strategy = Z_FIXED+1;
   11936 #else
   11937         mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
   11938 #endif
   11939 
   11940       else
   11941         (void) ThrowMagickException(exception,
   11942              GetMagickModule(),CoderWarning,
   11943              "ignoring invalid defined png:compression-strategy",
   11944              "=%s",value);
   11945     }
   11946 
   11947   value=GetImageOption(image_info,"png:compression-filter");
   11948   if (value == NULL)
   11949      value=GetImageArtifact(image,"png:compression-filter");
   11950   if (value != NULL)
   11951   {
   11952       /* To do: combinations of filters allowed by libpng
   11953        * masks 0x08 through 0xf8
   11954        *
   11955        * Implement this as a comma-separated list of 0,1,2,3,4,5
   11956        * where 5 is a special case meaning PNG_ALL_FILTERS.
   11957        */
   11958 
   11959       if (LocaleCompare(value,"0") == 0)
   11960         mng_info->write_png_compression_filter = 1;
   11961 
   11962       else if (LocaleCompare(value,"1") == 0)
   11963         mng_info->write_png_compression_filter = 2;
   11964 
   11965       else if (LocaleCompare(value,"2") == 0)
   11966         mng_info->write_png_compression_filter = 3;
   11967 
   11968       else if (LocaleCompare(value,"3") == 0)
   11969         mng_info->write_png_compression_filter = 4;
   11970 
   11971       else if (LocaleCompare(value,"4") == 0)
   11972         mng_info->write_png_compression_filter = 5;
   11973 
   11974       else if (LocaleCompare(value,"5") == 0)
   11975         mng_info->write_png_compression_filter = 6;
   11976 
   11977       else
   11978         (void) ThrowMagickException(exception,
   11979              GetMagickModule(),CoderWarning,
   11980              "ignoring invalid defined png:compression-filter",
   11981              "=%s",value);
   11982   }
   11983 
   11984   for (source=0; source<8; source++)
   11985   {
   11986     value = NULL;
   11987 
   11988     if (source == 0)
   11989       value=GetImageOption(image_info,"png:exclude-chunks");
   11990 
   11991     if (source == 1)
   11992       value=GetImageArtifact(image,"png:exclude-chunks");
   11993 
   11994     if (source == 2)
   11995       value=GetImageOption(image_info,"png:exclude-chunk");
   11996 
   11997     if (source == 3)
   11998       value=GetImageArtifact(image,"png:exclude-chunk");
   11999 
   12000     if (source == 4)
   12001       value=GetImageOption(image_info,"png:include-chunks");
   12002 
   12003     if (source == 5)
   12004       value=GetImageArtifact(image,"png:include-chunks");
   12005 
   12006     if (source == 6)
   12007       value=GetImageOption(image_info,"png:include-chunk");
   12008 
   12009     if (source == 7)
   12010       value=GetImageArtifact(image,"png:include-chunk");
   12011 
   12012     if (value == NULL)
   12013        continue;
   12014 
   12015     if (source < 4)
   12016       excluding = MagickTrue;
   12017     else
   12018       excluding = MagickFalse;
   12019 
   12020     if (logging != MagickFalse)
   12021       {
   12022         if (source == 0 || source == 2)
   12023            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12024               "  png:exclude-chunk=%s found in image options.\n", value);
   12025         else if (source == 1 || source == 3)
   12026            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12027               "  png:exclude-chunk=%s found in image artifacts.\n", value);
   12028         else if (source == 4 || source == 6)
   12029            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12030               "  png:include-chunk=%s found in image options.\n", value);
   12031         else /* if (source == 5 || source == 7) */
   12032            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12033               "  png:include-chunk=%s found in image artifacts.\n", value);
   12034       }
   12035 
   12036     if (IsOptionMember("all",value) != MagickFalse)
   12037       {
   12038         mng_info->ping_exclude_bKGD=excluding;
   12039         mng_info->ping_exclude_cHRM=excluding;
   12040         mng_info->ping_exclude_date=excluding;
   12041         mng_info->ping_exclude_EXIF=excluding;
   12042         mng_info->ping_exclude_gAMA=excluding;
   12043         mng_info->ping_exclude_iCCP=excluding;
   12044         /* mng_info->ping_exclude_iTXt=excluding; */
   12045         mng_info->ping_exclude_oFFs=excluding;
   12046         mng_info->ping_exclude_pHYs=excluding;
   12047         mng_info->ping_exclude_sRGB=excluding;
   12048         mng_info->ping_exclude_tEXt=excluding;
   12049         mng_info->ping_exclude_tIME=excluding;
   12050         mng_info->ping_exclude_tRNS=excluding;
   12051         mng_info->ping_exclude_vpAg=excluding;
   12052         mng_info->ping_exclude_zCCP=excluding;
   12053         mng_info->ping_exclude_zTXt=excluding;
   12054       }
   12055 
   12056     if (IsOptionMember("none",value) != MagickFalse)
   12057       {
   12058         mng_info->ping_exclude_bKGD=excluding != MagickFalse ? MagickFalse :
   12059           MagickTrue;
   12060         mng_info->ping_exclude_cHRM=excluding != MagickFalse ? MagickFalse :
   12061           MagickTrue;
   12062         mng_info->ping_exclude_date=excluding != MagickFalse ? MagickFalse :
   12063           MagickTrue;
   12064         mng_info->ping_exclude_EXIF=excluding != MagickFalse ? MagickFalse :
   12065           MagickTrue;
   12066         mng_info->ping_exclude_gAMA=excluding != MagickFalse ? MagickFalse :
   12067           MagickTrue;
   12068         mng_info->ping_exclude_iCCP=excluding != MagickFalse ? MagickFalse :
   12069           MagickTrue;
   12070         /* mng_info->ping_exclude_iTXt=!excluding; */
   12071         mng_info->ping_exclude_oFFs=excluding != MagickFalse ? MagickFalse :
   12072           MagickTrue;
   12073         mng_info->ping_exclude_pHYs=excluding != MagickFalse ? MagickFalse :
   12074           MagickTrue;
   12075         mng_info->ping_exclude_sRGB=excluding != MagickFalse ? MagickFalse :
   12076           MagickTrue;
   12077         mng_info->ping_exclude_tEXt=excluding != MagickFalse ? MagickFalse :
   12078           MagickTrue;
   12079         mng_info->ping_exclude_tIME=excluding != MagickFalse ? MagickFalse :
   12080           MagickTrue;
   12081         mng_info->ping_exclude_tRNS=excluding != MagickFalse ? MagickFalse :
   12082           MagickTrue;
   12083         mng_info->ping_exclude_vpAg=excluding != MagickFalse ? MagickFalse :
   12084           MagickTrue;
   12085         mng_info->ping_exclude_zCCP=excluding != MagickFalse ? MagickFalse :
   12086           MagickTrue;
   12087         mng_info->ping_exclude_zTXt=excluding != MagickFalse ? MagickFalse :
   12088           MagickTrue;
   12089       }
   12090 
   12091     if (IsOptionMember("bkgd",value) != MagickFalse)
   12092       mng_info->ping_exclude_bKGD=excluding;
   12093 
   12094     if (IsOptionMember("chrm",value) != MagickFalse)
   12095       mng_info->ping_exclude_cHRM=excluding;
   12096 
   12097     if (IsOptionMember("date",value) != MagickFalse)
   12098       mng_info->ping_exclude_date=excluding;
   12099 
   12100     if (IsOptionMember("exif",value) != MagickFalse)
   12101       mng_info->ping_exclude_EXIF=excluding;
   12102 
   12103     if (IsOptionMember("gama",value) != MagickFalse)
   12104       mng_info->ping_exclude_gAMA=excluding;
   12105 
   12106     if (IsOptionMember("iccp",value) != MagickFalse)
   12107       mng_info->ping_exclude_iCCP=excluding;
   12108 
   12109 #if 0
   12110     if (IsOptionMember("itxt",value) != MagickFalse)
   12111       mng_info->ping_exclude_iTXt=excluding;
   12112 #endif
   12113 
   12114     if (IsOptionMember("offs",value) != MagickFalse)
   12115       mng_info->ping_exclude_oFFs=excluding;
   12116 
   12117     if (IsOptionMember("phys",value) != MagickFalse)
   12118       mng_info->ping_exclude_pHYs=excluding;
   12119 
   12120     if (IsOptionMember("srgb",value) != MagickFalse)
   12121       mng_info->ping_exclude_sRGB=excluding;
   12122 
   12123     if (IsOptionMember("text",value) != MagickFalse)
   12124       mng_info->ping_exclude_tEXt=excluding;
   12125 
   12126     if (IsOptionMember("time",value) != MagickFalse)
   12127       mng_info->ping_exclude_tIME=excluding;
   12128 
   12129     if (IsOptionMember("trns",value) != MagickFalse)
   12130       mng_info->ping_exclude_tRNS=excluding;
   12131 
   12132     if (IsOptionMember("vpag",value) != MagickFalse)
   12133       mng_info->ping_exclude_vpAg=excluding;
   12134 
   12135     if (IsOptionMember("zccp",value) != MagickFalse)
   12136       mng_info->ping_exclude_zCCP=excluding;
   12137 
   12138     if (IsOptionMember("ztxt",value) != MagickFalse)
   12139       mng_info->ping_exclude_zTXt=excluding;
   12140   }
   12141 
   12142   if (logging != MagickFalse)
   12143   {
   12144     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12145       "  Chunks to be excluded from the output png:");
   12146     if (mng_info->ping_exclude_bKGD != MagickFalse)
   12147       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12148           "    bKGD");
   12149     if (mng_info->ping_exclude_cHRM != MagickFalse)
   12150       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12151           "    cHRM");
   12152     if (mng_info->ping_exclude_date != MagickFalse)
   12153       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12154           "    date");
   12155     if (mng_info->ping_exclude_EXIF != MagickFalse)
   12156       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12157           "    EXIF");
   12158     if (mng_info->ping_exclude_gAMA != MagickFalse)
   12159       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12160           "    gAMA");
   12161     if (mng_info->ping_exclude_iCCP != MagickFalse)
   12162       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12163           "    iCCP");
   12164 #if 0
   12165     if (mng_info->ping_exclude_iTXt != MagickFalse)
   12166       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12167           "    iTXt");
   12168 #endif
   12169 
   12170     if (mng_info->ping_exclude_oFFs != MagickFalse)
   12171       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12172           "    oFFs");
   12173     if (mng_info->ping_exclude_pHYs != MagickFalse)
   12174       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12175           "    pHYs");
   12176     if (mng_info->ping_exclude_sRGB != MagickFalse)
   12177       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12178           "    sRGB");
   12179     if (mng_info->ping_exclude_tEXt != MagickFalse)
   12180       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12181           "    tEXt");
   12182     if (mng_info->ping_exclude_tIME != MagickFalse)
   12183       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12184           "    tIME");
   12185     if (mng_info->ping_exclude_tRNS != MagickFalse)
   12186       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12187           "    tRNS");
   12188     if (mng_info->ping_exclude_vpAg != MagickFalse)
   12189       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12190           "    vpAg");
   12191     if (mng_info->ping_exclude_zCCP != MagickFalse)
   12192       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12193           "    zCCP");
   12194     if (mng_info->ping_exclude_zTXt != MagickFalse)
   12195       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12196           "    zTXt");
   12197   }
   12198 
   12199   mng_info->need_blob = MagickTrue;
   12200 
   12201   status=WriteOnePNGImage(mng_info,image_info,image,exception);
   12202 
   12203   MngInfoFreeStruct(mng_info,&have_mng_structure);
   12204 
   12205   if (logging != MagickFalse)
   12206     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
   12207 
   12208   return(status);
   12209 }
   12210 
   12211 #if defined(JNG_SUPPORTED)
   12212 
   12213 /* Write one JNG image */
   12214 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
   12215    const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
   12216 {
   12217   Image
   12218     *jpeg_image;
   12219 
   12220   ImageInfo
   12221     *jpeg_image_info;
   12222 
   12223   MagickBooleanType
   12224     logging,
   12225     status;
   12226 
   12227   size_t
   12228     length;
   12229 
   12230   unsigned char
   12231     *blob,
   12232     chunk[80],
   12233     *p;
   12234 
   12235   unsigned int
   12236     jng_alpha_compression_method,
   12237     jng_alpha_sample_depth,
   12238     jng_color_type,
   12239     transparent;
   12240 
   12241   size_t
   12242     jng_alpha_quality,
   12243     jng_quality;
   12244 
   12245   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
   12246     "  Enter WriteOneJNGImage()");
   12247 
   12248   blob=(unsigned char *) NULL;
   12249   jpeg_image=(Image *) NULL;
   12250   jpeg_image_info=(ImageInfo *) NULL;
   12251   length=0;
   12252 
   12253   status=MagickTrue;
   12254   transparent=image_info->type==GrayscaleAlphaType ||
   12255      image_info->type==TrueColorAlphaType ||
   12256      image->alpha_trait != UndefinedPixelTrait;
   12257 
   12258   jng_alpha_sample_depth = 0;
   12259 
   12260   jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
   12261 
   12262   jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
   12263 
   12264   jng_alpha_quality=image_info->quality == 0UL ? 75UL :
   12265       image_info->quality;
   12266 
   12267   if (jng_alpha_quality >= 1000)
   12268     jng_alpha_quality /= 1000;
   12269 
   12270   length=0;
   12271 
   12272   if (transparent != 0)
   12273     {
   12274       jng_color_type=14;
   12275 
   12276       /* Create JPEG blob, image, and image_info */
   12277       if (logging != MagickFalse)
   12278         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12279           "  Creating jpeg_image_info for alpha.");
   12280 
   12281       jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
   12282 
   12283       if (jpeg_image_info == (ImageInfo *) NULL)
   12284         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12285 
   12286       if (logging != MagickFalse)
   12287         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12288           "  Creating jpeg_image.");
   12289 
   12290       jpeg_image=SeparateImage(image,AlphaChannel,exception);
   12291       if (jpeg_image == (Image *) NULL)
   12292         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12293       (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
   12294       jpeg_image->alpha_trait=UndefinedPixelTrait;
   12295       jpeg_image->quality=jng_alpha_quality;
   12296       jpeg_image_info->type=GrayscaleType;
   12297       (void) SetImageType(jpeg_image,GrayscaleType,exception);
   12298       (void) AcquireUniqueFilename(jpeg_image->filename);
   12299       (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,
   12300         "%s",jpeg_image->filename);
   12301     }
   12302   else
   12303     {
   12304       jng_alpha_compression_method=0;
   12305       jng_color_type=10;
   12306       jng_alpha_sample_depth=0;
   12307     }
   12308 
   12309   /* To do: check bit depth of PNG alpha channel */
   12310 
   12311   /* Check if image is grayscale. */
   12312   if (image_info->type != TrueColorAlphaType && image_info->type !=
   12313     TrueColorType && SetImageGray(image,exception))
   12314     jng_color_type-=2;
   12315 
   12316   if (logging != MagickFalse)
   12317     {
   12318         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12319           "    JNG Quality           = %d",(int) jng_quality);
   12320         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12321           "    JNG Color Type        = %d",jng_color_type);
   12322         if (transparent != 0)
   12323           {
   12324             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12325               "    JNG Alpha Compression = %d",jng_alpha_compression_method);
   12326             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12327               "    JNG Alpha Depth       = %d",jng_alpha_sample_depth);
   12328             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12329               "    JNG Alpha Quality     = %d",(int) jng_alpha_quality);
   12330           }
   12331     }
   12332 
   12333   if (transparent != 0)
   12334     {
   12335       if (jng_alpha_compression_method==0)
   12336         {
   12337           const char
   12338             *value;
   12339 
   12340           /* Encode alpha as a grayscale PNG blob */
   12341           status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
   12342             exception);
   12343           if (status == MagickFalse)
   12344             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12345 
   12346           if (logging != MagickFalse)
   12347             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12348               "  Creating PNG blob.");
   12349 
   12350           (void) CopyMagickString(jpeg_image_info->magick,"PNG",MagickPathExtent);
   12351           (void) CopyMagickString(jpeg_image->magick,"PNG",MagickPathExtent);
   12352           jpeg_image_info->interlace=NoInterlace;
   12353 
   12354           /* Exclude all ancillary chunks */
   12355           (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
   12356 
   12357           blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,
   12358             &length,exception);
   12359 
   12360           /* Retrieve sample depth used */
   12361           value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
   12362           if (value != (char *) NULL)
   12363             jng_alpha_sample_depth= (unsigned int) value[0];
   12364         }
   12365       else
   12366         {
   12367           /* Encode alpha as a grayscale JPEG blob */
   12368 
   12369           status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
   12370             exception);
   12371           if (status == MagickFalse)
   12372             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12373 
   12374 
   12375           (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent);
   12376           (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
   12377           jpeg_image_info->interlace=NoInterlace;
   12378           if (logging != MagickFalse)
   12379             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12380               "  Creating blob.");
   12381           blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
   12382            exception);
   12383           jng_alpha_sample_depth=8;
   12384 
   12385           if (logging != MagickFalse)
   12386             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12387               "  Successfully read jpeg_image into a blob, length=%.20g.",
   12388               (double) length);
   12389 
   12390         }
   12391       /* Destroy JPEG image and image_info */
   12392       jpeg_image=DestroyImage(jpeg_image);
   12393       (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
   12394       jpeg_image_info=DestroyImageInfo(jpeg_image_info);
   12395     }
   12396 
   12397   /* Write JHDR chunk */
   12398   (void) WriteBlobMSBULong(image,16L);  /* chunk data length=16 */
   12399   PNGType(chunk,mng_JHDR);
   12400   LogPNGChunk(logging,mng_JHDR,16L);
   12401   PNGLong(chunk+4,(png_uint_32) image->columns);
   12402   PNGLong(chunk+8,(png_uint_32) image->rows);
   12403   chunk[12]=jng_color_type;
   12404   chunk[13]=8;  /* sample depth */
   12405   chunk[14]=8; /*jng_image_compression_method */
   12406   chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
   12407   chunk[16]=jng_alpha_sample_depth;
   12408   chunk[17]=jng_alpha_compression_method;
   12409   chunk[18]=0; /*jng_alpha_filter_method */
   12410   chunk[19]=0; /*jng_alpha_interlace_method */
   12411   (void) WriteBlob(image,20,chunk);
   12412   (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
   12413   if (logging != MagickFalse)
   12414     {
   12415       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12416         "    JNG width:%15lu",(unsigned long) image->columns);
   12417 
   12418       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12419         "    JNG height:%14lu",(unsigned long) image->rows);
   12420 
   12421       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12422         "    JNG color type:%10d",jng_color_type);
   12423 
   12424       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12425         "    JNG sample depth:%8d",8);
   12426 
   12427       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12428         "    JNG compression:%9d",8);
   12429 
   12430       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12431         "    JNG interlace:%11d",0);
   12432 
   12433       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12434         "    JNG alpha depth:%9d",jng_alpha_sample_depth);
   12435 
   12436       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12437         "    JNG alpha compression:%3d",jng_alpha_compression_method);
   12438 
   12439       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12440         "    JNG alpha filter:%8d",0);
   12441 
   12442       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12443         "    JNG alpha interlace:%5d",0);
   12444     }
   12445 
   12446   /* Write any JNG-chunk-b profiles */
   12447   (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
   12448 
   12449   /*
   12450      Write leading ancillary chunks
   12451   */
   12452 
   12453   if (transparent != 0)
   12454   {
   12455     /*
   12456       Write JNG bKGD chunk
   12457     */
   12458 
   12459     unsigned char
   12460       blue,
   12461       green,
   12462       red;
   12463 
   12464     ssize_t
   12465       num_bytes;
   12466 
   12467     if (jng_color_type == 8 || jng_color_type == 12)
   12468       num_bytes=6L;
   12469     else
   12470       num_bytes=10L;
   12471     (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
   12472     PNGType(chunk,mng_bKGD);
   12473     LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
   12474     red=ScaleQuantumToChar(image->background_color.red);
   12475     green=ScaleQuantumToChar(image->background_color.green);
   12476     blue=ScaleQuantumToChar(image->background_color.blue);
   12477     *(chunk+4)=0;
   12478     *(chunk+5)=red;
   12479     *(chunk+6)=0;
   12480     *(chunk+7)=green;
   12481     *(chunk+8)=0;
   12482     *(chunk+9)=blue;
   12483     (void) WriteBlob(image,(size_t) num_bytes,chunk);
   12484     (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
   12485   }
   12486 
   12487   if ((image->colorspace == sRGBColorspace || image->rendering_intent))
   12488     {
   12489       /*
   12490         Write JNG sRGB chunk
   12491       */
   12492       (void) WriteBlobMSBULong(image,1L);
   12493       PNGType(chunk,mng_sRGB);
   12494       LogPNGChunk(logging,mng_sRGB,1L);
   12495 
   12496       if (image->rendering_intent != UndefinedIntent)
   12497         chunk[4]=(unsigned char)
   12498           Magick_RenderingIntent_to_PNG_RenderingIntent(
   12499           (image->rendering_intent));
   12500 
   12501       else
   12502         chunk[4]=(unsigned char)
   12503           Magick_RenderingIntent_to_PNG_RenderingIntent(
   12504           (PerceptualIntent));
   12505 
   12506       (void) WriteBlob(image,5,chunk);
   12507       (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
   12508     }
   12509   else
   12510     {
   12511       if (image->gamma != 0.0)
   12512         {
   12513           /*
   12514              Write JNG gAMA chunk
   12515           */
   12516           (void) WriteBlobMSBULong(image,4L);
   12517           PNGType(chunk,mng_gAMA);
   12518           LogPNGChunk(logging,mng_gAMA,4L);
   12519           PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
   12520           (void) WriteBlob(image,8,chunk);
   12521           (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
   12522         }
   12523 
   12524       if ((mng_info->equal_chrms == MagickFalse) &&
   12525           (image->chromaticity.red_primary.x != 0.0))
   12526         {
   12527           PrimaryInfo
   12528             primary;
   12529 
   12530           /*
   12531              Write JNG cHRM chunk
   12532           */
   12533           (void) WriteBlobMSBULong(image,32L);
   12534           PNGType(chunk,mng_cHRM);
   12535           LogPNGChunk(logging,mng_cHRM,32L);
   12536           primary=image->chromaticity.white_point;
   12537           PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
   12538           PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
   12539           primary=image->chromaticity.red_primary;
   12540           PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
   12541           PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
   12542           primary=image->chromaticity.green_primary;
   12543           PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
   12544           PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
   12545           primary=image->chromaticity.blue_primary;
   12546           PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
   12547           PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
   12548           (void) WriteBlob(image,36,chunk);
   12549           (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
   12550         }
   12551     }
   12552 
   12553   if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
   12554     {
   12555       /*
   12556          Write JNG pHYs chunk
   12557       */
   12558       (void) WriteBlobMSBULong(image,9L);
   12559       PNGType(chunk,mng_pHYs);
   12560       LogPNGChunk(logging,mng_pHYs,9L);
   12561       if (image->units == PixelsPerInchResolution)
   12562         {
   12563           PNGLong(chunk+4,(png_uint_32)
   12564             (image->resolution.x*100.0/2.54+0.5));
   12565 
   12566           PNGLong(chunk+8,(png_uint_32)
   12567             (image->resolution.y*100.0/2.54+0.5));
   12568 
   12569           chunk[12]=1;
   12570         }
   12571 
   12572       else
   12573         {
   12574           if (image->units == PixelsPerCentimeterResolution)
   12575             {
   12576               PNGLong(chunk+4,(png_uint_32)
   12577                 (image->resolution.x*100.0+0.5));
   12578 
   12579               PNGLong(chunk+8,(png_uint_32)
   12580                 (image->resolution.y*100.0+0.5));
   12581 
   12582               chunk[12]=1;
   12583             }
   12584 
   12585           else
   12586             {
   12587               PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
   12588               PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
   12589               chunk[12]=0;
   12590             }
   12591         }
   12592       (void) WriteBlob(image,13,chunk);
   12593       (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
   12594     }
   12595 
   12596   if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
   12597     {
   12598       /*
   12599          Write JNG oFFs chunk
   12600       */
   12601       (void) WriteBlobMSBULong(image,9L);
   12602       PNGType(chunk,mng_oFFs);
   12603       LogPNGChunk(logging,mng_oFFs,9L);
   12604       PNGsLong(chunk+4,(ssize_t) (image->page.x));
   12605       PNGsLong(chunk+8,(ssize_t) (image->page.y));
   12606       chunk[12]=0;
   12607       (void) WriteBlob(image,13,chunk);
   12608       (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
   12609     }
   12610   if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
   12611     {
   12612        (void) WriteBlobMSBULong(image,9L);  /* data length=8 */
   12613        PNGType(chunk,mng_vpAg);
   12614        LogPNGChunk(logging,mng_vpAg,9L);
   12615        PNGLong(chunk+4,(png_uint_32) image->page.width);
   12616        PNGLong(chunk+8,(png_uint_32) image->page.height);
   12617        chunk[12]=0;   /* unit = pixels */
   12618        (void) WriteBlob(image,13,chunk);
   12619        (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
   12620     }
   12621 
   12622   if (transparent != 0)
   12623     {
   12624       if (jng_alpha_compression_method==0)
   12625         {
   12626           register ssize_t
   12627             i;
   12628 
   12629           size_t
   12630             len;
   12631 
   12632           /* Write IDAT chunk header */
   12633           if (logging != MagickFalse)
   12634             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12635               "  Write IDAT chunks from blob, length=%.20g.",(double)
   12636               length);
   12637 
   12638           /* Copy IDAT chunks */
   12639           len=0;
   12640           p=blob+8;
   12641           for (i=8; i<(ssize_t) length; i+=len+12)
   12642           {
   12643             len=(size_t) (*p) << 24;
   12644             len|=(size_t) (*(p+1)) << 16;
   12645             len|=(size_t) (*(p+2)) << 8;
   12646             len|=(size_t) (*(p+3));
   12647             p+=4;
   12648 
   12649             if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
   12650               {
   12651                 /* Found an IDAT chunk. */
   12652                 (void) WriteBlobMSBULong(image,len);
   12653                 LogPNGChunk(logging,mng_IDAT,len);
   12654                 (void) WriteBlob(image,len+4,p);
   12655                 (void) WriteBlobMSBULong(image, crc32(0,p,(uInt) len+4));
   12656               }
   12657 
   12658             else
   12659               {
   12660                 if (logging != MagickFalse)
   12661                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12662                     "    Skipping %c%c%c%c chunk, length=%.20g.",
   12663                     *(p),*(p+1),*(p+2),*(p+3),(double) len);
   12664               }
   12665             p+=(8+len);
   12666           }
   12667         }
   12668       else if (length != 0)
   12669         {
   12670           /* Write JDAA chunk header */
   12671           if (logging != MagickFalse)
   12672             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12673               "  Write JDAA chunk, length=%.20g.",(double) length);
   12674           (void) WriteBlobMSBULong(image,(size_t) length);
   12675           PNGType(chunk,mng_JDAA);
   12676           LogPNGChunk(logging,mng_JDAA,length);
   12677           /* Write JDAT chunk(s) data */
   12678           (void) WriteBlob(image,4,chunk);
   12679           (void) WriteBlob(image,length,blob);
   12680           (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
   12681              (uInt) length));
   12682         }
   12683       blob=(unsigned char *) RelinquishMagickMemory(blob);
   12684     }
   12685 
   12686   /* Encode image as a JPEG blob */
   12687   if (logging != MagickFalse)
   12688     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12689       "  Creating jpeg_image_info.");
   12690   jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
   12691   if (jpeg_image_info == (ImageInfo *) NULL)
   12692     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12693 
   12694   if (logging != MagickFalse)
   12695     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12696       "  Creating jpeg_image.");
   12697 
   12698   jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
   12699   if (jpeg_image == (Image *) NULL)
   12700     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12701   (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
   12702 
   12703   (void) AcquireUniqueFilename(jpeg_image->filename);
   12704   (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,"%s",
   12705     jpeg_image->filename);
   12706 
   12707   status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
   12708     exception);
   12709 
   12710   if (logging != MagickFalse)
   12711     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12712       "  Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
   12713       (double) jpeg_image->rows);
   12714 
   12715   if (status == MagickFalse)
   12716     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12717 
   12718   if (jng_color_type == 8 || jng_color_type == 12)
   12719     jpeg_image_info->type=GrayscaleType;
   12720 
   12721   jpeg_image_info->quality=jng_quality;
   12722   jpeg_image->quality=jng_quality;
   12723   (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent);
   12724   (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent);
   12725 
   12726   if (logging != MagickFalse)
   12727     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12728       "  Creating blob.");
   12729 
   12730   blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length,
   12731     exception);
   12732 
   12733   if (logging != MagickFalse)
   12734     {
   12735       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12736         "  Successfully read jpeg_image into a blob, length=%.20g.",
   12737         (double) length);
   12738 
   12739       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12740         "  Write JDAT chunk, length=%.20g.",(double) length);
   12741     }
   12742 
   12743   /* Write JDAT chunk(s) */
   12744   (void) WriteBlobMSBULong(image,(size_t) length);
   12745   PNGType(chunk,mng_JDAT);
   12746   LogPNGChunk(logging,mng_JDAT,length);
   12747   (void) WriteBlob(image,4,chunk);
   12748   (void) WriteBlob(image,length,blob);
   12749   (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
   12750 
   12751   jpeg_image=DestroyImage(jpeg_image);
   12752   (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
   12753   jpeg_image_info=DestroyImageInfo(jpeg_image_info);
   12754   blob=(unsigned char *) RelinquishMagickMemory(blob);
   12755 
   12756   /* Write any JNG-chunk-e profiles */
   12757   (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
   12758 
   12759   /* Write IEND chunk */
   12760   (void) WriteBlobMSBULong(image,0L);
   12761   PNGType(chunk,mng_IEND);
   12762   LogPNGChunk(logging,mng_IEND,0);
   12763   (void) WriteBlob(image,4,chunk);
   12764   (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
   12765 
   12766   if (logging != MagickFalse)
   12767     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12768       "  exit WriteOneJNGImage()");
   12769 
   12770   return(status);
   12771 }
   12772 
   12773 
   12774 /*
   12775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   12776 %                                                                             %
   12777 %                                                                             %
   12778 %                                                                             %
   12779 %   W r i t e J N G I m a g e                                                 %
   12780 %                                                                             %
   12781 %                                                                             %
   12782 %                                                                             %
   12783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   12784 %
   12785 %  WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
   12786 %
   12787 %  JNG support written by Glenn Randers-Pehrson, glennrp (at) image...
   12788 %
   12789 %  The format of the WriteJNGImage method is:
   12790 %
   12791 %      MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
   12792 %        Image *image,ExceptionInfo *exception)
   12793 %
   12794 %  A description of each parameter follows:
   12795 %
   12796 %    o image_info: the image info.
   12797 %
   12798 %    o image:  The image.
   12799 %
   12800 %    o exception: return any errors or warnings in this structure.
   12801 %
   12802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   12803 */
   12804 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
   12805   ExceptionInfo *exception)
   12806 {
   12807   MagickBooleanType
   12808     have_mng_structure,
   12809     logging,
   12810     status;
   12811 
   12812   MngInfo
   12813     *mng_info;
   12814 
   12815   /*
   12816     Open image file.
   12817   */
   12818   assert(image_info != (const ImageInfo *) NULL);
   12819   assert(image_info->signature == MagickCoreSignature);
   12820   assert(image != (Image *) NULL);
   12821   assert(image->signature == MagickCoreSignature);
   12822   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   12823   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
   12824   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   12825   if (status == MagickFalse)
   12826     return(status);
   12827   if ((image->columns > 65535UL) || (image->rows > 65535UL))
   12828     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
   12829 
   12830   /*
   12831     Allocate a MngInfo structure.
   12832   */
   12833   have_mng_structure=MagickFalse;
   12834   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
   12835   if (mng_info == (MngInfo *) NULL)
   12836     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12837   /*
   12838     Initialize members of the MngInfo structure.
   12839   */
   12840   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   12841   mng_info->image=image;
   12842   have_mng_structure=MagickTrue;
   12843 
   12844   (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
   12845 
   12846   status=WriteOneJNGImage(mng_info,image_info,image,exception);
   12847   (void) CloseBlob(image);
   12848 
   12849   (void) CatchImageException(image);
   12850   MngInfoFreeStruct(mng_info,&have_mng_structure);
   12851   if (logging != MagickFalse)
   12852     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
   12853   return(status);
   12854 }
   12855 #endif
   12856 
   12857 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
   12858   ExceptionInfo *exception)
   12859 {
   12860   const char
   12861     *option;
   12862 
   12863   Image
   12864     *next_image;
   12865 
   12866   MagickBooleanType
   12867     have_mng_structure,
   12868     status;
   12869 
   12870   volatile MagickBooleanType
   12871     logging;
   12872 
   12873   MngInfo
   12874     *mng_info;
   12875 
   12876   int
   12877     image_count,
   12878     need_iterations,
   12879     need_matte;
   12880 
   12881   volatile int
   12882 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
   12883     defined(PNG_MNG_FEATURES_SUPPORTED)
   12884     need_local_plte,
   12885 #endif
   12886     all_images_are_gray,
   12887     need_defi,
   12888     use_global_plte;
   12889 
   12890   register ssize_t
   12891     i;
   12892 
   12893   unsigned char
   12894     chunk[800];
   12895 
   12896   volatile unsigned int
   12897     write_jng,
   12898     write_mng;
   12899 
   12900   volatile size_t
   12901     scene;
   12902 
   12903   size_t
   12904     final_delay=0,
   12905     initial_delay;
   12906 
   12907 #if (PNG_LIBPNG_VER < 10200)
   12908     if (image_info->verbose)
   12909       printf("Your PNG library (libpng-%s) is rather old.\n",
   12910          PNG_LIBPNG_VER_STRING);
   12911 #endif
   12912 
   12913   /*
   12914     Open image file.
   12915   */
   12916   assert(image_info != (const ImageInfo *) NULL);
   12917   assert(image_info->signature == MagickCoreSignature);
   12918   assert(image != (Image *) NULL);
   12919   assert(image->signature == MagickCoreSignature);
   12920   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   12921   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
   12922   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   12923   if (status == MagickFalse)
   12924     return(status);
   12925 
   12926   /*
   12927     Allocate a MngInfo structure.
   12928   */
   12929   have_mng_structure=MagickFalse;
   12930   mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
   12931   if (mng_info == (MngInfo *) NULL)
   12932     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   12933   /*
   12934     Initialize members of the MngInfo structure.
   12935   */
   12936   (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
   12937   mng_info->image=image;
   12938   have_mng_structure=MagickTrue;
   12939   write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
   12940 
   12941   /*
   12942    * See if user has requested a specific PNG subformat to be used
   12943    * for all of the PNGs in the MNG being written, e.g.,
   12944    *
   12945    *    convert *.png png8:animation.mng
   12946    *
   12947    * To do: check -define png:bit_depth and png:color_type as well,
   12948    * or perhaps use mng:bit_depth and mng:color_type instead for
   12949    * global settings.
   12950    */
   12951 
   12952   mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
   12953   mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
   12954   mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
   12955 
   12956   write_jng=MagickFalse;
   12957   if (image_info->compression == JPEGCompression)
   12958     write_jng=MagickTrue;
   12959 
   12960   mng_info->adjoin=image_info->adjoin &&
   12961     (GetNextImageInList(image) != (Image *) NULL) && write_mng;
   12962 
   12963   if (logging != MagickFalse)
   12964     {
   12965       /* Log some info about the input */
   12966       Image
   12967         *p;
   12968 
   12969       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12970         "  Checking input image(s)\n"
   12971         "    Image_info depth: %.20g,    Type: %d",
   12972         (double) image_info->depth, image_info->type);
   12973 
   12974       scene=0;
   12975       for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
   12976       {
   12977 
   12978         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12979            "    Scene: %.20g\n,   Image depth: %.20g",
   12980            (double) scene++, (double) p->depth);
   12981 
   12982         if (p->alpha_trait != UndefinedPixelTrait)
   12983           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12984             "      Matte: True");
   12985 
   12986         else
   12987           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12988             "      Matte: False");
   12989 
   12990         if (p->storage_class == PseudoClass)
   12991           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12992             "      Storage class: PseudoClass");
   12993 
   12994         else
   12995           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   12996             "      Storage class: DirectClass");
   12997 
   12998         if (p->colors)
   12999           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13000             "      Number of colors: %.20g",(double) p->colors);
   13001 
   13002         else
   13003           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13004             "      Number of colors: unspecified");
   13005 
   13006         if (mng_info->adjoin == MagickFalse)
   13007           break;
   13008       }
   13009     }
   13010 
   13011   use_global_plte=MagickFalse;
   13012   all_images_are_gray=MagickFalse;
   13013 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
   13014   need_local_plte=MagickTrue;
   13015 #endif
   13016   need_defi=MagickFalse;
   13017   need_matte=MagickFalse;
   13018   mng_info->framing_mode=1;
   13019   mng_info->old_framing_mode=1;
   13020 
   13021   if (write_mng)
   13022       if (image_info->page != (char *) NULL)
   13023         {
   13024           /*
   13025             Determine image bounding box.
   13026           */
   13027           SetGeometry(image,&mng_info->page);
   13028           (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
   13029             &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
   13030         }
   13031   if (write_mng)
   13032     {
   13033       unsigned int
   13034         need_geom;
   13035 
   13036       unsigned short
   13037         red,
   13038         green,
   13039         blue;
   13040 
   13041       mng_info->page=image->page;
   13042       need_geom=MagickTrue;
   13043       if (mng_info->page.width || mng_info->page.height)
   13044          need_geom=MagickFalse;
   13045       /*
   13046         Check all the scenes.
   13047       */
   13048       initial_delay=image->delay;
   13049       need_iterations=MagickFalse;
   13050       mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
   13051       mng_info->equal_physs=MagickTrue,
   13052       mng_info->equal_gammas=MagickTrue;
   13053       mng_info->equal_srgbs=MagickTrue;
   13054       mng_info->equal_backgrounds=MagickTrue;
   13055       image_count=0;
   13056 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
   13057     defined(PNG_MNG_FEATURES_SUPPORTED)
   13058       all_images_are_gray=MagickTrue;
   13059       mng_info->equal_palettes=MagickFalse;
   13060       need_local_plte=MagickFalse;
   13061 #endif
   13062       for (next_image=image; next_image != (Image *) NULL; )
   13063       {
   13064         if (need_geom)
   13065           {
   13066             if ((next_image->columns+next_image->page.x) > mng_info->page.width)
   13067               mng_info->page.width=next_image->columns+next_image->page.x;
   13068 
   13069             if ((next_image->rows+next_image->page.y) > mng_info->page.height)
   13070               mng_info->page.height=next_image->rows+next_image->page.y;
   13071           }
   13072 
   13073         if (next_image->page.x || next_image->page.y)
   13074           need_defi=MagickTrue;
   13075 
   13076         if (next_image->alpha_trait != UndefinedPixelTrait)
   13077           need_matte=MagickTrue;
   13078 
   13079         if ((int) next_image->dispose >= BackgroundDispose)
   13080           if ((next_image->alpha_trait != UndefinedPixelTrait) ||
   13081                next_image->page.x || next_image->page.y ||
   13082               ((next_image->columns < mng_info->page.width) &&
   13083                (next_image->rows < mng_info->page.height)))
   13084             mng_info->need_fram=MagickTrue;
   13085 
   13086         if (next_image->iterations)
   13087           need_iterations=MagickTrue;
   13088 
   13089         final_delay=next_image->delay;
   13090 
   13091         if (final_delay != initial_delay || final_delay > 1UL*
   13092            next_image->ticks_per_second)
   13093           mng_info->need_fram=1;
   13094 
   13095 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
   13096     defined(PNG_MNG_FEATURES_SUPPORTED)
   13097         /*
   13098           check for global palette possibility.
   13099         */
   13100         if (image->alpha_trait != UndefinedPixelTrait)
   13101            need_local_plte=MagickTrue;
   13102 
   13103         if (need_local_plte == 0)
   13104           {
   13105             if (SetImageGray(image,exception) == MagickFalse)
   13106               all_images_are_gray=MagickFalse;
   13107             mng_info->equal_palettes=PalettesAreEqual(image,next_image);
   13108             if (use_global_plte == 0)
   13109               use_global_plte=mng_info->equal_palettes;
   13110             need_local_plte=!mng_info->equal_palettes;
   13111           }
   13112 #endif
   13113         if (GetNextImageInList(next_image) != (Image *) NULL)
   13114           {
   13115             if (next_image->background_color.red !=
   13116                 next_image->next->background_color.red ||
   13117                 next_image->background_color.green !=
   13118                 next_image->next->background_color.green ||
   13119                 next_image->background_color.blue !=
   13120                 next_image->next->background_color.blue)
   13121               mng_info->equal_backgrounds=MagickFalse;
   13122 
   13123             if (next_image->gamma != next_image->next->gamma)
   13124               mng_info->equal_gammas=MagickFalse;
   13125 
   13126             if (next_image->rendering_intent !=
   13127                 next_image->next->rendering_intent)
   13128               mng_info->equal_srgbs=MagickFalse;
   13129 
   13130             if ((next_image->units != next_image->next->units) ||
   13131                 (next_image->resolution.x != next_image->next->resolution.x) ||
   13132                 (next_image->resolution.y != next_image->next->resolution.y))
   13133               mng_info->equal_physs=MagickFalse;
   13134 
   13135             if (mng_info->equal_chrms)
   13136               {
   13137                 if (next_image->chromaticity.red_primary.x !=
   13138                     next_image->next->chromaticity.red_primary.x ||
   13139                     next_image->chromaticity.red_primary.y !=
   13140                     next_image->next->chromaticity.red_primary.y ||
   13141                     next_image->chromaticity.green_primary.x !=
   13142                     next_image->next->chromaticity.green_primary.x ||
   13143                     next_image->chromaticity.green_primary.y !=
   13144                     next_image->next->chromaticity.green_primary.y ||
   13145                     next_image->chromaticity.blue_primary.x !=
   13146                     next_image->next->chromaticity.blue_primary.x ||
   13147                     next_image->chromaticity.blue_primary.y !=
   13148                     next_image->next->chromaticity.blue_primary.y ||
   13149                     next_image->chromaticity.white_point.x !=
   13150                     next_image->next->chromaticity.white_point.x ||
   13151                     next_image->chromaticity.white_point.y !=
   13152                     next_image->next->chromaticity.white_point.y)
   13153                   mng_info->equal_chrms=MagickFalse;
   13154               }
   13155           }
   13156         image_count++;
   13157         next_image=GetNextImageInList(next_image);
   13158       }
   13159       if (image_count < 2)
   13160         {
   13161           mng_info->equal_backgrounds=MagickFalse;
   13162           mng_info->equal_chrms=MagickFalse;
   13163           mng_info->equal_gammas=MagickFalse;
   13164           mng_info->equal_srgbs=MagickFalse;
   13165           mng_info->equal_physs=MagickFalse;
   13166           use_global_plte=MagickFalse;
   13167 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
   13168           need_local_plte=MagickTrue;
   13169 #endif
   13170           need_iterations=MagickFalse;
   13171         }
   13172 
   13173      if (mng_info->need_fram == MagickFalse)
   13174        {
   13175          /*
   13176            Only certain framing rates 100/n are exactly representable without
   13177            the FRAM chunk but we'll allow some slop in VLC files
   13178          */
   13179          if (final_delay == 0)
   13180            {
   13181              if (need_iterations != MagickFalse)
   13182                {
   13183                  /*
   13184                    It's probably a GIF with loop; don't run it *too* fast.
   13185                  */
   13186                  if (mng_info->adjoin)
   13187                    {
   13188                      final_delay=10;
   13189                      (void) ThrowMagickException(exception,GetMagickModule(),
   13190                        CoderWarning,
   13191                        "input has zero delay between all frames; assuming",
   13192                        " 10 cs `%s'","");
   13193                    }
   13194                }
   13195              else
   13196                mng_info->ticks_per_second=0;
   13197            }
   13198          if (final_delay != 0)
   13199            mng_info->ticks_per_second=(png_uint_32)
   13200               (image->ticks_per_second/final_delay);
   13201          if (final_delay > 50)
   13202            mng_info->ticks_per_second=2;
   13203 
   13204          if (final_delay > 75)
   13205            mng_info->ticks_per_second=1;
   13206 
   13207          if (final_delay > 125)
   13208            mng_info->need_fram=MagickTrue;
   13209 
   13210          if (need_defi && final_delay > 2 && (final_delay != 4) &&
   13211             (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
   13212             (final_delay != 25) && (final_delay != 50) &&
   13213             (final_delay != (size_t) image->ticks_per_second))
   13214            mng_info->need_fram=MagickTrue;  /* make it exact; cannot be VLC */
   13215        }
   13216 
   13217      if (mng_info->need_fram != MagickFalse)
   13218         mng_info->ticks_per_second=image->ticks_per_second;
   13219      /*
   13220         If pseudocolor, we should also check to see if all the
   13221         palettes are identical and write a global PLTE if they are.
   13222         ../glennrp Feb 99.
   13223      */
   13224      /*
   13225         Write the MNG version 1.0 signature and MHDR chunk.
   13226      */
   13227      (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
   13228      (void) WriteBlobMSBULong(image,28L);  /* chunk data length=28 */
   13229      PNGType(chunk,mng_MHDR);
   13230      LogPNGChunk(logging,mng_MHDR,28L);
   13231      PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
   13232      PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
   13233      PNGLong(chunk+12,mng_info->ticks_per_second);
   13234      PNGLong(chunk+16,0L);  /* layer count=unknown */
   13235      PNGLong(chunk+20,0L);  /* frame count=unknown */
   13236      PNGLong(chunk+24,0L);  /* play time=unknown   */
   13237      if (write_jng)
   13238        {
   13239          if (need_matte)
   13240            {
   13241              if (need_defi || mng_info->need_fram || use_global_plte)
   13242                PNGLong(chunk+28,27L);    /* simplicity=LC+JNG */
   13243 
   13244              else
   13245                PNGLong(chunk+28,25L);    /* simplicity=VLC+JNG */
   13246            }
   13247 
   13248          else
   13249            {
   13250              if (need_defi || mng_info->need_fram || use_global_plte)
   13251                PNGLong(chunk+28,19L);  /* simplicity=LC+JNG, no transparency */
   13252 
   13253              else
   13254                PNGLong(chunk+28,17L);  /* simplicity=VLC+JNG, no transparency */
   13255            }
   13256        }
   13257 
   13258      else
   13259        {
   13260          if (need_matte)
   13261            {
   13262              if (need_defi || mng_info->need_fram || use_global_plte)
   13263                PNGLong(chunk+28,11L);    /* simplicity=LC */
   13264 
   13265              else
   13266                PNGLong(chunk+28,9L);    /* simplicity=VLC */
   13267            }
   13268 
   13269          else
   13270            {
   13271              if (need_defi || mng_info->need_fram || use_global_plte)
   13272                PNGLong(chunk+28,3L);    /* simplicity=LC, no transparency */
   13273 
   13274              else
   13275                PNGLong(chunk+28,1L);    /* simplicity=VLC, no transparency */
   13276            }
   13277        }
   13278      (void) WriteBlob(image,32,chunk);
   13279      (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
   13280      option=GetImageOption(image_info,"mng:need-cacheoff");
   13281      if (option != (const char *) NULL)
   13282        {
   13283          size_t
   13284            length;
   13285 
   13286          /*
   13287            Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
   13288          */
   13289          PNGType(chunk,mng_nEED);
   13290          length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
   13291          (void) WriteBlobMSBULong(image,(size_t) length);
   13292          LogPNGChunk(logging,mng_nEED,(size_t) length);
   13293          length+=4;
   13294          (void) WriteBlob(image,length,chunk);
   13295          (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
   13296        }
   13297      if ((GetPreviousImageInList(image) == (Image *) NULL) &&
   13298          (GetNextImageInList(image) != (Image *) NULL) &&
   13299          (image->iterations != 1))
   13300        {
   13301          /*
   13302            Write MNG TERM chunk
   13303          */
   13304          (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
   13305          PNGType(chunk,mng_TERM);
   13306          LogPNGChunk(logging,mng_TERM,10L);
   13307          chunk[4]=3;  /* repeat animation */
   13308          chunk[5]=0;  /* show last frame when done */
   13309          PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
   13310             final_delay/MagickMax(image->ticks_per_second,1)));
   13311 
   13312          if (image->iterations == 0)
   13313            PNGLong(chunk+10,PNG_UINT_31_MAX);
   13314 
   13315          else
   13316            PNGLong(chunk+10,(png_uint_32) image->iterations);
   13317 
   13318          if (logging != MagickFalse)
   13319            {
   13320              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13321                "     TERM delay: %.20g",(double) (mng_info->ticks_per_second*
   13322               final_delay/MagickMax(image->ticks_per_second,1)));
   13323 
   13324              if (image->iterations == 0)
   13325                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13326                  "     TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
   13327 
   13328              else
   13329                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13330                  "     Image iterations: %.20g",(double) image->iterations);
   13331            }
   13332          (void) WriteBlob(image,14,chunk);
   13333          (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
   13334        }
   13335      /*
   13336        To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
   13337      */
   13338      if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
   13339           mng_info->equal_srgbs)
   13340        {
   13341          /*
   13342            Write MNG sRGB chunk
   13343          */
   13344          (void) WriteBlobMSBULong(image,1L);
   13345          PNGType(chunk,mng_sRGB);
   13346          LogPNGChunk(logging,mng_sRGB,1L);
   13347 
   13348          if (image->rendering_intent != UndefinedIntent)
   13349            chunk[4]=(unsigned char)
   13350              Magick_RenderingIntent_to_PNG_RenderingIntent(
   13351              (image->rendering_intent));
   13352 
   13353          else
   13354            chunk[4]=(unsigned char)
   13355              Magick_RenderingIntent_to_PNG_RenderingIntent(
   13356                (PerceptualIntent));
   13357 
   13358          (void) WriteBlob(image,5,chunk);
   13359          (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
   13360          mng_info->have_write_global_srgb=MagickTrue;
   13361        }
   13362 
   13363      else
   13364        {
   13365          if (image->gamma && mng_info->equal_gammas)
   13366            {
   13367              /*
   13368                 Write MNG gAMA chunk
   13369              */
   13370              (void) WriteBlobMSBULong(image,4L);
   13371              PNGType(chunk,mng_gAMA);
   13372              LogPNGChunk(logging,mng_gAMA,4L);
   13373              PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
   13374              (void) WriteBlob(image,8,chunk);
   13375              (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
   13376              mng_info->have_write_global_gama=MagickTrue;
   13377            }
   13378          if (mng_info->equal_chrms)
   13379            {
   13380              PrimaryInfo
   13381                primary;
   13382 
   13383              /*
   13384                 Write MNG cHRM chunk
   13385              */
   13386              (void) WriteBlobMSBULong(image,32L);
   13387              PNGType(chunk,mng_cHRM);
   13388              LogPNGChunk(logging,mng_cHRM,32L);
   13389              primary=image->chromaticity.white_point;
   13390              PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
   13391              PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
   13392              primary=image->chromaticity.red_primary;
   13393              PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
   13394              PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
   13395              primary=image->chromaticity.green_primary;
   13396              PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
   13397              PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
   13398              primary=image->chromaticity.blue_primary;
   13399              PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
   13400              PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
   13401              (void) WriteBlob(image,36,chunk);
   13402              (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
   13403              mng_info->have_write_global_chrm=MagickTrue;
   13404            }
   13405        }
   13406      if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
   13407        {
   13408          /*
   13409             Write MNG pHYs chunk
   13410          */
   13411          (void) WriteBlobMSBULong(image,9L);
   13412          PNGType(chunk,mng_pHYs);
   13413          LogPNGChunk(logging,mng_pHYs,9L);
   13414 
   13415          if (image->units == PixelsPerInchResolution)
   13416            {
   13417              PNGLong(chunk+4,(png_uint_32)
   13418                (image->resolution.x*100.0/2.54+0.5));
   13419 
   13420              PNGLong(chunk+8,(png_uint_32)
   13421                (image->resolution.y*100.0/2.54+0.5));
   13422 
   13423              chunk[12]=1;
   13424            }
   13425 
   13426          else
   13427            {
   13428              if (image->units == PixelsPerCentimeterResolution)
   13429                {
   13430                  PNGLong(chunk+4,(png_uint_32)
   13431                    (image->resolution.x*100.0+0.5));
   13432 
   13433                  PNGLong(chunk+8,(png_uint_32)
   13434                    (image->resolution.y*100.0+0.5));
   13435 
   13436                  chunk[12]=1;
   13437                }
   13438 
   13439              else
   13440                {
   13441                  PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
   13442                  PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
   13443                  chunk[12]=0;
   13444                }
   13445            }
   13446          (void) WriteBlob(image,13,chunk);
   13447          (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
   13448        }
   13449      /*
   13450        Write MNG BACK chunk and global bKGD chunk, if the image is transparent
   13451        or does not cover the entire frame.
   13452      */
   13453      if (write_mng && ((image->alpha_trait != UndefinedPixelTrait) ||
   13454          image->page.x > 0 || image->page.y > 0 || (image->page.width &&
   13455          (image->page.width+image->page.x < mng_info->page.width))
   13456          || (image->page.height && (image->page.height+image->page.y
   13457          < mng_info->page.height))))
   13458        {
   13459          (void) WriteBlobMSBULong(image,6L);
   13460          PNGType(chunk,mng_BACK);
   13461          LogPNGChunk(logging,mng_BACK,6L);
   13462          red=ScaleQuantumToShort(image->background_color.red);
   13463          green=ScaleQuantumToShort(image->background_color.green);
   13464          blue=ScaleQuantumToShort(image->background_color.blue);
   13465          PNGShort(chunk+4,red);
   13466          PNGShort(chunk+6,green);
   13467          PNGShort(chunk+8,blue);
   13468          (void) WriteBlob(image,10,chunk);
   13469          (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
   13470          if (mng_info->equal_backgrounds)
   13471            {
   13472              (void) WriteBlobMSBULong(image,6L);
   13473              PNGType(chunk,mng_bKGD);
   13474              LogPNGChunk(logging,mng_bKGD,6L);
   13475              (void) WriteBlob(image,10,chunk);
   13476              (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
   13477            }
   13478        }
   13479 
   13480 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
   13481      if ((need_local_plte == MagickFalse) &&
   13482          (image->storage_class == PseudoClass) &&
   13483          (all_images_are_gray == MagickFalse))
   13484        {
   13485          size_t
   13486            data_length;
   13487 
   13488          /*
   13489            Write MNG PLTE chunk
   13490          */
   13491          data_length=3*image->colors;
   13492          (void) WriteBlobMSBULong(image,data_length);
   13493          PNGType(chunk,mng_PLTE);
   13494          LogPNGChunk(logging,mng_PLTE,data_length);
   13495 
   13496          for (i=0; i < (ssize_t) image->colors; i++)
   13497          {
   13498            chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
   13499              image->colormap[i].red) & 0xff);
   13500            chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
   13501              image->colormap[i].green) & 0xff);
   13502            chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
   13503              image->colormap[i].blue) & 0xff);
   13504          }
   13505 
   13506          (void) WriteBlob(image,data_length+4,chunk);
   13507          (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
   13508          mng_info->have_write_global_plte=MagickTrue;
   13509        }
   13510 #endif
   13511     }
   13512   scene=0;
   13513   mng_info->delay=0;
   13514 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
   13515     defined(PNG_MNG_FEATURES_SUPPORTED)
   13516   mng_info->equal_palettes=MagickFalse;
   13517 #endif
   13518   do
   13519   {
   13520     if (mng_info->adjoin)
   13521     {
   13522 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
   13523     defined(PNG_MNG_FEATURES_SUPPORTED)
   13524     /*
   13525       If we aren't using a global palette for the entire MNG, check to
   13526       see if we can use one for two or more consecutive images.
   13527     */
   13528     if (need_local_plte && use_global_plte && !all_images_are_gray)
   13529       {
   13530         if (mng_info->IsPalette)
   13531           {
   13532             /*
   13533               When equal_palettes is true, this image has the same palette
   13534               as the previous PseudoClass image
   13535             */
   13536             mng_info->have_write_global_plte=mng_info->equal_palettes;
   13537             mng_info->equal_palettes=PalettesAreEqual(image,image->next);
   13538             if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
   13539               {
   13540                 /*
   13541                   Write MNG PLTE chunk
   13542                 */
   13543                 size_t
   13544                   data_length;
   13545 
   13546                 data_length=3*image->colors;
   13547                 (void) WriteBlobMSBULong(image,data_length);
   13548                 PNGType(chunk,mng_PLTE);
   13549                 LogPNGChunk(logging,mng_PLTE,data_length);
   13550 
   13551                 for (i=0; i < (ssize_t) image->colors; i++)
   13552                 {
   13553                   chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
   13554                   chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
   13555                   chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
   13556                 }
   13557 
   13558                 (void) WriteBlob(image,data_length+4,chunk);
   13559                 (void) WriteBlobMSBULong(image,crc32(0,chunk,
   13560                    (uInt) (data_length+4)));
   13561                 mng_info->have_write_global_plte=MagickTrue;
   13562               }
   13563           }
   13564         else
   13565           mng_info->have_write_global_plte=MagickFalse;
   13566       }
   13567 #endif
   13568     if (need_defi)
   13569       {
   13570         ssize_t
   13571           previous_x,
   13572           previous_y;
   13573 
   13574         if (scene)
   13575           {
   13576             previous_x=mng_info->page.x;
   13577             previous_y=mng_info->page.y;
   13578           }
   13579         else
   13580           {
   13581             previous_x=0;
   13582             previous_y=0;
   13583           }
   13584         mng_info->page=image->page;
   13585         if ((mng_info->page.x !=  previous_x) ||
   13586             (mng_info->page.y != previous_y))
   13587           {
   13588              (void) WriteBlobMSBULong(image,12L);  /* data length=12 */
   13589              PNGType(chunk,mng_DEFI);
   13590              LogPNGChunk(logging,mng_DEFI,12L);
   13591              chunk[4]=0; /* object 0 MSB */
   13592              chunk[5]=0; /* object 0 LSB */
   13593              chunk[6]=0; /* visible  */
   13594              chunk[7]=0; /* abstract */
   13595              PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
   13596              PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
   13597              (void) WriteBlob(image,16,chunk);
   13598              (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
   13599           }
   13600       }
   13601     }
   13602 
   13603    mng_info->write_mng=write_mng;
   13604 
   13605    if ((int) image->dispose >= 3)
   13606      mng_info->framing_mode=3;
   13607 
   13608    if (mng_info->need_fram && mng_info->adjoin &&
   13609        ((image->delay != mng_info->delay) ||
   13610         (mng_info->framing_mode != mng_info->old_framing_mode)))
   13611      {
   13612        if (image->delay == mng_info->delay)
   13613          {
   13614            /*
   13615              Write a MNG FRAM chunk with the new framing mode.
   13616            */
   13617            (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
   13618            PNGType(chunk,mng_FRAM);
   13619            LogPNGChunk(logging,mng_FRAM,1L);
   13620            chunk[4]=(unsigned char) mng_info->framing_mode;
   13621            (void) WriteBlob(image,5,chunk);
   13622            (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
   13623          }
   13624        else
   13625          {
   13626            /*
   13627              Write a MNG FRAM chunk with the delay.
   13628            */
   13629            (void) WriteBlobMSBULong(image,10L);  /* data length=10 */
   13630            PNGType(chunk,mng_FRAM);
   13631            LogPNGChunk(logging,mng_FRAM,10L);
   13632            chunk[4]=(unsigned char) mng_info->framing_mode;
   13633            chunk[5]=0;  /* frame name separator (no name) */
   13634            chunk[6]=2;  /* flag for changing default delay */
   13635            chunk[7]=0;  /* flag for changing frame timeout */
   13636            chunk[8]=0;  /* flag for changing frame clipping */
   13637            chunk[9]=0;  /* flag for changing frame sync_id */
   13638            PNGLong(chunk+10,(png_uint_32)
   13639              ((mng_info->ticks_per_second*
   13640              image->delay)/MagickMax(image->ticks_per_second,1)));
   13641            (void) WriteBlob(image,14,chunk);
   13642            (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
   13643            mng_info->delay=(png_uint_32) image->delay;
   13644          }
   13645        mng_info->old_framing_mode=mng_info->framing_mode;
   13646      }
   13647 
   13648 #if defined(JNG_SUPPORTED)
   13649    if (image_info->compression == JPEGCompression)
   13650      {
   13651        ImageInfo
   13652          *write_info;
   13653 
   13654        if (logging != MagickFalse)
   13655          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13656            "  Writing JNG object.");
   13657        /* To do: specify the desired alpha compression method. */
   13658        write_info=CloneImageInfo(image_info);
   13659        write_info->compression=UndefinedCompression;
   13660        status=WriteOneJNGImage(mng_info,write_info,image,exception);
   13661        write_info=DestroyImageInfo(write_info);
   13662      }
   13663    else
   13664 #endif
   13665      {
   13666        if (logging != MagickFalse)
   13667          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   13668            "  Writing PNG object.");
   13669 
   13670        mng_info->need_blob = MagickFalse;
   13671        mng_info->ping_preserve_colormap = MagickFalse;
   13672 
   13673        /* We don't want any ancillary chunks written */
   13674        mng_info->ping_exclude_bKGD=MagickTrue;
   13675        mng_info->ping_exclude_cHRM=MagickTrue;
   13676        mng_info->ping_exclude_date=MagickTrue;
   13677        mng_info->ping_exclude_EXIF=MagickTrue;
   13678        mng_info->ping_exclude_gAMA=MagickTrue;
   13679        mng_info->ping_exclude_iCCP=MagickTrue;
   13680        /* mng_info->ping_exclude_iTXt=MagickTrue; */
   13681        mng_info->ping_exclude_oFFs=MagickTrue;
   13682        mng_info->ping_exclude_pHYs=MagickTrue;
   13683        mng_info->ping_exclude_sRGB=MagickTrue;
   13684        mng_info->ping_exclude_tEXt=MagickTrue;
   13685        mng_info->ping_exclude_tRNS=MagickTrue;
   13686        mng_info->ping_exclude_vpAg=MagickTrue;
   13687        mng_info->ping_exclude_zCCP=MagickTrue;
   13688        mng_info->ping_exclude_zTXt=MagickTrue;
   13689 
   13690        status=WriteOnePNGImage(mng_info,image_info,image,exception);
   13691      }
   13692 
   13693     if (status == MagickFalse)
   13694       {
   13695         MngInfoFreeStruct(mng_info,&have_mng_structure);
   13696         (void) CloseBlob(image);
   13697         return(MagickFalse);
   13698       }
   13699     (void) CatchImageException(image);
   13700     if (GetNextImageInList(image) == (Image *) NULL)
   13701       break;
   13702     image=SyncNextImageInList(image);
   13703     status=SetImageProgress(image,SaveImagesTag,scene++,
   13704       GetImageListLength(image));
   13705 
   13706     if (status == MagickFalse)
   13707       break;
   13708 
   13709   } while (mng_info->adjoin);
   13710 
   13711   if (write_mng)
   13712     {
   13713       while (GetPreviousImageInList(image) != (Image *) NULL)
   13714         image=GetPreviousImageInList(image);
   13715       /*
   13716         Write the MEND chunk.
   13717       */
   13718       (void) WriteBlobMSBULong(image,0x00000000L);
   13719       PNGType(chunk,mng_MEND);
   13720       LogPNGChunk(logging,mng_MEND,0L);
   13721       (void) WriteBlob(image,4,chunk);
   13722       (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
   13723     }
   13724   /*
   13725     Relinquish resources.
   13726   */
   13727   (void) CloseBlob(image);
   13728   MngInfoFreeStruct(mng_info,&have_mng_structure);
   13729 
   13730   if (logging != MagickFalse)
   13731     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
   13732 
   13733   return(MagickTrue);
   13734 }
   13735 #else /* PNG_LIBPNG_VER > 10011 */
   13736 
   13737 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
   13738 {
   13739   (void) image;
   13740   printf("Your PNG library is too old: You have libpng-%s\n",
   13741      PNG_LIBPNG_VER_STRING);
   13742 
   13743   ThrowBinaryException(CoderError,"PNG library is too old",
   13744      image_info->filename);
   13745 }
   13746 
   13747 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
   13748 {
   13749   return(WritePNGImage(image_info,image));
   13750 }
   13751 #endif /* PNG_LIBPNG_VER > 10011 */
   13752 #endif
   13753