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/* 42 Include declarations. 43*/ 44#include "MagickCore/studio.h" 45#include "MagickCore/artifact.h" 46#include "MagickCore/attribute.h" 47#include "MagickCore/blob.h" 48#include "MagickCore/blob-private.h" 49#include "MagickCore/cache.h" 50#include "MagickCore/channel.h" 51#include "MagickCore/color.h" 52#include "MagickCore/color-private.h" 53#include "MagickCore/colormap.h" 54#include "MagickCore/colorspace.h" 55#include "MagickCore/colorspace-private.h" 56#include "MagickCore/constitute.h" 57#include "MagickCore/enhance.h" 58#include "MagickCore/exception.h" 59#include "MagickCore/exception-private.h" 60#include "MagickCore/geometry.h" 61#include "MagickCore/histogram.h" 62#include "MagickCore/image.h" 63#include "MagickCore/image-private.h" 64#include "MagickCore/layer.h" 65#include "MagickCore/list.h" 66#include "MagickCore/log.h" 67#include "MagickCore/MagickCore.h" 68#include "MagickCore/memory_.h" 69#include "MagickCore/module.h" 70#include "MagickCore/monitor.h" 71#include "MagickCore/monitor-private.h" 72#include "MagickCore/option.h" 73#include "MagickCore/pixel.h" 74#include "MagickCore/pixel-accessor.h" 75#include "MagickCore/profile.h" 76#include "MagickCore/property.h" 77#include "MagickCore/quantum-private.h" 78#include "MagickCore/resource_.h" 79#include "MagickCore/semaphore.h" 80#include "MagickCore/quantum-private.h" 81#include "MagickCore/static.h" 82#include "MagickCore/statistic.h" 83#include "MagickCore/string_.h" 84#include "MagickCore/string-private.h" 85#include "MagickCore/transform.h" 86#include "MagickCore/utility.h" 87#if defined(MAGICKCORE_PNG_DELEGATE) 88 89/* Suppress libpng pedantic warnings that were added in 90 * libpng-1.2.41 and libpng-1.4.0. If you are working on 91 * migration to libpng-1.5, remove these defines and then 92 * fix any code that generates warnings. 93 */ 94/* #define PNG_DEPRECATED Use of this function is deprecated */ 95/* #define PNG_USE_RESULT The result of this function must be checked */ 96/* #define PNG_NORETURN This function does not return */ 97/* #define PNG_ALLOCATED The result of the function is new memory */ 98/* #define PNG_DEPSTRUCT Access to this struct member is deprecated */ 99 100/* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */ 101#define PNG_PTR_NORETURN 102 103#include "png.h" 104#include "zlib.h" 105 106/* ImageMagick differences */ 107#define first_scene scene 108 109#if PNG_LIBPNG_VER > 10011 110/* 111 Optional declarations. Define or undefine them as you like. 112*/ 113/* #define PNG_DEBUG -- turning this on breaks VisualC compiling */ 114 115/* 116 Features under construction. Define these to work on them. 117*/ 118#undef MNG_OBJECT_BUFFERS 119#undef MNG_BASI_SUPPORTED 120#define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */ 121#define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */ 122#if defined(MAGICKCORE_JPEG_DELEGATE) 123# define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */ 124#endif 125#if !defined(RGBColorMatchExact) 126#define IsPNGColorEqual(color,target) \ 127 (((color).red == (target).red) && \ 128 ((color).green == (target).green) && \ 129 ((color).blue == (target).blue)) 130#endif 131 132/* Table of recognized sRGB ICC profiles */ 133struct sRGB_info_struct 134{ 135 png_uint_32 len; 136 png_uint_32 crc; 137 png_byte intent; 138}; 139 140const struct sRGB_info_struct sRGB_info[] = 141{ 142 /* ICC v2 perceptual sRGB_IEC61966-2-1_black_scaled.icc */ 143 { 3048, 0x3b8772b9UL, 0}, 144 145 /* ICC v2 relative sRGB_IEC61966-2-1_no_black_scaling.icc */ 146 { 3052, 0x427ebb21UL, 1}, 147 148 /* ICC v4 perceptual sRGB_v4_ICC_preference_displayclass.icc */ 149 {60988, 0x306fd8aeUL, 0}, 150 151 /* ICC v4 perceptual sRGB_v4_ICC_preference.icc perceptual */ 152 {60960, 0xbbef7812UL, 0}, 153 154 /* HP? sRGB v2 media-relative sRGB_IEC61966-2-1_noBPC.icc */ 155 { 3024, 0x5d5129ceUL, 1}, 156 157 /* HP-Microsoft sRGB v2 perceptual */ 158 { 3144, 0x182ea552UL, 0}, 159 160 /* HP-Microsoft sRGB v2 media-relative */ 161 { 3144, 0xf29e526dUL, 1}, 162 163 /* Facebook's "2012/01/25 03:41:57", 524, "TINYsRGB.icc" */ 164 { 524, 0xd4938c39UL, 0}, 165 166 /* "2012/11/28 22:35:21", 3212, "Argyll_sRGB.icm") */ 167 { 3212, 0x034af5a1UL, 0}, 168 169 /* Not recognized */ 170 { 0, 0x00000000UL, 0}, 171}; 172 173/* Macros for left-bit-replication to ensure that pixels 174 * and PixelInfos all have the same image->depth, and for use 175 * in PNG8 quantization. 176 */ 177 178/* LBR01: Replicate top bit */ 179 180#define LBR01PacketRed(pixelpacket) \ 181 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \ 182 0 : QuantumRange); 183 184#define LBR01PacketGreen(pixelpacket) \ 185 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \ 186 0 : QuantumRange); 187 188#define LBR01PacketBlue(pixelpacket) \ 189 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \ 190 0 : QuantumRange); 191 192#define LBR01PacketAlpha(pixelpacket) \ 193 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \ 194 0 : QuantumRange); 195 196#define LBR01PacketRGB(pixelpacket) \ 197 { \ 198 LBR01PacketRed((pixelpacket)); \ 199 LBR01PacketGreen((pixelpacket)); \ 200 LBR01PacketBlue((pixelpacket)); \ 201 } 202 203#define LBR01PacketRGBO(pixelpacket) \ 204 { \ 205 LBR01PacketRGB((pixelpacket)); \ 206 LBR01PacketAlpha((pixelpacket)); \ 207 } 208 209#define LBR01PixelRed(pixel) \ 210 (SetPixelRed(image, \ 211 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \ 212 0 : QuantumRange,(pixel))); 213 214#define LBR01PixelGreen(pixel) \ 215 (SetPixelGreen(image, \ 216 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \ 217 0 : QuantumRange,(pixel))); 218 219#define LBR01PixelBlue(pixel) \ 220 (SetPixelBlue(image, \ 221 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \ 222 0 : QuantumRange,(pixel))); 223 224#define LBR01PixelAlpha(pixel) \ 225 (SetPixelAlpha(image, \ 226 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \ 227 0 : QuantumRange,(pixel))); 228 229#define LBR01PixelRGB(pixel) \ 230 { \ 231 LBR01PixelRed((pixel)); \ 232 LBR01PixelGreen((pixel)); \ 233 LBR01PixelBlue((pixel)); \ 234 } 235 236#define LBR01PixelRGBA(pixel) \ 237 { \ 238 LBR01PixelRGB((pixel)); \ 239 LBR01PixelAlpha((pixel)); \ 240 } 241 242/* LBR02: Replicate top 2 bits */ 243 244#define LBR02PacketRed(pixelpacket) \ 245 { \ 246 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \ 247 (pixelpacket).red=ScaleCharToQuantum( \ 248 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 249 } 250#define LBR02PacketGreen(pixelpacket) \ 251 { \ 252 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \ 253 (pixelpacket).green=ScaleCharToQuantum( \ 254 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 255 } 256#define LBR02PacketBlue(pixelpacket) \ 257 { \ 258 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \ 259 (pixelpacket).blue=ScaleCharToQuantum( \ 260 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 261 } 262#define LBR02PacketAlpha(pixelpacket) \ 263 { \ 264 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \ 265 (pixelpacket).alpha=ScaleCharToQuantum( \ 266 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 267 } 268 269#define LBR02PacketRGB(pixelpacket) \ 270 { \ 271 LBR02PacketRed((pixelpacket)); \ 272 LBR02PacketGreen((pixelpacket)); \ 273 LBR02PacketBlue((pixelpacket)); \ 274 } 275 276#define LBR02PacketRGBO(pixelpacket) \ 277 { \ 278 LBR02PacketRGB((pixelpacket)); \ 279 LBR02PacketAlpha((pixelpacket)); \ 280 } 281 282#define LBR02PixelRed(pixel) \ 283 { \ 284 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 285 & 0xc0; \ 286 SetPixelRed(image, ScaleCharToQuantum( \ 287 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 288 (pixel)); \ 289 } 290#define LBR02PixelGreen(pixel) \ 291 { \ 292 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 293 & 0xc0; \ 294 SetPixelGreen(image, ScaleCharToQuantum( \ 295 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 296 (pixel)); \ 297 } 298#define LBR02PixelBlue(pixel) \ 299 { \ 300 unsigned char lbr_bits= \ 301 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \ 302 SetPixelBlue(image, ScaleCharToQuantum( \ 303 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 304 (pixel)); \ 305 } 306#define LBR02PixelAlpha(pixel) \ 307 { \ 308 unsigned char lbr_bits= \ 309 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \ 310 SetPixelAlpha(image, ScaleCharToQuantum( \ 311 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 312 (pixel) ); \ 313 } 314 315#define LBR02PixelRGB(pixel) \ 316 { \ 317 LBR02PixelRed((pixel)); \ 318 LBR02PixelGreen((pixel)); \ 319 LBR02PixelBlue((pixel)); \ 320 } 321 322#define LBR02PixelRGBA(pixel) \ 323 { \ 324 LBR02PixelRGB((pixel)); \ 325 LBR02PixelAlpha((pixel)); \ 326 } 327 328/* LBR03: Replicate top 3 bits (only used with opaque pixels during 329 PNG8 quantization) */ 330 331#define LBR03PacketRed(pixelpacket) \ 332 { \ 333 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \ 334 (pixelpacket).red=ScaleCharToQuantum( \ 335 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 336 } 337#define LBR03PacketGreen(pixelpacket) \ 338 { \ 339 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \ 340 (pixelpacket).green=ScaleCharToQuantum( \ 341 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 342 } 343#define LBR03PacketBlue(pixelpacket) \ 344 { \ 345 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \ 346 (pixelpacket).blue=ScaleCharToQuantum( \ 347 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 348 } 349 350#define LBR03PacketRGB(pixelpacket) \ 351 { \ 352 LBR03PacketRed((pixelpacket)); \ 353 LBR03PacketGreen((pixelpacket)); \ 354 LBR03PacketBlue((pixelpacket)); \ 355 } 356 357#define LBR03PixelRed(pixel) \ 358 { \ 359 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 360 & 0xe0; \ 361 SetPixelRed(image, ScaleCharToQuantum( \ 362 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 363 } 364#define LBR03Green(pixel) \ 365 { \ 366 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 367 & 0xe0; \ 368 SetPixelGreen(image, ScaleCharToQuantum( \ 369 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 370 } 371#define LBR03Blue(pixel) \ 372 { \ 373 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \ 374 & 0xe0; \ 375 SetPixelBlue(image, ScaleCharToQuantum( \ 376 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 377 } 378 379#define LBR03RGB(pixel) \ 380 { \ 381 LBR03PixelRed((pixel)); \ 382 LBR03Green((pixel)); \ 383 LBR03Blue((pixel)); \ 384 } 385 386/* LBR04: Replicate top 4 bits */ 387 388#define LBR04PacketRed(pixelpacket) \ 389 { \ 390 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \ 391 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 392 } 393#define LBR04PacketGreen(pixelpacket) \ 394 { \ 395 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \ 396 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 397 } 398#define LBR04PacketBlue(pixelpacket) \ 399 { \ 400 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \ 401 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 402 } 403#define LBR04PacketAlpha(pixelpacket) \ 404 { \ 405 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \ 406 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 407 } 408 409#define LBR04PacketRGB(pixelpacket) \ 410 { \ 411 LBR04PacketRed((pixelpacket)); \ 412 LBR04PacketGreen((pixelpacket)); \ 413 LBR04PacketBlue((pixelpacket)); \ 414 } 415 416#define LBR04PacketRGBO(pixelpacket) \ 417 { \ 418 LBR04PacketRGB((pixelpacket)); \ 419 LBR04PacketAlpha((pixelpacket)); \ 420 } 421 422#define LBR04PixelRed(pixel) \ 423 { \ 424 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 425 & 0xf0; \ 426 SetPixelRed(image,\ 427 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 428 } 429#define LBR04PixelGreen(pixel) \ 430 { \ 431 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 432 & 0xf0; \ 433 SetPixelGreen(image,\ 434 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 435 } 436#define LBR04PixelBlue(pixel) \ 437 { \ 438 unsigned char lbr_bits= \ 439 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \ 440 SetPixelBlue(image,\ 441 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 442 } 443#define LBR04PixelAlpha(pixel) \ 444 { \ 445 unsigned char lbr_bits= \ 446 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \ 447 SetPixelAlpha(image,\ 448 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 449 } 450 451#define LBR04PixelRGB(pixel) \ 452 { \ 453 LBR04PixelRed((pixel)); \ 454 LBR04PixelGreen((pixel)); \ 455 LBR04PixelBlue((pixel)); \ 456 } 457 458#define LBR04PixelRGBA(pixel) \ 459 { \ 460 LBR04PixelRGB((pixel)); \ 461 LBR04PixelAlpha((pixel)); \ 462 } 463 464/* 465 Establish thread safety. 466 setjmp/longjmp is claimed to be safe on these platforms: 467 setjmp/longjmp is alleged to be unsafe on these platforms: 468*/ 469#ifdef PNG_SETJMP_SUPPORTED 470# ifndef IMPNG_SETJMP_IS_THREAD_SAFE 471# define IMPNG_SETJMP_NOT_THREAD_SAFE 472# endif 473 474# ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 475static SemaphoreInfo 476 *ping_semaphore = (SemaphoreInfo *) NULL; 477# endif 478#endif 479 480/* 481 This temporary until I set up malloc'ed object attributes array. 482 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but 483 waste more memory. 484*/ 485#define MNG_MAX_OBJECTS 256 486 487/* 488 If this not defined, spec is interpreted strictly. If it is 489 defined, an attempt will be made to recover from some errors, 490 including 491 o global PLTE too short 492*/ 493#undef MNG_LOOSE 494 495/* 496 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure 497 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work 498 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8, 499 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in 500 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here. 501 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and 502 will be enabled by default in libpng-1.2.0. 503*/ 504#ifdef PNG_MNG_FEATURES_SUPPORTED 505# ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 506# define PNG_READ_EMPTY_PLTE_SUPPORTED 507# endif 508# ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED 509# define PNG_WRITE_EMPTY_PLTE_SUPPORTED 510# endif 511#endif 512 513/* 514 Maximum valid size_t in PNG/MNG chunks is (2^31)-1 515 This macro is only defined in libpng-1.0.3 and later. 516 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6 517*/ 518#ifndef PNG_UINT_31_MAX 519#define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL 520#endif 521 522/* 523 Constant strings for known chunk types. If you need to add a chunk, 524 add a string holding the name here. To make the code more 525 portable, we use ASCII numbers like this, not characters. 526*/ 527 528static const png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'}; 529static const png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'}; 530static const png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'}; 531static const png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'}; 532static const png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'}; 533static const png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'}; 534static const png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'}; 535static const png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'}; 536static const png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'}; 537static const png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'}; 538static const png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'}; 539static const png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'}; 540static const png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'}; 541static const png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'}; 542static const png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'}; 543static const png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'}; 544static const png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'}; 545static const png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'}; 546static const png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'}; 547static const png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'}; 548static const png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'}; 549static const png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'}; 550static const png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'}; 551static const png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'}; 552static const png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'}; 553static const png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'}; 554static const png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'}; 555static const png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'}; 556static const png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'}; 557static const png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; 558static const png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'}; 559static const png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'}; 560static const png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'}; 561static const png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'}; 562 563#if defined(JNG_SUPPORTED) 564static const png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'}; 565static const png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'}; 566static const png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'}; 567static const png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'}; 568static const png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'}; 569static const png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'}; 570#endif 571 572#if 0 573/* Other known chunks that are not yet supported by ImageMagick: */ 574static const png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'}; 575static const png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'}; 576static const png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'}; 577static const png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'}; 578static const png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'}; 579static const png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'}; 580static const png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'}; 581#endif 582 583typedef struct _MngBox 584{ 585 long 586 left, 587 right, 588 top, 589 bottom; 590} MngBox; 591 592typedef struct _MngPair 593{ 594 volatile long 595 a, 596 b; 597} MngPair; 598 599#ifdef MNG_OBJECT_BUFFERS 600typedef struct _MngBuffer 601{ 602 603 size_t 604 height, 605 width; 606 607 Image 608 *image; 609 610 png_color 611 plte[256]; 612 613 int 614 reference_count; 615 616 unsigned char 617 alpha_sample_depth, 618 compression_method, 619 color_type, 620 concrete, 621 filter_method, 622 frozen, 623 image_type, 624 interlace_method, 625 pixel_sample_depth, 626 plte_length, 627 sample_depth, 628 viewable; 629} MngBuffer; 630#endif 631 632typedef struct _MngInfo 633{ 634 635#ifdef MNG_OBJECT_BUFFERS 636 MngBuffer 637 *ob[MNG_MAX_OBJECTS]; 638#endif 639 640 Image * 641 image; 642 643 RectangleInfo 644 page; 645 646 int 647 adjoin, 648#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 649 bytes_in_read_buffer, 650 found_empty_plte, 651#endif 652 equal_backgrounds, 653 equal_chrms, 654 equal_gammas, 655#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 656 defined(PNG_MNG_FEATURES_SUPPORTED) 657 equal_palettes, 658#endif 659 equal_physs, 660 equal_srgbs, 661 framing_mode, 662 have_global_bkgd, 663 have_global_chrm, 664 have_global_gama, 665 have_global_phys, 666 have_global_sbit, 667 have_global_srgb, 668 have_saved_bkgd_index, 669 have_write_global_chrm, 670 have_write_global_gama, 671 have_write_global_plte, 672 have_write_global_srgb, 673 need_fram, 674 object_id, 675 old_framing_mode, 676 saved_bkgd_index; 677 678 int 679 new_number_colors; 680 681 ssize_t 682 image_found, 683 loop_count[256], 684 loop_iteration[256], 685 scenes_found, 686 x_off[MNG_MAX_OBJECTS], 687 y_off[MNG_MAX_OBJECTS]; 688 689 MngBox 690 clip, 691 frame, 692 image_box, 693 object_clip[MNG_MAX_OBJECTS]; 694 695 unsigned char 696 /* These flags could be combined into one byte */ 697 exists[MNG_MAX_OBJECTS], 698 frozen[MNG_MAX_OBJECTS], 699 loop_active[256], 700 invisible[MNG_MAX_OBJECTS], 701 viewable[MNG_MAX_OBJECTS]; 702 703 MagickOffsetType 704 loop_jump[256]; 705 706 png_colorp 707 global_plte; 708 709 png_color_8 710 global_sbit; 711 712 png_byte 713#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 714 read_buffer[8], 715#endif 716 global_trns[256]; 717 718 float 719 global_gamma; 720 721 ChromaticityInfo 722 global_chrm; 723 724 RenderingIntent 725 global_srgb_intent; 726 727 unsigned int 728 delay, 729 global_plte_length, 730 global_trns_length, 731 global_x_pixels_per_unit, 732 global_y_pixels_per_unit, 733 mng_width, 734 mng_height, 735 ticks_per_second; 736 737 MagickBooleanType 738 need_blob; 739 740 unsigned int 741 IsPalette, 742 global_phys_unit_type, 743 basi_warning, 744 clon_warning, 745 dhdr_warning, 746 jhdr_warning, 747 magn_warning, 748 past_warning, 749 phyg_warning, 750 phys_warning, 751 sbit_warning, 752 show_warning, 753 mng_type, 754 write_mng, 755 write_png_colortype, 756 write_png_depth, 757 write_png_compression_level, 758 write_png_compression_strategy, 759 write_png_compression_filter, 760 write_png8, 761 write_png24, 762 write_png32, 763 write_png48, 764 write_png64; 765 766#ifdef MNG_BASI_SUPPORTED 767 size_t 768 basi_width, 769 basi_height; 770 771 unsigned int 772 basi_depth, 773 basi_color_type, 774 basi_compression_method, 775 basi_filter_type, 776 basi_interlace_method, 777 basi_red, 778 basi_green, 779 basi_blue, 780 basi_alpha, 781 basi_viewable; 782#endif 783 784 png_uint_16 785 magn_first, 786 magn_last, 787 magn_mb, 788 magn_ml, 789 magn_mr, 790 magn_mt, 791 magn_mx, 792 magn_my, 793 magn_methx, 794 magn_methy; 795 796 PixelInfo 797 mng_global_bkgd; 798 799 /* Added at version 6.6.6-7 */ 800 MagickBooleanType 801 ping_exclude_bKGD, 802 ping_exclude_cHRM, 803 ping_exclude_date, 804 ping_exclude_EXIF, 805 ping_exclude_gAMA, 806 ping_exclude_iCCP, 807 /* ping_exclude_iTXt, */ 808 ping_exclude_oFFs, 809 ping_exclude_pHYs, 810 ping_exclude_sRGB, 811 ping_exclude_tEXt, 812 ping_exclude_tRNS, 813 ping_exclude_vpAg, 814 ping_exclude_zCCP, /* hex-encoded iCCP */ 815 ping_exclude_zTXt, 816 ping_preserve_colormap, 817 /* Added at version 6.8.5-7 */ 818 ping_preserve_iCCP, 819 /* Added at version 6.8.9-9 */ 820 ping_exclude_tIME; 821 822} MngInfo; 823#endif /* VER */ 824 825/* 826 Forward declarations. 827*/ 828static MagickBooleanType 829 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *); 830 831static MagickBooleanType 832 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *); 833 834#if defined(JNG_SUPPORTED) 835static MagickBooleanType 836 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *); 837#endif 838 839#if PNG_LIBPNG_VER > 10011 840 841 842#if (MAGICKCORE_QUANTUM_DEPTH >= 16) 843static MagickBooleanType 844LosslessReduceDepthOK(Image *image,ExceptionInfo *exception) 845{ 846 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8. 847 * 848 * This is true if the high byte and the next highest byte of 849 * each sample of the image, the colormap, and the background color 850 * are equal to each other. We check this by seeing if the samples 851 * are unchanged when we scale them down to 8 and back up to Quantum. 852 * 853 * We don't use the method GetImageDepth() because it doesn't check 854 * background and doesn't handle PseudoClass specially. 855 */ 856 857#define QuantumToCharToQuantumEqQuantum(quantum) \ 858 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum) 859 860 MagickBooleanType 861 ok_to_reduce=MagickFalse; 862 863 if (image->depth >= 16) 864 { 865 866 const Quantum 867 *p; 868 869 ok_to_reduce= 870 QuantumToCharToQuantumEqQuantum(image->background_color.red) && 871 QuantumToCharToQuantumEqQuantum(image->background_color.green) && 872 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ? 873 MagickTrue : MagickFalse; 874 875 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass) 876 { 877 int indx; 878 879 for (indx=0; indx < (ssize_t) image->colors; indx++) 880 { 881 ok_to_reduce=( 882 QuantumToCharToQuantumEqQuantum( 883 image->colormap[indx].red) && 884 QuantumToCharToQuantumEqQuantum( 885 image->colormap[indx].green) && 886 QuantumToCharToQuantumEqQuantum( 887 image->colormap[indx].blue)) ? 888 MagickTrue : MagickFalse; 889 890 if (ok_to_reduce == MagickFalse) 891 break; 892 } 893 } 894 895 if ((ok_to_reduce != MagickFalse) && 896 (image->storage_class != PseudoClass)) 897 { 898 ssize_t 899 y; 900 901 register ssize_t 902 x; 903 904 for (y=0; y < (ssize_t) image->rows; y++) 905 { 906 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 907 908 if (p == (const Quantum *) NULL) 909 { 910 ok_to_reduce = MagickFalse; 911 break; 912 } 913 914 for (x=(ssize_t) image->columns-1; x >= 0; x--) 915 { 916 ok_to_reduce= 917 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) && 918 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) && 919 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ? 920 MagickTrue : MagickFalse; 921 922 if (ok_to_reduce == MagickFalse) 923 break; 924 925 p+=GetPixelChannels(image); 926 } 927 if (x >= 0) 928 break; 929 } 930 } 931 932 if (ok_to_reduce != MagickFalse) 933 { 934 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 935 " OK to reduce PNG bit depth to 8 without loss of info"); 936 } 937 else 938 { 939 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 940 " Not OK to reduce PNG bit depth to 8 without loss of info"); 941 } 942 } 943 944 return ok_to_reduce; 945} 946#endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */ 947 948static const char* PngColorTypeToString(const unsigned int color_type) 949{ 950 const char 951 *result = "Unknown"; 952 953 switch (color_type) 954 { 955 case PNG_COLOR_TYPE_GRAY: 956 result = "Gray"; 957 break; 958 case PNG_COLOR_TYPE_GRAY_ALPHA: 959 result = "Gray+Alpha"; 960 break; 961 case PNG_COLOR_TYPE_PALETTE: 962 result = "Palette"; 963 break; 964 case PNG_COLOR_TYPE_RGB: 965 result = "RGB"; 966 break; 967 case PNG_COLOR_TYPE_RGB_ALPHA: 968 result = "RGB+Alpha"; 969 break; 970 } 971 972 return result; 973} 974 975static int 976Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent) 977{ 978 switch (intent) 979 { 980 case PerceptualIntent: 981 return 0; 982 983 case RelativeIntent: 984 return 1; 985 986 case SaturationIntent: 987 return 2; 988 989 case AbsoluteIntent: 990 return 3; 991 992 default: 993 return -1; 994 } 995} 996 997static RenderingIntent 998Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent) 999{ 1000 switch (ping_intent) 1001 { 1002 case 0: 1003 return PerceptualIntent; 1004 1005 case 1: 1006 return RelativeIntent; 1007 1008 case 2: 1009 return SaturationIntent; 1010 1011 case 3: 1012 return AbsoluteIntent; 1013 1014 default: 1015 return UndefinedIntent; 1016 } 1017} 1018 1019static const char * 1020Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent) 1021{ 1022 switch (ping_intent) 1023 { 1024 case 0: 1025 return "Perceptual Intent"; 1026 1027 case 1: 1028 return "Relative Intent"; 1029 1030 case 2: 1031 return "Saturation Intent"; 1032 1033 case 3: 1034 return "Absolute Intent"; 1035 1036 default: 1037 return "Undefined Intent"; 1038 } 1039} 1040 1041static const char * 1042Magick_ColorType_from_PNG_ColorType(const int ping_colortype) 1043{ 1044 switch (ping_colortype) 1045 { 1046 case 0: 1047 return "Grayscale"; 1048 1049 case 2: 1050 return "Truecolor"; 1051 1052 case 3: 1053 return "Indexed"; 1054 1055 case 4: 1056 return "GrayAlpha"; 1057 1058 case 6: 1059 return "RGBA"; 1060 1061 default: 1062 return "UndefinedColorType"; 1063 } 1064} 1065 1066#endif /* PNG_LIBPNG_VER > 10011 */ 1067#endif /* MAGICKCORE_PNG_DELEGATE */ 1068 1069/* 1070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1071% % 1072% % 1073% % 1074% I s M N G % 1075% % 1076% % 1077% % 1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1079% 1080% IsMNG() returns MagickTrue if the image format type, identified by the 1081% magick string, is MNG. 1082% 1083% The format of the IsMNG method is: 1084% 1085% MagickBooleanType IsMNG(const unsigned char *magick,const size_t length) 1086% 1087% A description of each parameter follows: 1088% 1089% o magick: compare image format pattern against these bytes. 1090% 1091% o length: Specifies the length of the magick string. 1092% 1093% 1094*/ 1095static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length) 1096{ 1097 if (length < 8) 1098 return(MagickFalse); 1099 1100 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0) 1101 return(MagickTrue); 1102 1103 return(MagickFalse); 1104} 1105 1106/* 1107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1108% % 1109% % 1110% % 1111% I s J N G % 1112% % 1113% % 1114% % 1115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1116% 1117% IsJNG() returns MagickTrue if the image format type, identified by the 1118% magick string, is JNG. 1119% 1120% The format of the IsJNG method is: 1121% 1122% MagickBooleanType IsJNG(const unsigned char *magick,const size_t length) 1123% 1124% A description of each parameter follows: 1125% 1126% o magick: compare image format pattern against these bytes. 1127% 1128% o length: Specifies the length of the magick string. 1129% 1130% 1131*/ 1132static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length) 1133{ 1134 if (length < 8) 1135 return(MagickFalse); 1136 1137 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0) 1138 return(MagickTrue); 1139 1140 return(MagickFalse); 1141} 1142 1143/* 1144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1145% % 1146% % 1147% % 1148% I s P N G % 1149% % 1150% % 1151% % 1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1153% 1154% IsPNG() returns MagickTrue if the image format type, identified by the 1155% magick string, is PNG. 1156% 1157% The format of the IsPNG method is: 1158% 1159% MagickBooleanType IsPNG(const unsigned char *magick,const size_t length) 1160% 1161% A description of each parameter follows: 1162% 1163% o magick: compare image format pattern against these bytes. 1164% 1165% o length: Specifies the length of the magick string. 1166% 1167*/ 1168static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length) 1169{ 1170 if (length < 8) 1171 return(MagickFalse); 1172 1173 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0) 1174 return(MagickTrue); 1175 1176 return(MagickFalse); 1177} 1178 1179#if defined(MAGICKCORE_PNG_DELEGATE) 1180#if defined(__cplusplus) || defined(c_plusplus) 1181extern "C" { 1182#endif 1183 1184#if (PNG_LIBPNG_VER > 10011) 1185static size_t WriteBlobMSBULong(Image *image,const size_t value) 1186{ 1187 unsigned char 1188 buffer[4]; 1189 1190 assert(image != (Image *) NULL); 1191 assert(image->signature == MagickCoreSignature); 1192 buffer[0]=(unsigned char) (value >> 24); 1193 buffer[1]=(unsigned char) (value >> 16); 1194 buffer[2]=(unsigned char) (value >> 8); 1195 buffer[3]=(unsigned char) value; 1196 return((size_t) WriteBlob(image,4,buffer)); 1197} 1198 1199static void PNGLong(png_bytep p,png_uint_32 value) 1200{ 1201 *p++=(png_byte) ((value >> 24) & 0xff); 1202 *p++=(png_byte) ((value >> 16) & 0xff); 1203 *p++=(png_byte) ((value >> 8) & 0xff); 1204 *p++=(png_byte) (value & 0xff); 1205} 1206 1207#if defined(JNG_SUPPORTED) 1208static void PNGsLong(png_bytep p,png_int_32 value) 1209{ 1210 *p++=(png_byte) ((value >> 24) & 0xff); 1211 *p++=(png_byte) ((value >> 16) & 0xff); 1212 *p++=(png_byte) ((value >> 8) & 0xff); 1213 *p++=(png_byte) (value & 0xff); 1214} 1215#endif 1216 1217static void PNGShort(png_bytep p,png_uint_16 value) 1218{ 1219 *p++=(png_byte) ((value >> 8) & 0xff); 1220 *p++=(png_byte) (value & 0xff); 1221} 1222 1223static void PNGType(png_bytep p,const png_byte *type) 1224{ 1225 (void) CopyMagickMemory(p,type,4*sizeof(png_byte)); 1226} 1227 1228static void LogPNGChunk(MagickBooleanType logging, const png_byte *type, 1229 size_t length) 1230{ 1231 if (logging != MagickFalse) 1232 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1233 " Writing %c%c%c%c chunk, length: %.20g", 1234 type[0],type[1],type[2],type[3],(double) length); 1235} 1236#endif /* PNG_LIBPNG_VER > 10011 */ 1237 1238#if defined(__cplusplus) || defined(c_plusplus) 1239} 1240#endif 1241 1242#if PNG_LIBPNG_VER > 10011 1243/* 1244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1245% % 1246% % 1247% % 1248% R e a d P N G I m a g e % 1249% % 1250% % 1251% % 1252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1253% 1254% ReadPNGImage() reads a Portable Network Graphics (PNG) or 1255% Multiple-image Network Graphics (MNG) image file and returns it. It 1256% allocates the memory necessary for the new Image structure and returns a 1257% pointer to the new image or set of images. 1258% 1259% MNG support written by Glenn Randers-Pehrson, glennrp@image... 1260% 1261% The format of the ReadPNGImage method is: 1262% 1263% Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 1264% 1265% A description of each parameter follows: 1266% 1267% o image_info: the image info. 1268% 1269% o exception: return any errors or warnings in this structure. 1270% 1271% To do, more or less in chronological order (as of version 5.5.2, 1272% November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage): 1273% 1274% Get 16-bit cheap transparency working. 1275% 1276% (At this point, PNG decoding is supposed to be in full MNG-LC compliance) 1277% 1278% Preserve all unknown and not-yet-handled known chunks found in input 1279% PNG file and copy them into output PNG files according to the PNG 1280% copying rules. 1281% 1282% (At this point, PNG encoding should be in full MNG compliance) 1283% 1284% Provide options for choice of background to use when the MNG BACK 1285% chunk is not present or is not mandatory (i.e., leave transparent, 1286% user specified, MNG BACK, PNG bKGD) 1287% 1288% Implement LOOP/ENDL [done, but could do discretionary loops more 1289% efficiently by linking in the duplicate frames.]. 1290% 1291% Decode and act on the MHDR simplicity profile (offer option to reject 1292% files or attempt to process them anyway when the profile isn't LC or VLC). 1293% 1294% Upgrade to full MNG without Delta-PNG. 1295% 1296% o BACK [done a while ago except for background image ID] 1297% o MOVE [done 15 May 1999] 1298% o CLIP [done 15 May 1999] 1299% o DISC [done 19 May 1999] 1300% o SAVE [partially done 19 May 1999 (marks objects frozen)] 1301% o SEEK [partially done 19 May 1999 (discard function only)] 1302% o SHOW 1303% o PAST 1304% o BASI 1305% o MNG-level tEXt/iTXt/zTXt 1306% o pHYg 1307% o pHYs 1308% o sBIT 1309% o bKGD 1310% o iTXt (wait for libpng implementation). 1311% 1312% Use the scene signature to discover when an identical scene is 1313% being reused, and just point to the original image->exception instead 1314% of storing another set of pixels. This not specific to MNG 1315% but could be applied generally. 1316% 1317% Upgrade to full MNG with Delta-PNG. 1318% 1319% JNG tEXt/iTXt/zTXt 1320% 1321% We will not attempt to read files containing the CgBI chunk. 1322% They are really Xcode files meant for display on the iPhone. 1323% These are not valid PNG files and it is impossible to recover 1324% the original PNG from files that have been converted to Xcode-PNG, 1325% since irretrievable loss of color data has occurred due to the 1326% use of premultiplied alpha. 1327*/ 1328 1329#if defined(__cplusplus) || defined(c_plusplus) 1330extern "C" { 1331#endif 1332 1333/* 1334 This the function that does the actual reading of data. It is 1335 the same as the one supplied in libpng, except that it receives the 1336 datastream from the ReadBlob() function instead of standard input. 1337*/ 1338static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length) 1339{ 1340 Image 1341 *image; 1342 1343 image=(Image *) png_get_io_ptr(png_ptr); 1344 if (length != 0) 1345 { 1346 png_size_t 1347 check; 1348 1349 check=(png_size_t) ReadBlob(image,(size_t) length,data); 1350 if (check != length) 1351 { 1352 char 1353 msg[MagickPathExtent]; 1354 1355 (void) FormatLocaleString(msg,MagickPathExtent, 1356 "Expected %.20g bytes; found %.20g bytes",(double) length, 1357 (double) check); 1358 png_warning(png_ptr,msg); 1359 png_error(png_ptr,"Read Exception"); 1360 } 1361 } 1362} 1363 1364#if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \ 1365 !defined(PNG_MNG_FEATURES_SUPPORTED) 1366/* We use mng_get_data() instead of png_get_data() if we have a libpng 1367 * older than libpng-1.0.3a, which was the first to allow the empty 1368 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was 1369 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was 1370 * encountered after an empty PLTE, so we have to look ahead for bKGD 1371 * chunks and remove them from the datastream that is passed to libpng, 1372 * and store their contents for later use. 1373 */ 1374static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length) 1375{ 1376 MngInfo 1377 *mng_info; 1378 1379 Image 1380 *image; 1381 1382 png_size_t 1383 check; 1384 1385 register ssize_t 1386 i; 1387 1388 i=0; 1389 mng_info=(MngInfo *) png_get_io_ptr(png_ptr); 1390 image=(Image *) mng_info->image; 1391 while (mng_info->bytes_in_read_buffer && length) 1392 { 1393 data[i]=mng_info->read_buffer[i]; 1394 mng_info->bytes_in_read_buffer--; 1395 length--; 1396 i++; 1397 } 1398 if (length != 0) 1399 { 1400 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data); 1401 1402 if (check != length) 1403 png_error(png_ptr,"Read Exception"); 1404 1405 if (length == 4) 1406 { 1407 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && 1408 (data[3] == 0)) 1409 { 1410 check=(png_size_t) ReadBlob(image,(size_t) length, 1411 (char *) mng_info->read_buffer); 1412 mng_info->read_buffer[4]=0; 1413 mng_info->bytes_in_read_buffer=4; 1414 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0) 1415 mng_info->found_empty_plte=MagickTrue; 1416 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0) 1417 { 1418 mng_info->found_empty_plte=MagickFalse; 1419 mng_info->have_saved_bkgd_index=MagickFalse; 1420 } 1421 } 1422 1423 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && 1424 (data[3] == 1)) 1425 { 1426 check=(png_size_t) ReadBlob(image,(size_t) length, 1427 (char *) mng_info->read_buffer); 1428 mng_info->read_buffer[4]=0; 1429 mng_info->bytes_in_read_buffer=4; 1430 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0) 1431 if (mng_info->found_empty_plte) 1432 { 1433 /* 1434 Skip the bKGD data byte and CRC. 1435 */ 1436 check=(png_size_t) 1437 ReadBlob(image,5,(char *) mng_info->read_buffer); 1438 check=(png_size_t) ReadBlob(image,(size_t) length, 1439 (char *) mng_info->read_buffer); 1440 mng_info->saved_bkgd_index=mng_info->read_buffer[0]; 1441 mng_info->have_saved_bkgd_index=MagickTrue; 1442 mng_info->bytes_in_read_buffer=0; 1443 } 1444 } 1445 } 1446 } 1447} 1448#endif 1449 1450static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length) 1451{ 1452 Image 1453 *image; 1454 1455 image=(Image *) png_get_io_ptr(png_ptr); 1456 if (length != 0) 1457 { 1458 png_size_t 1459 check; 1460 1461 check=(png_size_t) WriteBlob(image,(size_t) length,data); 1462 1463 if (check != length) 1464 png_error(png_ptr,"WriteBlob Failed"); 1465 } 1466} 1467 1468static void png_flush_data(png_structp png_ptr) 1469{ 1470 (void) png_ptr; 1471} 1472 1473#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 1474static int PalettesAreEqual(Image *a,Image *b) 1475{ 1476 ssize_t 1477 i; 1478 1479 if ((a == (Image *) NULL) || (b == (Image *) NULL)) 1480 return((int) MagickFalse); 1481 1482 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass) 1483 return((int) MagickFalse); 1484 1485 if (a->colors != b->colors) 1486 return((int) MagickFalse); 1487 1488 for (i=0; i < (ssize_t) a->colors; i++) 1489 { 1490 if ((a->colormap[i].red != b->colormap[i].red) || 1491 (a->colormap[i].green != b->colormap[i].green) || 1492 (a->colormap[i].blue != b->colormap[i].blue)) 1493 return((int) MagickFalse); 1494 } 1495 1496 return((int) MagickTrue); 1497} 1498#endif 1499 1500static void MngInfoDiscardObject(MngInfo *mng_info,int i) 1501{ 1502 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) && 1503 mng_info->exists[i] && !mng_info->frozen[i]) 1504 { 1505#ifdef MNG_OBJECT_BUFFERS 1506 if (mng_info->ob[i] != (MngBuffer *) NULL) 1507 { 1508 if (mng_info->ob[i]->reference_count > 0) 1509 mng_info->ob[i]->reference_count--; 1510 1511 if (mng_info->ob[i]->reference_count == 0) 1512 { 1513 if (mng_info->ob[i]->image != (Image *) NULL) 1514 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image); 1515 1516 mng_info->ob[i]=DestroyString(mng_info->ob[i]); 1517 } 1518 } 1519 mng_info->ob[i]=(MngBuffer *) NULL; 1520#endif 1521 mng_info->exists[i]=MagickFalse; 1522 mng_info->invisible[i]=MagickFalse; 1523 mng_info->viewable[i]=MagickFalse; 1524 mng_info->frozen[i]=MagickFalse; 1525 mng_info->x_off[i]=0; 1526 mng_info->y_off[i]=0; 1527 mng_info->object_clip[i].left=0; 1528 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX; 1529 mng_info->object_clip[i].top=0; 1530 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX; 1531 } 1532} 1533 1534static void MngInfoFreeStruct(MngInfo *mng_info, 1535 MagickBooleanType *have_mng_structure) 1536{ 1537 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL)) 1538 { 1539 register ssize_t 1540 i; 1541 1542 for (i=1; i < MNG_MAX_OBJECTS; i++) 1543 MngInfoDiscardObject(mng_info,i); 1544 1545 if (mng_info->global_plte != (png_colorp) NULL) 1546 mng_info->global_plte=(png_colorp) 1547 RelinquishMagickMemory(mng_info->global_plte); 1548 1549 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info); 1550 *have_mng_structure=MagickFalse; 1551 } 1552} 1553 1554static MngBox mng_minimum_box(MngBox box1,MngBox box2) 1555{ 1556 MngBox 1557 box; 1558 1559 box=box1; 1560 if (box.left < box2.left) 1561 box.left=box2.left; 1562 1563 if (box.top < box2.top) 1564 box.top=box2.top; 1565 1566 if (box.right > box2.right) 1567 box.right=box2.right; 1568 1569 if (box.bottom > box2.bottom) 1570 box.bottom=box2.bottom; 1571 1572 return box; 1573} 1574 1575static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p) 1576{ 1577 MngBox 1578 box; 1579 1580 /* 1581 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk. 1582 */ 1583 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 1584 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); 1585 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]); 1586 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]); 1587 if (delta_type != 0) 1588 { 1589 box.left+=previous_box.left; 1590 box.right+=previous_box.right; 1591 box.top+=previous_box.top; 1592 box.bottom+=previous_box.bottom; 1593 } 1594 1595 return(box); 1596} 1597 1598static MngPair mng_read_pair(MngPair previous_pair,int delta_type, 1599 unsigned char *p) 1600{ 1601 MngPair 1602 pair; 1603 /* 1604 Read two ssize_ts from CLON, MOVE or PAST chunk 1605 */ 1606 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 1607 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); 1608 1609 if (delta_type != 0) 1610 { 1611 pair.a+=previous_pair.a; 1612 pair.b+=previous_pair.b; 1613 } 1614 1615 return(pair); 1616} 1617 1618static long mng_get_long(unsigned char *p) 1619{ 1620 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])); 1621} 1622 1623typedef struct _PNGErrorInfo 1624{ 1625 Image 1626 *image; 1627 1628 ExceptionInfo 1629 *exception; 1630} PNGErrorInfo; 1631 1632static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message) 1633{ 1634 ExceptionInfo 1635 *exception; 1636 1637 Image 1638 *image; 1639 1640 PNGErrorInfo 1641 *error_info; 1642 1643 error_info=(PNGErrorInfo *) png_get_error_ptr(ping); 1644 image=error_info->image; 1645 exception=error_info->exception; 1646 1647 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1648 " libpng-%s error: %s", png_get_libpng_ver(NULL),message); 1649 1650 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message, 1651 "`%s'",image->filename); 1652 1653#if (PNG_LIBPNG_VER < 10500) 1654 /* A warning about deprecated use of jmpbuf here is unavoidable if you 1655 * are building with libpng-1.4.x and can be ignored. 1656 */ 1657 longjmp(ping->jmpbuf,1); 1658#else 1659 png_longjmp(ping,1); 1660#endif 1661} 1662 1663static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message) 1664{ 1665 ExceptionInfo 1666 *exception; 1667 1668 Image 1669 *image; 1670 1671 PNGErrorInfo 1672 *error_info; 1673 1674 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0) 1675 png_error(ping, message); 1676 1677 error_info=(PNGErrorInfo *) png_get_error_ptr(ping); 1678 image=error_info->image; 1679 exception=error_info->exception; 1680 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1681 " libpng-%s warning: %s", png_get_libpng_ver(NULL),message); 1682 1683 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, 1684 message,"`%s'",image->filename); 1685} 1686 1687#ifdef PNG_USER_MEM_SUPPORTED 1688#if PNG_LIBPNG_VER >= 10400 1689static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size) 1690#else 1691static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size) 1692#endif 1693{ 1694 (void) png_ptr; 1695 return((png_voidp) AcquireMagickMemory((size_t) size)); 1696} 1697 1698/* 1699 Free a pointer. It is removed from the list at the same time. 1700*/ 1701static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr) 1702{ 1703 (void) png_ptr; 1704 ptr=RelinquishMagickMemory(ptr); 1705 return((png_free_ptr) NULL); 1706} 1707#endif 1708 1709#if defined(__cplusplus) || defined(c_plusplus) 1710} 1711#endif 1712 1713static int 1714Magick_png_read_raw_profile(png_struct *ping,Image *image, 1715 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception) 1716{ 1717 register ssize_t 1718 i; 1719 1720 register unsigned char 1721 *dp; 1722 1723 register png_charp 1724 sp; 1725 1726 png_uint_32 1727 length, 1728 nibbles; 1729 1730 StringInfo 1731 *profile; 1732 1733 const unsigned char 1734 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1735 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1736 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0, 1737 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1738 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12, 1739 13,14,15}; 1740 1741 sp=text[ii].text+1; 1742 /* look for newline */ 1743 while (*sp != '\n') 1744 sp++; 1745 1746 /* look for length */ 1747 while (*sp == '\0' || *sp == ' ' || *sp == '\n') 1748 sp++; 1749 1750 length=(png_uint_32) StringToLong(sp); 1751 1752 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1753 " length: %lu",(unsigned long) length); 1754 1755 while (*sp != ' ' && *sp != '\n') 1756 sp++; 1757 1758 /* allocate space */ 1759 if (length == 0) 1760 { 1761 png_warning(ping,"invalid profile length"); 1762 return(MagickFalse); 1763 } 1764 1765 profile=BlobToStringInfo((const void *) NULL,length); 1766 1767 if (profile == (StringInfo *) NULL) 1768 { 1769 png_warning(ping, "unable to copy profile"); 1770 return(MagickFalse); 1771 } 1772 1773 /* copy profile, skipping white space and column 1 "=" signs */ 1774 dp=GetStringInfoDatum(profile); 1775 nibbles=length*2; 1776 1777 for (i=0; i < (ssize_t) nibbles; i++) 1778 { 1779 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f') 1780 { 1781 if (*sp == '\0') 1782 { 1783 png_warning(ping, "ran out of profile data"); 1784 profile=DestroyStringInfo(profile); 1785 return(MagickFalse); 1786 } 1787 sp++; 1788 } 1789 1790 if (i%2 == 0) 1791 *dp=(unsigned char) (16*unhex[(int) *sp++]); 1792 1793 else 1794 (*dp++)+=unhex[(int) *sp++]; 1795 } 1796 /* 1797 We have already read "Raw profile type. 1798 */ 1799 (void) SetImageProfile(image,&text[ii].key[17],profile,exception); 1800 profile=DestroyStringInfo(profile); 1801 1802 if (image_info->verbose) 1803 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]); 1804 1805 return MagickTrue; 1806} 1807 1808#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 1809static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) 1810{ 1811 Image 1812 *image; 1813 1814 1815 /* The unknown chunk structure contains the chunk data: 1816 png_byte name[5]; 1817 png_byte *data; 1818 png_size_t size; 1819 1820 Note that libpng has already taken care of the CRC handling. 1821 */ 1822 1823 LogMagickEvent(CoderEvent,GetMagickModule(), 1824 " read_vpag_chunk: found %c%c%c%c chunk", 1825 chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]); 1826 1827 if (chunk->name[0] != 118 || chunk->name[1] != 112 || 1828 chunk->name[2] != 65 ||chunk-> name[3] != 103) 1829 return(0); /* Did not recognize */ 1830 1831 /* recognized vpAg */ 1832 1833 if (chunk->size != 9) 1834 return(-1); /* Error return */ 1835 1836 if (chunk->data[8] != 0) 1837 return(0); /* ImageMagick requires pixel units */ 1838 1839 image=(Image *) png_get_user_chunk_ptr(ping); 1840 1841 image->page.width=(size_t) ((chunk->data[0] << 24) | 1842 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]); 1843 1844 image->page.height=(size_t) ((chunk->data[4] << 24) | 1845 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]); 1846 1847 /* Return one of the following: */ 1848 /* return(-n); chunk had an error */ 1849 /* return(0); did not recognize */ 1850 /* return(n); success */ 1851 1852 return(1); 1853 1854} 1855#endif 1856 1857#if defined(PNG_tIME_SUPPORTED) 1858static void read_tIME_chunk(Image *image,png_struct *ping,png_info *info, 1859 ExceptionInfo *exception) 1860{ 1861 png_timep 1862 time; 1863 1864 if (png_get_tIME(ping,info,&time)) 1865 { 1866 char 1867 timestamp[21]; 1868 1869 FormatLocaleString(timestamp,21,"%04d-%02d-%02dT%02d:%02d:%02dZ", 1870 time->year,time->month,time->day,time->hour,time->minute,time->second); 1871 SetImageProperty(image,"png:tIME",timestamp,exception); 1872 } 1873} 1874#endif 1875 1876/* 1877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1878% % 1879% % 1880% % 1881% R e a d O n e P N G I m a g e % 1882% % 1883% % 1884% % 1885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1886% 1887% ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file 1888% (minus the 8-byte signature) and returns it. It allocates the memory 1889% necessary for the new Image structure and returns a pointer to the new 1890% image. 1891% 1892% The format of the ReadOnePNGImage method is: 1893% 1894% Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info, 1895% ExceptionInfo *exception) 1896% 1897% A description of each parameter follows: 1898% 1899% o mng_info: Specifies a pointer to a MngInfo structure. 1900% 1901% o image_info: the image info. 1902% 1903% o exception: return any errors or warnings in this structure. 1904% 1905*/ 1906static Image *ReadOnePNGImage(MngInfo *mng_info, 1907 const ImageInfo *image_info, ExceptionInfo *exception) 1908{ 1909 /* Read one PNG image */ 1910 1911 /* To do: Read the tEXt/Creation Time chunk into the date:create property */ 1912 1913 Image 1914 *image; 1915 1916 char 1917 im_vers[32], 1918 libpng_runv[32], 1919 libpng_vers[32], 1920 zlib_runv[32], 1921 zlib_vers[32]; 1922 1923 int 1924 intent, /* "PNG Rendering intent", which is ICC intent + 1 */ 1925 num_raw_profiles, 1926 num_text, 1927 num_text_total, 1928 num_passes, 1929 number_colors, 1930 pass, 1931 ping_bit_depth, 1932 ping_color_type, 1933 ping_file_depth, 1934 ping_interlace_method, 1935 ping_compression_method, 1936 ping_filter_method, 1937 ping_num_trans, 1938 unit_type; 1939 1940 double 1941 file_gamma; 1942 1943 MagickBooleanType 1944 logging, 1945 ping_found_cHRM, 1946 ping_found_gAMA, 1947 ping_found_iCCP, 1948 ping_found_sRGB, 1949 ping_found_sRGB_cHRM, 1950 ping_preserve_iCCP, 1951 status; 1952 1953 MemoryInfo 1954 *volatile pixel_info; 1955 1956 PixelInfo 1957 transparent_color; 1958 1959 PNGErrorInfo 1960 error_info; 1961 1962 png_bytep 1963 ping_trans_alpha; 1964 1965 png_color_16p 1966 ping_background, 1967 ping_trans_color; 1968 1969 png_info 1970 *end_info, 1971 *ping_info; 1972 1973 png_struct 1974 *ping; 1975 1976 png_textp 1977 text; 1978 1979 png_uint_32 1980 ping_height, 1981 ping_width, 1982 x_resolution, 1983 y_resolution; 1984 1985 QuantumInfo 1986 *quantum_info; 1987 1988 ssize_t 1989 ping_rowbytes, 1990 y; 1991 1992 register unsigned char 1993 *p; 1994 1995 register ssize_t 1996 i, 1997 x; 1998 1999 register Quantum 2000 *q; 2001 2002 size_t 2003 length, 2004 row_offset; 2005 2006 ssize_t 2007 j; 2008 2009 unsigned char 2010 *ping_pixels; 2011 2012#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED 2013 png_byte unused_chunks[]= 2014 { 2015 104, 73, 83, 84, (png_byte) '\0', /* hIST */ 2016 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ 2017 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ 2018 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ 2019 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ 2020#if !defined(PNG_tIME_SUPPORTED) 2021 116, 73, 77, 69, (png_byte) '\0', /* tIME */ 2022#endif 2023#ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */ 2024 /* ignore the APNG chunks */ 2025 97, 99, 84, 76, (png_byte) '\0', /* acTL */ 2026 102, 99, 84, 76, (png_byte) '\0', /* fcTL */ 2027 102, 100, 65, 84, (png_byte) '\0', /* fdAT */ 2028#endif 2029 }; 2030#endif 2031 2032 /* Define these outside of the following "if logging()" block so they will 2033 * show in debuggers. 2034 */ 2035 *im_vers='\0'; 2036 (void) ConcatenateMagickString(im_vers, 2037 MagickLibVersionText,32); 2038 (void) ConcatenateMagickString(im_vers, 2039 MagickLibAddendum,32); 2040 2041 *libpng_vers='\0'; 2042 (void) ConcatenateMagickString(libpng_vers, 2043 PNG_LIBPNG_VER_STRING,32); 2044 *libpng_runv='\0'; 2045 (void) ConcatenateMagickString(libpng_runv, 2046 png_get_libpng_ver(NULL),32); 2047 2048 *zlib_vers='\0'; 2049 (void) ConcatenateMagickString(zlib_vers, 2050 ZLIB_VERSION,32); 2051 *zlib_runv='\0'; 2052 (void) ConcatenateMagickString(zlib_runv, 2053 zlib_version,32); 2054 2055 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 2056 " Enter ReadOnePNGImage()\n" 2057 " IM version = %s\n" 2058 " Libpng version = %s", 2059 im_vers, libpng_vers); 2060 2061 if (logging != MagickFalse) 2062 { 2063 if (LocaleCompare(libpng_vers,libpng_runv) != 0) 2064 { 2065 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 2066 libpng_runv); 2067 } 2068 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s", 2069 zlib_vers); 2070 if (LocaleCompare(zlib_vers,zlib_runv) != 0) 2071 { 2072 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 2073 zlib_runv); 2074 } 2075 } 2076 2077#if (PNG_LIBPNG_VER < 10200) 2078 if (image_info->verbose) 2079 printf("Your PNG library (libpng-%s) is rather old.\n", 2080 PNG_LIBPNG_VER_STRING); 2081#endif 2082 2083#if (PNG_LIBPNG_VER >= 10400) 2084# ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */ 2085 if (image_info->verbose) 2086 { 2087 printf("Your PNG library (libpng-%s) is an old beta version.\n", 2088 PNG_LIBPNG_VER_STRING); 2089 printf("Please update it.\n"); 2090 } 2091# endif 2092#endif 2093 2094 2095 quantum_info = (QuantumInfo *) NULL; 2096 image=mng_info->image; 2097 2098 if (logging != MagickFalse) 2099 { 2100 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2101 " Before reading:\n" 2102 " image->alpha_trait=%d" 2103 " image->rendering_intent=%d\n" 2104 " image->colorspace=%d\n" 2105 " image->gamma=%f", 2106 (int) image->alpha_trait, (int) image->rendering_intent, 2107 (int) image->colorspace, image->gamma); 2108 } 2109 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent); 2110 2111 /* Set to an out-of-range color unless tRNS chunk is present */ 2112 transparent_color.red=65537; 2113 transparent_color.green=65537; 2114 transparent_color.blue=65537; 2115 transparent_color.alpha=65537; 2116 2117 number_colors=0; 2118 num_text = 0; 2119 num_text_total = 0; 2120 num_raw_profiles = 0; 2121 2122 ping_found_cHRM = MagickFalse; 2123 ping_found_gAMA = MagickFalse; 2124 ping_found_iCCP = MagickFalse; 2125 ping_found_sRGB = MagickFalse; 2126 ping_found_sRGB_cHRM = MagickFalse; 2127 ping_preserve_iCCP = MagickFalse; 2128 2129 2130 /* 2131 Allocate the PNG structures 2132 */ 2133#ifdef PNG_USER_MEM_SUPPORTED 2134 error_info.image=image; 2135 error_info.exception=exception; 2136 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info, 2137 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL, 2138 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free); 2139#else 2140 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info, 2141 MagickPNGErrorHandler,MagickPNGWarningHandler); 2142#endif 2143 if (ping == (png_struct *) NULL) 2144 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2145 2146 ping_info=png_create_info_struct(ping); 2147 2148 if (ping_info == (png_info *) NULL) 2149 { 2150 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL); 2151 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2152 } 2153 2154 end_info=png_create_info_struct(ping); 2155 2156 if (end_info == (png_info *) NULL) 2157 { 2158 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL); 2159 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2160 } 2161 2162 pixel_info=(MemoryInfo *) NULL; 2163 2164 if (setjmp(png_jmpbuf(ping))) 2165 { 2166 /* 2167 PNG image is corrupt. 2168 */ 2169 png_destroy_read_struct(&ping,&ping_info,&end_info); 2170 2171#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 2172 UnlockSemaphoreInfo(ping_semaphore); 2173#endif 2174 2175 if (pixel_info != (MemoryInfo *) NULL) 2176 pixel_info=RelinquishVirtualMemory(pixel_info); 2177 2178 if (logging != MagickFalse) 2179 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2180 " exit ReadOnePNGImage() with error."); 2181 2182 if (image != (Image *) NULL) 2183 { 2184 const char 2185 *option; 2186 2187 option=GetImageOption(image_info,"png:preserve-corrupt-image"); 2188 if (IsStringTrue(option) == MagickFalse) 2189 image->columns=0; 2190 } 2191 2192 return(GetFirstImageInList(image)); 2193 } 2194 2195 /* { For navigation to end of SETJMP-protected block. Within this 2196 * block, use png_error() instead of Throwing an Exception, to ensure 2197 * that libpng is able to clean up, and that the semaphore is unlocked. 2198 */ 2199 2200#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 2201 LockSemaphoreInfo(ping_semaphore); 2202#endif 2203 2204#ifdef PNG_BENIGN_ERRORS_SUPPORTED 2205 /* Allow benign errors */ 2206 png_set_benign_errors(ping, 1); 2207#endif 2208 2209#ifdef PNG_SET_USER_LIMITS_SUPPORTED 2210 /* Reject images with too many rows or columns */ 2211 png_set_user_limits(ping, 2212 (png_uint_32) MagickMin(0x7fffffffL, 2213 GetMagickResourceLimit(WidthResource)), 2214 (png_uint_32) MagickMin(0x7fffffffL, 2215 GetMagickResourceLimit(HeightResource))); 2216#endif /* PNG_SET_USER_LIMITS_SUPPORTED */ 2217 2218 /* 2219 Prepare PNG for reading. 2220 */ 2221 2222 mng_info->image_found++; 2223 png_set_sig_bytes(ping,8); 2224 2225 if (LocaleCompare(image_info->magick,"MNG") == 0) 2226 { 2227#if defined(PNG_MNG_FEATURES_SUPPORTED) 2228 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); 2229 png_set_read_fn(ping,image,png_get_data); 2230#else 2231#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) 2232 png_permit_empty_plte(ping,MagickTrue); 2233 png_set_read_fn(ping,image,png_get_data); 2234#else 2235 mng_info->image=image; 2236 mng_info->bytes_in_read_buffer=0; 2237 mng_info->found_empty_plte=MagickFalse; 2238 mng_info->have_saved_bkgd_index=MagickFalse; 2239 png_set_read_fn(ping,mng_info,mng_get_data); 2240#endif 2241#endif 2242 } 2243 2244 else 2245 png_set_read_fn(ping,image,png_get_data); 2246 2247 { 2248 const char 2249 *value; 2250 2251 value=GetImageOption(image_info,"profile:skip"); 2252 2253 if (IsOptionMember("ICC",value) == MagickFalse) 2254 { 2255 2256 value=GetImageOption(image_info,"png:preserve-iCCP"); 2257 2258 if (value == NULL) 2259 value=GetImageArtifact(image,"png:preserve-iCCP"); 2260 2261 if (value != NULL) 2262 ping_preserve_iCCP=MagickTrue; 2263 2264#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED) 2265 /* Don't let libpng check for ICC/sRGB profile because we're going 2266 * to do that anyway. This feature was added at libpng-1.6.12. 2267 * If logging, go ahead and check and issue a warning as appropriate. 2268 */ 2269 if (logging == MagickFalse) 2270 png_set_option(ping, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); 2271#endif 2272 } 2273#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 2274 else 2275 { 2276 png_set_keep_unknown_chunks(ping, 1, mng_iCCP, 1); 2277 } 2278#endif 2279 } 2280#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 2281 /* Ignore unused chunks and all unknown chunks except for vpAg */ 2282#if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */ 2283 png_set_keep_unknown_chunks(ping, 2, NULL, 0); 2284#else 2285 png_set_keep_unknown_chunks(ping, 1, NULL, 0); 2286#endif 2287 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1); 2288 png_set_keep_unknown_chunks(ping, 1, unused_chunks, 2289 (int)sizeof(unused_chunks)/5); 2290 /* Callback for other unknown chunks */ 2291 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback); 2292#endif 2293 2294#ifdef PNG_SET_USER_LIMITS_SUPPORTED 2295# if (PNG_LIBPNG_VER >= 10400) 2296 /* Limit the size of the chunk storage cache used for sPLT, text, 2297 * and unknown chunks. 2298 */ 2299 png_set_chunk_cache_max(ping, 32767); 2300# endif 2301#endif 2302 2303#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED 2304 /* Disable new libpng-1.5.10 feature */ 2305 png_set_check_for_invalid_index (ping, 0); 2306#endif 2307 2308#if (PNG_LIBPNG_VER < 10400) 2309# if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ 2310 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__) 2311 /* Disable thread-unsafe features of pnggccrd */ 2312 if (png_access_version_number() >= 10200) 2313 { 2314 png_uint_32 mmx_disable_mask=0; 2315 png_uint_32 asm_flags; 2316 2317 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ 2318 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ 2319 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ 2320 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); 2321 asm_flags=png_get_asm_flags(ping); 2322 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask); 2323 } 2324# endif 2325#endif 2326 2327 png_read_info(ping,ping_info); 2328 2329 png_get_IHDR(ping,ping_info,&ping_width,&ping_height, 2330 &ping_bit_depth,&ping_color_type, 2331 &ping_interlace_method,&ping_compression_method, 2332 &ping_filter_method); 2333 2334 ping_file_depth = ping_bit_depth; 2335 2336 /* Swap bytes if requested */ 2337 if (ping_file_depth == 16) 2338 { 2339 const char 2340 *value; 2341 2342 value=GetImageOption(image_info,"png:swap-bytes"); 2343 2344 if (value == NULL) 2345 value=GetImageArtifact(image,"png:swap-bytes"); 2346 2347 if (value != NULL) 2348 png_set_swap(ping); 2349 } 2350 2351 /* Save bit-depth and color-type in case we later want to write a PNG00 */ 2352 { 2353 char 2354 msg[MagickPathExtent]; 2355 2356 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_color_type); 2357 (void) SetImageProperty(image,"png:IHDR.color-type-orig",msg,exception); 2358 2359 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_bit_depth); 2360 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig",msg,exception); 2361 } 2362 2363 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans, 2364 &ping_trans_color); 2365 2366 (void) png_get_bKGD(ping, ping_info, &ping_background); 2367 2368 if (ping_bit_depth < 8) 2369 { 2370 png_set_packing(ping); 2371 ping_bit_depth = 8; 2372 } 2373 2374 image->depth=ping_bit_depth; 2375 image->depth=GetImageQuantumDepth(image,MagickFalse); 2376 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace; 2377 2378 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 2379 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) 2380 { 2381 image->rendering_intent=UndefinedIntent; 2382 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent); 2383 (void) ResetMagickMemory(&image->chromaticity,0, 2384 sizeof(image->chromaticity)); 2385 } 2386 2387 if (logging != MagickFalse) 2388 { 2389 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2390 " PNG width: %.20g, height: %.20g\n" 2391 " PNG color_type: %d, bit_depth: %d\n" 2392 " PNG compression_method: %d\n" 2393 " PNG interlace_method: %d, filter_method: %d", 2394 (double) ping_width, (double) ping_height, 2395 ping_color_type, ping_bit_depth, 2396 ping_compression_method, 2397 ping_interlace_method,ping_filter_method); 2398 2399 } 2400 2401 if (png_get_valid(ping,ping_info, PNG_INFO_iCCP)) 2402 { 2403 ping_found_iCCP=MagickTrue; 2404 if (logging != MagickFalse) 2405 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2406 " Found PNG iCCP chunk."); 2407 } 2408 2409 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA)) 2410 { 2411 ping_found_gAMA=MagickTrue; 2412 if (logging != MagickFalse) 2413 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2414 " Found PNG gAMA chunk."); 2415 } 2416 2417 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2418 { 2419 ping_found_cHRM=MagickTrue; 2420 if (logging != MagickFalse) 2421 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2422 " Found PNG cHRM chunk."); 2423 } 2424 2425 if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info, 2426 PNG_INFO_sRGB)) 2427 { 2428 ping_found_sRGB=MagickTrue; 2429 if (logging != MagickFalse) 2430 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2431 " Found PNG sRGB chunk."); 2432 } 2433 2434#ifdef PNG_READ_iCCP_SUPPORTED 2435 if (ping_found_iCCP !=MagickTrue && 2436 ping_found_sRGB != MagickTrue && 2437 png_get_valid(ping,ping_info, PNG_INFO_iCCP)) 2438 { 2439 ping_found_iCCP=MagickTrue; 2440 if (logging != MagickFalse) 2441 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2442 " Found PNG iCCP chunk."); 2443 } 2444 2445 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP)) 2446 { 2447 int 2448 compression; 2449 2450#if (PNG_LIBPNG_VER < 10500) 2451 png_charp 2452 info; 2453#else 2454 png_bytep 2455 info; 2456#endif 2457 2458 png_charp 2459 name; 2460 2461 png_uint_32 2462 profile_length; 2463 2464 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info, 2465 &profile_length); 2466 2467 if (profile_length != 0) 2468 { 2469 StringInfo 2470 *profile; 2471 2472 if (logging != MagickFalse) 2473 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2474 " Reading PNG iCCP chunk."); 2475 2476 profile=BlobToStringInfo(info,profile_length); 2477 2478 if (profile == (StringInfo *) NULL) 2479 { 2480 png_warning(ping, "ICC profile is NULL"); 2481 profile=DestroyStringInfo(profile); 2482 } 2483 else 2484 { 2485 if (ping_preserve_iCCP == MagickFalse) 2486 { 2487 int 2488 icheck, 2489 got_crc=0; 2490 2491 2492 png_uint_32 2493 length, 2494 profile_crc=0; 2495 2496 unsigned char 2497 *data; 2498 2499 length=(png_uint_32) GetStringInfoLength(profile); 2500 2501 for (icheck=0; sRGB_info[icheck].len > 0; icheck++) 2502 { 2503 if (length == sRGB_info[icheck].len) 2504 { 2505 if (got_crc == 0) 2506 { 2507 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2508 " Got a %lu-byte ICC profile (potentially sRGB)", 2509 (unsigned long) length); 2510 2511 data=GetStringInfoDatum(profile); 2512 profile_crc=crc32(0,data,length); 2513 2514 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2515 " with crc=%8x",(unsigned int) profile_crc); 2516 got_crc++; 2517 } 2518 2519 if (profile_crc == sRGB_info[icheck].crc) 2520 { 2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2522 " It is sRGB with rendering intent = %s", 2523 Magick_RenderingIntentString_from_PNG_RenderingIntent( 2524 sRGB_info[icheck].intent)); 2525 if (image->rendering_intent==UndefinedIntent) 2526 { 2527 image->rendering_intent= 2528 Magick_RenderingIntent_from_PNG_RenderingIntent( 2529 sRGB_info[icheck].intent); 2530 } 2531 break; 2532 } 2533 } 2534 } 2535 if (sRGB_info[icheck].len == 0) 2536 { 2537 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2538 " Got a %lu-byte ICC profile not recognized as sRGB", 2539 (unsigned long) length); 2540 (void) SetImageProfile(image,"icc",profile,exception); 2541 } 2542 } 2543 else /* Preserve-iCCP */ 2544 { 2545 (void) SetImageProfile(image,"icc",profile,exception); 2546 } 2547 2548 profile=DestroyStringInfo(profile); 2549 } 2550 } 2551 } 2552#endif 2553 2554#if defined(PNG_READ_sRGB_SUPPORTED) 2555 { 2556 if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info, 2557 PNG_INFO_sRGB)) 2558 { 2559 if (png_get_sRGB(ping,ping_info,&intent)) 2560 { 2561 if (image->rendering_intent == UndefinedIntent) 2562 image->rendering_intent= 2563 Magick_RenderingIntent_from_PNG_RenderingIntent (intent); 2564 2565 if (logging != MagickFalse) 2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2567 " Reading PNG sRGB chunk: rendering_intent: %d",intent); 2568 } 2569 } 2570 2571 else if (mng_info->have_global_srgb) 2572 { 2573 if (image->rendering_intent == UndefinedIntent) 2574 image->rendering_intent= 2575 Magick_RenderingIntent_from_PNG_RenderingIntent 2576 (mng_info->global_srgb_intent); 2577 } 2578 } 2579#endif 2580 2581 2582 { 2583 if (!png_get_gAMA(ping,ping_info,&file_gamma)) 2584 if (mng_info->have_global_gama) 2585 png_set_gAMA(ping,ping_info,mng_info->global_gamma); 2586 2587 if (png_get_gAMA(ping,ping_info,&file_gamma)) 2588 { 2589 image->gamma=(float) file_gamma; 2590 if (logging != MagickFalse) 2591 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2592 " Reading PNG gAMA chunk: gamma: %f",file_gamma); 2593 } 2594 } 2595 2596 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2597 { 2598 if (mng_info->have_global_chrm != MagickFalse) 2599 { 2600 (void) png_set_cHRM(ping,ping_info, 2601 mng_info->global_chrm.white_point.x, 2602 mng_info->global_chrm.white_point.y, 2603 mng_info->global_chrm.red_primary.x, 2604 mng_info->global_chrm.red_primary.y, 2605 mng_info->global_chrm.green_primary.x, 2606 mng_info->global_chrm.green_primary.y, 2607 mng_info->global_chrm.blue_primary.x, 2608 mng_info->global_chrm.blue_primary.y); 2609 } 2610 } 2611 2612 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2613 { 2614 (void) png_get_cHRM(ping,ping_info, 2615 &image->chromaticity.white_point.x, 2616 &image->chromaticity.white_point.y, 2617 &image->chromaticity.red_primary.x, 2618 &image->chromaticity.red_primary.y, 2619 &image->chromaticity.green_primary.x, 2620 &image->chromaticity.green_primary.y, 2621 &image->chromaticity.blue_primary.x, 2622 &image->chromaticity.blue_primary.y); 2623 2624 ping_found_cHRM=MagickTrue; 2625 2626 if (image->chromaticity.red_primary.x>0.6399f && 2627 image->chromaticity.red_primary.x<0.6401f && 2628 image->chromaticity.red_primary.y>0.3299f && 2629 image->chromaticity.red_primary.y<0.3301f && 2630 image->chromaticity.green_primary.x>0.2999f && 2631 image->chromaticity.green_primary.x<0.3001f && 2632 image->chromaticity.green_primary.y>0.5999f && 2633 image->chromaticity.green_primary.y<0.6001f && 2634 image->chromaticity.blue_primary.x>0.1499f && 2635 image->chromaticity.blue_primary.x<0.1501f && 2636 image->chromaticity.blue_primary.y>0.0599f && 2637 image->chromaticity.blue_primary.y<0.0601f && 2638 image->chromaticity.white_point.x>0.3126f && 2639 image->chromaticity.white_point.x<0.3128f && 2640 image->chromaticity.white_point.y>0.3289f && 2641 image->chromaticity.white_point.y<0.3291f) 2642 ping_found_sRGB_cHRM=MagickTrue; 2643 } 2644 2645 if (image->rendering_intent != UndefinedIntent) 2646 { 2647 if (ping_found_sRGB != MagickTrue && 2648 (ping_found_gAMA != MagickTrue || 2649 (image->gamma > .45 && image->gamma < .46)) && 2650 (ping_found_cHRM != MagickTrue || 2651 ping_found_sRGB_cHRM != MagickFalse) && 2652 ping_found_iCCP != MagickTrue) 2653 { 2654 png_set_sRGB(ping,ping_info, 2655 Magick_RenderingIntent_to_PNG_RenderingIntent 2656 (image->rendering_intent)); 2657 file_gamma=1.000f/2.200f; 2658 ping_found_sRGB=MagickTrue; 2659 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2660 " Setting sRGB as if in input"); 2661 } 2662 } 2663 2664#if defined(PNG_oFFs_SUPPORTED) 2665 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs)) 2666 { 2667 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info); 2668 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info); 2669 2670 if (logging != MagickFalse) 2671 if (image->page.x || image->page.y) 2672 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2673 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double) 2674 image->page.x,(double) image->page.y); 2675 } 2676#endif 2677#if defined(PNG_pHYs_SUPPORTED) 2678 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 2679 { 2680 if (mng_info->have_global_phys) 2681 { 2682 png_set_pHYs(ping,ping_info, 2683 mng_info->global_x_pixels_per_unit, 2684 mng_info->global_y_pixels_per_unit, 2685 mng_info->global_phys_unit_type); 2686 } 2687 } 2688 2689 x_resolution=0; 2690 y_resolution=0; 2691 unit_type=0; 2692 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 2693 { 2694 /* 2695 Set image resolution. 2696 */ 2697 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution, 2698 &unit_type); 2699 image->resolution.x=(double) x_resolution; 2700 image->resolution.y=(double) y_resolution; 2701 2702 if (unit_type == PNG_RESOLUTION_METER) 2703 { 2704 image->units=PixelsPerCentimeterResolution; 2705 image->resolution.x=(double) x_resolution/100.0; 2706 image->resolution.y=(double) y_resolution/100.0; 2707 } 2708 2709 if (logging != MagickFalse) 2710 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2711 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.", 2712 (double) x_resolution,(double) y_resolution,unit_type); 2713 } 2714#endif 2715 2716 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE)) 2717 { 2718 png_colorp 2719 palette; 2720 2721 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 2722 2723 if ((number_colors == 0) && 2724 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)) 2725 { 2726 if (mng_info->global_plte_length) 2727 { 2728 png_set_PLTE(ping,ping_info,mng_info->global_plte, 2729 (int) mng_info->global_plte_length); 2730 2731 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 2732 { 2733 if (mng_info->global_trns_length) 2734 { 2735 png_warning(ping, 2736 "global tRNS has more entries than global PLTE"); 2737 } 2738 else 2739 { 2740 png_set_tRNS(ping,ping_info,mng_info->global_trns, 2741 (int) mng_info->global_trns_length,NULL); 2742 } 2743 } 2744#ifdef PNG_READ_bKGD_SUPPORTED 2745 if ( 2746#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 2747 mng_info->have_saved_bkgd_index || 2748#endif 2749 png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 2750 { 2751 png_color_16 2752 background; 2753 2754#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 2755 if (mng_info->have_saved_bkgd_index) 2756 background.index=mng_info->saved_bkgd_index; 2757#endif 2758 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD)) 2759 background.index=ping_background->index; 2760 2761 background.red=(png_uint_16) 2762 mng_info->global_plte[background.index].red; 2763 2764 background.green=(png_uint_16) 2765 mng_info->global_plte[background.index].green; 2766 2767 background.blue=(png_uint_16) 2768 mng_info->global_plte[background.index].blue; 2769 2770 background.gray=(png_uint_16) 2771 mng_info->global_plte[background.index].green; 2772 2773 png_set_bKGD(ping,ping_info,&background); 2774 } 2775#endif 2776 } 2777 else 2778 png_error(ping,"No global PLTE in file"); 2779 } 2780 } 2781 2782#ifdef PNG_READ_bKGD_SUPPORTED 2783 if (mng_info->have_global_bkgd && 2784 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD))) 2785 image->background_color=mng_info->mng_global_bkgd; 2786 2787 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 2788 { 2789 unsigned int 2790 bkgd_scale; 2791 2792 /* Set image background color. 2793 * Scale background components to 16-bit, then scale 2794 * to quantum depth 2795 */ 2796 2797 bkgd_scale = 1; 2798 2799 if (ping_file_depth == 1) 2800 bkgd_scale = 255; 2801 2802 else if (ping_file_depth == 2) 2803 bkgd_scale = 85; 2804 2805 else if (ping_file_depth == 4) 2806 bkgd_scale = 17; 2807 2808 if (ping_file_depth <= 8) 2809 bkgd_scale *= 257; 2810 2811 ping_background->red *= bkgd_scale; 2812 ping_background->green *= bkgd_scale; 2813 ping_background->blue *= bkgd_scale; 2814 2815 if (logging != MagickFalse) 2816 { 2817 if (logging != MagickFalse) 2818 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2819 " Reading PNG bKGD chunk, raw ping_background=(%d,%d,%d).\n" 2820 " bkgd_scale=%d. ping_background=(%d,%d,%d).", 2821 ping_background->red,ping_background->green, 2822 ping_background->blue, 2823 bkgd_scale,ping_background->red, 2824 ping_background->green,ping_background->blue); 2825 } 2826 2827 image->background_color.red= 2828 ScaleShortToQuantum(ping_background->red); 2829 2830 image->background_color.green= 2831 ScaleShortToQuantum(ping_background->green); 2832 2833 image->background_color.blue= 2834 ScaleShortToQuantum(ping_background->blue); 2835 2836 image->background_color.alpha=OpaqueAlpha; 2837 2838 if (logging != MagickFalse) 2839 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2840 " image->background_color=(%.20g,%.20g,%.20g).", 2841 (double) image->background_color.red, 2842 (double) image->background_color.green, 2843 (double) image->background_color.blue); 2844 } 2845#endif /* PNG_READ_bKGD_SUPPORTED */ 2846 2847 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 2848 { 2849 /* 2850 Image has a tRNS chunk. 2851 */ 2852 int 2853 max_sample; 2854 2855 size_t 2856 one=1; 2857 2858 if (logging != MagickFalse) 2859 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2860 " Reading PNG tRNS chunk."); 2861 2862 max_sample = (int) ((one << ping_file_depth) - 1); 2863 2864 if ((ping_color_type == PNG_COLOR_TYPE_GRAY && 2865 (int)ping_trans_color->gray > max_sample) || 2866 (ping_color_type == PNG_COLOR_TYPE_RGB && 2867 ((int)ping_trans_color->red > max_sample || 2868 (int)ping_trans_color->green > max_sample || 2869 (int)ping_trans_color->blue > max_sample))) 2870 { 2871 if (logging != MagickFalse) 2872 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2873 " Ignoring PNG tRNS chunk with out-of-range sample."); 2874 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0); 2875 png_set_invalid(ping,ping_info,PNG_INFO_tRNS); 2876 image->alpha_trait=UndefinedPixelTrait; 2877 } 2878 else 2879 { 2880 int 2881 scale_to_short; 2882 2883 scale_to_short = 65535L/((1UL << ping_file_depth)-1); 2884 2885 /* Scale transparent_color to short */ 2886 transparent_color.red= scale_to_short*ping_trans_color->red; 2887 transparent_color.green= scale_to_short*ping_trans_color->green; 2888 transparent_color.blue= scale_to_short*ping_trans_color->blue; 2889 transparent_color.alpha= scale_to_short*ping_trans_color->gray; 2890 2891 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 2892 { 2893 if (logging != MagickFalse) 2894 { 2895 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2896 " Raw tRNS graylevel = %d, scaled graylevel = %d.", 2897 (int) ping_trans_color->gray,(int) transparent_color.alpha); 2898 2899 } 2900 transparent_color.red=transparent_color.alpha; 2901 transparent_color.green=transparent_color.alpha; 2902 transparent_color.blue=transparent_color.alpha; 2903 } 2904 } 2905 } 2906#if defined(PNG_READ_sBIT_SUPPORTED) 2907 if (mng_info->have_global_sbit) 2908 { 2909 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT)) 2910 png_set_sBIT(ping,ping_info,&mng_info->global_sbit); 2911 } 2912#endif 2913 num_passes=png_set_interlace_handling(ping); 2914 2915 png_read_update_info(ping,ping_info); 2916 2917 ping_rowbytes=png_get_rowbytes(ping,ping_info); 2918 2919 /* 2920 Initialize image structure. 2921 */ 2922 mng_info->image_box.left=0; 2923 mng_info->image_box.right=(ssize_t) ping_width; 2924 mng_info->image_box.top=0; 2925 mng_info->image_box.bottom=(ssize_t) ping_height; 2926 if (mng_info->mng_type == 0) 2927 { 2928 mng_info->mng_width=ping_width; 2929 mng_info->mng_height=ping_height; 2930 mng_info->frame=mng_info->image_box; 2931 mng_info->clip=mng_info->image_box; 2932 } 2933 2934 else 2935 { 2936 image->page.y=mng_info->y_off[mng_info->object_id]; 2937 } 2938 2939 image->compression=ZipCompression; 2940 image->columns=ping_width; 2941 image->rows=ping_height; 2942 2943 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 2944 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) 2945 { 2946 double 2947 image_gamma = image->gamma; 2948 2949 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2950 " image->gamma=%f",(float) image_gamma); 2951 2952 if (image_gamma > 0.75) 2953 { 2954 /* Set image->rendering_intent to Undefined, 2955 * image->colorspace to GRAY, and reset image->chromaticity. 2956 */ 2957 image->intensity = Rec709LuminancePixelIntensityMethod; 2958 SetImageColorspace(image,GRAYColorspace,exception); 2959 } 2960 else 2961 { 2962 RenderingIntent 2963 save_rendering_intent = image->rendering_intent; 2964 ChromaticityInfo 2965 save_chromaticity = image->chromaticity; 2966 2967 SetImageColorspace(image,GRAYColorspace,exception); 2968 image->rendering_intent = save_rendering_intent; 2969 image->chromaticity = save_chromaticity; 2970 } 2971 2972 image->gamma = image_gamma; 2973 } 2974 2975 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2976 " image->colorspace=%d",(int) image->colorspace); 2977 2978 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) || 2979 ((int) ping_bit_depth < 16 && 2980 (int) ping_color_type == PNG_COLOR_TYPE_GRAY)) 2981 { 2982 size_t 2983 one; 2984 2985 image->storage_class=PseudoClass; 2986 one=1; 2987 image->colors=one << ping_file_depth; 2988#if (MAGICKCORE_QUANTUM_DEPTH == 8) 2989 if (image->colors > 256) 2990 image->colors=256; 2991#else 2992 if (image->colors > 65536L) 2993 image->colors=65536L; 2994#endif 2995 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 2996 { 2997 png_colorp 2998 palette; 2999 3000 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 3001 image->colors=(size_t) number_colors; 3002 3003 if (logging != MagickFalse) 3004 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3005 " Reading PNG PLTE chunk: number_colors: %d.",number_colors); 3006 } 3007 } 3008 3009 if (image->storage_class == PseudoClass) 3010 { 3011 /* 3012 Initialize image colormap. 3013 */ 3014 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 3015 png_error(ping,"Memory allocation failed"); 3016 3017 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3018 { 3019 png_colorp 3020 palette; 3021 3022 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 3023 3024 for (i=0; i < (ssize_t) number_colors; i++) 3025 { 3026 image->colormap[i].red=ScaleCharToQuantum(palette[i].red); 3027 image->colormap[i].green=ScaleCharToQuantum(palette[i].green); 3028 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue); 3029 } 3030 3031 for ( ; i < (ssize_t) image->colors; i++) 3032 { 3033 image->colormap[i].red=0; 3034 image->colormap[i].green=0; 3035 image->colormap[i].blue=0; 3036 } 3037 } 3038 3039 else 3040 { 3041 Quantum 3042 scale; 3043 3044 scale = (Quantum) ((65535UL)/((1UL << ping_file_depth)-1)); 3045 3046#if (MAGICKCORE_QUANTUM_DEPTH > 16) 3047 scale = ScaleShortToQuantum(scale); 3048#endif 3049 3050 for (i=0; i < (ssize_t) image->colors; i++) 3051 { 3052 image->colormap[i].red=(Quantum) (i*scale); 3053 image->colormap[i].green=(Quantum) (i*scale); 3054 image->colormap[i].blue=(Quantum) (i*scale); 3055 } 3056 } 3057 } 3058 3059 /* Set some properties for reporting by "identify" */ 3060 { 3061 char 3062 msg[MagickPathExtent]; 3063 3064 /* encode ping_width, ping_height, ping_file_depth, ping_color_type, 3065 ping_interlace_method in value */ 3066 3067 (void) FormatLocaleString(msg,MagickPathExtent, 3068 "%d, %d",(int) ping_width, (int) ping_height); 3069 (void) SetImageProperty(image,"png:IHDR.width,height",msg,exception); 3070 3071 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_file_depth); 3072 (void) SetImageProperty(image,"png:IHDR.bit_depth",msg,exception); 3073 3074 (void) FormatLocaleString(msg,MagickPathExtent,"%d (%s)", 3075 (int) ping_color_type, 3076 Magick_ColorType_from_PNG_ColorType((int)ping_color_type)); 3077 (void) SetImageProperty(image,"png:IHDR.color_type",msg,exception); 3078 3079 if (ping_interlace_method == 0) 3080 { 3081 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Not interlaced)", 3082 (int) ping_interlace_method); 3083 } 3084 else if (ping_interlace_method == 1) 3085 { 3086 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Adam7 method)", 3087 (int) ping_interlace_method); 3088 } 3089 else 3090 { 3091 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Unknown method)", 3092 (int) ping_interlace_method); 3093 } 3094 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception); 3095 3096 if (number_colors != 0) 3097 { 3098 (void) FormatLocaleString(msg,MagickPathExtent,"%d", 3099 (int) number_colors); 3100 (void) SetImageProperty(image,"png:PLTE.number_colors",msg, 3101 exception); 3102 } 3103 } 3104#if defined(PNG_tIME_SUPPORTED) 3105 read_tIME_chunk(image,ping,ping_info,exception); 3106#endif 3107 3108 3109 /* 3110 Read image scanlines. 3111 */ 3112 if (image->delay != 0) 3113 mng_info->scenes_found++; 3114 3115 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || ( 3116 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t) 3117 (image_info->first_scene+image_info->number_scenes)))) 3118 { 3119 /* This happens later in non-ping decodes */ 3120 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3121 image->storage_class=DirectClass; 3122 image->alpha_trait= 3123 (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3124 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3125 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3126 BlendPixelTrait : UndefinedPixelTrait; 3127 3128 if (logging != MagickFalse) 3129 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3130 " Skipping PNG image data for scene %.20g",(double) 3131 mng_info->scenes_found-1); 3132 png_destroy_read_struct(&ping,&ping_info,&end_info); 3133 3134#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3135 UnlockSemaphoreInfo(ping_semaphore); 3136#endif 3137 3138 if (logging != MagickFalse) 3139 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3140 " exit ReadOnePNGImage()."); 3141 3142 return(image); 3143 } 3144 3145 if (logging != MagickFalse) 3146 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3147 " Reading PNG IDAT chunk(s)"); 3148 3149 status=SetImageExtent(image,image->columns,image->rows,exception); 3150 if (status == MagickFalse) 3151 return(DestroyImageList(image)); 3152 3153 if (num_passes > 1) 3154 pixel_info=AcquireVirtualMemory(image->rows,ping_rowbytes* 3155 sizeof(*ping_pixels)); 3156 else 3157 pixel_info=AcquireVirtualMemory(ping_rowbytes,sizeof(*ping_pixels)); 3158 3159 if (pixel_info == (MemoryInfo *) NULL) 3160 png_error(ping,"Memory allocation failed"); 3161 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 3162 3163 if (logging != MagickFalse) 3164 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3165 " Converting PNG pixels to pixel packets"); 3166 /* 3167 Convert PNG pixels to pixel packets. 3168 */ 3169 quantum_info=AcquireQuantumInfo(image_info,image); 3170 3171 if (quantum_info == (QuantumInfo *) NULL) 3172 png_error(ping,"Failed to allocate quantum_info"); 3173 3174 (void) SetQuantumEndian(image,quantum_info,MSBEndian); 3175 3176 { 3177 3178 MagickBooleanType 3179 found_transparent_pixel; 3180 3181 found_transparent_pixel=MagickFalse; 3182 3183 if (image->storage_class == DirectClass) 3184 { 3185 for (pass=0; pass < num_passes; pass++) 3186 { 3187 /* 3188 Convert image to DirectClass pixel packets. 3189 */ 3190 image->alpha_trait= 3191 (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3192 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3193 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3194 BlendPixelTrait : UndefinedPixelTrait; 3195 3196 for (y=0; y < (ssize_t) image->rows; y++) 3197 { 3198 if (num_passes > 1) 3199 row_offset=ping_rowbytes*y; 3200 3201 else 3202 row_offset=0; 3203 3204 png_read_row(ping,ping_pixels+row_offset,NULL); 3205 3206 if (pass < num_passes-1) 3207 continue; 3208 3209 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3210 3211 if (q == (Quantum *) NULL) 3212 break; 3213 3214 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY) 3215 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3216 GrayQuantum,ping_pixels+row_offset,exception); 3217 3218 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 3219 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3220 GrayAlphaQuantum,ping_pixels+row_offset,exception); 3221 3222 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 3223 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3224 RGBAQuantum,ping_pixels+row_offset,exception); 3225 3226 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3227 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3228 IndexQuantum,ping_pixels+row_offset,exception); 3229 3230 else /* ping_color_type == PNG_COLOR_TYPE_RGB */ 3231 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3232 RGBQuantum,ping_pixels+row_offset,exception); 3233 3234 if (found_transparent_pixel == MagickFalse) 3235 { 3236 /* Is there a transparent pixel in the row? */ 3237 if (y== 0 && logging != MagickFalse) 3238 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3239 " Looking for cheap transparent pixel"); 3240 3241 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3242 { 3243 if ((ping_color_type == PNG_COLOR_TYPE_RGBA || 3244 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && 3245 (GetPixelAlpha(image,q) != OpaqueAlpha)) 3246 { 3247 if (logging != MagickFalse) 3248 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3249 " ...got one."); 3250 3251 found_transparent_pixel = MagickTrue; 3252 break; 3253 } 3254 if ((ping_color_type == PNG_COLOR_TYPE_RGB || 3255 ping_color_type == PNG_COLOR_TYPE_GRAY) && 3256 (ScaleQuantumToShort(GetPixelRed(image,q)) == 3257 transparent_color.red && 3258 ScaleQuantumToShort(GetPixelGreen(image,q)) == 3259 transparent_color.green && 3260 ScaleQuantumToShort(GetPixelBlue(image,q)) == 3261 transparent_color.blue)) 3262 { 3263 if (logging != MagickFalse) 3264 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3265 " ...got one."); 3266 found_transparent_pixel = MagickTrue; 3267 break; 3268 } 3269 q+=GetPixelChannels(image); 3270 } 3271 } 3272 3273 if (num_passes == 1) 3274 { 3275 status=SetImageProgress(image,LoadImageTag, 3276 (MagickOffsetType) y, image->rows); 3277 3278 if (status == MagickFalse) 3279 break; 3280 } 3281 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3282 break; 3283 } 3284 3285 if (num_passes != 1) 3286 { 3287 status=SetImageProgress(image,LoadImageTag,pass,num_passes); 3288 if (status == MagickFalse) 3289 break; 3290 } 3291 } 3292 } 3293 3294 else /* image->storage_class != DirectClass */ 3295 3296 for (pass=0; pass < num_passes; pass++) 3297 { 3298 Quantum 3299 *quantum_scanline; 3300 3301 register Quantum 3302 *r; 3303 3304 /* 3305 Convert grayscale image to PseudoClass pixel packets. 3306 */ 3307 if (logging != MagickFalse) 3308 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3309 " Converting grayscale pixels to pixel packets"); 3310 3311 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ? 3312 BlendPixelTrait : UndefinedPixelTrait; 3313 3314 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns, 3315 (image->alpha_trait == BlendPixelTrait? 2 : 1)* 3316 sizeof(*quantum_scanline)); 3317 3318 if (quantum_scanline == (Quantum *) NULL) 3319 png_error(ping,"Memory allocation failed"); 3320 3321 for (y=0; y < (ssize_t) image->rows; y++) 3322 { 3323 Quantum 3324 alpha; 3325 3326 if (num_passes > 1) 3327 row_offset=ping_rowbytes*y; 3328 3329 else 3330 row_offset=0; 3331 3332 png_read_row(ping,ping_pixels+row_offset,NULL); 3333 3334 if (pass < num_passes-1) 3335 continue; 3336 3337 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 3338 3339 if (q == (Quantum *) NULL) 3340 break; 3341 3342 p=ping_pixels+row_offset; 3343 r=quantum_scanline; 3344 3345 switch (ping_bit_depth) 3346 { 3347 case 8: 3348 { 3349 3350 if (ping_color_type == 4) 3351 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3352 { 3353 *r++=*p++; 3354 3355 alpha=ScaleCharToQuantum((unsigned char)*p++); 3356 3357 SetPixelAlpha(image,alpha,q); 3358 3359 if (alpha != OpaqueAlpha) 3360 found_transparent_pixel = MagickTrue; 3361 3362 q+=GetPixelChannels(image); 3363 } 3364 3365 else 3366 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3367 *r++=*p++; 3368 3369 break; 3370 } 3371 3372 case 16: 3373 { 3374 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3375 { 3376#if (MAGICKCORE_QUANTUM_DEPTH >= 16) 3377 unsigned short 3378 quantum; 3379 3380 if (image->colors > 256) 3381 quantum=((*p++) << 8); 3382 3383 else 3384 quantum=0; 3385 3386 quantum|=(*p++); 3387 *r=ScaleShortToQuantum(quantum); 3388 r++; 3389 3390 if (ping_color_type == 4) 3391 { 3392 if (image->colors > 256) 3393 quantum=((*p++) << 8); 3394 else 3395 quantum=0; 3396 3397 quantum|=(*p++); 3398 3399 alpha=ScaleShortToQuantum(quantum); 3400 SetPixelAlpha(image,alpha,q); 3401 3402 if (alpha != OpaqueAlpha) 3403 found_transparent_pixel = MagickTrue; 3404 3405 q+=GetPixelChannels(image); 3406 } 3407 3408#else /* MAGICKCORE_QUANTUM_DEPTH == 8 */ 3409 *r++=(*p++); 3410 p++; /* strip low byte */ 3411 3412 if (ping_color_type == 4) 3413 { 3414 SetPixelAlpha(image,*p++,q); 3415 3416 if (GetPixelAlpha(image,q) != OpaqueAlpha) 3417 found_transparent_pixel = MagickTrue; 3418 3419 p++; 3420 q+=GetPixelChannels(image); 3421 } 3422#endif 3423 } 3424 3425 break; 3426 } 3427 3428 default: 3429 break; 3430 } 3431 3432 /* 3433 Transfer image scanline. 3434 */ 3435 r=quantum_scanline; 3436 3437 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3438 3439 if (q == (Quantum *) NULL) 3440 break; 3441 for (x=0; x < (ssize_t) image->columns; x++) 3442 { 3443 SetPixelIndex(image,*r++,q); 3444 q+=GetPixelChannels(image); 3445 } 3446 3447 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3448 break; 3449 3450 if (num_passes == 1) 3451 { 3452 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 3453 image->rows); 3454 3455 if (status == MagickFalse) 3456 break; 3457 } 3458 } 3459 3460 if (num_passes != 1) 3461 { 3462 status=SetImageProgress(image,LoadImageTag,pass,num_passes); 3463 3464 if (status == MagickFalse) 3465 break; 3466 } 3467 3468 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline); 3469 } 3470 3471 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait : 3472 UndefinedPixelTrait; 3473 3474 if (logging != MagickFalse) 3475 { 3476 if (found_transparent_pixel != MagickFalse) 3477 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3478 " Found transparent pixel"); 3479 else 3480 { 3481 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3482 " No transparent pixel was found"); 3483 3484 ping_color_type&=0x03; 3485 } 3486 } 3487 } 3488 3489 if (quantum_info != (QuantumInfo *) NULL) 3490 quantum_info=DestroyQuantumInfo(quantum_info); 3491 3492 if (image->storage_class == PseudoClass) 3493 { 3494 PixelTrait 3495 alpha_trait; 3496 3497 alpha_trait=image->alpha_trait; 3498 image->alpha_trait=UndefinedPixelTrait; 3499 (void) SyncImage(image,exception); 3500 image->alpha_trait=alpha_trait; 3501 } 3502 3503 png_read_end(ping,end_info); 3504 3505 if (logging != MagickFalse) 3506 { 3507 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3508 " image->storage_class=%d\n",(int) image->storage_class); 3509 } 3510 3511 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 < 3512 (ssize_t) image_info->first_scene && image->delay != 0) 3513 { 3514 png_destroy_read_struct(&ping,&ping_info,&end_info); 3515 pixel_info=RelinquishVirtualMemory(pixel_info); 3516 image->colors=2; 3517 (void) SetImageBackgroundColor(image,exception); 3518#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3519 UnlockSemaphoreInfo(ping_semaphore); 3520#endif 3521 if (logging != MagickFalse) 3522 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3523 " exit ReadOnePNGImage() early."); 3524 return(image); 3525 } 3526 3527 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3528 { 3529 ClassType 3530 storage_class; 3531 3532 /* 3533 Image has a transparent background. 3534 */ 3535 storage_class=image->storage_class; 3536 image->alpha_trait=BlendPixelTrait; 3537 3538/* Balfour fix from imagemagick discourse server, 5 Feb 2010 */ 3539 3540 if (storage_class == PseudoClass) 3541 { 3542 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3543 { 3544 for (x=0; x < ping_num_trans; x++) 3545 { 3546 image->colormap[x].alpha_trait=BlendPixelTrait; 3547 image->colormap[x].alpha = 3548 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]); 3549 } 3550 } 3551 3552 else if (ping_color_type == PNG_COLOR_TYPE_GRAY) 3553 { 3554 for (x=0; x < (int) image->colors; x++) 3555 { 3556 if (ScaleQuantumToShort(image->colormap[x].red) == 3557 transparent_color.alpha) 3558 { 3559 image->colormap[x].alpha_trait=BlendPixelTrait; 3560 image->colormap[x].alpha = (Quantum) TransparentAlpha; 3561 } 3562 } 3563 } 3564 (void) SyncImage(image,exception); 3565 } 3566 3567#if 1 /* Should have already been done above, but glennrp problem P10 3568 * needs this. 3569 */ 3570 else 3571 { 3572 for (y=0; y < (ssize_t) image->rows; y++) 3573 { 3574 image->storage_class=storage_class; 3575 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3576 3577 if (q == (Quantum *) NULL) 3578 break; 3579 3580 3581 /* Caution: on a Q8 build, this does not distinguish between 3582 * 16-bit colors that differ only in the low byte 3583 */ 3584 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3585 { 3586 if (ScaleQuantumToShort(GetPixelRed(image,q)) == 3587 transparent_color.red && 3588 ScaleQuantumToShort(GetPixelGreen(image,q)) == 3589 transparent_color.green && 3590 ScaleQuantumToShort(GetPixelBlue(image,q)) == 3591 transparent_color.blue) 3592 { 3593 SetPixelAlpha(image,TransparentAlpha,q); 3594 } 3595 3596#if 0 /* I have not found a case where this is needed. */ 3597 else 3598 { 3599 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha; 3600 } 3601#endif 3602 3603 q+=GetPixelChannels(image); 3604 } 3605 3606 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3607 break; 3608 } 3609 } 3610#endif 3611 3612 image->storage_class=DirectClass; 3613 } 3614 3615 for (j = 0; j < 2; j++) 3616 { 3617 if (j == 0) 3618 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ? 3619 MagickTrue : MagickFalse; 3620 else 3621 status = png_get_text(ping,end_info,&text,&num_text) != 0 ? 3622 MagickTrue : MagickFalse; 3623 3624 if (status != MagickFalse) 3625 for (i=0; i < (ssize_t) num_text; i++) 3626 { 3627 /* Check for a profile */ 3628 3629 if (logging != MagickFalse) 3630 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3631 " Reading PNG text chunk"); 3632 3633 if (strlen(text[i].key) > 16 && 3634 memcmp(text[i].key, "Raw profile type ",17) == 0) 3635 { 3636 const char 3637 *value; 3638 3639 value=GetImageOption(image_info,"profile:skip"); 3640 3641 if (IsOptionMember(text[i].key+17,value) == MagickFalse) 3642 { 3643 (void) Magick_png_read_raw_profile(ping,image,image_info,text, 3644 (int) i,exception); 3645 num_raw_profiles++; 3646 if (logging != MagickFalse) 3647 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3648 " Read raw profile %s",text[i].key+17); 3649 } 3650 else 3651 { 3652 if (logging != MagickFalse) 3653 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3654 " Skipping raw profile %s",text[i].key+17); 3655 } 3656 } 3657 3658 else 3659 { 3660 char 3661 *value; 3662 3663 length=text[i].text_length; 3664 value=(char *) AcquireQuantumMemory(length+MagickPathExtent, 3665 sizeof(*value)); 3666 if (value == (char *) NULL) 3667 { 3668 png_error(ping,"Memory allocation failed"); 3669 break; 3670 } 3671 *value='\0'; 3672 (void) ConcatenateMagickString(value,text[i].text,length+2); 3673 3674 /* Don't save "density" or "units" property if we have a pHYs 3675 * chunk 3676 */ 3677 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) || 3678 (LocaleCompare(text[i].key,"density") != 0 && 3679 LocaleCompare(text[i].key,"units") != 0)) 3680 (void) SetImageProperty(image,text[i].key,value,exception); 3681 3682 if (logging != MagickFalse) 3683 { 3684 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3685 " length: %lu\n" 3686 " Keyword: %s", 3687 (unsigned long) length, 3688 text[i].key); 3689 } 3690 3691 value=DestroyString(value); 3692 } 3693 } 3694 num_text_total += num_text; 3695 } 3696 3697#ifdef MNG_OBJECT_BUFFERS 3698 /* 3699 Store the object if necessary. 3700 */ 3701 if (object_id && !mng_info->frozen[object_id]) 3702 { 3703 if (mng_info->ob[object_id] == (MngBuffer *) NULL) 3704 { 3705 /* 3706 create a new object buffer. 3707 */ 3708 mng_info->ob[object_id]=(MngBuffer *) 3709 AcquireMagickMemory(sizeof(MngBuffer)); 3710 3711 if (mng_info->ob[object_id] != (MngBuffer *) NULL) 3712 { 3713 mng_info->ob[object_id]->image=(Image *) NULL; 3714 mng_info->ob[object_id]->reference_count=1; 3715 } 3716 } 3717 3718 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) || 3719 mng_info->ob[object_id]->frozen) 3720 { 3721 if (mng_info->ob[object_id] == (MngBuffer *) NULL) 3722 png_error(ping,"Memory allocation failed"); 3723 3724 if (mng_info->ob[object_id]->frozen) 3725 png_error(ping,"Cannot overwrite frozen MNG object buffer"); 3726 } 3727 3728 else 3729 { 3730 3731 if (mng_info->ob[object_id]->image != (Image *) NULL) 3732 mng_info->ob[object_id]->image=DestroyImage 3733 (mng_info->ob[object_id]->image); 3734 3735 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue, 3736 exception); 3737 3738 if (mng_info->ob[object_id]->image != (Image *) NULL) 3739 mng_info->ob[object_id]->image->file=(FILE *) NULL; 3740 3741 else 3742 png_error(ping, "Cloning image for object buffer failed"); 3743 3744 if (ping_width > 250000L || ping_height > 250000L) 3745 png_error(ping,"PNG Image dimensions are too large."); 3746 3747 mng_info->ob[object_id]->width=ping_width; 3748 mng_info->ob[object_id]->height=ping_height; 3749 mng_info->ob[object_id]->color_type=ping_color_type; 3750 mng_info->ob[object_id]->sample_depth=ping_bit_depth; 3751 mng_info->ob[object_id]->interlace_method=ping_interlace_method; 3752 mng_info->ob[object_id]->compression_method= 3753 ping_compression_method; 3754 mng_info->ob[object_id]->filter_method=ping_filter_method; 3755 3756 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE)) 3757 { 3758 png_colorp 3759 plte; 3760 3761 /* 3762 Copy the PLTE to the object buffer. 3763 */ 3764 png_get_PLTE(ping,ping_info,&plte,&number_colors); 3765 mng_info->ob[object_id]->plte_length=number_colors; 3766 3767 for (i=0; i < number_colors; i++) 3768 { 3769 mng_info->ob[object_id]->plte[i]=plte[i]; 3770 } 3771 } 3772 3773 else 3774 mng_info->ob[object_id]->plte_length=0; 3775 } 3776 } 3777#endif 3778 3779 /* Set image->alpha_trait to MagickTrue if the input colortype supports 3780 * alpha or if a valid tRNS chunk is present, no matter whether there 3781 * is actual transparency present. 3782 */ 3783 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3784 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3785 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3786 BlendPixelTrait : UndefinedPixelTrait; 3787 3788#if 0 /* I'm not sure what's wrong here but it does not work. */ 3789 if (image->alpha_trait != UndefinedPixelTrait) 3790 { 3791 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 3792 (void) SetImageType(image,GrayscaleAlphaType,exception); 3793 3794 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 3795 (void) SetImageType(image,PaletteAlphaType,exception); 3796 3797 else 3798 (void) SetImageType(image,TrueColorAlphaType,exception); 3799 } 3800 3801 else 3802 { 3803 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 3804 (void) SetImageType(image,GrayscaleType,exception); 3805 3806 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 3807 (void) SetImageType(image,PaletteType,exception); 3808 3809 else 3810 (void) SetImageType(image,TrueColorType,exception); 3811 } 3812#endif 3813 3814 /* Set more properties for identify to retrieve */ 3815 { 3816 char 3817 msg[MagickPathExtent]; 3818 3819 if (num_text_total != 0) 3820 { 3821 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */ 3822 (void) FormatLocaleString(msg,MagickPathExtent, 3823 "%d tEXt/zTXt/iTXt chunks were found", num_text_total); 3824 (void) SetImageProperty(image,"png:text",msg, 3825 exception); 3826 } 3827 3828 if (num_raw_profiles != 0) 3829 { 3830 (void) FormatLocaleString(msg,MagickPathExtent, 3831 "%d were found", num_raw_profiles); 3832 (void) SetImageProperty(image,"png:text-encoded profiles",msg, 3833 exception); 3834 } 3835 3836 if (ping_found_cHRM != MagickFalse) 3837 { 3838 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3839 "chunk was found (see Chromaticity, above)"); 3840 (void) SetImageProperty(image,"png:cHRM",msg, 3841 exception); 3842 } 3843 3844 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 3845 { 3846 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3847 "chunk was found (see Background color, above)"); 3848 (void) SetImageProperty(image,"png:bKGD",msg, 3849 exception); 3850 } 3851 3852 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3853 "chunk was found"); 3854 3855#if defined(PNG_iCCP_SUPPORTED) 3856 if (ping_found_iCCP != MagickFalse) 3857 (void) SetImageProperty(image,"png:iCCP",msg, 3858 exception); 3859#endif 3860 3861 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3862 (void) SetImageProperty(image,"png:tRNS",msg, 3863 exception); 3864 3865#if defined(PNG_sRGB_SUPPORTED) 3866 if (ping_found_sRGB != MagickFalse) 3867 { 3868 (void) FormatLocaleString(msg,MagickPathExtent, 3869 "intent=%d (%s)", 3870 (int) intent, 3871 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent)); 3872 (void) SetImageProperty(image,"png:sRGB",msg, 3873 exception); 3874 } 3875#endif 3876 3877 if (ping_found_gAMA != MagickFalse) 3878 { 3879 (void) FormatLocaleString(msg,MagickPathExtent, 3880 "gamma=%.8g (See Gamma, above)", 3881 file_gamma); 3882 (void) SetImageProperty(image,"png:gAMA",msg, 3883 exception); 3884 } 3885 3886#if defined(PNG_pHYs_SUPPORTED) 3887 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 3888 { 3889 (void) FormatLocaleString(msg,MagickPathExtent, 3890 "x_res=%.10g, y_res=%.10g, units=%d", 3891 (double) x_resolution,(double) y_resolution, unit_type); 3892 (void) SetImageProperty(image,"png:pHYs",msg, 3893 exception); 3894 } 3895#endif 3896 3897#if defined(PNG_oFFs_SUPPORTED) 3898 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs)) 3899 { 3900 (void) FormatLocaleString(msg,MagickPathExtent,"x_off=%.20g, y_off=%.20g", 3901 (double) image->page.x,(double) image->page.y); 3902 (void) SetImageProperty(image,"png:oFFs",msg, 3903 exception); 3904 } 3905#endif 3906 3907#if defined(PNG_tIME_SUPPORTED) 3908 read_tIME_chunk(image,ping,end_info,exception); 3909#endif 3910 3911 if ((image->page.width != 0 && image->page.width != image->columns) || 3912 (image->page.height != 0 && image->page.height != image->rows)) 3913 { 3914 (void) FormatLocaleString(msg,MagickPathExtent, 3915 "width=%.20g, height=%.20g", 3916 (double) image->page.width,(double) image->page.height); 3917 (void) SetImageProperty(image,"png:vpAg",msg, 3918 exception); 3919 } 3920 } 3921 3922 /* 3923 Relinquish resources. 3924 */ 3925 png_destroy_read_struct(&ping,&ping_info,&end_info); 3926 3927 pixel_info=RelinquishVirtualMemory(pixel_info); 3928 3929 if (logging != MagickFalse) 3930 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3931 " exit ReadOnePNGImage()"); 3932 3933#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3934 UnlockSemaphoreInfo(ping_semaphore); 3935#endif 3936 3937 /* } for navigation to beginning of SETJMP-protected block, revert to 3938 * Throwing an Exception when an error occurs. 3939 */ 3940 3941 return(image); 3942 3943/* end of reading one PNG image */ 3944} 3945 3946static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 3947{ 3948 Image 3949 *image; 3950 3951 MagickBooleanType 3952 have_mng_structure, 3953 logging, 3954 status; 3955 3956 MngInfo 3957 *mng_info; 3958 3959 char 3960 magic_number[MagickPathExtent]; 3961 3962 ssize_t 3963 count; 3964 3965 /* 3966 Open image file. 3967 */ 3968 assert(image_info != (const ImageInfo *) NULL); 3969 assert(image_info->signature == MagickCoreSignature); 3970 3971 if (image_info->debug != MagickFalse) 3972 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 3973 image_info->filename); 3974 3975 assert(exception != (ExceptionInfo *) NULL); 3976 assert(exception->signature == MagickCoreSignature); 3977 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()"); 3978 image=AcquireImage(image_info,exception); 3979 mng_info=(MngInfo *) NULL; 3980 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 3981 3982 if (status == MagickFalse) 3983 ThrowReaderException(FileOpenError,"UnableToOpenFile"); 3984 3985 /* 3986 Verify PNG signature. 3987 */ 3988 count=ReadBlob(image,8,(unsigned char *) magic_number); 3989 3990 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0) 3991 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 3992 3993 /* 3994 Allocate a MngInfo structure. 3995 */ 3996 have_mng_structure=MagickFalse; 3997 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 3998 3999 if (mng_info == (MngInfo *) NULL) 4000 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4001 4002 /* 4003 Initialize members of the MngInfo structure. 4004 */ 4005 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 4006 mng_info->image=image; 4007 have_mng_structure=MagickTrue; 4008 4009 image=ReadOnePNGImage(mng_info,image_info,exception); 4010 MngInfoFreeStruct(mng_info,&have_mng_structure); 4011 4012 if (image == (Image *) NULL) 4013 { 4014 if (logging != MagickFalse) 4015 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4016 "exit ReadPNGImage() with error"); 4017 4018 return((Image *) NULL); 4019 } 4020 4021 (void) CloseBlob(image); 4022 4023 if ((image->columns == 0) || (image->rows == 0)) 4024 { 4025 if (logging != MagickFalse) 4026 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4027 "exit ReadPNGImage() with error."); 4028 4029 ThrowReaderException(CorruptImageError,"CorruptImage"); 4030 } 4031 4032 if ((IssRGBColorspace(image->colorspace) != MagickFalse) && 4033 ((image->gamma < .45) || (image->gamma > .46)) && 4034 !(image->chromaticity.red_primary.x>0.6399f && 4035 image->chromaticity.red_primary.x<0.6401f && 4036 image->chromaticity.red_primary.y>0.3299f && 4037 image->chromaticity.red_primary.y<0.3301f && 4038 image->chromaticity.green_primary.x>0.2999f && 4039 image->chromaticity.green_primary.x<0.3001f && 4040 image->chromaticity.green_primary.y>0.5999f && 4041 image->chromaticity.green_primary.y<0.6001f && 4042 image->chromaticity.blue_primary.x>0.1499f && 4043 image->chromaticity.blue_primary.x<0.1501f && 4044 image->chromaticity.blue_primary.y>0.0599f && 4045 image->chromaticity.blue_primary.y<0.0601f && 4046 image->chromaticity.white_point.x>0.3126f && 4047 image->chromaticity.white_point.x<0.3128f && 4048 image->chromaticity.white_point.y>0.3289f && 4049 image->chromaticity.white_point.y<0.3291f)) 4050 { 4051 SetImageColorspace(image,RGBColorspace,exception); 4052 } 4053 4054 if (logging != MagickFalse) 4055 { 4056 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4057 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.", 4058 (double) image->page.width,(double) image->page.height, 4059 (double) image->page.x,(double) image->page.y); 4060 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4061 " image->colorspace: %d", (int) image->colorspace); 4062 } 4063 4064 if (logging != MagickFalse) 4065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()"); 4066 4067 return(image); 4068} 4069 4070 4071 4072#if defined(JNG_SUPPORTED) 4073/* 4074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4075% % 4076% % 4077% % 4078% R e a d O n e J N G I m a g e % 4079% % 4080% % 4081% % 4082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4083% 4084% ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file 4085% (minus the 8-byte signature) and returns it. It allocates the memory 4086% necessary for the new Image structure and returns a pointer to the new 4087% image. 4088% 4089% JNG support written by Glenn Randers-Pehrson, glennrp@image... 4090% 4091% The format of the ReadOneJNGImage method is: 4092% 4093% Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info, 4094% ExceptionInfo *exception) 4095% 4096% A description of each parameter follows: 4097% 4098% o mng_info: Specifies a pointer to a MngInfo structure. 4099% 4100% o image_info: the image info. 4101% 4102% o exception: return any errors or warnings in this structure. 4103% 4104*/ 4105static Image *ReadOneJNGImage(MngInfo *mng_info, 4106 const ImageInfo *image_info, ExceptionInfo *exception) 4107{ 4108 Image 4109 *alpha_image, 4110 *color_image, 4111 *image, 4112 *jng_image; 4113 4114 ImageInfo 4115 *alpha_image_info, 4116 *color_image_info; 4117 4118 MagickBooleanType 4119 logging; 4120 4121 ssize_t 4122 y; 4123 4124 MagickBooleanType 4125 status; 4126 4127 png_uint_32 4128 jng_height, 4129 jng_width; 4130 4131 png_byte 4132 jng_color_type, 4133 jng_image_sample_depth, 4134 jng_image_compression_method, 4135 jng_image_interlace_method, 4136 jng_alpha_sample_depth, 4137 jng_alpha_compression_method, 4138 jng_alpha_filter_method, 4139 jng_alpha_interlace_method; 4140 4141 register const Quantum 4142 *s; 4143 4144 register ssize_t 4145 i, 4146 x; 4147 4148 register Quantum 4149 *q; 4150 4151 register unsigned char 4152 *p; 4153 4154 unsigned int 4155 read_JSEP, 4156 reading_idat; 4157 4158 size_t 4159 length; 4160 4161 jng_alpha_compression_method=0; 4162 jng_alpha_sample_depth=8; 4163 jng_color_type=0; 4164 jng_height=0; 4165 jng_width=0; 4166 alpha_image=(Image *) NULL; 4167 color_image=(Image *) NULL; 4168 alpha_image_info=(ImageInfo *) NULL; 4169 color_image_info=(ImageInfo *) NULL; 4170 4171 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 4172 " Enter ReadOneJNGImage()"); 4173 4174 image=mng_info->image; 4175 4176 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 4177 { 4178 /* 4179 Allocate next image structure. 4180 */ 4181 if (logging != MagickFalse) 4182 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4183 " AcquireNextImage()"); 4184 4185 AcquireNextImage(image_info,image,exception); 4186 4187 if (GetNextImageInList(image) == (Image *) NULL) 4188 return((Image *) NULL); 4189 4190 image=SyncNextImageInList(image); 4191 } 4192 mng_info->image=image; 4193 4194 /* 4195 Signature bytes have already been read. 4196 */ 4197 4198 read_JSEP=MagickFalse; 4199 reading_idat=MagickFalse; 4200 for (;;) 4201 { 4202 char 4203 type[MagickPathExtent]; 4204 4205 unsigned char 4206 *chunk; 4207 4208 unsigned int 4209 count; 4210 4211 /* 4212 Read a new JNG chunk. 4213 */ 4214 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 4215 2*GetBlobSize(image)); 4216 4217 if (status == MagickFalse) 4218 break; 4219 4220 type[0]='\0'; 4221 (void) ConcatenateMagickString(type,"errr",MagickPathExtent); 4222 length=ReadBlobMSBLong(image); 4223 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type); 4224 4225 if (logging != MagickFalse) 4226 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4227 " Reading JNG chunk type %c%c%c%c, length: %.20g", 4228 type[0],type[1],type[2],type[3],(double) length); 4229 4230 if (length > PNG_UINT_31_MAX || count == 0) 4231 ThrowReaderException(CorruptImageError,"CorruptImage"); 4232 4233 p=NULL; 4234 chunk=(unsigned char *) NULL; 4235 4236 if (length != 0) 4237 { 4238 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); 4239 4240 if (chunk == (unsigned char *) NULL) 4241 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4242 4243 for (i=0; i < (ssize_t) length; i++) 4244 chunk[i]=(unsigned char) ReadBlobByte(image); 4245 4246 p=chunk; 4247 } 4248 4249 (void) ReadBlobMSBLong(image); /* read crc word */ 4250 4251 if (memcmp(type,mng_JHDR,4) == 0) 4252 { 4253 if (length == 16) 4254 { 4255 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 4256 (p[2] << 8) | p[3]); 4257 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 4258 (p[6] << 8) | p[7]); 4259 if ((jng_width == 0) || (jng_height == 0)) 4260 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 4261 jng_color_type=p[8]; 4262 jng_image_sample_depth=p[9]; 4263 jng_image_compression_method=p[10]; 4264 jng_image_interlace_method=p[11]; 4265 4266 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace : 4267 NoInterlace; 4268 4269 jng_alpha_sample_depth=p[12]; 4270 jng_alpha_compression_method=p[13]; 4271 jng_alpha_filter_method=p[14]; 4272 jng_alpha_interlace_method=p[15]; 4273 4274 if (logging != MagickFalse) 4275 { 4276 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4277 " jng_width: %16lu, jng_height: %16lu\n" 4278 " jng_color_type: %16d, jng_image_sample_depth: %3d\n" 4279 " jng_image_compression_method:%3d", 4280 (unsigned long) jng_width, (unsigned long) jng_height, 4281 jng_color_type, jng_image_sample_depth, 4282 jng_image_compression_method); 4283 4284 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4285 " jng_image_interlace_method: %3d" 4286 " jng_alpha_sample_depth: %3d", 4287 jng_image_interlace_method, 4288 jng_alpha_sample_depth); 4289 4290 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4291 " jng_alpha_compression_method:%3d\n" 4292 " jng_alpha_filter_method: %3d\n" 4293 " jng_alpha_interlace_method: %3d", 4294 jng_alpha_compression_method, 4295 jng_alpha_filter_method, 4296 jng_alpha_interlace_method); 4297 } 4298 } 4299 4300 if (length != 0) 4301 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4302 4303 continue; 4304 } 4305 4306 4307 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) && 4308 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) || 4309 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0))) 4310 { 4311 /* 4312 o create color_image 4313 o open color_blob, attached to color_image 4314 o if (color type has alpha) 4315 open alpha_blob, attached to alpha_image 4316 */ 4317 4318 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo)); 4319 4320 if (color_image_info == (ImageInfo *) NULL) 4321 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4322 4323 GetImageInfo(color_image_info); 4324 color_image=AcquireImage(color_image_info,exception); 4325 4326 if (color_image == (Image *) NULL) 4327 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4328 4329 if (logging != MagickFalse) 4330 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4331 " Creating color_blob."); 4332 4333 (void) AcquireUniqueFilename(color_image->filename); 4334 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode, 4335 exception); 4336 4337 if (status == MagickFalse) 4338 return((Image *) NULL); 4339 4340 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12)) 4341 { 4342 alpha_image_info=(ImageInfo *) 4343 AcquireMagickMemory(sizeof(ImageInfo)); 4344 4345 if (alpha_image_info == (ImageInfo *) NULL) 4346 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4347 4348 GetImageInfo(alpha_image_info); 4349 alpha_image=AcquireImage(alpha_image_info,exception); 4350 4351 if (alpha_image == (Image *) NULL) 4352 { 4353 alpha_image=DestroyImage(alpha_image); 4354 ThrowReaderException(ResourceLimitError, 4355 "MemoryAllocationFailed"); 4356 } 4357 4358 if (logging != MagickFalse) 4359 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4360 " Creating alpha_blob."); 4361 4362 (void) AcquireUniqueFilename(alpha_image->filename); 4363 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode, 4364 exception); 4365 4366 if (status == MagickFalse) 4367 return((Image *) NULL); 4368 4369 if (jng_alpha_compression_method == 0) 4370 { 4371 unsigned char 4372 data[18]; 4373 4374 if (logging != MagickFalse) 4375 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4376 " Writing IHDR chunk to alpha_blob."); 4377 4378 (void) WriteBlob(alpha_image,8,(const unsigned char *) 4379 "\211PNG\r\n\032\n"); 4380 4381 (void) WriteBlobMSBULong(alpha_image,13L); 4382 PNGType(data,mng_IHDR); 4383 LogPNGChunk(logging,mng_IHDR,13L); 4384 PNGLong(data+4,jng_width); 4385 PNGLong(data+8,jng_height); 4386 data[12]=jng_alpha_sample_depth; 4387 data[13]=0; /* color_type gray */ 4388 data[14]=0; /* compression method 0 */ 4389 data[15]=0; /* filter_method 0 */ 4390 data[16]=0; /* interlace_method 0 */ 4391 (void) WriteBlob(alpha_image,17,data); 4392 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17)); 4393 } 4394 } 4395 reading_idat=MagickTrue; 4396 } 4397 4398 if (memcmp(type,mng_JDAT,4) == 0) 4399 { 4400 /* Copy chunk to color_image->blob */ 4401 4402 if (logging != MagickFalse) 4403 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4404 " Copying JDAT chunk data to color_blob."); 4405 4406 (void) WriteBlob(color_image,length,chunk); 4407 4408 if (length != 0) 4409 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4410 4411 continue; 4412 } 4413 4414 if (memcmp(type,mng_IDAT,4) == 0) 4415 { 4416 png_byte 4417 data[5]; 4418 4419 /* Copy IDAT header and chunk data to alpha_image->blob */ 4420 4421 if (alpha_image != NULL && image_info->ping == MagickFalse) 4422 { 4423 if (logging != MagickFalse) 4424 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4425 " Copying IDAT chunk data to alpha_blob."); 4426 4427 (void) WriteBlobMSBULong(alpha_image,(size_t) length); 4428 PNGType(data,mng_IDAT); 4429 LogPNGChunk(logging,mng_IDAT,length); 4430 (void) WriteBlob(alpha_image,4,data); 4431 (void) WriteBlob(alpha_image,length,chunk); 4432 (void) WriteBlobMSBULong(alpha_image, 4433 crc32(crc32(0,data,4),chunk,(uInt) length)); 4434 } 4435 4436 if (length != 0) 4437 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4438 4439 continue; 4440 } 4441 4442 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0)) 4443 { 4444 /* Copy chunk data to alpha_image->blob */ 4445 4446 if (alpha_image != NULL && image_info->ping == MagickFalse) 4447 { 4448 if (logging != MagickFalse) 4449 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4450 " Copying JDAA chunk data to alpha_blob."); 4451 4452 (void) WriteBlob(alpha_image,length,chunk); 4453 } 4454 4455 if (length != 0) 4456 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4457 4458 continue; 4459 } 4460 4461 if (memcmp(type,mng_JSEP,4) == 0) 4462 { 4463 read_JSEP=MagickTrue; 4464 4465 if (length != 0) 4466 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4467 4468 continue; 4469 } 4470 4471 if (memcmp(type,mng_bKGD,4) == 0) 4472 { 4473 if (length == 2) 4474 { 4475 image->background_color.red=ScaleCharToQuantum(p[1]); 4476 image->background_color.green=image->background_color.red; 4477 image->background_color.blue=image->background_color.red; 4478 } 4479 4480 if (length == 6) 4481 { 4482 image->background_color.red=ScaleCharToQuantum(p[1]); 4483 image->background_color.green=ScaleCharToQuantum(p[3]); 4484 image->background_color.blue=ScaleCharToQuantum(p[5]); 4485 } 4486 4487 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4488 continue; 4489 } 4490 4491 if (memcmp(type,mng_gAMA,4) == 0) 4492 { 4493 if (length == 4) 4494 image->gamma=((float) mng_get_long(p))*0.00001; 4495 4496 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4497 continue; 4498 } 4499 4500 if (memcmp(type,mng_cHRM,4) == 0) 4501 { 4502 if (length == 32) 4503 { 4504 image->chromaticity.white_point.x=0.00001*mng_get_long(p); 4505 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]); 4506 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]); 4507 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]); 4508 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]); 4509 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]); 4510 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]); 4511 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]); 4512 } 4513 4514 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4515 continue; 4516 } 4517 4518 if (memcmp(type,mng_sRGB,4) == 0) 4519 { 4520 if (length == 1) 4521 { 4522 image->rendering_intent= 4523 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]); 4524 image->gamma=1.000f/2.200f; 4525 image->chromaticity.red_primary.x=0.6400f; 4526 image->chromaticity.red_primary.y=0.3300f; 4527 image->chromaticity.green_primary.x=0.3000f; 4528 image->chromaticity.green_primary.y=0.6000f; 4529 image->chromaticity.blue_primary.x=0.1500f; 4530 image->chromaticity.blue_primary.y=0.0600f; 4531 image->chromaticity.white_point.x=0.3127f; 4532 image->chromaticity.white_point.y=0.3290f; 4533 } 4534 4535 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4536 continue; 4537 } 4538 4539 if (memcmp(type,mng_oFFs,4) == 0) 4540 { 4541 if (length > 8) 4542 { 4543 image->page.x=(ssize_t) mng_get_long(p); 4544 image->page.y=(ssize_t) mng_get_long(&p[4]); 4545 4546 if ((int) p[8] != 0) 4547 { 4548 image->page.x/=10000; 4549 image->page.y/=10000; 4550 } 4551 } 4552 4553 if (length != 0) 4554 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4555 4556 continue; 4557 } 4558 4559 if (memcmp(type,mng_pHYs,4) == 0) 4560 { 4561 if (length > 8) 4562 { 4563 image->resolution.x=(double) mng_get_long(p); 4564 image->resolution.y=(double) mng_get_long(&p[4]); 4565 if ((int) p[8] == PNG_RESOLUTION_METER) 4566 { 4567 image->units=PixelsPerCentimeterResolution; 4568 image->resolution.x=image->resolution.x/100.0f; 4569 image->resolution.y=image->resolution.y/100.0f; 4570 } 4571 } 4572 4573 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4574 continue; 4575 } 4576 4577#if 0 4578 if (memcmp(type,mng_iCCP,4) == 0) 4579 { 4580 /* To do: */ 4581 if (length != 0) 4582 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4583 4584 continue; 4585 } 4586#endif 4587 4588 if (length != 0) 4589 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4590 4591 if (memcmp(type,mng_IEND,4)) 4592 continue; 4593 4594 break; 4595 } 4596 4597 4598 /* IEND found */ 4599 4600 /* 4601 Finish up reading image data: 4602 4603 o read main image from color_blob. 4604 4605 o close color_blob. 4606 4607 o if (color_type has alpha) 4608 if alpha_encoding is PNG 4609 read secondary image from alpha_blob via ReadPNG 4610 if alpha_encoding is JPEG 4611 read secondary image from alpha_blob via ReadJPEG 4612 4613 o close alpha_blob. 4614 4615 o copy intensity of secondary image into 4616 alpha samples of main image. 4617 4618 o destroy the secondary image. 4619 */ 4620 4621 if (color_image_info == (ImageInfo *) NULL) 4622 { 4623 assert(color_image == (Image *) NULL); 4624 assert(alpha_image == (Image *) NULL); 4625 return((Image *) NULL); 4626 } 4627 4628 if (color_image == (Image *) NULL) 4629 { 4630 assert(alpha_image == (Image *) NULL); 4631 return((Image *) NULL); 4632 } 4633 4634 (void) SeekBlob(color_image,0,SEEK_SET); 4635 4636 if (logging != MagickFalse) 4637 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4638 " Reading jng_image from color_blob."); 4639 4640 assert(color_image_info != (ImageInfo *) NULL); 4641 (void) FormatLocaleString(color_image_info->filename,MagickPathExtent,"%s", 4642 color_image->filename); 4643 4644 color_image_info->ping=MagickFalse; /* To do: avoid this */ 4645 jng_image=ReadImage(color_image_info,exception); 4646 4647 (void) RelinquishUniqueFileResource(color_image->filename); 4648 color_image=DestroyImage(color_image); 4649 color_image_info=DestroyImageInfo(color_image_info); 4650 4651 if (jng_image == (Image *) NULL) 4652 return((Image *) NULL); 4653 4654 if (logging != MagickFalse) 4655 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4656 " Copying jng_image pixels to main image."); 4657 4658 image->rows=jng_height; 4659 image->columns=jng_width; 4660 4661 status=SetImageExtent(image,image->columns,image->rows,exception); 4662 if (status == MagickFalse) 4663 return(DestroyImageList(image)); 4664 4665 for (y=0; y < (ssize_t) image->rows; y++) 4666 { 4667 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception); 4668 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 4669 for (x=(ssize_t) image->columns; x != 0; x--) 4670 { 4671 SetPixelRed(image,GetPixelRed(jng_image,s),q); 4672 SetPixelGreen(image,GetPixelGreen(jng_image,s),q); 4673 SetPixelBlue(image,GetPixelBlue(jng_image,s),q); 4674 q+=GetPixelChannels(image); 4675 s+=GetPixelChannels(jng_image); 4676 } 4677 4678 if (SyncAuthenticPixels(image,exception) == MagickFalse) 4679 break; 4680 } 4681 4682 jng_image=DestroyImage(jng_image); 4683 4684 if (image_info->ping == MagickFalse) 4685 { 4686 if (jng_color_type >= 12) 4687 { 4688 if (jng_alpha_compression_method == 0) 4689 { 4690 png_byte 4691 data[5]; 4692 (void) WriteBlobMSBULong(alpha_image,0x00000000L); 4693 PNGType(data,mng_IEND); 4694 LogPNGChunk(logging,mng_IEND,0L); 4695 (void) WriteBlob(alpha_image,4,data); 4696 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4)); 4697 } 4698 4699 (void) CloseBlob(alpha_image); 4700 4701 if (logging != MagickFalse) 4702 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4703 " Reading alpha from alpha_blob."); 4704 4705 (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent, 4706 "%s",alpha_image->filename); 4707 4708 jng_image=ReadImage(alpha_image_info,exception); 4709 4710 if (jng_image != (Image *) NULL) 4711 for (y=0; y < (ssize_t) image->rows; y++) 4712 { 4713 s=GetVirtualPixels(jng_image,0,y,image->columns,1, 4714 exception); 4715 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 4716 4717 if (image->alpha_trait != UndefinedPixelTrait) 4718 for (x=(ssize_t) image->columns; x != 0; x--) 4719 { 4720 SetPixelAlpha(image,GetPixelRed(jng_image,s),q); 4721 q+=GetPixelChannels(image); 4722 s+=GetPixelChannels(jng_image); 4723 } 4724 4725 else 4726 for (x=(ssize_t) image->columns; x != 0; x--) 4727 { 4728 SetPixelAlpha(image,GetPixelRed(jng_image,s),q); 4729 if (GetPixelAlpha(image,q) != OpaqueAlpha) 4730 image->alpha_trait=BlendPixelTrait; 4731 q+=GetPixelChannels(image); 4732 s+=GetPixelChannels(jng_image); 4733 } 4734 4735 if (SyncAuthenticPixels(image,exception) == MagickFalse) 4736 break; 4737 } 4738 (void) RelinquishUniqueFileResource(alpha_image->filename); 4739 alpha_image=DestroyImage(alpha_image); 4740 alpha_image_info=DestroyImageInfo(alpha_image_info); 4741 if (jng_image != (Image *) NULL) 4742 jng_image=DestroyImage(jng_image); 4743 } 4744 } 4745 4746 /* Read the JNG image. */ 4747 4748 if (mng_info->mng_type == 0) 4749 { 4750 mng_info->mng_width=jng_width; 4751 mng_info->mng_height=jng_height; 4752 } 4753 4754 if (image->page.width == 0 && image->page.height == 0) 4755 { 4756 image->page.width=jng_width; 4757 image->page.height=jng_height; 4758 } 4759 4760 if (image->page.x == 0 && image->page.y == 0) 4761 { 4762 image->page.x=mng_info->x_off[mng_info->object_id]; 4763 image->page.y=mng_info->y_off[mng_info->object_id]; 4764 } 4765 4766 else 4767 { 4768 image->page.y=mng_info->y_off[mng_info->object_id]; 4769 } 4770 4771 mng_info->image_found++; 4772 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image), 4773 2*GetBlobSize(image)); 4774 4775 if (status == MagickFalse) 4776 return((Image *) NULL); 4777 4778 if (logging != MagickFalse) 4779 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4780 " exit ReadOneJNGImage()"); 4781 4782 return(image); 4783} 4784 4785/* 4786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4787% % 4788% % 4789% % 4790% R e a d J N G I m a g e % 4791% % 4792% % 4793% % 4794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4795% 4796% ReadJNGImage() reads a JPEG Network Graphics (JNG) image file 4797% (including the 8-byte signature) and returns it. It allocates the memory 4798% necessary for the new Image structure and returns a pointer to the new 4799% image. 4800% 4801% JNG support written by Glenn Randers-Pehrson, glennrp@image... 4802% 4803% The format of the ReadJNGImage method is: 4804% 4805% Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo 4806% *exception) 4807% 4808% A description of each parameter follows: 4809% 4810% o image_info: the image info. 4811% 4812% o exception: return any errors or warnings in this structure. 4813% 4814*/ 4815 4816static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 4817{ 4818 Image 4819 *image; 4820 4821 MagickBooleanType 4822 have_mng_structure, 4823 logging, 4824 status; 4825 4826 MngInfo 4827 *mng_info; 4828 4829 char 4830 magic_number[MagickPathExtent]; 4831 4832 size_t 4833 count; 4834 4835 /* 4836 Open image file. 4837 */ 4838 assert(image_info != (const ImageInfo *) NULL); 4839 assert(image_info->signature == MagickCoreSignature); 4840 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename); 4841 assert(exception != (ExceptionInfo *) NULL); 4842 assert(exception->signature == MagickCoreSignature); 4843 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()"); 4844 image=AcquireImage(image_info,exception); 4845 mng_info=(MngInfo *) NULL; 4846 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 4847 4848 if (status == MagickFalse) 4849 return((Image *) NULL); 4850 4851 if (LocaleCompare(image_info->magick,"JNG") != 0) 4852 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 4853 4854 /* Verify JNG signature. */ 4855 4856 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number); 4857 4858 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0) 4859 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 4860 4861 /* Allocate a MngInfo structure. */ 4862 4863 have_mng_structure=MagickFalse; 4864 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info)); 4865 4866 if (mng_info == (MngInfo *) NULL) 4867 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4868 4869 /* Initialize members of the MngInfo structure. */ 4870 4871 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 4872 have_mng_structure=MagickTrue; 4873 4874 mng_info->image=image; 4875 image=ReadOneJNGImage(mng_info,image_info,exception); 4876 MngInfoFreeStruct(mng_info,&have_mng_structure); 4877 4878 if (image == (Image *) NULL) 4879 { 4880 if (logging != MagickFalse) 4881 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4882 "exit ReadJNGImage() with error"); 4883 4884 return((Image *) NULL); 4885 } 4886 (void) CloseBlob(image); 4887 4888 if (image->columns == 0 || image->rows == 0) 4889 { 4890 if (logging != MagickFalse) 4891 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4892 "exit ReadJNGImage() with error"); 4893 4894 ThrowReaderException(CorruptImageError,"CorruptImage"); 4895 } 4896 4897 if (logging != MagickFalse) 4898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()"); 4899 4900 return(image); 4901} 4902#endif 4903 4904static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 4905{ 4906 char 4907 page_geometry[MagickPathExtent]; 4908 4909 Image 4910 *image; 4911 4912 MagickBooleanType 4913 logging, 4914 have_mng_structure; 4915 4916 volatile int 4917 first_mng_object, 4918 object_id, 4919 term_chunk_found, 4920 skip_to_iend; 4921 4922 volatile ssize_t 4923 image_count=0; 4924 4925 MagickBooleanType 4926 status; 4927 4928 MagickOffsetType 4929 offset; 4930 4931 MngInfo 4932 *mng_info; 4933 4934 MngBox 4935 default_fb, 4936 fb, 4937 previous_fb; 4938 4939#if defined(MNG_INSERT_LAYERS) 4940 PixelInfo 4941 mng_background_color; 4942#endif 4943 4944 register unsigned char 4945 *p; 4946 4947 register ssize_t 4948 i; 4949 4950 size_t 4951 count; 4952 4953 ssize_t 4954 loop_level; 4955 4956 volatile short 4957 skipping_loop; 4958 4959#if defined(MNG_INSERT_LAYERS) 4960 unsigned int 4961 mandatory_back=0; 4962#endif 4963 4964 volatile unsigned int 4965#ifdef MNG_OBJECT_BUFFERS 4966 mng_background_object=0, 4967#endif 4968 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */ 4969 4970 size_t 4971 default_frame_timeout, 4972 frame_timeout, 4973#if defined(MNG_INSERT_LAYERS) 4974 image_height, 4975 image_width, 4976#endif 4977 length; 4978 4979 /* These delays are all measured in image ticks_per_second, 4980 * not in MNG ticks_per_second 4981 */ 4982 volatile size_t 4983 default_frame_delay, 4984 final_delay, 4985 final_image_delay, 4986 frame_delay, 4987#if defined(MNG_INSERT_LAYERS) 4988 insert_layers, 4989#endif 4990 mng_iterations=1, 4991 simplicity=0, 4992 subframe_height=0, 4993 subframe_width=0; 4994 4995 previous_fb.top=0; 4996 previous_fb.bottom=0; 4997 previous_fb.left=0; 4998 previous_fb.right=0; 4999 default_fb.top=0; 5000 default_fb.bottom=0; 5001 default_fb.left=0; 5002 default_fb.right=0; 5003 5004 /* Open image file. */ 5005 5006 assert(image_info != (const ImageInfo *) NULL); 5007 assert(image_info->signature == MagickCoreSignature); 5008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename); 5009 assert(exception != (ExceptionInfo *) NULL); 5010 assert(exception->signature == MagickCoreSignature); 5011 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()"); 5012 image=AcquireImage(image_info,exception); 5013 mng_info=(MngInfo *) NULL; 5014 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 5015 5016 if (status == MagickFalse) 5017 return((Image *) NULL); 5018 5019 first_mng_object=MagickFalse; 5020 skipping_loop=(-1); 5021 have_mng_structure=MagickFalse; 5022 5023 /* Allocate a MngInfo structure. */ 5024 5025 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 5026 5027 if (mng_info == (MngInfo *) NULL) 5028 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 5029 5030 /* Initialize members of the MngInfo structure. */ 5031 5032 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 5033 mng_info->image=image; 5034 have_mng_structure=MagickTrue; 5035 5036 if (LocaleCompare(image_info->magick,"MNG") == 0) 5037 { 5038 char 5039 magic_number[MagickPathExtent]; 5040 5041 /* Verify MNG signature. */ 5042 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number); 5043 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0) 5044 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 5045 5046 /* Initialize some nonzero members of the MngInfo structure. */ 5047 for (i=0; i < MNG_MAX_OBJECTS; i++) 5048 { 5049 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX; 5050 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX; 5051 } 5052 mng_info->exists[0]=MagickTrue; 5053 } 5054 5055 first_mng_object=MagickTrue; 5056 mng_type=0; 5057#if defined(MNG_INSERT_LAYERS) 5058 insert_layers=MagickFalse; /* should be False when converting or mogrifying */ 5059#endif 5060 default_frame_delay=0; 5061 default_frame_timeout=0; 5062 frame_delay=0; 5063 final_delay=1; 5064 mng_info->ticks_per_second=1UL*image->ticks_per_second; 5065 object_id=0; 5066 skip_to_iend=MagickFalse; 5067 term_chunk_found=MagickFalse; 5068 mng_info->framing_mode=1; 5069#if defined(MNG_INSERT_LAYERS) 5070 mandatory_back=MagickFalse; 5071#endif 5072#if defined(MNG_INSERT_LAYERS) 5073 mng_background_color=image->background_color; 5074#endif 5075 default_fb=mng_info->frame; 5076 previous_fb=mng_info->frame; 5077 do 5078 { 5079 char 5080 type[MagickPathExtent]; 5081 5082 if (LocaleCompare(image_info->magick,"MNG") == 0) 5083 { 5084 unsigned char 5085 *chunk; 5086 5087 /* 5088 Read a new chunk. 5089 */ 5090 type[0]='\0'; 5091 (void) ConcatenateMagickString(type,"errr",MagickPathExtent); 5092 length=ReadBlobMSBLong(image); 5093 count=(size_t) ReadBlob(image,4,(unsigned char *) type); 5094 5095 if (logging != MagickFalse) 5096 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5097 " Reading MNG chunk type %c%c%c%c, length: %.20g", 5098 type[0],type[1],type[2],type[3],(double) length); 5099 5100 if (length > PNG_UINT_31_MAX) 5101 { 5102 status=MagickFalse; 5103 break; 5104 } 5105 5106 if (count == 0) 5107 ThrowReaderException(CorruptImageError,"CorruptImage"); 5108 5109 p=NULL; 5110 chunk=(unsigned char *) NULL; 5111 5112 if (length != 0) 5113 { 5114 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); 5115 5116 if (chunk == (unsigned char *) NULL) 5117 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 5118 5119 for (i=0; i < (ssize_t) length; i++) 5120 chunk[i]=(unsigned char) ReadBlobByte(image); 5121 5122 p=chunk; 5123 } 5124 5125 (void) ReadBlobMSBLong(image); /* read crc word */ 5126 5127#if !defined(JNG_SUPPORTED) 5128 if (memcmp(type,mng_JHDR,4) == 0) 5129 { 5130 skip_to_iend=MagickTrue; 5131 5132 if (mng_info->jhdr_warning == 0) 5133 (void) ThrowMagickException(exception,GetMagickModule(), 5134 CoderError,"JNGCompressNotSupported","`%s'",image->filename); 5135 5136 mng_info->jhdr_warning++; 5137 } 5138#endif 5139 if (memcmp(type,mng_DHDR,4) == 0) 5140 { 5141 skip_to_iend=MagickTrue; 5142 5143 if (mng_info->dhdr_warning == 0) 5144 (void) ThrowMagickException(exception,GetMagickModule(), 5145 CoderError,"DeltaPNGNotSupported","`%s'",image->filename); 5146 5147 mng_info->dhdr_warning++; 5148 } 5149 if (memcmp(type,mng_MEND,4) == 0) 5150 break; 5151 5152 if (skip_to_iend) 5153 { 5154 if (memcmp(type,mng_IEND,4) == 0) 5155 skip_to_iend=MagickFalse; 5156 5157 if (length != 0) 5158 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5159 5160 if (logging != MagickFalse) 5161 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5162 " Skip to IEND."); 5163 5164 continue; 5165 } 5166 5167 if (memcmp(type,mng_MHDR,4) == 0) 5168 { 5169 if (length != 28) 5170 { 5171 if (chunk) 5172 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5173 ThrowReaderException(CorruptImageError,"CorruptImage"); 5174 } 5175 5176 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 5177 (p[2] << 8) | p[3]); 5178 5179 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 5180 (p[6] << 8) | p[7]); 5181 5182 if (logging != MagickFalse) 5183 { 5184 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5185 " MNG width: %.20g",(double) mng_info->mng_width); 5186 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5187 " MNG height: %.20g",(double) mng_info->mng_height); 5188 } 5189 5190 p+=8; 5191 mng_info->ticks_per_second=(size_t) mng_get_long(p); 5192 5193 if (mng_info->ticks_per_second == 0) 5194 default_frame_delay=0; 5195 5196 else 5197 default_frame_delay=1UL*image->ticks_per_second/ 5198 mng_info->ticks_per_second; 5199 5200 frame_delay=default_frame_delay; 5201 simplicity=0; 5202 5203 p+=16; 5204 simplicity=(size_t) mng_get_long(p); 5205 5206 mng_type=1; /* Full MNG */ 5207 5208 if ((simplicity != 0) && ((simplicity | 11) == 11)) 5209 mng_type=2; /* LC */ 5210 5211 if ((simplicity != 0) && ((simplicity | 9) == 9)) 5212 mng_type=3; /* VLC */ 5213 5214#if defined(MNG_INSERT_LAYERS) 5215 if (mng_type != 3) 5216 insert_layers=MagickTrue; 5217#endif 5218 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 5219 { 5220 /* Allocate next image structure. */ 5221 AcquireNextImage(image_info,image,exception); 5222 5223 if (GetNextImageInList(image) == (Image *) NULL) 5224 return((Image *) NULL); 5225 5226 image=SyncNextImageInList(image); 5227 mng_info->image=image; 5228 } 5229 5230 if ((mng_info->mng_width > 65535L) || 5231 (mng_info->mng_height > 65535L)) 5232 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit"); 5233 5234 (void) FormatLocaleString(page_geometry,MagickPathExtent, 5235 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double) 5236 mng_info->mng_height); 5237 5238 mng_info->frame.left=0; 5239 mng_info->frame.right=(ssize_t) mng_info->mng_width; 5240 mng_info->frame.top=0; 5241 mng_info->frame.bottom=(ssize_t) mng_info->mng_height; 5242 mng_info->clip=default_fb=previous_fb=mng_info->frame; 5243 5244 for (i=0; i < MNG_MAX_OBJECTS; i++) 5245 mng_info->object_clip[i]=mng_info->frame; 5246 5247 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5248 continue; 5249 } 5250 5251 if (memcmp(type,mng_TERM,4) == 0) 5252 { 5253 int 5254 repeat=0; 5255 5256 if (length != 0) 5257 repeat=p[0]; 5258 5259 if (repeat == 3) 5260 { 5261 final_delay=(png_uint_32) mng_get_long(&p[2]); 5262 mng_iterations=(png_uint_32) mng_get_long(&p[6]); 5263 5264 if (mng_iterations == PNG_UINT_31_MAX) 5265 mng_iterations=0; 5266 5267 image->iterations=mng_iterations; 5268 term_chunk_found=MagickTrue; 5269 } 5270 5271 if (logging != MagickFalse) 5272 { 5273 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5274 " repeat=%d, final_delay=%.20g, iterations=%.20g", 5275 repeat,(double) final_delay, (double) image->iterations); 5276 } 5277 5278 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5279 continue; 5280 } 5281 if (memcmp(type,mng_DEFI,4) == 0) 5282 { 5283 if (mng_type == 3) 5284 (void) ThrowMagickException(exception,GetMagickModule(), 5285 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'", 5286 image->filename); 5287 5288 if (length < 2) 5289 { 5290 if (chunk) 5291 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5292 ThrowReaderException(CorruptImageError,"CorruptImage"); 5293 } 5294 5295 object_id=(p[0] << 8) | p[1]; 5296 5297 if (mng_type == 2 && object_id != 0) 5298 (void) ThrowMagickException(exception,GetMagickModule(), 5299 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'", 5300 image->filename); 5301 5302 if (object_id > MNG_MAX_OBJECTS) 5303 { 5304 /* 5305 Instead of using a warning we should allocate a larger 5306 MngInfo structure and continue. 5307 */ 5308 (void) ThrowMagickException(exception,GetMagickModule(), 5309 CoderError,"object id too large","`%s'",image->filename); 5310 object_id=MNG_MAX_OBJECTS; 5311 } 5312 5313 if (mng_info->exists[object_id]) 5314 if (mng_info->frozen[object_id]) 5315 { 5316 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5317 (void) ThrowMagickException(exception, 5318 GetMagickModule(),CoderError, 5319 "DEFI cannot redefine a frozen MNG object","`%s'", 5320 image->filename); 5321 continue; 5322 } 5323 5324 mng_info->exists[object_id]=MagickTrue; 5325 5326 if (length > 2) 5327 mng_info->invisible[object_id]=p[2]; 5328 5329 /* 5330 Extract object offset info. 5331 */ 5332 if (length > 11) 5333 { 5334 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) | 5335 (p[5] << 16) | (p[6] << 8) | p[7]); 5336 5337 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) | 5338 (p[9] << 16) | (p[10] << 8) | p[11]); 5339 5340 if (logging != MagickFalse) 5341 { 5342 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5343 " x_off[%d]: %.20g, y_off[%d]: %.20g", 5344 object_id,(double) mng_info->x_off[object_id], 5345 object_id,(double) mng_info->y_off[object_id]); 5346 } 5347 } 5348 5349 /* 5350 Extract object clipping info. 5351 */ 5352 if (length > 27) 5353 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0, 5354 &p[12]); 5355 5356 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5357 continue; 5358 } 5359 if (memcmp(type,mng_bKGD,4) == 0) 5360 { 5361 mng_info->have_global_bkgd=MagickFalse; 5362 5363 if (length > 5) 5364 { 5365 mng_info->mng_global_bkgd.red= 5366 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); 5367 5368 mng_info->mng_global_bkgd.green= 5369 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); 5370 5371 mng_info->mng_global_bkgd.blue= 5372 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); 5373 5374 mng_info->have_global_bkgd=MagickTrue; 5375 } 5376 5377 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5378 continue; 5379 } 5380 if (memcmp(type,mng_BACK,4) == 0) 5381 { 5382#if defined(MNG_INSERT_LAYERS) 5383 if (length > 6) 5384 mandatory_back=p[6]; 5385 5386 else 5387 mandatory_back=0; 5388 5389 if (mandatory_back && length > 5) 5390 { 5391 mng_background_color.red= 5392 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); 5393 5394 mng_background_color.green= 5395 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); 5396 5397 mng_background_color.blue= 5398 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); 5399 5400 mng_background_color.alpha=OpaqueAlpha; 5401 } 5402 5403#ifdef MNG_OBJECT_BUFFERS 5404 if (length > 8) 5405 mng_background_object=(p[7] << 8) | p[8]; 5406#endif 5407#endif 5408 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5409 continue; 5410 } 5411 5412 if (memcmp(type,mng_PLTE,4) == 0) 5413 { 5414 /* Read global PLTE. */ 5415 5416 if (length && (length < 769)) 5417 { 5418 if (mng_info->global_plte == (png_colorp) NULL) 5419 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256, 5420 sizeof(*mng_info->global_plte)); 5421 5422 for (i=0; i < (ssize_t) (length/3); i++) 5423 { 5424 mng_info->global_plte[i].red=p[3*i]; 5425 mng_info->global_plte[i].green=p[3*i+1]; 5426 mng_info->global_plte[i].blue=p[3*i+2]; 5427 } 5428 5429 mng_info->global_plte_length=(unsigned int) (length/3); 5430 } 5431#ifdef MNG_LOOSE 5432 for ( ; i < 256; i++) 5433 { 5434 mng_info->global_plte[i].red=i; 5435 mng_info->global_plte[i].green=i; 5436 mng_info->global_plte[i].blue=i; 5437 } 5438 5439 if (length != 0) 5440 mng_info->global_plte_length=256; 5441#endif 5442 else 5443 mng_info->global_plte_length=0; 5444 5445 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5446 continue; 5447 } 5448 5449 if (memcmp(type,mng_tRNS,4) == 0) 5450 { 5451 /* read global tRNS */ 5452 5453 if (length > 0 && length < 257) 5454 for (i=0; i < (ssize_t) length; i++) 5455 mng_info->global_trns[i]=p[i]; 5456 5457#ifdef MNG_LOOSE 5458 for ( ; i < 256; i++) 5459 mng_info->global_trns[i]=255; 5460#endif 5461 mng_info->global_trns_length=(unsigned int) length; 5462 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5463 continue; 5464 } 5465 if (memcmp(type,mng_gAMA,4) == 0) 5466 { 5467 if (length == 4) 5468 { 5469 ssize_t 5470 igamma; 5471 5472 igamma=mng_get_long(p); 5473 mng_info->global_gamma=((float) igamma)*0.00001; 5474 mng_info->have_global_gama=MagickTrue; 5475 } 5476 5477 else 5478 mng_info->have_global_gama=MagickFalse; 5479 5480 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5481 continue; 5482 } 5483 5484 if (memcmp(type,mng_cHRM,4) == 0) 5485 { 5486 /* Read global cHRM */ 5487 5488 if (length == 32) 5489 { 5490 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p); 5491 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]); 5492 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]); 5493 mng_info->global_chrm.red_primary.y=0.00001* 5494 mng_get_long(&p[12]); 5495 mng_info->global_chrm.green_primary.x=0.00001* 5496 mng_get_long(&p[16]); 5497 mng_info->global_chrm.green_primary.y=0.00001* 5498 mng_get_long(&p[20]); 5499 mng_info->global_chrm.blue_primary.x=0.00001* 5500 mng_get_long(&p[24]); 5501 mng_info->global_chrm.blue_primary.y=0.00001* 5502 mng_get_long(&p[28]); 5503 mng_info->have_global_chrm=MagickTrue; 5504 } 5505 else 5506 mng_info->have_global_chrm=MagickFalse; 5507 5508 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5509 continue; 5510 } 5511 5512 if (memcmp(type,mng_sRGB,4) == 0) 5513 { 5514 /* 5515 Read global sRGB. 5516 */ 5517 if (length != 0) 5518 { 5519 mng_info->global_srgb_intent= 5520 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]); 5521 mng_info->have_global_srgb=MagickTrue; 5522 } 5523 else 5524 mng_info->have_global_srgb=MagickFalse; 5525 5526 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5527 continue; 5528 } 5529 5530 if (memcmp(type,mng_iCCP,4) == 0) 5531 { 5532 /* To do: */ 5533 5534 /* 5535 Read global iCCP. 5536 */ 5537 if (length != 0) 5538 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5539 5540 continue; 5541 } 5542 5543 if (memcmp(type,mng_FRAM,4) == 0) 5544 { 5545 if (mng_type == 3) 5546 (void) ThrowMagickException(exception,GetMagickModule(), 5547 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'", 5548 image->filename); 5549 5550 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4)) 5551 image->delay=frame_delay; 5552 5553 frame_delay=default_frame_delay; 5554 frame_timeout=default_frame_timeout; 5555 fb=default_fb; 5556 5557 if (length != 0) 5558 if (p[0]) 5559 mng_info->framing_mode=p[0]; 5560 5561 if (logging != MagickFalse) 5562 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5563 " Framing_mode=%d",mng_info->framing_mode); 5564 5565 if (length > 6) 5566 { 5567 /* Note the delay and frame clipping boundaries. */ 5568 5569 p++; /* framing mode */ 5570 5571 while (*p && ((p-chunk) < (ssize_t) length)) 5572 p++; /* frame name */ 5573 5574 p++; /* frame name terminator */ 5575 5576 if ((p-chunk) < (ssize_t) (length-4)) 5577 { 5578 int 5579 change_delay, 5580 change_timeout, 5581 change_clipping; 5582 5583 change_delay=(*p++); 5584 change_timeout=(*p++); 5585 change_clipping=(*p++); 5586 p++; /* change_sync */ 5587 5588 if (change_delay) 5589 { 5590 frame_delay=1UL*image->ticks_per_second* 5591 mng_get_long(p); 5592 5593 if (mng_info->ticks_per_second != 0) 5594 frame_delay/=mng_info->ticks_per_second; 5595 5596 else 5597 frame_delay=PNG_UINT_31_MAX; 5598 5599 if (change_delay == 2) 5600 default_frame_delay=frame_delay; 5601 5602 p+=4; 5603 5604 if (logging != MagickFalse) 5605 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5606 " Framing_delay=%.20g",(double) frame_delay); 5607 } 5608 5609 if (change_timeout) 5610 { 5611 frame_timeout=1UL*image->ticks_per_second* 5612 mng_get_long(p); 5613 5614 if (mng_info->ticks_per_second != 0) 5615 frame_timeout/=mng_info->ticks_per_second; 5616 5617 else 5618 frame_timeout=PNG_UINT_31_MAX; 5619 5620 if (change_timeout == 2) 5621 default_frame_timeout=frame_timeout; 5622 5623 p+=4; 5624 5625 if (logging != MagickFalse) 5626 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5627 " Framing_timeout=%.20g",(double) frame_timeout); 5628 } 5629 5630 if (change_clipping) 5631 { 5632 fb=mng_read_box(previous_fb,(char) p[0],&p[1]); 5633 p+=17; 5634 previous_fb=fb; 5635 5636 if (logging != MagickFalse) 5637 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5638 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g", 5639 (double) fb.left,(double) fb.right,(double) fb.top, 5640 (double) fb.bottom); 5641 5642 if (change_clipping == 2) 5643 default_fb=fb; 5644 } 5645 } 5646 } 5647 mng_info->clip=fb; 5648 mng_info->clip=mng_minimum_box(fb,mng_info->frame); 5649 5650 subframe_width=(size_t) (mng_info->clip.right 5651 -mng_info->clip.left); 5652 5653 subframe_height=(size_t) (mng_info->clip.bottom 5654 -mng_info->clip.top); 5655 /* 5656 Insert a background layer behind the frame if framing_mode is 4. 5657 */ 5658#if defined(MNG_INSERT_LAYERS) 5659 if (logging != MagickFalse) 5660 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5661 " subframe_width=%.20g, subframe_height=%.20g",(double) 5662 subframe_width,(double) subframe_height); 5663 5664 if (insert_layers && (mng_info->framing_mode == 4) && 5665 (subframe_width) && (subframe_height)) 5666 { 5667 /* Allocate next image structure. */ 5668 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 5669 { 5670 AcquireNextImage(image_info,image,exception); 5671 5672 if (GetNextImageInList(image) == (Image *) NULL) 5673 { 5674 image=DestroyImageList(image); 5675 MngInfoFreeStruct(mng_info,&have_mng_structure); 5676 return((Image *) NULL); 5677 } 5678 5679 image=SyncNextImageInList(image); 5680 } 5681 5682 mng_info->image=image; 5683 5684 if (term_chunk_found) 5685 { 5686 image->start_loop=MagickTrue; 5687 image->iterations=mng_iterations; 5688 term_chunk_found=MagickFalse; 5689 } 5690 5691 else 5692 image->start_loop=MagickFalse; 5693 5694 image->columns=subframe_width; 5695 image->rows=subframe_height; 5696 image->page.width=subframe_width; 5697 image->page.height=subframe_height; 5698 image->page.x=mng_info->clip.left; 5699 image->page.y=mng_info->clip.top; 5700 image->background_color=mng_background_color; 5701 image->alpha_trait=UndefinedPixelTrait; 5702 image->delay=0; 5703 (void) SetImageBackgroundColor(image,exception); 5704 5705 if (logging != MagickFalse) 5706 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5707 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", 5708 (double) mng_info->clip.left,(double) mng_info->clip.right, 5709 (double) mng_info->clip.top,(double) mng_info->clip.bottom); 5710 } 5711#endif 5712 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5713 continue; 5714 } 5715 5716 if (memcmp(type,mng_CLIP,4) == 0) 5717 { 5718 unsigned int 5719 first_object, 5720 last_object; 5721 5722 /* 5723 Read CLIP. 5724 */ 5725 if (length > 3) 5726 { 5727 first_object=(p[0] << 8) | p[1]; 5728 last_object=(p[2] << 8) | p[3]; 5729 p+=4; 5730 5731 for (i=(int) first_object; i <= (int) last_object; i++) 5732 { 5733 if (mng_info->exists[i] && !mng_info->frozen[i]) 5734 { 5735 MngBox 5736 box; 5737 5738 box=mng_info->object_clip[i]; 5739 if ((p-chunk) < (ssize_t) (length-17)) 5740 mng_info->object_clip[i]= 5741 mng_read_box(box,(char) p[0],&p[1]); 5742 } 5743 } 5744 5745 } 5746 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5747 continue; 5748 } 5749 5750 if (memcmp(type,mng_SAVE,4) == 0) 5751 { 5752 for (i=1; i < MNG_MAX_OBJECTS; i++) 5753 if (mng_info->exists[i]) 5754 { 5755 mng_info->frozen[i]=MagickTrue; 5756#ifdef MNG_OBJECT_BUFFERS 5757 if (mng_info->ob[i] != (MngBuffer *) NULL) 5758 mng_info->ob[i]->frozen=MagickTrue; 5759#endif 5760 } 5761 5762 if (length != 0) 5763 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5764 5765 continue; 5766 } 5767 5768 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0)) 5769 { 5770 /* Read DISC or SEEK. */ 5771 5772 if ((length == 0) || !memcmp(type,mng_SEEK,4)) 5773 { 5774 for (i=1; i < MNG_MAX_OBJECTS; i++) 5775 MngInfoDiscardObject(mng_info,i); 5776 } 5777 5778 else 5779 { 5780 register ssize_t 5781 j; 5782 5783 for (j=1; j < (ssize_t) length; j+=2) 5784 { 5785 i=p[j-1] << 8 | p[j]; 5786 MngInfoDiscardObject(mng_info,i); 5787 } 5788 } 5789 5790 if (length != 0) 5791 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5792 5793 continue; 5794 } 5795 5796 if (memcmp(type,mng_MOVE,4) == 0) 5797 { 5798 size_t 5799 first_object, 5800 last_object; 5801 5802 /* read MOVE */ 5803 5804 if (length > 3) 5805 { 5806 first_object=(p[0] << 8) | p[1]; 5807 last_object=(p[2] << 8) | p[3]; 5808 p+=4; 5809 5810 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++) 5811 { 5812 if (mng_info->exists[i] && !mng_info->frozen[i] && 5813 (p-chunk) < (ssize_t) (length-8)) 5814 { 5815 MngPair 5816 new_pair; 5817 5818 MngPair 5819 old_pair; 5820 5821 old_pair.a=mng_info->x_off[i]; 5822 old_pair.b=mng_info->y_off[i]; 5823 new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]); 5824 mng_info->x_off[i]=new_pair.a; 5825 mng_info->y_off[i]=new_pair.b; 5826 } 5827 } 5828 } 5829 5830 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5831 continue; 5832 } 5833 5834 if (memcmp(type,mng_LOOP,4) == 0) 5835 { 5836 ssize_t loop_iters=1; 5837 if (length > 4) 5838 { 5839 loop_level=chunk[0]; 5840 mng_info->loop_active[loop_level]=1; /* mark loop active */ 5841 5842 /* Record starting point. */ 5843 loop_iters=mng_get_long(&chunk[1]); 5844 5845 if (logging != MagickFalse) 5846 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5847 " LOOP level %.20g has %.20g iterations ", 5848 (double) loop_level, (double) loop_iters); 5849 5850 if (loop_iters == 0) 5851 skipping_loop=loop_level; 5852 5853 else 5854 { 5855 mng_info->loop_jump[loop_level]=TellBlob(image); 5856 mng_info->loop_count[loop_level]=loop_iters; 5857 } 5858 5859 mng_info->loop_iteration[loop_level]=0; 5860 } 5861 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5862 continue; 5863 } 5864 5865 if (memcmp(type,mng_ENDL,4) == 0) 5866 { 5867 if (length > 0) 5868 { 5869 loop_level=chunk[0]; 5870 5871 if (skipping_loop > 0) 5872 { 5873 if (skipping_loop == loop_level) 5874 { 5875 /* 5876 Found end of zero-iteration loop. 5877 */ 5878 skipping_loop=(-1); 5879 mng_info->loop_active[loop_level]=0; 5880 } 5881 } 5882 5883 else 5884 { 5885 if (mng_info->loop_active[loop_level] == 1) 5886 { 5887 mng_info->loop_count[loop_level]--; 5888 mng_info->loop_iteration[loop_level]++; 5889 5890 if (logging != MagickFalse) 5891 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5892 " ENDL: LOOP level %.20g has %.20g remaining iters ", 5893 (double) loop_level,(double) 5894 mng_info->loop_count[loop_level]); 5895 5896 if (mng_info->loop_count[loop_level] != 0) 5897 { 5898 offset= 5899 SeekBlob(image,mng_info->loop_jump[loop_level], 5900 SEEK_SET); 5901 5902 if (offset < 0) 5903 ThrowReaderException(CorruptImageError, 5904 "ImproperImageHeader"); 5905 } 5906 5907 else 5908 { 5909 short 5910 last_level; 5911 5912 /* 5913 Finished loop. 5914 */ 5915 mng_info->loop_active[loop_level]=0; 5916 last_level=(-1); 5917 for (i=0; i < loop_level; i++) 5918 if (mng_info->loop_active[i] == 1) 5919 last_level=(short) i; 5920 loop_level=last_level; 5921 } 5922 } 5923 } 5924 } 5925 5926 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5927 continue; 5928 } 5929 5930 if (memcmp(type,mng_CLON,4) == 0) 5931 { 5932 if (mng_info->clon_warning == 0) 5933 (void) ThrowMagickException(exception,GetMagickModule(), 5934 CoderError,"CLON is not implemented yet","`%s'", 5935 image->filename); 5936 5937 mng_info->clon_warning++; 5938 } 5939 5940 if (memcmp(type,mng_MAGN,4) == 0) 5941 { 5942 png_uint_16 5943 magn_first, 5944 magn_last, 5945 magn_mb, 5946 magn_ml, 5947 magn_mr, 5948 magn_mt, 5949 magn_mx, 5950 magn_my, 5951 magn_methx, 5952 magn_methy; 5953 5954 if (length > 1) 5955 magn_first=(p[0] << 8) | p[1]; 5956 5957 else 5958 magn_first=0; 5959 5960 if (length > 3) 5961 magn_last=(p[2] << 8) | p[3]; 5962 5963 else 5964 magn_last=magn_first; 5965#ifndef MNG_OBJECT_BUFFERS 5966 if (magn_first || magn_last) 5967 if (mng_info->magn_warning == 0) 5968 { 5969 (void) ThrowMagickException(exception, 5970 GetMagickModule(),CoderError, 5971 "MAGN is not implemented yet for nonzero objects", 5972 "`%s'",image->filename); 5973 5974 mng_info->magn_warning++; 5975 } 5976#endif 5977 if (length > 4) 5978 magn_methx=p[4]; 5979 5980 else 5981 magn_methx=0; 5982 5983 if (length > 6) 5984 magn_mx=(p[5] << 8) | p[6]; 5985 5986 else 5987 magn_mx=1; 5988 5989 if (magn_mx == 0) 5990 magn_mx=1; 5991 5992 if (length > 8) 5993 magn_my=(p[7] << 8) | p[8]; 5994 5995 else 5996 magn_my=magn_mx; 5997 5998 if (magn_my == 0) 5999 magn_my=1; 6000 6001 if (length > 10) 6002 magn_ml=(p[9] << 8) | p[10]; 6003 6004 else 6005 magn_ml=magn_mx; 6006 6007 if (magn_ml == 0) 6008 magn_ml=1; 6009 6010 if (length > 12) 6011 magn_mr=(p[11] << 8) | p[12]; 6012 6013 else 6014 magn_mr=magn_mx; 6015 6016 if (magn_mr == 0) 6017 magn_mr=1; 6018 6019 if (length > 14) 6020 magn_mt=(p[13] << 8) | p[14]; 6021 6022 else 6023 magn_mt=magn_my; 6024 6025 if (magn_mt == 0) 6026 magn_mt=1; 6027 6028 if (length > 16) 6029 magn_mb=(p[15] << 8) | p[16]; 6030 6031 else 6032 magn_mb=magn_my; 6033 6034 if (magn_mb == 0) 6035 magn_mb=1; 6036 6037 if (length > 17) 6038 magn_methy=p[17]; 6039 6040 else 6041 magn_methy=magn_methx; 6042 6043 6044 if (magn_methx > 5 || magn_methy > 5) 6045 if (mng_info->magn_warning == 0) 6046 { 6047 (void) ThrowMagickException(exception, 6048 GetMagickModule(),CoderError, 6049 "Unknown MAGN method in MNG datastream","`%s'", 6050 image->filename); 6051 6052 mng_info->magn_warning++; 6053 } 6054#ifdef MNG_OBJECT_BUFFERS 6055 /* Magnify existing objects in the range magn_first to magn_last */ 6056#endif 6057 if (magn_first == 0 || magn_last == 0) 6058 { 6059 /* Save the magnification factors for object 0 */ 6060 mng_info->magn_mb=magn_mb; 6061 mng_info->magn_ml=magn_ml; 6062 mng_info->magn_mr=magn_mr; 6063 mng_info->magn_mt=magn_mt; 6064 mng_info->magn_mx=magn_mx; 6065 mng_info->magn_my=magn_my; 6066 mng_info->magn_methx=magn_methx; 6067 mng_info->magn_methy=magn_methy; 6068 } 6069 } 6070 6071 if (memcmp(type,mng_PAST,4) == 0) 6072 { 6073 if (mng_info->past_warning == 0) 6074 (void) ThrowMagickException(exception,GetMagickModule(), 6075 CoderError,"PAST is not implemented yet","`%s'", 6076 image->filename); 6077 6078 mng_info->past_warning++; 6079 } 6080 6081 if (memcmp(type,mng_SHOW,4) == 0) 6082 { 6083 if (mng_info->show_warning == 0) 6084 (void) ThrowMagickException(exception,GetMagickModule(), 6085 CoderError,"SHOW is not implemented yet","`%s'", 6086 image->filename); 6087 6088 mng_info->show_warning++; 6089 } 6090 6091 if (memcmp(type,mng_sBIT,4) == 0) 6092 { 6093 if (length < 4) 6094 mng_info->have_global_sbit=MagickFalse; 6095 6096 else 6097 { 6098 mng_info->global_sbit.gray=p[0]; 6099 mng_info->global_sbit.red=p[0]; 6100 mng_info->global_sbit.green=p[1]; 6101 mng_info->global_sbit.blue=p[2]; 6102 mng_info->global_sbit.alpha=p[3]; 6103 mng_info->have_global_sbit=MagickTrue; 6104 } 6105 } 6106 if (memcmp(type,mng_pHYs,4) == 0) 6107 { 6108 if (length > 8) 6109 { 6110 mng_info->global_x_pixels_per_unit= 6111 (size_t) mng_get_long(p); 6112 mng_info->global_y_pixels_per_unit= 6113 (size_t) mng_get_long(&p[4]); 6114 mng_info->global_phys_unit_type=p[8]; 6115 mng_info->have_global_phys=MagickTrue; 6116 } 6117 6118 else 6119 mng_info->have_global_phys=MagickFalse; 6120 } 6121 if (memcmp(type,mng_pHYg,4) == 0) 6122 { 6123 if (mng_info->phyg_warning == 0) 6124 (void) ThrowMagickException(exception,GetMagickModule(), 6125 CoderError,"pHYg is not implemented.","`%s'",image->filename); 6126 6127 mng_info->phyg_warning++; 6128 } 6129 if (memcmp(type,mng_BASI,4) == 0) 6130 { 6131 skip_to_iend=MagickTrue; 6132 6133 if (mng_info->basi_warning == 0) 6134 (void) ThrowMagickException(exception,GetMagickModule(), 6135 CoderError,"BASI is not implemented yet","`%s'", 6136 image->filename); 6137 6138 mng_info->basi_warning++; 6139#ifdef MNG_BASI_SUPPORTED 6140 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 6141 (p[2] << 8) | p[3]); 6142 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 6143 (p[6] << 8) | p[7]); 6144 basi_color_type=p[8]; 6145 basi_compression_method=p[9]; 6146 basi_filter_type=p[10]; 6147 basi_interlace_method=p[11]; 6148 if (length > 11) 6149 basi_red=(p[12] << 8) & p[13]; 6150 6151 else 6152 basi_red=0; 6153 6154 if (length > 13) 6155 basi_green=(p[14] << 8) & p[15]; 6156 6157 else 6158 basi_green=0; 6159 6160 if (length > 15) 6161 basi_blue=(p[16] << 8) & p[17]; 6162 6163 else 6164 basi_blue=0; 6165 6166 if (length > 17) 6167 basi_alpha=(p[18] << 8) & p[19]; 6168 6169 else 6170 { 6171 if (basi_sample_depth == 16) 6172 basi_alpha=65535L; 6173 else 6174 basi_alpha=255; 6175 } 6176 6177 if (length > 19) 6178 basi_viewable=p[20]; 6179 6180 else 6181 basi_viewable=0; 6182 6183#endif 6184 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6185 continue; 6186 } 6187 6188 if (memcmp(type,mng_IHDR,4) 6189#if defined(JNG_SUPPORTED) 6190 && memcmp(type,mng_JHDR,4) 6191#endif 6192 ) 6193 { 6194 /* Not an IHDR or JHDR chunk */ 6195 if (length != 0) 6196 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6197 6198 continue; 6199 } 6200/* Process IHDR */ 6201 if (logging != MagickFalse) 6202 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6203 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]); 6204 6205 mng_info->exists[object_id]=MagickTrue; 6206 mng_info->viewable[object_id]=MagickTrue; 6207 6208 if (mng_info->invisible[object_id]) 6209 { 6210 if (logging != MagickFalse) 6211 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6212 " Skipping invisible object"); 6213 6214 skip_to_iend=MagickTrue; 6215 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6216 continue; 6217 } 6218#if defined(MNG_INSERT_LAYERS) 6219 if (length < 8) 6220 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 6221 6222 image_width=(size_t) mng_get_long(p); 6223 image_height=(size_t) mng_get_long(&p[4]); 6224#endif 6225 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6226 6227 /* 6228 Insert a transparent background layer behind the entire animation 6229 if it is not full screen. 6230 */ 6231#if defined(MNG_INSERT_LAYERS) 6232 if (insert_layers && mng_type && first_mng_object) 6233 { 6234 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) || 6235 (image_width < mng_info->mng_width) || 6236 (mng_info->clip.right < (ssize_t) mng_info->mng_width) || 6237 (image_height < mng_info->mng_height) || 6238 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height)) 6239 { 6240 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6241 { 6242 /* 6243 Allocate next image structure. 6244 */ 6245 AcquireNextImage(image_info,image,exception); 6246 6247 if (GetNextImageInList(image) == (Image *) NULL) 6248 { 6249 image=DestroyImageList(image); 6250 MngInfoFreeStruct(mng_info,&have_mng_structure); 6251 return((Image *) NULL); 6252 } 6253 6254 image=SyncNextImageInList(image); 6255 } 6256 mng_info->image=image; 6257 6258 if (term_chunk_found) 6259 { 6260 image->start_loop=MagickTrue; 6261 image->iterations=mng_iterations; 6262 term_chunk_found=MagickFalse; 6263 } 6264 6265 else 6266 image->start_loop=MagickFalse; 6267 6268 /* Make a background rectangle. */ 6269 6270 image->delay=0; 6271 image->columns=mng_info->mng_width; 6272 image->rows=mng_info->mng_height; 6273 image->page.width=mng_info->mng_width; 6274 image->page.height=mng_info->mng_height; 6275 image->page.x=0; 6276 image->page.y=0; 6277 image->background_color=mng_background_color; 6278 (void) SetImageBackgroundColor(image,exception); 6279 if (logging != MagickFalse) 6280 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6281 " Inserted transparent background layer, W=%.20g, H=%.20g", 6282 (double) mng_info->mng_width,(double) mng_info->mng_height); 6283 } 6284 } 6285 /* 6286 Insert a background layer behind the upcoming image if 6287 framing_mode is 3, and we haven't already inserted one. 6288 */ 6289 if (insert_layers && (mng_info->framing_mode == 3) && 6290 (subframe_width) && (subframe_height) && (simplicity == 0 || 6291 (simplicity & 0x08))) 6292 { 6293 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6294 { 6295 /* 6296 Allocate next image structure. 6297 */ 6298 AcquireNextImage(image_info,image,exception); 6299 6300 if (GetNextImageInList(image) == (Image *) NULL) 6301 { 6302 image=DestroyImageList(image); 6303 MngInfoFreeStruct(mng_info,&have_mng_structure); 6304 return((Image *) NULL); 6305 } 6306 6307 image=SyncNextImageInList(image); 6308 } 6309 6310 mng_info->image=image; 6311 6312 if (term_chunk_found) 6313 { 6314 image->start_loop=MagickTrue; 6315 image->iterations=mng_iterations; 6316 term_chunk_found=MagickFalse; 6317 } 6318 6319 else 6320 image->start_loop=MagickFalse; 6321 6322 image->delay=0; 6323 image->columns=subframe_width; 6324 image->rows=subframe_height; 6325 image->page.width=subframe_width; 6326 image->page.height=subframe_height; 6327 image->page.x=mng_info->clip.left; 6328 image->page.y=mng_info->clip.top; 6329 image->background_color=mng_background_color; 6330 image->alpha_trait=UndefinedPixelTrait; 6331 (void) SetImageBackgroundColor(image,exception); 6332 6333 if (logging != MagickFalse) 6334 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6335 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", 6336 (double) mng_info->clip.left,(double) mng_info->clip.right, 6337 (double) mng_info->clip.top,(double) mng_info->clip.bottom); 6338 } 6339#endif /* MNG_INSERT_LAYERS */ 6340 first_mng_object=MagickFalse; 6341 6342 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6343 { 6344 /* 6345 Allocate next image structure. 6346 */ 6347 AcquireNextImage(image_info,image,exception); 6348 6349 if (GetNextImageInList(image) == (Image *) NULL) 6350 { 6351 image=DestroyImageList(image); 6352 MngInfoFreeStruct(mng_info,&have_mng_structure); 6353 return((Image *) NULL); 6354 } 6355 6356 image=SyncNextImageInList(image); 6357 } 6358 mng_info->image=image; 6359 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 6360 GetBlobSize(image)); 6361 6362 if (status == MagickFalse) 6363 break; 6364 6365 if (term_chunk_found) 6366 { 6367 image->start_loop=MagickTrue; 6368 term_chunk_found=MagickFalse; 6369 } 6370 6371 else 6372 image->start_loop=MagickFalse; 6373 6374 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3) 6375 { 6376 image->delay=frame_delay; 6377 frame_delay=default_frame_delay; 6378 } 6379 6380 else 6381 image->delay=0; 6382 6383 image->page.width=mng_info->mng_width; 6384 image->page.height=mng_info->mng_height; 6385 image->page.x=mng_info->x_off[object_id]; 6386 image->page.y=mng_info->y_off[object_id]; 6387 image->iterations=mng_iterations; 6388 6389 /* 6390 Seek back to the beginning of the IHDR or JHDR chunk's length field. 6391 */ 6392 6393 if (logging != MagickFalse) 6394 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6395 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1], 6396 type[2],type[3]); 6397 6398 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR); 6399 6400 if (offset < 0) 6401 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 6402 } 6403 6404 mng_info->image=image; 6405 mng_info->mng_type=mng_type; 6406 mng_info->object_id=object_id; 6407 6408 if (memcmp(type,mng_IHDR,4) == 0) 6409 image=ReadOnePNGImage(mng_info,image_info,exception); 6410 6411#if defined(JNG_SUPPORTED) 6412 else 6413 image=ReadOneJNGImage(mng_info,image_info,exception); 6414#endif 6415 6416 if (image == (Image *) NULL) 6417 { 6418 if (logging != MagickFalse) 6419 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6420 "exit ReadJNGImage() with error"); 6421 6422 MngInfoFreeStruct(mng_info,&have_mng_structure); 6423 return((Image *) NULL); 6424 } 6425 6426 if (image->columns == 0 || image->rows == 0) 6427 { 6428 (void) CloseBlob(image); 6429 image=DestroyImageList(image); 6430 MngInfoFreeStruct(mng_info,&have_mng_structure); 6431 return((Image *) NULL); 6432 } 6433 6434 mng_info->image=image; 6435 6436 if (mng_type) 6437 { 6438 MngBox 6439 crop_box; 6440 6441 if (mng_info->magn_methx || mng_info->magn_methy) 6442 { 6443 png_uint_32 6444 magnified_height, 6445 magnified_width; 6446 6447 if (logging != MagickFalse) 6448 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6449 " Processing MNG MAGN chunk"); 6450 6451 if (mng_info->magn_methx == 1) 6452 { 6453 magnified_width=mng_info->magn_ml; 6454 6455 if (image->columns > 1) 6456 magnified_width += mng_info->magn_mr; 6457 6458 if (image->columns > 2) 6459 magnified_width += (png_uint_32) 6460 ((image->columns-2)*(mng_info->magn_mx)); 6461 } 6462 6463 else 6464 { 6465 magnified_width=(png_uint_32) image->columns; 6466 6467 if (image->columns > 1) 6468 magnified_width += mng_info->magn_ml-1; 6469 6470 if (image->columns > 2) 6471 magnified_width += mng_info->magn_mr-1; 6472 6473 if (image->columns > 3) 6474 magnified_width += (png_uint_32) 6475 ((image->columns-3)*(mng_info->magn_mx-1)); 6476 } 6477 6478 if (mng_info->magn_methy == 1) 6479 { 6480 magnified_height=mng_info->magn_mt; 6481 6482 if (image->rows > 1) 6483 magnified_height += mng_info->magn_mb; 6484 6485 if (image->rows > 2) 6486 magnified_height += (png_uint_32) 6487 ((image->rows-2)*(mng_info->magn_my)); 6488 } 6489 6490 else 6491 { 6492 magnified_height=(png_uint_32) image->rows; 6493 6494 if (image->rows > 1) 6495 magnified_height += mng_info->magn_mt-1; 6496 6497 if (image->rows > 2) 6498 magnified_height += mng_info->magn_mb-1; 6499 6500 if (image->rows > 3) 6501 magnified_height += (png_uint_32) 6502 ((image->rows-3)*(mng_info->magn_my-1)); 6503 } 6504 6505 if (magnified_height > image->rows || 6506 magnified_width > image->columns) 6507 { 6508 Image 6509 *large_image; 6510 6511 int 6512 yy; 6513 6514 Quantum 6515 *next, 6516 *prev; 6517 6518 png_uint_16 6519 magn_methx, 6520 magn_methy; 6521 6522 ssize_t 6523 m, 6524 y; 6525 6526 register Quantum 6527 *n, 6528 *q; 6529 6530 register ssize_t 6531 x; 6532 6533 /* Allocate next image structure. */ 6534 6535 if (logging != MagickFalse) 6536 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6537 " Allocate magnified image"); 6538 6539 AcquireNextImage(image_info,image,exception); 6540 6541 if (GetNextImageInList(image) == (Image *) NULL) 6542 { 6543 image=DestroyImageList(image); 6544 MngInfoFreeStruct(mng_info,&have_mng_structure); 6545 return((Image *) NULL); 6546 } 6547 6548 large_image=SyncNextImageInList(image); 6549 6550 large_image->columns=magnified_width; 6551 large_image->rows=magnified_height; 6552 6553 magn_methx=mng_info->magn_methx; 6554 magn_methy=mng_info->magn_methy; 6555 6556#if (MAGICKCORE_QUANTUM_DEPTH > 16) 6557#define QM unsigned short 6558 if (magn_methx != 1 || magn_methy != 1) 6559 { 6560 /* 6561 Scale pixels to unsigned shorts to prevent 6562 overflow of intermediate values of interpolations 6563 */ 6564 for (y=0; y < (ssize_t) image->rows; y++) 6565 { 6566 q=GetAuthenticPixels(image,0,y,image->columns,1, 6567 exception); 6568 6569 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6570 { 6571 SetPixelRed(image,ScaleQuantumToShort( 6572 GetPixelRed(image,q)),q); 6573 SetPixelGreen(image,ScaleQuantumToShort( 6574 GetPixelGreen(image,q)),q); 6575 SetPixelBlue(image,ScaleQuantumToShort( 6576 GetPixelBlue(image,q)),q); 6577 SetPixelAlpha(image,ScaleQuantumToShort( 6578 GetPixelAlpha(image,q)),q); 6579 q+=GetPixelChannels(image); 6580 } 6581 6582 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6583 break; 6584 } 6585 } 6586#else 6587#define QM Quantum 6588#endif 6589 6590 if (image->alpha_trait != UndefinedPixelTrait) 6591 (void) SetImageBackgroundColor(large_image,exception); 6592 6593 else 6594 { 6595 large_image->background_color.alpha=OpaqueAlpha; 6596 (void) SetImageBackgroundColor(large_image,exception); 6597 6598 if (magn_methx == 4) 6599 magn_methx=2; 6600 6601 if (magn_methx == 5) 6602 magn_methx=3; 6603 6604 if (magn_methy == 4) 6605 magn_methy=2; 6606 6607 if (magn_methy == 5) 6608 magn_methy=3; 6609 } 6610 6611 /* magnify the rows into the right side of the large image */ 6612 6613 if (logging != MagickFalse) 6614 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6615 " Magnify the rows to %.20g",(double) large_image->rows); 6616 m=(ssize_t) mng_info->magn_mt; 6617 yy=0; 6618 length=(size_t) GetPixelChannels(image)*image->columns; 6619 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next)); 6620 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev)); 6621 6622 if ((prev == (Quantum *) NULL) || 6623 (next == (Quantum *) NULL)) 6624 { 6625 image=DestroyImageList(image); 6626 MngInfoFreeStruct(mng_info,&have_mng_structure); 6627 ThrowReaderException(ResourceLimitError, 6628 "MemoryAllocationFailed"); 6629 } 6630 6631 n=GetAuthenticPixels(image,0,0,image->columns,1,exception); 6632 (void) CopyMagickMemory(next,n,length); 6633 6634 for (y=0; y < (ssize_t) image->rows; y++) 6635 { 6636 if (y == 0) 6637 m=(ssize_t) mng_info->magn_mt; 6638 6639 else if (magn_methy > 1 && y == (ssize_t) image->rows-2) 6640 m=(ssize_t) mng_info->magn_mb; 6641 6642 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1) 6643 m=(ssize_t) mng_info->magn_mb; 6644 6645 else if (magn_methy > 1 && y == (ssize_t) image->rows-1) 6646 m=1; 6647 6648 else 6649 m=(ssize_t) mng_info->magn_my; 6650 6651 n=prev; 6652 prev=next; 6653 next=n; 6654 6655 if (y < (ssize_t) image->rows-1) 6656 { 6657 n=GetAuthenticPixels(image,0,y+1,image->columns,1, 6658 exception); 6659 (void) CopyMagickMemory(next,n,length); 6660 } 6661 6662 for (i=0; i < m; i++, yy++) 6663 { 6664 register Quantum 6665 *pixels; 6666 6667 assert(yy < (ssize_t) large_image->rows); 6668 pixels=prev; 6669 n=next; 6670 q=GetAuthenticPixels(large_image,0,yy,large_image->columns, 6671 1,exception); 6672 q+=(large_image->columns-image->columns)* 6673 GetPixelChannels(large_image); 6674 6675 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6676 { 6677 /* To do: get color as function of indexes[x] */ 6678 /* 6679 if (image->storage_class == PseudoClass) 6680 { 6681 } 6682 */ 6683 6684 if (magn_methy <= 1) 6685 { 6686 /* replicate previous */ 6687 SetPixelRed(large_image,GetPixelRed(image,pixels),q); 6688 SetPixelGreen(large_image,GetPixelGreen(image, 6689 pixels),q); 6690 SetPixelBlue(large_image,GetPixelBlue(image, 6691 pixels),q); 6692 SetPixelAlpha(large_image,GetPixelAlpha(image, 6693 pixels),q); 6694 } 6695 6696 else if (magn_methy == 2 || magn_methy == 4) 6697 { 6698 if (i == 0) 6699 { 6700 SetPixelRed(large_image,GetPixelRed(image, 6701 pixels),q); 6702 SetPixelGreen(large_image,GetPixelGreen(image, 6703 pixels),q); 6704 SetPixelBlue(large_image,GetPixelBlue(image, 6705 pixels),q); 6706 SetPixelAlpha(large_image,GetPixelAlpha(image, 6707 pixels),q); 6708 } 6709 6710 else 6711 { 6712 /* Interpolate */ 6713 SetPixelRed(large_image,((QM) (((ssize_t) 6714 (2*i*(GetPixelRed(image,n) 6715 -GetPixelRed(image,pixels)+m))/ 6716 ((ssize_t) (m*2)) 6717 +GetPixelRed(image,pixels)))),q); 6718 SetPixelGreen(large_image,((QM) (((ssize_t) 6719 (2*i*(GetPixelGreen(image,n) 6720 -GetPixelGreen(image,pixels)+m))/ 6721 ((ssize_t) (m*2)) 6722 +GetPixelGreen(image,pixels)))),q); 6723 SetPixelBlue(large_image,((QM) (((ssize_t) 6724 (2*i*(GetPixelBlue(image,n) 6725 -GetPixelBlue(image,pixels)+m))/ 6726 ((ssize_t) (m*2)) 6727 +GetPixelBlue(image,pixels)))),q); 6728 6729 if (image->alpha_trait != UndefinedPixelTrait) 6730 SetPixelAlpha(large_image, ((QM) (((ssize_t) 6731 (2*i*(GetPixelAlpha(image,n) 6732 -GetPixelAlpha(image,pixels)+m)) 6733 /((ssize_t) (m*2))+ 6734 GetPixelAlpha(image,pixels)))),q); 6735 } 6736 6737 if (magn_methy == 4) 6738 { 6739 /* Replicate nearest */ 6740 if (i <= ((m+1) << 1)) 6741 SetPixelAlpha(large_image,GetPixelAlpha(image, 6742 pixels),q); 6743 else 6744 SetPixelAlpha(large_image,GetPixelAlpha(image, 6745 n),q); 6746 } 6747 } 6748 6749 else /* if (magn_methy == 3 || magn_methy == 5) */ 6750 { 6751 /* Replicate nearest */ 6752 if (i <= ((m+1) << 1)) 6753 { 6754 SetPixelRed(large_image,GetPixelRed(image, 6755 pixels),q); 6756 SetPixelGreen(large_image,GetPixelGreen(image, 6757 pixels),q); 6758 SetPixelBlue(large_image,GetPixelBlue(image, 6759 pixels),q); 6760 SetPixelAlpha(large_image,GetPixelAlpha(image, 6761 pixels),q); 6762 } 6763 6764 else 6765 { 6766 SetPixelRed(large_image,GetPixelRed(image,n),q); 6767 SetPixelGreen(large_image,GetPixelGreen(image,n), 6768 q); 6769 SetPixelBlue(large_image,GetPixelBlue(image,n), 6770 q); 6771 SetPixelAlpha(large_image,GetPixelAlpha(image,n), 6772 q); 6773 } 6774 6775 if (magn_methy == 5) 6776 { 6777 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i* 6778 (GetPixelAlpha(image,n) 6779 -GetPixelAlpha(image,pixels)) 6780 +m))/((ssize_t) (m*2)) 6781 +GetPixelAlpha(image,pixels)),q); 6782 } 6783 } 6784 n+=GetPixelChannels(image); 6785 q+=GetPixelChannels(large_image); 6786 pixels+=GetPixelChannels(image); 6787 } /* x */ 6788 6789 if (SyncAuthenticPixels(large_image,exception) == 0) 6790 break; 6791 6792 } /* i */ 6793 } /* y */ 6794 6795 prev=(Quantum *) RelinquishMagickMemory(prev); 6796 next=(Quantum *) RelinquishMagickMemory(next); 6797 6798 length=image->columns; 6799 6800 if (logging != MagickFalse) 6801 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6802 " Delete original image"); 6803 6804 DeleteImageFromList(&image); 6805 6806 image=large_image; 6807 6808 mng_info->image=image; 6809 6810 /* magnify the columns */ 6811 if (logging != MagickFalse) 6812 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6813 " Magnify the columns to %.20g",(double) image->columns); 6814 6815 for (y=0; y < (ssize_t) image->rows; y++) 6816 { 6817 register Quantum 6818 *pixels; 6819 6820 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 6821 pixels=q+(image->columns-length)*GetPixelChannels(image); 6822 n=pixels+GetPixelChannels(image); 6823 6824 for (x=(ssize_t) (image->columns-length); 6825 x < (ssize_t) image->columns; x++) 6826 { 6827 /* To do: Rewrite using Get/Set***PixelChannel() */ 6828 6829 if (x == (ssize_t) (image->columns-length)) 6830 m=(ssize_t) mng_info->magn_ml; 6831 6832 else if (magn_methx > 1 && x == (ssize_t) image->columns-2) 6833 m=(ssize_t) mng_info->magn_mr; 6834 6835 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1) 6836 m=(ssize_t) mng_info->magn_mr; 6837 6838 else if (magn_methx > 1 && x == (ssize_t) image->columns-1) 6839 m=1; 6840 6841 else 6842 m=(ssize_t) mng_info->magn_mx; 6843 6844 for (i=0; i < m; i++) 6845 { 6846 if (magn_methx <= 1) 6847 { 6848 /* replicate previous */ 6849 SetPixelRed(image,GetPixelRed(image,pixels),q); 6850 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6851 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6852 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6853 } 6854 6855 else if (magn_methx == 2 || magn_methx == 4) 6856 { 6857 if (i == 0) 6858 { 6859 SetPixelRed(image,GetPixelRed(image,pixels),q); 6860 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6861 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6862 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6863 } 6864 6865 /* To do: Rewrite using Get/Set***PixelChannel() */ 6866 else 6867 { 6868 /* Interpolate */ 6869 SetPixelRed(image,(QM) ((2*i*( 6870 GetPixelRed(image,n) 6871 -GetPixelRed(image,pixels))+m) 6872 /((ssize_t) (m*2))+ 6873 GetPixelRed(image,pixels)),q); 6874 6875 SetPixelGreen(image,(QM) ((2*i*( 6876 GetPixelGreen(image,n) 6877 -GetPixelGreen(image,pixels))+m) 6878 /((ssize_t) (m*2))+ 6879 GetPixelGreen(image,pixels)),q); 6880 6881 SetPixelBlue(image,(QM) ((2*i*( 6882 GetPixelBlue(image,n) 6883 -GetPixelBlue(image,pixels))+m) 6884 /((ssize_t) (m*2))+ 6885 GetPixelBlue(image,pixels)),q); 6886 if (image->alpha_trait != UndefinedPixelTrait) 6887 SetPixelAlpha(image,(QM) ((2*i*( 6888 GetPixelAlpha(image,n) 6889 -GetPixelAlpha(image,pixels))+m) 6890 /((ssize_t) (m*2))+ 6891 GetPixelAlpha(image,pixels)),q); 6892 } 6893 6894 if (magn_methx == 4) 6895 { 6896 /* Replicate nearest */ 6897 if (i <= ((m+1) << 1)) 6898 { 6899 SetPixelAlpha(image, 6900 GetPixelAlpha(image,pixels)+0,q); 6901 } 6902 else 6903 { 6904 SetPixelAlpha(image, 6905 GetPixelAlpha(image,n)+0,q); 6906 } 6907 } 6908 } 6909 6910 else /* if (magn_methx == 3 || magn_methx == 5) */ 6911 { 6912 /* Replicate nearest */ 6913 if (i <= ((m+1) << 1)) 6914 { 6915 SetPixelRed(image,GetPixelRed(image,pixels),q); 6916 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6917 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6918 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6919 } 6920 6921 else 6922 { 6923 SetPixelRed(image,GetPixelRed(image,n),q); 6924 SetPixelGreen(image,GetPixelGreen(image,n),q); 6925 SetPixelBlue(image,GetPixelBlue(image,n),q); 6926 SetPixelAlpha(image,GetPixelAlpha(image,n),q); 6927 } 6928 6929 if (magn_methx == 5) 6930 { 6931 /* Interpolate */ 6932 SetPixelAlpha(image, 6933 (QM) ((2*i*( GetPixelAlpha(image,n) 6934 -GetPixelAlpha(image,pixels))+m)/ 6935 ((ssize_t) (m*2)) 6936 +GetPixelAlpha(image,pixels)),q); 6937 } 6938 } 6939 q+=GetPixelChannels(image); 6940 } 6941 n+=GetPixelChannels(image); 6942 } 6943 6944 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6945 break; 6946 } 6947#if (MAGICKCORE_QUANTUM_DEPTH > 16) 6948 if (magn_methx != 1 || magn_methy != 1) 6949 { 6950 /* 6951 Rescale pixels to Quantum 6952 */ 6953 for (y=0; y < (ssize_t) image->rows; y++) 6954 { 6955 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 6956 6957 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6958 { 6959 SetPixelRed(image,ScaleShortToQuantum( 6960 GetPixelRed(image,q)),q); 6961 SetPixelGreen(image,ScaleShortToQuantum( 6962 GetPixelGreen(image,q)),q); 6963 SetPixelBlue(image,ScaleShortToQuantum( 6964 GetPixelBlue(image,q)),q); 6965 SetPixelAlpha(image,ScaleShortToQuantum( 6966 GetPixelAlpha(image,q)),q); 6967 q+=GetPixelChannels(image); 6968 } 6969 6970 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6971 break; 6972 } 6973 } 6974#endif 6975 if (logging != MagickFalse) 6976 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6977 " Finished MAGN processing"); 6978 } 6979 } 6980 6981 /* 6982 Crop_box is with respect to the upper left corner of the MNG. 6983 */ 6984 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id]; 6985 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id]; 6986 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id]; 6987 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id]; 6988 crop_box=mng_minimum_box(crop_box,mng_info->clip); 6989 crop_box=mng_minimum_box(crop_box,mng_info->frame); 6990 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]); 6991 if ((crop_box.left != (mng_info->image_box.left 6992 +mng_info->x_off[object_id])) || 6993 (crop_box.right != (mng_info->image_box.right 6994 +mng_info->x_off[object_id])) || 6995 (crop_box.top != (mng_info->image_box.top 6996 +mng_info->y_off[object_id])) || 6997 (crop_box.bottom != (mng_info->image_box.bottom 6998 +mng_info->y_off[object_id]))) 6999 { 7000 if (logging != MagickFalse) 7001 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7002 " Crop the PNG image"); 7003 7004 if ((crop_box.left < crop_box.right) && 7005 (crop_box.top < crop_box.bottom)) 7006 { 7007 Image 7008 *im; 7009 7010 RectangleInfo 7011 crop_info; 7012 7013 /* 7014 Crop_info is with respect to the upper left corner of 7015 the image. 7016 */ 7017 crop_info.x=(crop_box.left-mng_info->x_off[object_id]); 7018 crop_info.y=(crop_box.top-mng_info->y_off[object_id]); 7019 crop_info.width=(size_t) (crop_box.right-crop_box.left); 7020 crop_info.height=(size_t) (crop_box.bottom-crop_box.top); 7021 image->page.width=image->columns; 7022 image->page.height=image->rows; 7023 image->page.x=0; 7024 image->page.y=0; 7025 im=CropImage(image,&crop_info,exception); 7026 7027 if (im != (Image *) NULL) 7028 { 7029 image->columns=im->columns; 7030 image->rows=im->rows; 7031 im=DestroyImage(im); 7032 image->page.width=image->columns; 7033 image->page.height=image->rows; 7034 image->page.x=crop_box.left; 7035 image->page.y=crop_box.top; 7036 } 7037 } 7038 7039 else 7040 { 7041 /* 7042 No pixels in crop area. The MNG spec still requires 7043 a layer, though, so make a single transparent pixel in 7044 the top left corner. 7045 */ 7046 image->columns=1; 7047 image->rows=1; 7048 image->colors=2; 7049 (void) SetImageBackgroundColor(image,exception); 7050 image->page.width=1; 7051 image->page.height=1; 7052 image->page.x=0; 7053 image->page.y=0; 7054 } 7055 } 7056#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 7057 image=mng_info->image; 7058#endif 7059 } 7060 7061#if (MAGICKCORE_QUANTUM_DEPTH > 16) 7062 /* PNG does not handle depths greater than 16 so reduce it even 7063 * if lossy. 7064 */ 7065 if (image->depth > 16) 7066 image->depth=16; 7067#endif 7068 7069#if (MAGICKCORE_QUANTUM_DEPTH > 8) 7070 if (image->depth > 8) 7071 { 7072 /* To do: fill low byte properly */ 7073 image->depth=16; 7074 } 7075 7076 if (LosslessReduceDepthOK(image,exception) != MagickFalse) 7077 image->depth = 8; 7078#endif 7079 7080 if (image_info->number_scenes != 0) 7081 { 7082 if (mng_info->scenes_found > 7083 (ssize_t) (image_info->first_scene+image_info->number_scenes)) 7084 break; 7085 } 7086 7087 if (logging != MagickFalse) 7088 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7089 " Finished reading image datastream."); 7090 7091 } while (LocaleCompare(image_info->magick,"MNG") == 0); 7092 7093 (void) CloseBlob(image); 7094 7095 if (logging != MagickFalse) 7096 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7097 " Finished reading all image datastreams."); 7098 7099#if defined(MNG_INSERT_LAYERS) 7100 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) && 7101 (mng_info->mng_height)) 7102 { 7103 /* 7104 Insert a background layer if nothing else was found. 7105 */ 7106 if (logging != MagickFalse) 7107 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7108 " No images found. Inserting a background layer."); 7109 7110 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 7111 { 7112 /* 7113 Allocate next image structure. 7114 */ 7115 AcquireNextImage(image_info,image,exception); 7116 if (GetNextImageInList(image) == (Image *) NULL) 7117 { 7118 image=DestroyImageList(image); 7119 MngInfoFreeStruct(mng_info,&have_mng_structure); 7120 7121 if (logging != MagickFalse) 7122 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7123 " Allocation failed, returning NULL."); 7124 7125 return((Image *) NULL); 7126 } 7127 image=SyncNextImageInList(image); 7128 } 7129 image->columns=mng_info->mng_width; 7130 image->rows=mng_info->mng_height; 7131 image->page.width=mng_info->mng_width; 7132 image->page.height=mng_info->mng_height; 7133 image->page.x=0; 7134 image->page.y=0; 7135 image->background_color=mng_background_color; 7136 image->alpha_trait=UndefinedPixelTrait; 7137 7138 if (image_info->ping == MagickFalse) 7139 (void) SetImageBackgroundColor(image,exception); 7140 7141 mng_info->image_found++; 7142 } 7143#endif 7144 image->iterations=mng_iterations; 7145 7146 if (mng_iterations == 1) 7147 image->start_loop=MagickTrue; 7148 7149 while (GetPreviousImageInList(image) != (Image *) NULL) 7150 { 7151 image_count++; 7152 if (image_count > 10*mng_info->image_found) 7153 { 7154 if (logging != MagickFalse) 7155 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning"); 7156 7157 (void) ThrowMagickException(exception,GetMagickModule(), 7158 CoderError,"Linked list is corrupted, beginning of list not found", 7159 "`%s'",image_info->filename); 7160 7161 return((Image *) NULL); 7162 } 7163 7164 image=GetPreviousImageInList(image); 7165 7166 if (GetNextImageInList(image) == (Image *) NULL) 7167 { 7168 if (logging != MagickFalse) 7169 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list"); 7170 7171 (void) ThrowMagickException(exception,GetMagickModule(), 7172 CoderError,"Linked list is corrupted; next_image is NULL","`%s'", 7173 image_info->filename); 7174 } 7175 } 7176 7177 if (mng_info->ticks_per_second && mng_info->image_found > 1 && 7178 GetNextImageInList(image) == 7179 (Image *) NULL) 7180 { 7181 if (logging != MagickFalse) 7182 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7183 " First image null"); 7184 7185 (void) ThrowMagickException(exception,GetMagickModule(), 7186 CoderError,"image->next for first image is NULL but shouldn't be.", 7187 "`%s'",image_info->filename); 7188 } 7189 7190 if (mng_info->image_found == 0) 7191 { 7192 if (logging != MagickFalse) 7193 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7194 " No visible images found."); 7195 7196 (void) ThrowMagickException(exception,GetMagickModule(), 7197 CoderError,"No visible images in file","`%s'",image_info->filename); 7198 7199 if (image != (Image *) NULL) 7200 image=DestroyImageList(image); 7201 7202 MngInfoFreeStruct(mng_info,&have_mng_structure); 7203 return((Image *) NULL); 7204 } 7205 7206 if (mng_info->ticks_per_second) 7207 final_delay=1UL*MagickMax(image->ticks_per_second,1L)* 7208 final_delay/mng_info->ticks_per_second; 7209 7210 else 7211 image->start_loop=MagickTrue; 7212 7213 /* Find final nonzero image delay */ 7214 final_image_delay=0; 7215 7216 while (GetNextImageInList(image) != (Image *) NULL) 7217 { 7218 if (image->delay) 7219 final_image_delay=image->delay; 7220 7221 image=GetNextImageInList(image); 7222 } 7223 7224 if (final_delay < final_image_delay) 7225 final_delay=final_image_delay; 7226 7227 image->delay=final_delay; 7228 7229 if (logging != MagickFalse) 7230 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7231 " image->delay=%.20g, final_delay=%.20g",(double) image->delay, 7232 (double) final_delay); 7233 7234 if (logging != MagickFalse) 7235 { 7236 int 7237 scene; 7238 7239 scene=0; 7240 image=GetFirstImageInList(image); 7241 7242 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7243 " Before coalesce:"); 7244 7245 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7246 " scene 0 delay=%.20g",(double) image->delay); 7247 7248 while (GetNextImageInList(image) != (Image *) NULL) 7249 { 7250 image=GetNextImageInList(image); 7251 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7252 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay); 7253 } 7254 } 7255 7256 image=GetFirstImageInList(image); 7257#ifdef MNG_COALESCE_LAYERS 7258 if (insert_layers) 7259 { 7260 Image 7261 *next_image, 7262 *next; 7263 7264 size_t 7265 scene; 7266 7267 if (logging != MagickFalse) 7268 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images"); 7269 7270 scene=image->scene; 7271 next_image=CoalesceImages(image,exception); 7272 7273 if (next_image == (Image *) NULL) 7274 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 7275 7276 image=DestroyImageList(image); 7277 image=next_image; 7278 7279 for (next=image; next != (Image *) NULL; next=next_image) 7280 { 7281 next->page.width=mng_info->mng_width; 7282 next->page.height=mng_info->mng_height; 7283 next->page.x=0; 7284 next->page.y=0; 7285 next->scene=scene++; 7286 next_image=GetNextImageInList(next); 7287 7288 if (next_image == (Image *) NULL) 7289 break; 7290 7291 if (next->delay == 0) 7292 { 7293 scene--; 7294 next_image->previous=GetPreviousImageInList(next); 7295 if (GetPreviousImageInList(next) == (Image *) NULL) 7296 image=next_image; 7297 else 7298 next->previous->next=next_image; 7299 next=DestroyImage(next); 7300 } 7301 } 7302 } 7303#endif 7304 7305 while (GetNextImageInList(image) != (Image *) NULL) 7306 image=GetNextImageInList(image); 7307 7308 image->dispose=BackgroundDispose; 7309 7310 if (logging != MagickFalse) 7311 { 7312 int 7313 scene; 7314 7315 scene=0; 7316 image=GetFirstImageInList(image); 7317 7318 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7319 " After coalesce:"); 7320 7321 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7322 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay, 7323 (double) image->dispose); 7324 7325 while (GetNextImageInList(image) != (Image *) NULL) 7326 { 7327 image=GetNextImageInList(image); 7328 7329 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7330 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++, 7331 (double) image->delay,(double) image->dispose); 7332 } 7333 } 7334 7335 image=GetFirstImageInList(image); 7336 MngInfoFreeStruct(mng_info,&have_mng_structure); 7337 have_mng_structure=MagickFalse; 7338 7339 if (logging != MagickFalse) 7340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()"); 7341 7342 return(GetFirstImageInList(image)); 7343} 7344#else /* PNG_LIBPNG_VER > 10011 */ 7345static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 7346{ 7347 printf("Your PNG library is too old: You have libpng-%s\n", 7348 PNG_LIBPNG_VER_STRING); 7349 7350 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 7351 "PNG library is too old","`%s'",image_info->filename); 7352 7353 return(Image *) NULL; 7354} 7355 7356static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 7357{ 7358 return(ReadPNGImage(image_info,exception)); 7359} 7360#endif /* PNG_LIBPNG_VER > 10011 */ 7361#endif 7362 7363/* 7364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7365% % 7366% % 7367% % 7368% R e g i s t e r P N G I m a g e % 7369% % 7370% % 7371% % 7372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7373% 7374% RegisterPNGImage() adds properties for the PNG image format to 7375% the list of supported formats. The properties include the image format 7376% tag, a method to read and/or write the format, whether the format 7377% supports the saving of more than one frame to the same file or blob, 7378% whether the format supports native in-memory I/O, and a brief 7379% description of the format. 7380% 7381% The format of the RegisterPNGImage method is: 7382% 7383% size_t RegisterPNGImage(void) 7384% 7385*/ 7386ModuleExport size_t RegisterPNGImage(void) 7387{ 7388 char 7389 version[MagickPathExtent]; 7390 7391 MagickInfo 7392 *entry; 7393 7394 static const char 7395 *PNGNote= 7396 { 7397 "See http://www.libpng.org/ for details about the PNG format." 7398 }, 7399 7400 *JNGNote= 7401 { 7402 "See http://www.libpng.org/pub/mng/ for details about the JNG\n" 7403 "format." 7404 }, 7405 7406 *MNGNote= 7407 { 7408 "See http://www.libpng.org/pub/mng/ for details about the MNG\n" 7409 "format." 7410 }; 7411 7412 *version='\0'; 7413 7414#if defined(PNG_LIBPNG_VER_STRING) 7415 (void) ConcatenateMagickString(version,"libpng ",MagickPathExtent); 7416 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MagickPathExtent); 7417 7418 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0) 7419 { 7420 (void) ConcatenateMagickString(version,",",MagickPathExtent); 7421 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL), 7422 MagickPathExtent); 7423 } 7424#endif 7425 7426 entry=AcquireMagickInfo("PNG","MNG","Multiple-image Network Graphics"); 7427 entry->flags|=CoderSeekableStreamFlag; /* To do: eliminate this. */ 7428 7429#if defined(MAGICKCORE_PNG_DELEGATE) 7430 entry->decoder=(DecodeImageHandler *) ReadMNGImage; 7431 entry->encoder=(EncodeImageHandler *) WriteMNGImage; 7432#endif 7433 7434 entry->magick=(IsImageFormatHandler *) IsMNG; 7435 7436 if (*version != '\0') 7437 entry->version=ConstantString(version); 7438 7439 entry->mime_type=ConstantString("video/x-mng"); 7440 entry->note=ConstantString(MNGNote); 7441 (void) RegisterMagickInfo(entry); 7442 7443 entry=AcquireMagickInfo("PNG","PNG","Portable Network Graphics"); 7444 7445#if defined(MAGICKCORE_PNG_DELEGATE) 7446 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7447 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7448#endif 7449 7450 entry->magick=(IsImageFormatHandler *) IsPNG; 7451 entry->flags^=CoderAdjoinFlag; 7452 entry->mime_type=ConstantString("image/png"); 7453 7454 if (*version != '\0') 7455 entry->version=ConstantString(version); 7456 7457 entry->note=ConstantString(PNGNote); 7458 (void) RegisterMagickInfo(entry); 7459 7460 entry=AcquireMagickInfo("PNG","PNG8", 7461 "8-bit indexed with optional binary transparency"); 7462 7463#if defined(MAGICKCORE_PNG_DELEGATE) 7464 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7465 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7466#endif 7467 7468 entry->magick=(IsImageFormatHandler *) IsPNG; 7469 entry->flags^=CoderAdjoinFlag; 7470 entry->mime_type=ConstantString("image/png"); 7471 (void) RegisterMagickInfo(entry); 7472 7473 entry=AcquireMagickInfo("PNG","PNG24", 7474 "opaque or binary transparent 24-bit RGB"); 7475 *version='\0'; 7476 7477#if defined(ZLIB_VERSION) 7478 (void) ConcatenateMagickString(version,"zlib ",MagickPathExtent); 7479 (void) ConcatenateMagickString(version,ZLIB_VERSION,MagickPathExtent); 7480 7481 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0) 7482 { 7483 (void) ConcatenateMagickString(version,",",MagickPathExtent); 7484 (void) ConcatenateMagickString(version,zlib_version,MagickPathExtent); 7485 } 7486#endif 7487 7488 if (*version != '\0') 7489 entry->version=ConstantString(version); 7490 7491#if defined(MAGICKCORE_PNG_DELEGATE) 7492 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7493 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7494#endif 7495 7496 entry->magick=(IsImageFormatHandler *) IsPNG; 7497 entry->flags^=CoderAdjoinFlag; 7498 entry->mime_type=ConstantString("image/png"); 7499 (void) RegisterMagickInfo(entry); 7500 7501 entry=AcquireMagickInfo("PNG","PNG32","opaque or transparent 32-bit RGBA"); 7502 7503#if defined(MAGICKCORE_PNG_DELEGATE) 7504 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7505 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7506#endif 7507 7508 entry->magick=(IsImageFormatHandler *) IsPNG; 7509 entry->flags^=CoderAdjoinFlag; 7510 entry->mime_type=ConstantString("image/png"); 7511 (void) RegisterMagickInfo(entry); 7512 7513 entry=AcquireMagickInfo("PNG","PNG48", 7514 "opaque or binary transparent 48-bit RGB"); 7515 7516#if defined(MAGICKCORE_PNG_DELEGATE) 7517 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7518 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7519#endif 7520 7521 entry->magick=(IsImageFormatHandler *) IsPNG; 7522 entry->flags^=CoderAdjoinFlag; 7523 entry->mime_type=ConstantString("image/png"); 7524 (void) RegisterMagickInfo(entry); 7525 7526 entry=AcquireMagickInfo("PNG","PNG64","opaque or transparent 64-bit RGBA"); 7527 7528#if defined(MAGICKCORE_PNG_DELEGATE) 7529 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7530 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7531#endif 7532 7533 entry->magick=(IsImageFormatHandler *) IsPNG; 7534 entry->flags^=CoderAdjoinFlag; 7535 entry->mime_type=ConstantString("image/png"); 7536 (void) RegisterMagickInfo(entry); 7537 7538 entry=AcquireMagickInfo("PNG","PNG00", 7539 "PNG inheriting bit-depth, color-type from original, if possible"); 7540 7541#if defined(MAGICKCORE_PNG_DELEGATE) 7542 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7543 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7544#endif 7545 7546 entry->magick=(IsImageFormatHandler *) IsPNG; 7547 entry->flags^=CoderAdjoinFlag; 7548 entry->mime_type=ConstantString("image/png"); 7549 (void) RegisterMagickInfo(entry); 7550 7551 entry=AcquireMagickInfo("PNG","JNG","JPEG Network Graphics"); 7552 7553#if defined(JNG_SUPPORTED) 7554#if defined(MAGICKCORE_PNG_DELEGATE) 7555 entry->decoder=(DecodeImageHandler *) ReadJNGImage; 7556 entry->encoder=(EncodeImageHandler *) WriteJNGImage; 7557#endif 7558#endif 7559 7560 entry->magick=(IsImageFormatHandler *) IsJNG; 7561 entry->flags^=CoderAdjoinFlag; 7562 entry->mime_type=ConstantString("image/x-jng"); 7563 entry->note=ConstantString(JNGNote); 7564 (void) RegisterMagickInfo(entry); 7565 7566#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 7567 ping_semaphore=AcquireSemaphoreInfo(); 7568#endif 7569 7570 return(MagickImageCoderSignature); 7571} 7572 7573/* 7574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7575% % 7576% % 7577% % 7578% U n r e g i s t e r P N G I m a g e % 7579% % 7580% % 7581% % 7582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7583% 7584% UnregisterPNGImage() removes format registrations made by the 7585% PNG module from the list of supported formats. 7586% 7587% The format of the UnregisterPNGImage method is: 7588% 7589% UnregisterPNGImage(void) 7590% 7591*/ 7592ModuleExport void UnregisterPNGImage(void) 7593{ 7594 (void) UnregisterMagickInfo("MNG"); 7595 (void) UnregisterMagickInfo("PNG"); 7596 (void) UnregisterMagickInfo("PNG8"); 7597 (void) UnregisterMagickInfo("PNG24"); 7598 (void) UnregisterMagickInfo("PNG32"); 7599 (void) UnregisterMagickInfo("PNG48"); 7600 (void) UnregisterMagickInfo("PNG64"); 7601 (void) UnregisterMagickInfo("PNG00"); 7602 (void) UnregisterMagickInfo("JNG"); 7603 7604#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 7605 if (ping_semaphore != (SemaphoreInfo *) NULL) 7606 RelinquishSemaphoreInfo(&ping_semaphore); 7607#endif 7608} 7609 7610#if defined(MAGICKCORE_PNG_DELEGATE) 7611#if PNG_LIBPNG_VER > 10011 7612/* 7613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7614% % 7615% % 7616% % 7617% W r i t e M N G I m a g e % 7618% % 7619% % 7620% % 7621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7622% 7623% WriteMNGImage() writes an image in the Portable Network Graphics 7624% Group's "Multiple-image Network Graphics" encoded image format. 7625% 7626% MNG support written by Glenn Randers-Pehrson, glennrp@image... 7627% 7628% The format of the WriteMNGImage method is: 7629% 7630% MagickBooleanType WriteMNGImage(const ImageInfo *image_info, 7631% Image *image,ExceptionInfo *exception) 7632% 7633% A description of each parameter follows. 7634% 7635% o image_info: the image info. 7636% 7637% o image: The image. 7638% 7639% o exception: return any errors or warnings in this structure. 7640% 7641% To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also 7642% "To do" under ReadPNGImage): 7643% 7644% Preserve all unknown and not-yet-handled known chunks found in input 7645% PNG file and copy them into output PNG files according to the PNG 7646% copying rules. 7647% 7648% Write the iCCP chunk at MNG level when (icc profile length > 0) 7649% 7650% Improve selection of color type (use indexed-colour or indexed-colour 7651% with tRNS when 256 or fewer unique RGBA values are present). 7652% 7653% Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3) 7654% This will be complicated if we limit ourselves to generating MNG-LC 7655% files. For now we ignore disposal method 3 and simply overlay the next 7656% image on it. 7657% 7658% Check for identical PLTE's or PLTE/tRNS combinations and use a 7659% global MNG PLTE or PLTE/tRNS combination when appropriate. 7660% [mostly done 15 June 1999 but still need to take care of tRNS] 7661% 7662% Check for identical sRGB and replace with a global sRGB (and remove 7663% gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and 7664% replace with global gAMA/cHRM (or with sRGB if appropriate; replace 7665% local gAMA/cHRM with local sRGB if appropriate). 7666% 7667% Check for identical sBIT chunks and write global ones. 7668% 7669% Provide option to skip writing the signature tEXt chunks. 7670% 7671% Use signatures to detect identical objects and reuse the first 7672% instance of such objects instead of writing duplicate objects. 7673% 7674% Use a smaller-than-32k value of compression window size when 7675% appropriate. 7676% 7677% Encode JNG datastreams. Mostly done as of 5.5.2; need to write 7678% ancillary text chunks and save profiles. 7679% 7680% Provide an option to force LC files (to ensure exact framing rate) 7681% instead of VLC. 7682% 7683% Provide an option to force VLC files instead of LC, even when offsets 7684% are present. This will involve expanding the embedded images with a 7685% transparent region at the top and/or left. 7686*/ 7687 7688static void 7689Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping, 7690 png_info *ping_info, unsigned char *profile_type, unsigned char 7691 *profile_description, unsigned char *profile_data, png_uint_32 length) 7692{ 7693 png_textp 7694 text; 7695 7696 register ssize_t 7697 i; 7698 7699 unsigned char 7700 *sp; 7701 7702 png_charp 7703 dp; 7704 7705 png_uint_32 7706 allocated_length, 7707 description_length; 7708 7709 unsigned char 7710 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 7711 7712 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0) 7713 return; 7714 7715 if (image_info->verbose) 7716 { 7717 (void) printf("writing raw profile: type=%s, length=%.20g\n", 7718 (char *) profile_type, (double) length); 7719 } 7720 7721#if PNG_LIBPNG_VER >= 10400 7722 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text)); 7723#else 7724 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); 7725#endif 7726 description_length=(png_uint_32) strlen((const char *) profile_description); 7727 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20 7728 + description_length); 7729#if PNG_LIBPNG_VER >= 10400 7730 text[0].text=(png_charp) png_malloc(ping, 7731 (png_alloc_size_t) allocated_length); 7732 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80); 7733#else 7734 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length); 7735 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80); 7736#endif 7737 text[0].key[0]='\0'; 7738 (void) ConcatenateMagickString(text[0].key, 7739 "Raw profile type ",MagickPathExtent); 7740 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62); 7741 sp=profile_data; 7742 dp=text[0].text; 7743 *dp++='\n'; 7744 (void) CopyMagickString(dp,(const char *) profile_description, 7745 allocated_length); 7746 dp+=description_length; 7747 *dp++='\n'; 7748 (void) FormatLocaleString(dp,allocated_length- 7749 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length); 7750 dp+=8; 7751 7752 for (i=0; i < (ssize_t) length; i++) 7753 { 7754 if (i%36 == 0) 7755 *dp++='\n'; 7756 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)]; 7757 *(dp++)=(char) hex[((*sp++ ) & 0x0f)]; 7758 } 7759 7760 *dp++='\n'; 7761 *dp='\0'; 7762 text[0].text_length=(png_size_t) (dp-text[0].text); 7763 text[0].compression=image_info->compression == NoCompression || 7764 (image_info->compression == UndefinedCompression && 7765 text[0].text_length < 128) ? -1 : 0; 7766 7767 if (text[0].text_length <= allocated_length) 7768 png_set_text(ping,ping_info,text,1); 7769 7770 png_free(ping,text[0].text); 7771 png_free(ping,text[0].key); 7772 png_free(ping,text); 7773} 7774 7775static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image, 7776 const char *string, MagickBooleanType logging) 7777{ 7778 char 7779 *name; 7780 7781 const StringInfo 7782 *profile; 7783 7784 unsigned char 7785 *data; 7786 7787 png_uint_32 length; 7788 7789 ResetImageProfileIterator(image); 7790 7791 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 7792 { 7793 profile=GetImageProfile(image,name); 7794 7795 if (profile != (const StringInfo *) NULL) 7796 { 7797 StringInfo 7798 *ping_profile; 7799 7800 if (LocaleNCompare(name,string,11) == 0) 7801 { 7802 if (logging != MagickFalse) 7803 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7804 " Found %s profile",name); 7805 7806 ping_profile=CloneStringInfo(profile); 7807 data=GetStringInfoDatum(ping_profile), 7808 length=(png_uint_32) GetStringInfoLength(ping_profile); 7809 data[4]=data[3]; 7810 data[3]=data[2]; 7811 data[2]=data[1]; 7812 data[1]=data[0]; 7813 (void) WriteBlobMSBULong(image,length-5); /* data length */ 7814 (void) WriteBlob(image,length-1,data+1); 7815 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1)); 7816 ping_profile=DestroyStringInfo(ping_profile); 7817 } 7818 } 7819 7820 name=GetNextImageProfile(image); 7821 } 7822 7823 return(MagickTrue); 7824} 7825 7826static inline MagickBooleanType Magick_png_color_equal(const Image *image, 7827 const Quantum *p, const PixelInfo *q) 7828{ 7829 MagickRealType 7830 value; 7831 7832 value=(MagickRealType) p[image->channel_map[RedPixelChannel].offset]; 7833 if (AbsolutePixelValue(value-q->red) >= MagickEpsilon) 7834 return(MagickFalse); 7835 value=(MagickRealType) p[image->channel_map[GreenPixelChannel].offset]; 7836 if (AbsolutePixelValue(value-q->green) >= MagickEpsilon) 7837 return(MagickFalse); 7838 value=(MagickRealType) p[image->channel_map[BluePixelChannel].offset]; 7839 if (AbsolutePixelValue(value-q->blue) >= MagickEpsilon) 7840 return(MagickFalse); 7841 7842 return(MagickTrue); 7843} 7844 7845#if defined(PNG_tIME_SUPPORTED) 7846static void write_tIME_chunk(Image *image,png_struct *ping,png_info *info, 7847 const char *date,ExceptionInfo *exception) 7848{ 7849 unsigned int 7850 day, 7851 hour, 7852 minute, 7853 month, 7854 second, 7855 year; 7856 7857 png_time 7858 ptime; 7859 7860 time_t 7861 ttime; 7862 7863 if (date != (const char *) NULL) 7864 { 7865 if (sscanf(date,"%d-%d-%dT%d:%d:%dZ",&year,&month,&day,&hour,&minute, 7866 &second) != 6) 7867 { 7868 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 7869 "Invalid date format specified for png:tIME","`%s'", 7870 image->filename); 7871 return; 7872 } 7873 ptime.year=(png_uint_16) year; 7874 ptime.month=(png_byte) month; 7875 ptime.day=(png_byte) day; 7876 ptime.hour=(png_byte) hour; 7877 ptime.minute=(png_byte) minute; 7878 ptime.second=(png_byte) second; 7879 } 7880 else 7881 { 7882 time(&ttime); 7883 png_convert_from_time_t(&ptime,ttime); 7884 } 7885 png_set_tIME(ping,info,&ptime); 7886} 7887#endif 7888 7889/* Write one PNG image */ 7890static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, 7891 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception) 7892{ 7893 char 7894 im_vers[32], 7895 libpng_runv[32], 7896 libpng_vers[32], 7897 zlib_runv[32], 7898 zlib_vers[32]; 7899 7900 Image 7901 *image; 7902 7903 ImageInfo 7904 *image_info; 7905 7906 char 7907 s[2]; 7908 7909 const char 7910 *name, 7911 *property, 7912 *value; 7913 7914 const StringInfo 7915 *profile; 7916 7917 int 7918 num_passes, 7919 pass; 7920 7921 png_byte 7922 ping_trans_alpha[256]; 7923 7924 png_color 7925 palette[257]; 7926 7927 png_color_16 7928 ping_background, 7929 ping_trans_color; 7930 7931 png_info 7932 *ping_info; 7933 7934 png_struct 7935 *ping; 7936 7937 png_uint_32 7938 ping_height, 7939 ping_width; 7940 7941 ssize_t 7942 y; 7943 7944 MagickBooleanType 7945 image_matte, 7946 logging, 7947 matte, 7948 7949 ping_have_blob, 7950 ping_have_cheap_transparency, 7951 ping_have_color, 7952 ping_have_non_bw, 7953 ping_have_PLTE, 7954 ping_have_bKGD, 7955 ping_have_iCCP, 7956 ping_have_pHYs, 7957 ping_have_sRGB, 7958 ping_have_tRNS, 7959 7960 ping_exclude_bKGD, 7961 ping_exclude_cHRM, 7962 ping_exclude_date, 7963 /* ping_exclude_EXIF, */ 7964 ping_exclude_gAMA, 7965 ping_exclude_iCCP, 7966 /* ping_exclude_iTXt, */ 7967 ping_exclude_oFFs, 7968 ping_exclude_pHYs, 7969 ping_exclude_sRGB, 7970 ping_exclude_tEXt, 7971 ping_exclude_tIME, 7972 /* ping_exclude_tRNS, */ 7973 ping_exclude_vpAg, 7974 ping_exclude_zCCP, /* hex-encoded iCCP */ 7975 ping_exclude_zTXt, 7976 7977 ping_preserve_colormap, 7978 ping_preserve_iCCP, 7979 ping_need_colortype_warning, 7980 7981 status, 7982 tried_332, 7983 tried_333, 7984 tried_444; 7985 7986 MemoryInfo 7987 *volatile pixel_info; 7988 7989 QuantumInfo 7990 *quantum_info; 7991 7992 PNGErrorInfo 7993 error_info; 7994 7995 register ssize_t 7996 i, 7997 x; 7998 7999 unsigned char 8000 *ping_pixels; 8001 8002 volatile int 8003 image_colors, 8004 ping_bit_depth, 8005 ping_color_type, 8006 ping_interlace_method, 8007 ping_compression_method, 8008 ping_filter_method, 8009 ping_num_trans; 8010 8011 volatile size_t 8012 image_depth, 8013 old_bit_depth; 8014 8015 size_t 8016 quality, 8017 rowbytes, 8018 save_image_depth; 8019 8020 int 8021 j, 8022 number_colors, 8023 number_opaque, 8024 number_semitransparent, 8025 number_transparent, 8026 ping_pHYs_unit_type; 8027 8028 png_uint_32 8029 ping_pHYs_x_resolution, 8030 ping_pHYs_y_resolution; 8031 8032 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 8033 " Enter WriteOnePNGImage()"); 8034 8035 image = CloneImage(IMimage,0,0,MagickFalse,exception); 8036 image_info=(ImageInfo *) CloneImageInfo(IMimage_info); 8037 if (image_info == (ImageInfo *) NULL) 8038 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed"); 8039 8040 /* Define these outside of the following "if logging()" block so they will 8041 * show in debuggers. 8042 */ 8043 *im_vers='\0'; 8044 (void) ConcatenateMagickString(im_vers, 8045 MagickLibVersionText,MagickPathExtent); 8046 (void) ConcatenateMagickString(im_vers, 8047 MagickLibAddendum,MagickPathExtent); 8048 8049 *libpng_vers='\0'; 8050 (void) ConcatenateMagickString(libpng_vers, 8051 PNG_LIBPNG_VER_STRING,32); 8052 *libpng_runv='\0'; 8053 (void) ConcatenateMagickString(libpng_runv, 8054 png_get_libpng_ver(NULL),32); 8055 8056 *zlib_vers='\0'; 8057 (void) ConcatenateMagickString(zlib_vers, 8058 ZLIB_VERSION,32); 8059 *zlib_runv='\0'; 8060 (void) ConcatenateMagickString(zlib_runv, 8061 zlib_version,32); 8062 8063 if (logging != MagickFalse) 8064 { 8065 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s", 8066 im_vers); 8067 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s", 8068 libpng_vers); 8069 if (LocaleCompare(libpng_vers,libpng_runv) != 0) 8070 { 8071 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 8072 libpng_runv); 8073 } 8074 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s", 8075 zlib_vers); 8076 if (LocaleCompare(zlib_vers,zlib_runv) != 0) 8077 { 8078 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 8079 zlib_runv); 8080 } 8081 } 8082 8083 /* Initialize some stuff */ 8084 ping_bit_depth=0, 8085 ping_color_type=0, 8086 ping_interlace_method=0, 8087 ping_compression_method=0, 8088 ping_filter_method=0, 8089 ping_num_trans = 0; 8090 8091 ping_background.red = 0; 8092 ping_background.green = 0; 8093 ping_background.blue = 0; 8094 ping_background.gray = 0; 8095 ping_background.index = 0; 8096 8097 ping_trans_color.red=0; 8098 ping_trans_color.green=0; 8099 ping_trans_color.blue=0; 8100 ping_trans_color.gray=0; 8101 8102 ping_pHYs_unit_type = 0; 8103 ping_pHYs_x_resolution = 0; 8104 ping_pHYs_y_resolution = 0; 8105 8106 ping_have_blob=MagickFalse; 8107 ping_have_cheap_transparency=MagickFalse; 8108 ping_have_color=MagickTrue; 8109 ping_have_non_bw=MagickTrue; 8110 ping_have_PLTE=MagickFalse; 8111 ping_have_bKGD=MagickFalse; 8112 ping_have_iCCP=MagickFalse; 8113 ping_have_pHYs=MagickFalse; 8114 ping_have_sRGB=MagickFalse; 8115 ping_have_tRNS=MagickFalse; 8116 8117 ping_exclude_bKGD=mng_info->ping_exclude_bKGD; 8118 ping_exclude_cHRM=mng_info->ping_exclude_cHRM; 8119 ping_exclude_date=mng_info->ping_exclude_date; 8120 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */ 8121 ping_exclude_gAMA=mng_info->ping_exclude_gAMA; 8122 ping_exclude_iCCP=mng_info->ping_exclude_iCCP; 8123 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */ 8124 ping_exclude_oFFs=mng_info->ping_exclude_oFFs; 8125 ping_exclude_pHYs=mng_info->ping_exclude_pHYs; 8126 ping_exclude_sRGB=mng_info->ping_exclude_sRGB; 8127 ping_exclude_tEXt=mng_info->ping_exclude_tEXt; 8128 ping_exclude_tIME=mng_info->ping_exclude_tIME; 8129 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */ 8130 ping_exclude_vpAg=mng_info->ping_exclude_vpAg; 8131 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */ 8132 ping_exclude_zTXt=mng_info->ping_exclude_zTXt; 8133 8134 ping_preserve_colormap = mng_info->ping_preserve_colormap; 8135 ping_preserve_iCCP = mng_info->ping_preserve_iCCP; 8136 ping_need_colortype_warning = MagickFalse; 8137 8138 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk, 8139 * i.e., eliminate the ICC profile and set image->rendering_intent. 8140 * Note that this will not involve any changes to the actual pixels 8141 * but merely passes information to applications that read the resulting 8142 * PNG image. 8143 * 8144 * To do: recognize other variants of the sRGB profile, using the CRC to 8145 * verify all recognized variants including the 7 already known. 8146 * 8147 * Work around libpng16+ rejecting some "known invalid sRGB profiles". 8148 * 8149 * Use something other than image->rendering_intent to record the fact 8150 * that the sRGB profile was found. 8151 * 8152 * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC 8153 * profile. Record the Blackpoint Compensation, if any. 8154 */ 8155 if (ping_exclude_sRGB == MagickFalse && ping_preserve_iCCP == MagickFalse) 8156 { 8157 char 8158 *name; 8159 8160 const StringInfo 8161 *profile; 8162 8163 ResetImageProfileIterator(image); 8164 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 8165 { 8166 profile=GetImageProfile(image,name); 8167 8168 if (profile != (StringInfo *) NULL) 8169 { 8170 if ((LocaleCompare(name,"ICC") == 0) || 8171 (LocaleCompare(name,"ICM") == 0)) 8172 8173 { 8174 int 8175 icheck, 8176 got_crc=0; 8177 8178 8179 png_uint_32 8180 length, 8181 profile_crc=0; 8182 8183 unsigned char 8184 *data; 8185 8186 length=(png_uint_32) GetStringInfoLength(profile); 8187 8188 for (icheck=0; sRGB_info[icheck].len > 0; icheck++) 8189 { 8190 if (length == sRGB_info[icheck].len) 8191 { 8192 if (got_crc == 0) 8193 { 8194 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8195 " Got a %lu-byte ICC profile (potentially sRGB)", 8196 (unsigned long) length); 8197 8198 data=GetStringInfoDatum(profile); 8199 profile_crc=crc32(0,data,length); 8200 8201 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8202 " with crc=%8x",(unsigned int) profile_crc); 8203 got_crc++; 8204 } 8205 8206 if (profile_crc == sRGB_info[icheck].crc) 8207 { 8208 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8209 " It is sRGB with rendering intent = %s", 8210 Magick_RenderingIntentString_from_PNG_RenderingIntent( 8211 sRGB_info[icheck].intent)); 8212 if (image->rendering_intent==UndefinedIntent) 8213 { 8214 image->rendering_intent= 8215 Magick_RenderingIntent_from_PNG_RenderingIntent( 8216 sRGB_info[icheck].intent); 8217 } 8218 ping_exclude_iCCP = MagickTrue; 8219 ping_exclude_zCCP = MagickTrue; 8220 ping_have_sRGB = MagickTrue; 8221 break; 8222 } 8223 } 8224 } 8225 if (sRGB_info[icheck].len == 0) 8226 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8227 " Got a %lu-byte ICC profile not recognized as sRGB", 8228 (unsigned long) length); 8229 } 8230 } 8231 name=GetNextImageProfile(image); 8232 } 8233 } 8234 8235 number_opaque = 0; 8236 number_semitransparent = 0; 8237 number_transparent = 0; 8238 8239 if (logging != MagickFalse) 8240 { 8241 if (image->storage_class == UndefinedClass) 8242 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8243 " image->storage_class=UndefinedClass"); 8244 if (image->storage_class == DirectClass) 8245 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8246 " image->storage_class=DirectClass"); 8247 if (image->storage_class == PseudoClass) 8248 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8249 " image->storage_class=PseudoClass"); 8250 (void) LogMagickEvent(CoderEvent,GetMagickModule(), image->taint ? 8251 " image->taint=MagickTrue": 8252 " image->taint=MagickFalse"); 8253 } 8254 8255 if (image->storage_class == PseudoClass && 8256 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 || 8257 mng_info->write_png48 || mng_info->write_png64 || 8258 (mng_info->write_png_colortype != 1 && 8259 mng_info->write_png_colortype != 5))) 8260 { 8261 (void) SyncImage(image,exception); 8262 image->storage_class = DirectClass; 8263 } 8264 8265 if (ping_preserve_colormap == MagickFalse) 8266 { 8267 if (image->storage_class != PseudoClass && image->colormap != NULL) 8268 { 8269 /* Free the bogus colormap; it can cause trouble later */ 8270 if (logging != MagickFalse) 8271 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8272 " Freeing bogus colormap"); 8273 (void) RelinquishMagickMemory(image->colormap); 8274 image->colormap=NULL; 8275 } 8276 } 8277 8278 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 8279 (void) TransformImageColorspace(image,sRGBColorspace,exception); 8280 8281 /* 8282 Sometimes we get PseudoClass images whose RGB values don't match 8283 the colors in the colormap. This code syncs the RGB values. 8284 */ 8285 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass) 8286 (void) SyncImage(image,exception); 8287 8288#if (MAGICKCORE_QUANTUM_DEPTH == 8) 8289 if (image->depth > 8) 8290 { 8291 if (logging != MagickFalse) 8292 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8293 " Reducing PNG bit depth to 8 since this is a Q8 build."); 8294 8295 image->depth=8; 8296 } 8297#endif 8298 8299 /* Respect the -depth option */ 8300 if (image->depth < 4) 8301 { 8302 register Quantum 8303 *r; 8304 8305 if (image->depth > 2) 8306 { 8307 /* Scale to 4-bit */ 8308 LBR04PacketRGBO(image->background_color); 8309 8310 for (y=0; y < (ssize_t) image->rows; y++) 8311 { 8312 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8313 8314 if (r == (Quantum *) NULL) 8315 break; 8316 8317 for (x=0; x < (ssize_t) image->columns; x++) 8318 { 8319 LBR04PixelRGBA(r); 8320 r+=GetPixelChannels(image); 8321 } 8322 8323 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8324 break; 8325 } 8326 8327 if (image->storage_class == PseudoClass && image->colormap != NULL) 8328 { 8329 for (i=0; i < (ssize_t) image->colors; i++) 8330 { 8331 LBR04PacketRGBO(image->colormap[i]); 8332 } 8333 } 8334 } 8335 else if (image->depth > 1) 8336 { 8337 /* Scale to 2-bit */ 8338 LBR02PacketRGBO(image->background_color); 8339 8340 for (y=0; y < (ssize_t) image->rows; y++) 8341 { 8342 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8343 8344 if (r == (Quantum *) NULL) 8345 break; 8346 8347 for (x=0; x < (ssize_t) image->columns; x++) 8348 { 8349 LBR02PixelRGBA(r); 8350 r+=GetPixelChannels(image); 8351 } 8352 8353 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8354 break; 8355 } 8356 8357 if (image->storage_class == PseudoClass && image->colormap != NULL) 8358 { 8359 for (i=0; i < (ssize_t) image->colors; i++) 8360 { 8361 LBR02PacketRGBO(image->colormap[i]); 8362 } 8363 } 8364 } 8365 else 8366 { 8367 /* Scale to 1-bit */ 8368 LBR01PacketRGBO(image->background_color); 8369 8370 for (y=0; y < (ssize_t) image->rows; y++) 8371 { 8372 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8373 8374 if (r == (Quantum *) NULL) 8375 break; 8376 8377 for (x=0; x < (ssize_t) image->columns; x++) 8378 { 8379 LBR01PixelRGBA(r); 8380 r+=GetPixelChannels(image); 8381 } 8382 8383 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8384 break; 8385 } 8386 8387 if (image->storage_class == PseudoClass && image->colormap != NULL) 8388 { 8389 for (i=0; i < (ssize_t) image->colors; i++) 8390 { 8391 LBR01PacketRGBO(image->colormap[i]); 8392 } 8393 } 8394 } 8395 } 8396 8397 /* To do: set to next higher multiple of 8 */ 8398 if (image->depth < 8) 8399 image->depth=8; 8400 8401#if (MAGICKCORE_QUANTUM_DEPTH > 16) 8402 /* PNG does not handle depths greater than 16 so reduce it even 8403 * if lossy 8404 */ 8405 if (image->depth > 8) 8406 image->depth=16; 8407#endif 8408 8409#if (MAGICKCORE_QUANTUM_DEPTH > 8) 8410 if (image->depth > 8) 8411 { 8412 /* To do: fill low byte properly */ 8413 image->depth=16; 8414 } 8415 8416 if (image->depth == 16 && mng_info->write_png_depth != 16) 8417 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse) 8418 image->depth = 8; 8419#endif 8420 8421 image_colors = (int) image->colors; 8422 number_opaque = (int) image->colors; 8423 number_transparent = 0; 8424 number_semitransparent = 0; 8425 8426 if (mng_info->write_png_colortype && 8427 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 && 8428 mng_info->write_png_colortype < 4 && 8429 image->alpha_trait == UndefinedPixelTrait))) 8430 { 8431 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we 8432 * are not going to need the result. 8433 */ 8434 if (mng_info->write_png_colortype == 1 || 8435 mng_info->write_png_colortype == 5) 8436 ping_have_color=MagickFalse; 8437 8438 if (image->alpha_trait != UndefinedPixelTrait) 8439 { 8440 number_transparent = 2; 8441 number_semitransparent = 1; 8442 } 8443 } 8444 8445 if (mng_info->write_png_colortype < 7) 8446 { 8447 /* BUILD_PALETTE 8448 * 8449 * Normally we run this just once, but in the case of writing PNG8 8450 * we reduce the transparency to binary and run again, then if there 8451 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1 8452 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA 8453 * palette. Then (To do) we take care of a final reduction that is only 8454 * needed if there are still 256 colors present and one of them has both 8455 * transparent and opaque instances. 8456 */ 8457 8458 tried_332 = MagickFalse; 8459 tried_333 = MagickFalse; 8460 tried_444 = MagickFalse; 8461 8462 for (j=0; j<6; j++) 8463 { 8464 /* 8465 * Sometimes we get DirectClass images that have 256 colors or fewer. 8466 * This code will build a colormap. 8467 * 8468 * Also, sometimes we get PseudoClass images with an out-of-date 8469 * colormap. This code will replace the colormap with a new one. 8470 * Sometimes we get PseudoClass images that have more than 256 colors. 8471 * This code will delete the colormap and change the image to 8472 * DirectClass. 8473 * 8474 * If image->alpha_trait is MagickFalse, we ignore the alpha channel 8475 * even though it sometimes contains left-over non-opaque values. 8476 * 8477 * Also we gather some information (number of opaque, transparent, 8478 * and semitransparent pixels, and whether the image has any non-gray 8479 * pixels or only black-and-white pixels) that we might need later. 8480 * 8481 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6) 8482 * we need to check for bogus non-opaque values, at least. 8483 */ 8484 8485 int 8486 n; 8487 8488 PixelInfo 8489 opaque[260], 8490 semitransparent[260], 8491 transparent[260]; 8492 8493 register const Quantum 8494 *s; 8495 8496 register Quantum 8497 *q, 8498 *r; 8499 8500 if (logging != MagickFalse) 8501 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8502 " Enter BUILD_PALETTE:"); 8503 8504 if (logging != MagickFalse) 8505 { 8506 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8507 " image->columns=%.20g",(double) image->columns); 8508 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8509 " image->rows=%.20g",(double) image->rows); 8510 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8511 " image->alpha_trait=%.20g",(double) image->alpha_trait); 8512 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8513 " image->depth=%.20g",(double) image->depth); 8514 8515 if (image->storage_class == PseudoClass && image->colormap != NULL) 8516 { 8517 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8518 " Original colormap:"); 8519 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8520 " i (red,green,blue,alpha)"); 8521 8522 for (i=0; i < 256; i++) 8523 { 8524 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8525 " %d (%d,%d,%d,%d)", 8526 (int) i, 8527 (int) image->colormap[i].red, 8528 (int) image->colormap[i].green, 8529 (int) image->colormap[i].blue, 8530 (int) image->colormap[i].alpha); 8531 } 8532 8533 for (i=image->colors - 10; i < (ssize_t) image->colors; i++) 8534 { 8535 if (i > 255) 8536 { 8537 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8538 " %d (%d,%d,%d,%d)", 8539 (int) i, 8540 (int) image->colormap[i].red, 8541 (int) image->colormap[i].green, 8542 (int) image->colormap[i].blue, 8543 (int) image->colormap[i].alpha); 8544 } 8545 } 8546 } 8547 8548 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8549 " image->colors=%d",(int) image->colors); 8550 8551 if (image->colors == 0) 8552 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8553 " (zero means unknown)"); 8554 8555 if (ping_preserve_colormap == MagickFalse) 8556 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8557 " Regenerate the colormap"); 8558 } 8559 8560 image_colors=0; 8561 number_opaque = 0; 8562 number_semitransparent = 0; 8563 number_transparent = 0; 8564 8565 for (y=0; y < (ssize_t) image->rows; y++) 8566 { 8567 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8568 8569 if (q == (Quantum *) NULL) 8570 break; 8571 8572 for (x=0; x < (ssize_t) image->columns; x++) 8573 { 8574 if (image->alpha_trait == UndefinedPixelTrait || 8575 GetPixelAlpha(image,q) == OpaqueAlpha) 8576 { 8577 if (number_opaque < 259) 8578 { 8579 if (number_opaque == 0) 8580 { 8581 GetPixelInfoPixel(image, q, opaque); 8582 opaque[0].alpha=OpaqueAlpha; 8583 number_opaque=1; 8584 } 8585 8586 for (i=0; i< (ssize_t) number_opaque; i++) 8587 { 8588 if (Magick_png_color_equal(image,q,opaque+i)) 8589 break; 8590 } 8591 8592 if (i == (ssize_t) number_opaque && number_opaque < 259) 8593 { 8594 number_opaque++; 8595 GetPixelInfoPixel(image, q, opaque+i); 8596 opaque[i].alpha=OpaqueAlpha; 8597 } 8598 } 8599 } 8600 else if (GetPixelAlpha(image,q) == TransparentAlpha) 8601 { 8602 if (number_transparent < 259) 8603 { 8604 if (number_transparent == 0) 8605 { 8606 GetPixelInfoPixel(image, q, transparent); 8607 ping_trans_color.red=(unsigned short) 8608 GetPixelRed(image,q); 8609 ping_trans_color.green=(unsigned short) 8610 GetPixelGreen(image,q); 8611 ping_trans_color.blue=(unsigned short) 8612 GetPixelBlue(image,q); 8613 ping_trans_color.gray=(unsigned short) 8614 GetPixelGray(image,q); 8615 number_transparent = 1; 8616 } 8617 8618 for (i=0; i< (ssize_t) number_transparent; i++) 8619 { 8620 if (Magick_png_color_equal(image,q,transparent+i)) 8621 break; 8622 } 8623 8624 if (i == (ssize_t) number_transparent && 8625 number_transparent < 259) 8626 { 8627 number_transparent++; 8628 GetPixelInfoPixel(image,q,transparent+i); 8629 } 8630 } 8631 } 8632 else 8633 { 8634 if (number_semitransparent < 259) 8635 { 8636 if (number_semitransparent == 0) 8637 { 8638 GetPixelInfoPixel(image,q,semitransparent); 8639 number_semitransparent = 1; 8640 } 8641 8642 for (i=0; i< (ssize_t) number_semitransparent; i++) 8643 { 8644 if (Magick_png_color_equal(image,q,semitransparent+i) 8645 && GetPixelAlpha(image,q) == 8646 semitransparent[i].alpha) 8647 break; 8648 } 8649 8650 if (i == (ssize_t) number_semitransparent && 8651 number_semitransparent < 259) 8652 { 8653 number_semitransparent++; 8654 GetPixelInfoPixel(image, q, semitransparent+i); 8655 } 8656 } 8657 } 8658 q+=GetPixelChannels(image); 8659 } 8660 } 8661 8662 if (mng_info->write_png8 == MagickFalse && 8663 ping_exclude_bKGD == MagickFalse) 8664 { 8665 /* Add the background color to the palette, if it 8666 * isn't already there. 8667 */ 8668 if (logging != MagickFalse) 8669 { 8670 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8671 " Check colormap for background (%d,%d,%d)", 8672 (int) image->background_color.red, 8673 (int) image->background_color.green, 8674 (int) image->background_color.blue); 8675 } 8676 for (i=0; i<number_opaque; i++) 8677 { 8678 if (opaque[i].red == image->background_color.red && 8679 opaque[i].green == image->background_color.green && 8680 opaque[i].blue == image->background_color.blue) 8681 break; 8682 } 8683 if (number_opaque < 259 && i == number_opaque) 8684 { 8685 opaque[i] = image->background_color; 8686 ping_background.index = i; 8687 number_opaque++; 8688 if (logging != MagickFalse) 8689 { 8690 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8691 " background_color index is %d",(int) i); 8692 } 8693 8694 } 8695 else if (logging != MagickFalse) 8696 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8697 " No room in the colormap to add background color"); 8698 } 8699 8700 image_colors=number_opaque+number_transparent+number_semitransparent; 8701 8702 if (logging != MagickFalse) 8703 { 8704 if (image_colors > 256) 8705 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8706 " image has more than 256 colors"); 8707 8708 else 8709 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8710 " image has %d colors",image_colors); 8711 } 8712 8713 if (ping_preserve_colormap != MagickFalse) 8714 break; 8715 8716 if (mng_info->write_png_colortype != 7) /* We won't need this info */ 8717 { 8718 ping_have_color=MagickFalse; 8719 ping_have_non_bw=MagickFalse; 8720 8721 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 8722 { 8723 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8724 "incompatible colorspace"); 8725 ping_have_color=MagickTrue; 8726 ping_have_non_bw=MagickTrue; 8727 } 8728 8729 if(image_colors > 256) 8730 { 8731 for (y=0; y < (ssize_t) image->rows; y++) 8732 { 8733 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8734 8735 if (q == (Quantum *) NULL) 8736 break; 8737 8738 s=q; 8739 for (x=0; x < (ssize_t) image->columns; x++) 8740 { 8741 if (GetPixelRed(image,s) != GetPixelGreen(image,s) || 8742 GetPixelRed(image,s) != GetPixelBlue(image,s)) 8743 { 8744 ping_have_color=MagickTrue; 8745 ping_have_non_bw=MagickTrue; 8746 break; 8747 } 8748 s+=GetPixelChannels(image); 8749 } 8750 8751 if (ping_have_color != MagickFalse) 8752 break; 8753 8754 /* Worst case is black-and-white; we are looking at every 8755 * pixel twice. 8756 */ 8757 8758 if (ping_have_non_bw == MagickFalse) 8759 { 8760 s=q; 8761 for (x=0; x < (ssize_t) image->columns; x++) 8762 { 8763 if (GetPixelRed(image,s) != 0 && 8764 GetPixelRed(image,s) != QuantumRange) 8765 { 8766 ping_have_non_bw=MagickTrue; 8767 break; 8768 } 8769 s+=GetPixelChannels(image); 8770 } 8771 } 8772 } 8773 } 8774 } 8775 8776 if (image_colors < 257) 8777 { 8778 PixelInfo 8779 colormap[260]; 8780 8781 /* 8782 * Initialize image colormap. 8783 */ 8784 8785 if (logging != MagickFalse) 8786 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8787 " Sort the new colormap"); 8788 8789 /* Sort palette, transparent first */; 8790 8791 n = 0; 8792 8793 for (i=0; i<number_transparent; i++) 8794 colormap[n++] = transparent[i]; 8795 8796 for (i=0; i<number_semitransparent; i++) 8797 colormap[n++] = semitransparent[i]; 8798 8799 for (i=0; i<number_opaque; i++) 8800 colormap[n++] = opaque[i]; 8801 8802 ping_background.index += 8803 (number_transparent + number_semitransparent); 8804 8805 /* image_colors < 257; search the colormap instead of the pixels 8806 * to get ping_have_color and ping_have_non_bw 8807 */ 8808 for (i=0; i<n; i++) 8809 { 8810 if (ping_have_color == MagickFalse) 8811 { 8812 if (colormap[i].red != colormap[i].green || 8813 colormap[i].red != colormap[i].blue) 8814 { 8815 ping_have_color=MagickTrue; 8816 ping_have_non_bw=MagickTrue; 8817 break; 8818 } 8819 } 8820 8821 if (ping_have_non_bw == MagickFalse) 8822 { 8823 if (colormap[i].red != 0 && colormap[i].red != QuantumRange) 8824 ping_have_non_bw=MagickTrue; 8825 } 8826 } 8827 8828 if ((mng_info->ping_exclude_tRNS == MagickFalse || 8829 (number_transparent == 0 && number_semitransparent == 0)) && 8830 (((mng_info->write_png_colortype-1) == 8831 PNG_COLOR_TYPE_PALETTE) || 8832 (mng_info->write_png_colortype == 0))) 8833 { 8834 if (logging != MagickFalse) 8835 { 8836 if (n != (ssize_t) image_colors) 8837 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8838 " image_colors (%d) and n (%d) don't match", 8839 image_colors, n); 8840 8841 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8842 " AcquireImageColormap"); 8843 } 8844 8845 image->colors = image_colors; 8846 8847 if (AcquireImageColormap(image,image_colors,exception) == 8848 MagickFalse) 8849 ThrowWriterException(ResourceLimitError, 8850 "MemoryAllocationFailed"); 8851 8852 for (i=0; i< (ssize_t) image_colors; i++) 8853 image->colormap[i] = colormap[i]; 8854 8855 if (logging != MagickFalse) 8856 { 8857 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8858 " image->colors=%d (%d)", 8859 (int) image->colors, image_colors); 8860 8861 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8862 " Update the pixel indexes"); 8863 } 8864 8865 /* Sync the pixel indices with the new colormap */ 8866 8867 for (y=0; y < (ssize_t) image->rows; y++) 8868 { 8869 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8870 8871 if (q == (Quantum *) NULL) 8872 break; 8873 8874 for (x=0; x < (ssize_t) image->columns; x++) 8875 { 8876 for (i=0; i< (ssize_t) image_colors; i++) 8877 { 8878 if ((image->alpha_trait == UndefinedPixelTrait || 8879 image->colormap[i].alpha == GetPixelAlpha(image,q)) && 8880 image->colormap[i].red == GetPixelRed(image,q) && 8881 image->colormap[i].green == GetPixelGreen(image,q) && 8882 image->colormap[i].blue == GetPixelBlue(image,q)) 8883 { 8884 SetPixelIndex(image,i,q); 8885 break; 8886 } 8887 } 8888 q+=GetPixelChannels(image); 8889 } 8890 8891 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8892 break; 8893 } 8894 } 8895 } 8896 8897 if (logging != MagickFalse) 8898 { 8899 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8900 " image->colors=%d", (int) image->colors); 8901 8902 if (image->colormap != NULL) 8903 { 8904 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8905 " i (red,green,blue,alpha)"); 8906 8907 for (i=0; i < (ssize_t) image->colors; i++) 8908 { 8909 if (i < 300 || i >= (ssize_t) image->colors - 10) 8910 { 8911 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8912 " %d (%d,%d,%d,%d)", 8913 (int) i, 8914 (int) image->colormap[i].red, 8915 (int) image->colormap[i].green, 8916 (int) image->colormap[i].blue, 8917 (int) image->colormap[i].alpha); 8918 } 8919 } 8920 } 8921 8922 if (number_transparent < 257) 8923 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8924 " number_transparent = %d", 8925 number_transparent); 8926 else 8927 8928 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8929 " number_transparent > 256"); 8930 8931 if (number_opaque < 257) 8932 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8933 " number_opaque = %d", 8934 number_opaque); 8935 8936 else 8937 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8938 " number_opaque > 256"); 8939 8940 if (number_semitransparent < 257) 8941 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8942 " number_semitransparent = %d", 8943 number_semitransparent); 8944 8945 else 8946 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8947 " number_semitransparent > 256"); 8948 8949 if (ping_have_non_bw == MagickFalse) 8950 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8951 " All pixels and the background are black or white"); 8952 8953 else if (ping_have_color == MagickFalse) 8954 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8955 " All pixels and the background are gray"); 8956 8957 else 8958 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8959 " At least one pixel or the background is non-gray"); 8960 8961 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8962 " Exit BUILD_PALETTE:"); 8963 } 8964 8965 if (mng_info->write_png8 == MagickFalse) 8966 break; 8967 8968 /* Make any reductions necessary for the PNG8 format */ 8969 if (image_colors <= 256 && 8970 image_colors != 0 && image->colormap != NULL && 8971 number_semitransparent == 0 && 8972 number_transparent <= 1) 8973 break; 8974 8975 /* PNG8 can't have semitransparent colors so we threshold the 8976 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one 8977 * transparent color so if more than one is transparent we merge 8978 * them into image->background_color. 8979 */ 8980 if (number_semitransparent != 0 || number_transparent > 1) 8981 { 8982 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8983 " Thresholding the alpha channel to binary"); 8984 8985 for (y=0; y < (ssize_t) image->rows; y++) 8986 { 8987 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8988 8989 if (r == (Quantum *) NULL) 8990 break; 8991 8992 for (x=0; x < (ssize_t) image->columns; x++) 8993 { 8994 if (GetPixelAlpha(image,r) < OpaqueAlpha/2) 8995 { 8996 SetPixelViaPixelInfo(image,&image->background_color,r); 8997 SetPixelAlpha(image,TransparentAlpha,r); 8998 } 8999 else 9000 SetPixelAlpha(image,OpaqueAlpha,r); 9001 r+=GetPixelChannels(image); 9002 } 9003 9004 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9005 break; 9006 9007 if (image_colors != 0 && image_colors <= 256 && 9008 image->colormap != NULL) 9009 for (i=0; i<image_colors; i++) 9010 image->colormap[i].alpha = 9011 (image->colormap[i].alpha > TransparentAlpha/2 ? 9012 TransparentAlpha : OpaqueAlpha); 9013 } 9014 continue; 9015 } 9016 9017 /* PNG8 can't have more than 256 colors so we quantize the pixels and 9018 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the 9019 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256 9020 * colors or less. 9021 */ 9022 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9023 { 9024 if (logging != MagickFalse) 9025 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9026 " Quantizing the background color to 4-4-4"); 9027 9028 tried_444 = MagickTrue; 9029 9030 LBR04PacketRGB(image->background_color); 9031 9032 if (logging != MagickFalse) 9033 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9034 " Quantizing the pixel colors to 4-4-4"); 9035 9036 if (image->colormap == NULL) 9037 { 9038 for (y=0; y < (ssize_t) image->rows; y++) 9039 { 9040 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9041 9042 if (r == (Quantum *) NULL) 9043 break; 9044 9045 for (x=0; x < (ssize_t) image->columns; x++) 9046 { 9047 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9048 LBR04PixelRGB(r); 9049 r+=GetPixelChannels(image); 9050 } 9051 9052 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9053 break; 9054 } 9055 } 9056 9057 else /* Should not reach this; colormap already exists and 9058 must be <= 256 */ 9059 { 9060 if (logging != MagickFalse) 9061 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9062 " Quantizing the colormap to 4-4-4"); 9063 9064 for (i=0; i<image_colors; i++) 9065 { 9066 LBR04PacketRGB(image->colormap[i]); 9067 } 9068 } 9069 continue; 9070 } 9071 9072 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9073 { 9074 if (logging != MagickFalse) 9075 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9076 " Quantizing the background color to 3-3-3"); 9077 9078 tried_333 = MagickTrue; 9079 9080 LBR03PacketRGB(image->background_color); 9081 9082 if (logging != MagickFalse) 9083 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9084 " Quantizing the pixel colors to 3-3-3-1"); 9085 9086 if (image->colormap == NULL) 9087 { 9088 for (y=0; y < (ssize_t) image->rows; y++) 9089 { 9090 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9091 9092 if (r == (Quantum *) NULL) 9093 break; 9094 9095 for (x=0; x < (ssize_t) image->columns; x++) 9096 { 9097 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9098 LBR03RGB(r); 9099 r+=GetPixelChannels(image); 9100 } 9101 9102 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9103 break; 9104 } 9105 } 9106 9107 else /* Should not reach this; colormap already exists and 9108 must be <= 256 */ 9109 { 9110 if (logging != MagickFalse) 9111 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9112 " Quantizing the colormap to 3-3-3-1"); 9113 for (i=0; i<image_colors; i++) 9114 { 9115 LBR03PacketRGB(image->colormap[i]); 9116 } 9117 } 9118 continue; 9119 } 9120 9121 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9122 { 9123 if (logging != MagickFalse) 9124 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9125 " Quantizing the background color to 3-3-2"); 9126 9127 tried_332 = MagickTrue; 9128 9129 /* Red and green were already done so we only quantize the blue 9130 * channel 9131 */ 9132 9133 LBR02PacketBlue(image->background_color); 9134 9135 if (logging != MagickFalse) 9136 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9137 " Quantizing the pixel colors to 3-3-2-1"); 9138 9139 if (image->colormap == NULL) 9140 { 9141 for (y=0; y < (ssize_t) image->rows; y++) 9142 { 9143 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9144 9145 if (r == (Quantum *) NULL) 9146 break; 9147 9148 for (x=0; x < (ssize_t) image->columns; x++) 9149 { 9150 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9151 LBR02PixelBlue(r); 9152 r+=GetPixelChannels(image); 9153 } 9154 9155 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9156 break; 9157 } 9158 } 9159 9160 else /* Should not reach this; colormap already exists and 9161 must be <= 256 */ 9162 { 9163 if (logging != MagickFalse) 9164 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9165 " Quantizing the colormap to 3-3-2-1"); 9166 for (i=0; i<image_colors; i++) 9167 { 9168 LBR02PacketBlue(image->colormap[i]); 9169 } 9170 } 9171 continue; 9172 } 9173 9174 if (image_colors == 0 || image_colors > 256) 9175 { 9176 /* Take care of special case with 256 opaque colors + 1 transparent 9177 * color. We don't need to quantize to 2-3-2-1; we only need to 9178 * eliminate one color, so we'll merge the two darkest red 9179 * colors (0x49, 0, 0) -> (0x24, 0, 0). 9180 */ 9181 if (logging != MagickFalse) 9182 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9183 " Merging two dark red background colors to 3-3-2-1"); 9184 9185 if (ScaleQuantumToChar(image->background_color.red) == 0x49 && 9186 ScaleQuantumToChar(image->background_color.green) == 0x00 && 9187 ScaleQuantumToChar(image->background_color.blue) == 0x00) 9188 { 9189 image->background_color.red=ScaleCharToQuantum(0x24); 9190 } 9191 9192 if (logging != MagickFalse) 9193 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9194 " Merging two dark red pixel colors to 3-3-2-1"); 9195 9196 if (image->colormap == NULL) 9197 { 9198 for (y=0; y < (ssize_t) image->rows; y++) 9199 { 9200 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9201 9202 if (r == (Quantum *) NULL) 9203 break; 9204 9205 for (x=0; x < (ssize_t) image->columns; x++) 9206 { 9207 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 && 9208 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 && 9209 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 && 9210 GetPixelAlpha(image,r) == OpaqueAlpha) 9211 { 9212 SetPixelRed(image,ScaleCharToQuantum(0x24),r); 9213 } 9214 r+=GetPixelChannels(image); 9215 } 9216 9217 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9218 break; 9219 9220 } 9221 } 9222 9223 else 9224 { 9225 for (i=0; i<image_colors; i++) 9226 { 9227 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 && 9228 ScaleQuantumToChar(image->colormap[i].green) == 0x00 && 9229 ScaleQuantumToChar(image->colormap[i].blue) == 0x00) 9230 { 9231 image->colormap[i].red=ScaleCharToQuantum(0x24); 9232 } 9233 } 9234 } 9235 } 9236 } 9237 } 9238 /* END OF BUILD_PALETTE */ 9239 9240 /* If we are excluding the tRNS chunk and there is transparency, 9241 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6) 9242 * PNG. 9243 */ 9244 if (mng_info->ping_exclude_tRNS != MagickFalse && 9245 (number_transparent != 0 || number_semitransparent != 0)) 9246 { 9247 unsigned int colortype=mng_info->write_png_colortype; 9248 9249 if (ping_have_color == MagickFalse) 9250 mng_info->write_png_colortype = 5; 9251 9252 else 9253 mng_info->write_png_colortype = 7; 9254 9255 if (colortype != 0 && 9256 mng_info->write_png_colortype != colortype) 9257 ping_need_colortype_warning=MagickTrue; 9258 9259 } 9260 9261 /* See if cheap transparency is possible. It is only possible 9262 * when there is a single transparent color, no semitransparent 9263 * color, and no opaque color that has the same RGB components 9264 * as the transparent color. We only need this information if 9265 * we are writing a PNG with colortype 0 or 2, and we have not 9266 * excluded the tRNS chunk. 9267 */ 9268 if (number_transparent == 1 && 9269 mng_info->write_png_colortype < 4) 9270 { 9271 ping_have_cheap_transparency = MagickTrue; 9272 9273 if (number_semitransparent != 0) 9274 ping_have_cheap_transparency = MagickFalse; 9275 9276 else if (image_colors == 0 || image_colors > 256 || 9277 image->colormap == NULL) 9278 { 9279 register const Quantum 9280 *q; 9281 9282 for (y=0; y < (ssize_t) image->rows; y++) 9283 { 9284 q=GetVirtualPixels(image,0,y,image->columns,1, exception); 9285 9286 if (q == (Quantum *) NULL) 9287 break; 9288 9289 for (x=0; x < (ssize_t) image->columns; x++) 9290 { 9291 if (GetPixelAlpha(image,q) != TransparentAlpha && 9292 (unsigned short) GetPixelRed(image,q) == 9293 ping_trans_color.red && 9294 (unsigned short) GetPixelGreen(image,q) == 9295 ping_trans_color.green && 9296 (unsigned short) GetPixelBlue(image,q) == 9297 ping_trans_color.blue) 9298 { 9299 ping_have_cheap_transparency = MagickFalse; 9300 break; 9301 } 9302 9303 q+=GetPixelChannels(image); 9304 } 9305 9306 if (ping_have_cheap_transparency == MagickFalse) 9307 break; 9308 } 9309 } 9310 else 9311 { 9312 /* Assuming that image->colormap[0] is the one transparent color 9313 * and that all others are opaque. 9314 */ 9315 if (image_colors > 1) 9316 for (i=1; i<image_colors; i++) 9317 if (image->colormap[i].red == image->colormap[0].red && 9318 image->colormap[i].green == image->colormap[0].green && 9319 image->colormap[i].blue == image->colormap[0].blue) 9320 { 9321 ping_have_cheap_transparency = MagickFalse; 9322 break; 9323 } 9324 } 9325 9326 if (logging != MagickFalse) 9327 { 9328 if (ping_have_cheap_transparency == MagickFalse) 9329 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9330 " Cheap transparency is not possible."); 9331 9332 else 9333 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9334 " Cheap transparency is possible."); 9335 } 9336 } 9337 else 9338 ping_have_cheap_transparency = MagickFalse; 9339 9340 image_depth=image->depth; 9341 9342 quantum_info = (QuantumInfo *) NULL; 9343 number_colors=0; 9344 image_colors=(int) image->colors; 9345 image_matte=image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse; 9346 9347 if (mng_info->write_png_colortype < 5) 9348 mng_info->IsPalette=image->storage_class == PseudoClass && 9349 image_colors <= 256 && image->colormap != NULL; 9350 else 9351 mng_info->IsPalette = MagickFalse; 9352 9353 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) && 9354 (image->colors == 0 || image->colormap == NULL)) 9355 { 9356 image_info=DestroyImageInfo(image_info); 9357 image=DestroyImage(image); 9358 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 9359 "Cannot write PNG8 or color-type 3; colormap is NULL", 9360 "`%s'",IMimage->filename); 9361 return(MagickFalse); 9362 } 9363 9364 /* 9365 Allocate the PNG structures 9366 */ 9367#ifdef PNG_USER_MEM_SUPPORTED 9368 error_info.image=image; 9369 error_info.exception=exception; 9370 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info, 9371 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL, 9372 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free); 9373 9374#else 9375 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info, 9376 MagickPNGErrorHandler,MagickPNGWarningHandler); 9377 9378#endif 9379 if (ping == (png_struct *) NULL) 9380 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 9381 9382 ping_info=png_create_info_struct(ping); 9383 9384 if (ping_info == (png_info *) NULL) 9385 { 9386 png_destroy_write_struct(&ping,(png_info **) NULL); 9387 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 9388 } 9389 9390 png_set_write_fn(ping,image,png_put_data,png_flush_data); 9391 pixel_info=(MemoryInfo *) NULL; 9392 9393 if (setjmp(png_jmpbuf(ping))) 9394 { 9395 /* 9396 PNG write failed. 9397 */ 9398#ifdef PNG_DEBUG 9399 if (image_info->verbose) 9400 (void) printf("PNG write has failed.\n"); 9401#endif 9402 png_destroy_write_struct(&ping,&ping_info); 9403#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 9404 UnlockSemaphoreInfo(ping_semaphore); 9405#endif 9406 9407 if (pixel_info != (MemoryInfo *) NULL) 9408 pixel_info=RelinquishVirtualMemory(pixel_info); 9409 9410 if (quantum_info != (QuantumInfo *) NULL) 9411 quantum_info=DestroyQuantumInfo(quantum_info); 9412 9413 if (ping_have_blob != MagickFalse) 9414 (void) CloseBlob(image); 9415 image_info=DestroyImageInfo(image_info); 9416 image=DestroyImage(image); 9417 return(MagickFalse); 9418 } 9419 9420 /* { For navigation to end of SETJMP-protected block. Within this 9421 * block, use png_error() instead of Throwing an Exception, to ensure 9422 * that libpng is able to clean up, and that the semaphore is unlocked. 9423 */ 9424 9425#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 9426 LockSemaphoreInfo(ping_semaphore); 9427#endif 9428 9429#ifdef PNG_BENIGN_ERRORS_SUPPORTED 9430 /* Allow benign errors */ 9431 png_set_benign_errors(ping, 1); 9432#endif 9433 9434#ifdef PNG_SET_USER_LIMITS_SUPPORTED 9435 /* Reject images with too many rows or columns */ 9436 png_set_user_limits(ping, 9437 (png_uint_32) MagickMin(0x7fffffffL, 9438 GetMagickResourceLimit(WidthResource)), 9439 (png_uint_32) MagickMin(0x7fffffffL, 9440 GetMagickResourceLimit(HeightResource))); 9441#endif /* PNG_SET_USER_LIMITS_SUPPORTED */ 9442 9443 /* 9444 Prepare PNG for writing. 9445 */ 9446 9447#if defined(PNG_MNG_FEATURES_SUPPORTED) 9448 if (mng_info->write_mng) 9449 { 9450 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); 9451# ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED 9452 /* Disable new libpng-1.5.10 feature when writing a MNG because 9453 * zero-length PLTE is OK 9454 */ 9455 png_set_check_for_invalid_index (ping, 0); 9456# endif 9457 } 9458 9459#else 9460# ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 9461 if (mng_info->write_mng) 9462 png_permit_empty_plte(ping,MagickTrue); 9463 9464# endif 9465#endif 9466 9467 x=0; 9468 9469 ping_width=(png_uint_32) image->columns; 9470 ping_height=(png_uint_32) image->rows; 9471 9472 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32) 9473 image_depth=8; 9474 9475 if (mng_info->write_png48 || mng_info->write_png64) 9476 image_depth=16; 9477 9478 if (mng_info->write_png_depth != 0) 9479 image_depth=mng_info->write_png_depth; 9480 9481 /* Adjust requested depth to next higher valid depth if necessary */ 9482 if (image_depth > 8) 9483 image_depth=16; 9484 9485 if ((image_depth > 4) && (image_depth < 8)) 9486 image_depth=8; 9487 9488 if (image_depth == 3) 9489 image_depth=4; 9490 9491 if (logging != MagickFalse) 9492 { 9493 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9494 " width=%.20g",(double) ping_width); 9495 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9496 " height=%.20g",(double) ping_height); 9497 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9498 " image_matte=%.20g",(double) image->alpha_trait); 9499 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9500 " image->depth=%.20g",(double) image->depth); 9501 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9502 " Tentative ping_bit_depth=%.20g",(double) image_depth); 9503 } 9504 9505 save_image_depth=image_depth; 9506 ping_bit_depth=(png_byte) save_image_depth; 9507 9508 9509#if defined(PNG_pHYs_SUPPORTED) 9510 if (ping_exclude_pHYs == MagickFalse) 9511 { 9512 if ((image->resolution.x != 0) && (image->resolution.y != 0) && 9513 (!mng_info->write_mng || !mng_info->equal_physs)) 9514 { 9515 if (logging != MagickFalse) 9516 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9517 " Setting up pHYs chunk"); 9518 9519 if (image->units == PixelsPerInchResolution) 9520 { 9521 ping_pHYs_unit_type=PNG_RESOLUTION_METER; 9522 ping_pHYs_x_resolution= 9523 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54); 9524 ping_pHYs_y_resolution= 9525 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54); 9526 } 9527 9528 else if (image->units == PixelsPerCentimeterResolution) 9529 { 9530 ping_pHYs_unit_type=PNG_RESOLUTION_METER; 9531 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5); 9532 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5); 9533 } 9534 9535 else 9536 { 9537 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN; 9538 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x; 9539 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y; 9540 } 9541 9542 if (logging != MagickFalse) 9543 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9544 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.", 9545 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution, 9546 (int) ping_pHYs_unit_type); 9547 ping_have_pHYs = MagickTrue; 9548 } 9549 } 9550#endif 9551 9552 if (ping_exclude_bKGD == MagickFalse) 9553 { 9554 if ((!mng_info->adjoin || !mng_info->equal_backgrounds)) 9555 { 9556 unsigned int 9557 mask; 9558 9559 mask=0xffff; 9560 if (ping_bit_depth == 8) 9561 mask=0x00ff; 9562 9563 if (ping_bit_depth == 4) 9564 mask=0x000f; 9565 9566 if (ping_bit_depth == 2) 9567 mask=0x0003; 9568 9569 if (ping_bit_depth == 1) 9570 mask=0x0001; 9571 9572 ping_background.red=(png_uint_16) 9573 (ScaleQuantumToShort(image->background_color.red) & mask); 9574 9575 ping_background.green=(png_uint_16) 9576 (ScaleQuantumToShort(image->background_color.green) & mask); 9577 9578 ping_background.blue=(png_uint_16) 9579 (ScaleQuantumToShort(image->background_color.blue) & mask); 9580 9581 ping_background.gray=(png_uint_16) ping_background.green; 9582 } 9583 9584 if (logging != MagickFalse) 9585 { 9586 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9587 " Setting up bKGD chunk (1)"); 9588 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9589 " background_color index is %d", 9590 (int) ping_background.index); 9591 9592 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9593 " ping_bit_depth=%d",ping_bit_depth); 9594 } 9595 9596 ping_have_bKGD = MagickTrue; 9597 } 9598 9599 /* 9600 Select the color type. 9601 */ 9602 matte=image_matte; 9603 old_bit_depth=0; 9604 9605 if (mng_info->IsPalette && mng_info->write_png8) 9606 { 9607 /* To do: make this a function cause it's used twice, except 9608 for reducing the sample depth from 8. */ 9609 9610 number_colors=image_colors; 9611 9612 ping_have_tRNS=MagickFalse; 9613 9614 /* 9615 Set image palette. 9616 */ 9617 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 9618 9619 if (logging != MagickFalse) 9620 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9621 " Setting up PLTE chunk with %d colors (%d)", 9622 number_colors, image_colors); 9623 9624 for (i=0; i < (ssize_t) number_colors; i++) 9625 { 9626 palette[i].red=ScaleQuantumToChar(image->colormap[i].red); 9627 palette[i].green=ScaleQuantumToChar(image->colormap[i].green); 9628 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); 9629 if (logging != MagickFalse) 9630 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9631#if MAGICKCORE_QUANTUM_DEPTH == 8 9632 " %3ld (%3d,%3d,%3d)", 9633#else 9634 " %5ld (%5d,%5d,%5d)", 9635#endif 9636 (long) i,palette[i].red,palette[i].green,palette[i].blue); 9637 9638 } 9639 9640 ping_have_PLTE=MagickTrue; 9641 image_depth=ping_bit_depth; 9642 ping_num_trans=0; 9643 9644 if (matte != MagickFalse) 9645 { 9646 /* 9647 Identify which colormap entry is transparent. 9648 */ 9649 assert(number_colors <= 256); 9650 assert(image->colormap != NULL); 9651 9652 for (i=0; i < (ssize_t) number_transparent; i++) 9653 ping_trans_alpha[i]=0; 9654 9655 9656 ping_num_trans=(unsigned short) (number_transparent + 9657 number_semitransparent); 9658 9659 if (ping_num_trans == 0) 9660 ping_have_tRNS=MagickFalse; 9661 9662 else 9663 ping_have_tRNS=MagickTrue; 9664 } 9665 9666 if (ping_exclude_bKGD == MagickFalse) 9667 { 9668 /* 9669 * Identify which colormap entry is the background color. 9670 */ 9671 9672 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++) 9673 if (IsPNGColorEqual(ping_background,image->colormap[i])) 9674 break; 9675 9676 ping_background.index=(png_byte) i; 9677 9678 if (logging != MagickFalse) 9679 { 9680 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9681 " background_color index is %d", 9682 (int) ping_background.index); 9683 } 9684 } 9685 } /* end of write_png8 */ 9686 9687 else if (mng_info->write_png_colortype == 1) 9688 { 9689 image_matte=MagickFalse; 9690 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY; 9691 } 9692 9693 else if (mng_info->write_png24 || mng_info->write_png48 || 9694 mng_info->write_png_colortype == 3) 9695 { 9696 image_matte=MagickFalse; 9697 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9698 } 9699 9700 else if (mng_info->write_png32 || mng_info->write_png64 || 9701 mng_info->write_png_colortype == 7) 9702 { 9703 image_matte=MagickTrue; 9704 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; 9705 } 9706 9707 else /* mng_info->write_pngNN not specified */ 9708 { 9709 image_depth=ping_bit_depth; 9710 9711 if (mng_info->write_png_colortype != 0) 9712 { 9713 ping_color_type=(png_byte) mng_info->write_png_colortype-1; 9714 9715 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 9716 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 9717 image_matte=MagickTrue; 9718 9719 else 9720 image_matte=MagickFalse; 9721 9722 if (logging != MagickFalse) 9723 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9724 " PNG colortype %d was specified:",(int) ping_color_type); 9725 } 9726 9727 else /* write_png_colortype not specified */ 9728 { 9729 if (logging != MagickFalse) 9730 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9731 " Selecting PNG colortype:"); 9732 9733 ping_color_type=(png_byte) ((matte != MagickFalse)? 9734 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB); 9735 9736 if (image_info->type == TrueColorType) 9737 { 9738 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9739 image_matte=MagickFalse; 9740 } 9741 9742 if (image_info->type == TrueColorAlphaType) 9743 { 9744 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; 9745 image_matte=MagickTrue; 9746 } 9747 9748 if (image_info->type == PaletteType || 9749 image_info->type == PaletteAlphaType) 9750 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 9751 9752 if (mng_info->write_png_colortype == 0 && 9753 image_info->type == UndefinedType) 9754 { 9755 if (ping_have_color == MagickFalse) 9756 { 9757 if (image_matte == MagickFalse) 9758 { 9759 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY; 9760 image_matte=MagickFalse; 9761 } 9762 9763 else 9764 { 9765 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA; 9766 image_matte=MagickTrue; 9767 } 9768 } 9769 else 9770 { 9771 if (image_matte == MagickFalse) 9772 { 9773 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9774 image_matte=MagickFalse; 9775 } 9776 9777 else 9778 { 9779 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA; 9780 image_matte=MagickTrue; 9781 } 9782 } 9783 } 9784 9785 } 9786 9787 if (logging != MagickFalse) 9788 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9789 " Selected PNG colortype=%d",ping_color_type); 9790 9791 if (ping_bit_depth < 8) 9792 { 9793 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 9794 ping_color_type == PNG_COLOR_TYPE_RGB || 9795 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 9796 ping_bit_depth=8; 9797 } 9798 9799 old_bit_depth=ping_bit_depth; 9800 9801 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 9802 { 9803 if (image->alpha_trait == UndefinedPixelTrait && ping_have_non_bw == MagickFalse) 9804 ping_bit_depth=1; 9805 } 9806 9807 if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 9808 { 9809 size_t one = 1; 9810 ping_bit_depth=1; 9811 9812 if (image->colors == 0) 9813 { 9814 /* DO SOMETHING */ 9815 png_error(ping,"image has 0 colors"); 9816 } 9817 9818 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors) 9819 ping_bit_depth <<= 1; 9820 } 9821 9822 if (logging != MagickFalse) 9823 { 9824 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9825 " Number of colors: %.20g",(double) image_colors); 9826 9827 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9828 " Tentative PNG bit depth: %d",ping_bit_depth); 9829 } 9830 9831 if (ping_bit_depth < (int) mng_info->write_png_depth) 9832 ping_bit_depth = mng_info->write_png_depth; 9833 } 9834 9835 image_depth=ping_bit_depth; 9836 9837 if (logging != MagickFalse) 9838 { 9839 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9840 " Tentative PNG color type: %s (%.20g)", 9841 PngColorTypeToString(ping_color_type), 9842 (double) ping_color_type); 9843 9844 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9845 " image_info->type: %.20g",(double) image_info->type); 9846 9847 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9848 " image_depth: %.20g",(double) image_depth); 9849 9850 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9851 9852 " image->depth: %.20g",(double) image->depth); 9853 9854 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9855 " ping_bit_depth: %.20g",(double) ping_bit_depth); 9856 } 9857 9858 if (matte != MagickFalse) 9859 { 9860 if (mng_info->IsPalette) 9861 { 9862 if (mng_info->write_png_colortype == 0) 9863 { 9864 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA; 9865 9866 if (ping_have_color != MagickFalse) 9867 ping_color_type=PNG_COLOR_TYPE_RGBA; 9868 } 9869 9870 /* 9871 * Determine if there is any transparent color. 9872 */ 9873 if (number_transparent + number_semitransparent == 0) 9874 { 9875 /* 9876 No transparent pixels are present. Change 4 or 6 to 0 or 2. 9877 */ 9878 9879 image_matte=MagickFalse; 9880 9881 if (mng_info->write_png_colortype == 0) 9882 ping_color_type&=0x03; 9883 } 9884 9885 else 9886 { 9887 unsigned int 9888 mask; 9889 9890 mask=0xffff; 9891 9892 if (ping_bit_depth == 8) 9893 mask=0x00ff; 9894 9895 if (ping_bit_depth == 4) 9896 mask=0x000f; 9897 9898 if (ping_bit_depth == 2) 9899 mask=0x0003; 9900 9901 if (ping_bit_depth == 1) 9902 mask=0x0001; 9903 9904 ping_trans_color.red=(png_uint_16) 9905 (ScaleQuantumToShort(image->colormap[0].red) & mask); 9906 9907 ping_trans_color.green=(png_uint_16) 9908 (ScaleQuantumToShort(image->colormap[0].green) & mask); 9909 9910 ping_trans_color.blue=(png_uint_16) 9911 (ScaleQuantumToShort(image->colormap[0].blue) & mask); 9912 9913 ping_trans_color.gray=(png_uint_16) 9914 (ScaleQuantumToShort(GetPixelInfoIntensity(image, 9915 image->colormap)) & mask); 9916 9917 ping_trans_color.index=(png_byte) 0; 9918 9919 ping_have_tRNS=MagickTrue; 9920 } 9921 9922 if (ping_have_tRNS != MagickFalse) 9923 { 9924 /* 9925 * Determine if there is one and only one transparent color 9926 * and if so if it is fully transparent. 9927 */ 9928 if (ping_have_cheap_transparency == MagickFalse) 9929 ping_have_tRNS=MagickFalse; 9930 } 9931 9932 if (ping_have_tRNS != MagickFalse) 9933 { 9934 if (mng_info->write_png_colortype == 0) 9935 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */ 9936 9937 if (image_depth == 8) 9938 { 9939 ping_trans_color.red&=0xff; 9940 ping_trans_color.green&=0xff; 9941 ping_trans_color.blue&=0xff; 9942 ping_trans_color.gray&=0xff; 9943 } 9944 } 9945 } 9946 else 9947 { 9948 if (image_depth == 8) 9949 { 9950 ping_trans_color.red&=0xff; 9951 ping_trans_color.green&=0xff; 9952 ping_trans_color.blue&=0xff; 9953 ping_trans_color.gray&=0xff; 9954 } 9955 } 9956 } 9957 9958 matte=image_matte; 9959 9960 if (ping_have_tRNS != MagickFalse) 9961 image_matte=MagickFalse; 9962 9963 if ((mng_info->IsPalette) && 9964 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE && 9965 ping_have_color == MagickFalse && 9966 (image_matte == MagickFalse || image_depth >= 8)) 9967 { 9968 size_t one=1; 9969 9970 if (image_matte != MagickFalse) 9971 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA; 9972 9973 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA) 9974 { 9975 ping_color_type=PNG_COLOR_TYPE_GRAY; 9976 9977 if (save_image_depth == 16 && image_depth == 8) 9978 { 9979 if (logging != MagickFalse) 9980 { 9981 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9982 " Scaling ping_trans_color (0)"); 9983 } 9984 ping_trans_color.gray*=0x0101; 9985 } 9986 } 9987 9988 if (image_depth > MAGICKCORE_QUANTUM_DEPTH) 9989 image_depth=MAGICKCORE_QUANTUM_DEPTH; 9990 9991 if ((image_colors == 0) || 9992 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize)) 9993 image_colors=(int) (one << image_depth); 9994 9995 if (image_depth > 8) 9996 ping_bit_depth=16; 9997 9998 else 9999 { 10000 ping_bit_depth=8; 10001 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 10002 { 10003 if(!mng_info->write_png_depth) 10004 { 10005 ping_bit_depth=1; 10006 10007 while ((int) (one << ping_bit_depth) 10008 < (ssize_t) image_colors) 10009 ping_bit_depth <<= 1; 10010 } 10011 } 10012 10013 else if (ping_color_type == 10014 PNG_COLOR_TYPE_GRAY && image_colors < 17 && 10015 mng_info->IsPalette) 10016 { 10017 /* Check if grayscale is reducible */ 10018 10019 int 10020 depth_4_ok=MagickTrue, 10021 depth_2_ok=MagickTrue, 10022 depth_1_ok=MagickTrue; 10023 10024 for (i=0; i < (ssize_t) image_colors; i++) 10025 { 10026 unsigned char 10027 intensity; 10028 10029 intensity=ScaleQuantumToChar(image->colormap[i].red); 10030 10031 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4)) 10032 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse; 10033 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2)) 10034 depth_2_ok=depth_1_ok=MagickFalse; 10035 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1)) 10036 depth_1_ok=MagickFalse; 10037 } 10038 10039 if (depth_1_ok && mng_info->write_png_depth <= 1) 10040 ping_bit_depth=1; 10041 10042 else if (depth_2_ok && mng_info->write_png_depth <= 2) 10043 ping_bit_depth=2; 10044 10045 else if (depth_4_ok && mng_info->write_png_depth <= 4) 10046 ping_bit_depth=4; 10047 } 10048 } 10049 10050 image_depth=ping_bit_depth; 10051 } 10052 10053 else 10054 10055 if (mng_info->IsPalette) 10056 { 10057 number_colors=image_colors; 10058 10059 if (image_depth <= 8) 10060 { 10061 /* 10062 Set image palette. 10063 */ 10064 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 10065 10066 if (!(mng_info->have_write_global_plte && matte == MagickFalse)) 10067 { 10068 for (i=0; i < (ssize_t) number_colors; i++) 10069 { 10070 palette[i].red=ScaleQuantumToChar(image->colormap[i].red); 10071 palette[i].green=ScaleQuantumToChar(image->colormap[i].green); 10072 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); 10073 } 10074 10075 if (logging != MagickFalse) 10076 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10077 " Setting up PLTE chunk with %d colors", 10078 number_colors); 10079 10080 ping_have_PLTE=MagickTrue; 10081 } 10082 10083 /* color_type is PNG_COLOR_TYPE_PALETTE */ 10084 if (mng_info->write_png_depth == 0) 10085 { 10086 size_t 10087 one; 10088 10089 ping_bit_depth=1; 10090 one=1; 10091 10092 while ((one << ping_bit_depth) < (size_t) number_colors) 10093 ping_bit_depth <<= 1; 10094 } 10095 10096 ping_num_trans=0; 10097 10098 if (matte != MagickFalse) 10099 { 10100 /* 10101 * Set up trans_colors array. 10102 */ 10103 assert(number_colors <= 256); 10104 10105 ping_num_trans=(unsigned short) (number_transparent + 10106 number_semitransparent); 10107 10108 if (ping_num_trans == 0) 10109 ping_have_tRNS=MagickFalse; 10110 10111 else 10112 { 10113 if (logging != MagickFalse) 10114 { 10115 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10116 " Scaling ping_trans_color (1)"); 10117 } 10118 ping_have_tRNS=MagickTrue; 10119 10120 for (i=0; i < ping_num_trans; i++) 10121 { 10122 ping_trans_alpha[i]= (png_byte) 10123 ScaleQuantumToChar(image->colormap[i].alpha); 10124 } 10125 } 10126 } 10127 } 10128 } 10129 10130 else 10131 { 10132 10133 if (image_depth < 8) 10134 image_depth=8; 10135 10136 if ((save_image_depth == 16) && (image_depth == 8)) 10137 { 10138 if (logging != MagickFalse) 10139 { 10140 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10141 " Scaling ping_trans_color from (%d,%d,%d)", 10142 (int) ping_trans_color.red, 10143 (int) ping_trans_color.green, 10144 (int) ping_trans_color.blue); 10145 } 10146 10147 ping_trans_color.red*=0x0101; 10148 ping_trans_color.green*=0x0101; 10149 ping_trans_color.blue*=0x0101; 10150 ping_trans_color.gray*=0x0101; 10151 10152 if (logging != MagickFalse) 10153 { 10154 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10155 " to (%d,%d,%d)", 10156 (int) ping_trans_color.red, 10157 (int) ping_trans_color.green, 10158 (int) ping_trans_color.blue); 10159 } 10160 } 10161 } 10162 10163 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth) 10164 ping_bit_depth = (ssize_t) mng_info->write_png_depth; 10165 10166 /* 10167 Adjust background and transparency samples in sub-8-bit grayscale files. 10168 */ 10169 if (ping_bit_depth < 8 && ping_color_type == 10170 PNG_COLOR_TYPE_GRAY) 10171 { 10172 png_uint_16 10173 maxval; 10174 10175 size_t 10176 one=1; 10177 10178 maxval=(png_uint_16) ((one << ping_bit_depth)-1); 10179 10180 if (ping_exclude_bKGD == MagickFalse) 10181 { 10182 10183 ping_background.gray=(png_uint_16) ((maxval/65535.)* 10184 (ScaleQuantumToShort(((GetPixelInfoIntensity(image, 10185 &image->background_color))) +.5))); 10186 10187 if (logging != MagickFalse) 10188 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10189 " Setting up bKGD chunk (2)"); 10190 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10191 " background_color index is %d", 10192 (int) ping_background.index); 10193 10194 ping_have_bKGD = MagickTrue; 10195 } 10196 10197 if (logging != MagickFalse) 10198 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10199 " Scaling ping_trans_color.gray from %d", 10200 (int)ping_trans_color.gray); 10201 10202 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*( 10203 ping_trans_color.gray)+.5); 10204 10205 if (logging != MagickFalse) 10206 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10207 " to %d", (int)ping_trans_color.gray); 10208 } 10209 10210 if (ping_exclude_bKGD == MagickFalse) 10211 { 10212 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 10213 { 10214 /* 10215 Identify which colormap entry is the background color. 10216 */ 10217 10218 number_colors=image_colors; 10219 10220 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++) 10221 if (IsPNGColorEqual(image->background_color,image->colormap[i])) 10222 break; 10223 10224 ping_background.index=(png_byte) i; 10225 10226 if (logging != MagickFalse) 10227 { 10228 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10229 " Setting up bKGD chunk with index=%d",(int) i); 10230 } 10231 10232 if (i < (ssize_t) number_colors) 10233 { 10234 ping_have_bKGD = MagickTrue; 10235 10236 if (logging != MagickFalse) 10237 { 10238 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10239 " background =(%d,%d,%d)", 10240 (int) ping_background.red, 10241 (int) ping_background.green, 10242 (int) ping_background.blue); 10243 } 10244 } 10245 10246 else /* Can't happen */ 10247 { 10248 if (logging != MagickFalse) 10249 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10250 " No room in PLTE to add bKGD color"); 10251 ping_have_bKGD = MagickFalse; 10252 } 10253 } 10254 } 10255 10256 if (logging != MagickFalse) 10257 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10258 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type), 10259 ping_color_type); 10260 /* 10261 Initialize compression level and filtering. 10262 */ 10263 if (logging != MagickFalse) 10264 { 10265 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10266 " Setting up deflate compression"); 10267 10268 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10269 " Compression buffer size: 32768"); 10270 } 10271 10272 png_set_compression_buffer_size(ping,32768L); 10273 10274 if (logging != MagickFalse) 10275 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10276 " Compression mem level: 9"); 10277 10278 png_set_compression_mem_level(ping, 9); 10279 10280 /* Untangle the "-quality" setting: 10281 10282 Undefined is 0; the default is used. 10283 Default is 75 10284 10285 10's digit: 10286 10287 0 or omitted: Use Z_HUFFMAN_ONLY strategy with the 10288 zlib default compression level 10289 10290 1-9: the zlib compression level 10291 10292 1's digit: 10293 10294 0-4: the PNG filter method 10295 10296 5: libpng adaptive filtering if compression level > 5 10297 libpng filter type "none" if compression level <= 5 10298 or if image is grayscale or palette 10299 10300 6: libpng adaptive filtering 10301 10302 7: "LOCO" filtering (intrapixel differing) if writing 10303 a MNG, otherwise "none". Did not work in IM-6.7.0-9 10304 and earlier because of a missing "else". 10305 10306 8: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive 10307 filtering. Unused prior to IM-6.7.0-10, was same as 6 10308 10309 9: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters 10310 Unused prior to IM-6.7.0-10, was same as 6 10311 10312 Note that using the -quality option, not all combinations of 10313 PNG filter type, zlib compression level, and zlib compression 10314 strategy are possible. This will be addressed soon in a 10315 release that accomodates "-define png:compression-strategy", etc. 10316 10317 */ 10318 10319 quality=image_info->quality == UndefinedCompressionQuality ? 75UL : 10320 image_info->quality; 10321 10322 if (quality <= 9) 10323 { 10324 if (mng_info->write_png_compression_strategy == 0) 10325 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1; 10326 } 10327 10328 else if (mng_info->write_png_compression_level == 0) 10329 { 10330 int 10331 level; 10332 10333 level=(int) MagickMin((ssize_t) quality/10,9); 10334 10335 mng_info->write_png_compression_level = level+1; 10336 } 10337 10338 if (mng_info->write_png_compression_strategy == 0) 10339 { 10340 if ((quality %10) == 8 || (quality %10) == 9) 10341#ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */ 10342 mng_info->write_png_compression_strategy=Z_RLE+1; 10343#else 10344 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 10345#endif 10346 } 10347 10348 if (mng_info->write_png_compression_filter == 0) 10349 mng_info->write_png_compression_filter=((int) quality % 10) + 1; 10350 10351 if (logging != MagickFalse) 10352 { 10353 if (mng_info->write_png_compression_level) 10354 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10355 " Compression level: %d", 10356 (int) mng_info->write_png_compression_level-1); 10357 10358 if (mng_info->write_png_compression_strategy) 10359 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10360 " Compression strategy: %d", 10361 (int) mng_info->write_png_compression_strategy-1); 10362 10363 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10364 " Setting up filtering"); 10365 10366 if (mng_info->write_png_compression_filter == 6) 10367 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10368 " Base filter method: ADAPTIVE"); 10369 else if (mng_info->write_png_compression_filter == 0 || 10370 mng_info->write_png_compression_filter == 1) 10371 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10372 " Base filter method: NONE"); 10373 else 10374 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10375 " Base filter method: %d", 10376 (int) mng_info->write_png_compression_filter-1); 10377 } 10378 10379 if (mng_info->write_png_compression_level != 0) 10380 png_set_compression_level(ping,mng_info->write_png_compression_level-1); 10381 10382 if (mng_info->write_png_compression_filter == 6) 10383 { 10384 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 10385 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) || 10386 (quality < 50)) 10387 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10388 else 10389 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS); 10390 } 10391 else if (mng_info->write_png_compression_filter == 7 || 10392 mng_info->write_png_compression_filter == 10) 10393 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS); 10394 10395 else if (mng_info->write_png_compression_filter == 8) 10396 { 10397#if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING) 10398 if (mng_info->write_mng) 10399 { 10400 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) || 10401 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA)) 10402 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING; 10403 } 10404#endif 10405 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10406 } 10407 10408 else if (mng_info->write_png_compression_filter == 9) 10409 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10410 10411 else if (mng_info->write_png_compression_filter != 0) 10412 png_set_filter(ping,PNG_FILTER_TYPE_BASE, 10413 mng_info->write_png_compression_filter-1); 10414 10415 if (mng_info->write_png_compression_strategy != 0) 10416 png_set_compression_strategy(ping, 10417 mng_info->write_png_compression_strategy-1); 10418 10419 ping_interlace_method=image_info->interlace != NoInterlace; 10420 10421 if (mng_info->write_mng) 10422 png_set_sig_bytes(ping,8); 10423 10424 /* Bail out if cannot meet defined png:bit-depth or png:color-type */ 10425 10426 if (mng_info->write_png_colortype != 0) 10427 { 10428 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY) 10429 if (ping_have_color != MagickFalse) 10430 { 10431 ping_color_type = PNG_COLOR_TYPE_RGB; 10432 10433 if (ping_bit_depth < 8) 10434 ping_bit_depth=8; 10435 } 10436 10437 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA) 10438 if (ping_have_color != MagickFalse) 10439 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA; 10440 } 10441 10442 if (ping_need_colortype_warning != MagickFalse || 10443 ((mng_info->write_png_depth && 10444 (int) mng_info->write_png_depth != ping_bit_depth) || 10445 (mng_info->write_png_colortype && 10446 ((int) mng_info->write_png_colortype-1 != ping_color_type && 10447 mng_info->write_png_colortype != 7 && 10448 !(mng_info->write_png_colortype == 5 && ping_color_type == 0))))) 10449 { 10450 if (logging != MagickFalse) 10451 { 10452 if (ping_need_colortype_warning != MagickFalse) 10453 { 10454 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10455 " Image has transparency but tRNS chunk was excluded"); 10456 } 10457 10458 if (mng_info->write_png_depth) 10459 { 10460 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10461 " Defined png:bit-depth=%u, Computed depth=%u", 10462 mng_info->write_png_depth, 10463 ping_bit_depth); 10464 } 10465 10466 if (mng_info->write_png_colortype) 10467 { 10468 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10469 " Defined png:color-type=%u, Computed color type=%u", 10470 mng_info->write_png_colortype-1, 10471 ping_color_type); 10472 } 10473 } 10474 10475 png_warning(ping, 10476 "Cannot write image with defined png:bit-depth or png:color-type."); 10477 } 10478 10479 if (image_matte != MagickFalse && image->alpha_trait == UndefinedPixelTrait) 10480 { 10481 /* Add an opaque matte channel */ 10482 image->alpha_trait = BlendPixelTrait; 10483 (void) SetImageAlpha(image,OpaqueAlpha,exception); 10484 10485 if (logging != MagickFalse) 10486 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10487 " Added an opaque matte channel"); 10488 } 10489 10490 if (number_transparent != 0 || number_semitransparent != 0) 10491 { 10492 if (ping_color_type < 4) 10493 { 10494 ping_have_tRNS=MagickTrue; 10495 if (logging != MagickFalse) 10496 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10497 " Setting ping_have_tRNS=MagickTrue."); 10498 } 10499 } 10500 10501 if (logging != MagickFalse) 10502 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10503 " Writing PNG header chunks"); 10504 10505 png_set_IHDR(ping,ping_info,ping_width,ping_height, 10506 ping_bit_depth,ping_color_type, 10507 ping_interlace_method,ping_compression_method, 10508 ping_filter_method); 10509 10510 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse) 10511 { 10512 png_set_PLTE(ping,ping_info,palette,number_colors); 10513 10514 if (logging != MagickFalse) 10515 { 10516 for (i=0; i< (ssize_t) number_colors; i++) 10517 { 10518 if (i < ping_num_trans) 10519 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10520 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)", 10521 (int) i, 10522 (int) palette[i].red, 10523 (int) palette[i].green, 10524 (int) palette[i].blue, 10525 (int) i, 10526 (int) ping_trans_alpha[i]); 10527 else 10528 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10529 " PLTE[%d] = (%d,%d,%d)", 10530 (int) i, 10531 (int) palette[i].red, 10532 (int) palette[i].green, 10533 (int) palette[i].blue); 10534 } 10535 } 10536 } 10537 10538 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */ 10539 if (ping_exclude_sRGB != MagickFalse || 10540 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10541 { 10542 if ((ping_exclude_tEXt == MagickFalse || 10543 ping_exclude_zTXt == MagickFalse) && 10544 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)) 10545 { 10546 ResetImageProfileIterator(image); 10547 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 10548 { 10549 profile=GetImageProfile(image,name); 10550 10551 if (profile != (StringInfo *) NULL) 10552 { 10553#ifdef PNG_WRITE_iCCP_SUPPORTED 10554 if ((LocaleCompare(name,"ICC") == 0) || 10555 (LocaleCompare(name,"ICM") == 0)) 10556 { 10557 10558 if (ping_exclude_iCCP == MagickFalse) 10559 { 10560 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10561 " Setting up iCCP chunk"); 10562 10563 png_set_iCCP(ping,ping_info,(png_charp) name,0, 10564#if (PNG_LIBPNG_VER < 10500) 10565 (png_charp) GetStringInfoDatum(profile), 10566#else 10567 (const png_byte *) GetStringInfoDatum(profile), 10568#endif 10569 (png_uint_32) GetStringInfoLength(profile)); 10570 ping_have_iCCP = MagickTrue; 10571 } 10572 } 10573 10574 else 10575#endif 10576 if (ping_exclude_zCCP == MagickFalse) 10577 { 10578 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10579 " Setting up zTXT chunk with uuencoded ICC"); 10580 Magick_png_write_raw_profile(image_info,ping,ping_info, 10581 (unsigned char *) name,(unsigned char *) name, 10582 GetStringInfoDatum(profile), 10583 (png_uint_32) GetStringInfoLength(profile)); 10584 ping_have_iCCP = MagickTrue; 10585 } 10586 } 10587 10588 if (logging != MagickFalse) 10589 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10590 " Setting up text chunk with %s profile",name); 10591 10592 name=GetNextImageProfile(image); 10593 } 10594 } 10595 } 10596 10597#if defined(PNG_WRITE_sRGB_SUPPORTED) 10598 if ((mng_info->have_write_global_srgb == 0) && 10599 ping_have_iCCP != MagickTrue && 10600 (ping_have_sRGB != MagickFalse || 10601 png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10602 { 10603 if (ping_exclude_sRGB == MagickFalse) 10604 { 10605 /* 10606 Note image rendering intent. 10607 */ 10608 if (logging != MagickFalse) 10609 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10610 " Setting up sRGB chunk"); 10611 10612 (void) png_set_sRGB(ping,ping_info,( 10613 Magick_RenderingIntent_to_PNG_RenderingIntent( 10614 image->rendering_intent))); 10615 10616 ping_have_sRGB = MagickTrue; 10617 } 10618 } 10619 10620 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10621#endif 10622 { 10623 if (ping_exclude_gAMA == MagickFalse && 10624 ping_have_iCCP == MagickFalse && 10625 ping_have_sRGB == MagickFalse && 10626 (ping_exclude_sRGB == MagickFalse || 10627 (image->gamma < .45 || image->gamma > .46))) 10628 { 10629 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0)) 10630 { 10631 /* 10632 Note image gamma. 10633 To do: check for cHRM+gAMA == sRGB, and write sRGB instead. 10634 */ 10635 if (logging != MagickFalse) 10636 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10637 " Setting up gAMA chunk"); 10638 10639 png_set_gAMA(ping,ping_info,image->gamma); 10640 } 10641 } 10642 10643 if (ping_exclude_cHRM == MagickFalse && ping_have_sRGB == MagickFalse) 10644 { 10645 if ((mng_info->have_write_global_chrm == 0) && 10646 (image->chromaticity.red_primary.x != 0.0)) 10647 { 10648 /* 10649 Note image chromaticity. 10650 Note: if cHRM+gAMA == sRGB write sRGB instead. 10651 */ 10652 PrimaryInfo 10653 bp, 10654 gp, 10655 rp, 10656 wp; 10657 10658 wp=image->chromaticity.white_point; 10659 rp=image->chromaticity.red_primary; 10660 gp=image->chromaticity.green_primary; 10661 bp=image->chromaticity.blue_primary; 10662 10663 if (logging != MagickFalse) 10664 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10665 " Setting up cHRM chunk"); 10666 10667 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y, 10668 bp.x,bp.y); 10669 } 10670 } 10671 } 10672 10673 if (ping_exclude_bKGD == MagickFalse) 10674 { 10675 if (ping_have_bKGD != MagickFalse) 10676 { 10677 png_set_bKGD(ping,ping_info,&ping_background); 10678 if (logging != MagickFalse) 10679 { 10680 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10681 " Setting up bKGD chunk"); 10682 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10683 " background color = (%d,%d,%d)", 10684 (int) ping_background.red, 10685 (int) ping_background.green, 10686 (int) ping_background.blue); 10687 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10688 " index = %d, gray=%d", 10689 (int) ping_background.index, 10690 (int) ping_background.gray); 10691 } 10692 } 10693 } 10694 10695 if (ping_exclude_pHYs == MagickFalse) 10696 { 10697 if (ping_have_pHYs != MagickFalse) 10698 { 10699 png_set_pHYs(ping,ping_info, 10700 ping_pHYs_x_resolution, 10701 ping_pHYs_y_resolution, 10702 ping_pHYs_unit_type); 10703 10704 if (logging != MagickFalse) 10705 { 10706 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10707 " Setting up pHYs chunk"); 10708 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10709 " x_resolution=%lu", 10710 (unsigned long) ping_pHYs_x_resolution); 10711 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10712 " y_resolution=%lu", 10713 (unsigned long) ping_pHYs_y_resolution); 10714 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10715 " unit_type=%lu", 10716 (unsigned long) ping_pHYs_unit_type); 10717 } 10718 } 10719 } 10720 10721#if defined(PNG_oFFs_SUPPORTED) 10722 if (ping_exclude_oFFs == MagickFalse) 10723 { 10724 if (image->page.x || image->page.y) 10725 { 10726 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x, 10727 (png_int_32) image->page.y, 0); 10728 10729 if (logging != MagickFalse) 10730 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10731 " Setting up oFFs chunk with x=%d, y=%d, units=0", 10732 (int) image->page.x, (int) image->page.y); 10733 } 10734 } 10735#endif 10736 10737#if defined(PNG_tIME_SUPPORTED) 10738 if (ping_exclude_tIME == MagickFalse) 10739 { 10740 const char 10741 *timestamp; 10742 10743 if (image->taint == MagickFalse) 10744 { 10745 timestamp=GetImageOption(image_info,"png:tIME"); 10746 10747 if (timestamp == (const char *) NULL) 10748 timestamp=GetImageProperty(image,"png:tIME",exception); 10749 } 10750 10751 else 10752 { 10753 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10754 " Reset tIME in tainted image"); 10755 10756 timestamp=GetImageProperty(image,"date:modify",exception); 10757 } 10758 10759 if (timestamp != (const char *) NULL) 10760 write_tIME_chunk(image,ping,ping_info,timestamp,exception); 10761 } 10762#endif 10763 10764 if (mng_info->need_blob != MagickFalse) 10765 { 10766 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) == 10767 MagickFalse) 10768 png_error(ping,"WriteBlob Failed"); 10769 10770 ping_have_blob=MagickTrue; 10771 } 10772 10773 png_write_info_before_PLTE(ping, ping_info); 10774 10775 if (ping_have_tRNS != MagickFalse && ping_color_type < 4) 10776 { 10777 if (logging != MagickFalse) 10778 { 10779 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10780 " Calling png_set_tRNS with num_trans=%d",ping_num_trans); 10781 } 10782 10783 if (ping_color_type == 3) 10784 (void) png_set_tRNS(ping, ping_info, 10785 ping_trans_alpha, 10786 ping_num_trans, 10787 NULL); 10788 10789 else 10790 { 10791 (void) png_set_tRNS(ping, ping_info, 10792 NULL, 10793 0, 10794 &ping_trans_color); 10795 10796 if (logging != MagickFalse) 10797 { 10798 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10799 " tRNS color =(%d,%d,%d)", 10800 (int) ping_trans_color.red, 10801 (int) ping_trans_color.green, 10802 (int) ping_trans_color.blue); 10803 } 10804 } 10805 } 10806 10807 /* write any png-chunk-b profiles */ 10808 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging); 10809 10810 png_write_info(ping,ping_info); 10811 10812 /* write any PNG-chunk-m profiles */ 10813 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging); 10814 10815 if (ping_exclude_vpAg == MagickFalse) 10816 { 10817 if ((image->page.width != 0 && image->page.width != image->columns) || 10818 (image->page.height != 0 && image->page.height != image->rows)) 10819 { 10820 unsigned char 10821 chunk[14]; 10822 10823 (void) WriteBlobMSBULong(image,9L); /* data length=8 */ 10824 PNGType(chunk,mng_vpAg); 10825 LogPNGChunk(logging,mng_vpAg,9L); 10826 PNGLong(chunk+4,(png_uint_32) image->page.width); 10827 PNGLong(chunk+8,(png_uint_32) image->page.height); 10828 chunk[12]=0; /* unit = pixels */ 10829 (void) WriteBlob(image,13,chunk); 10830 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 10831 } 10832 } 10833 10834#if (PNG_LIBPNG_VER == 10206) 10835 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */ 10836#define PNG_HAVE_IDAT 0x04 10837 ping->mode |= PNG_HAVE_IDAT; 10838#undef PNG_HAVE_IDAT 10839#endif 10840 10841 png_set_packing(ping); 10842 /* 10843 Allocate memory. 10844 */ 10845 rowbytes=image->columns; 10846 if (image_depth > 8) 10847 rowbytes*=2; 10848 switch (ping_color_type) 10849 { 10850 case PNG_COLOR_TYPE_RGB: 10851 rowbytes*=3; 10852 break; 10853 10854 case PNG_COLOR_TYPE_GRAY_ALPHA: 10855 rowbytes*=2; 10856 break; 10857 10858 case PNG_COLOR_TYPE_RGBA: 10859 rowbytes*=4; 10860 break; 10861 10862 default: 10863 break; 10864 } 10865 10866 if (logging != MagickFalse) 10867 { 10868 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10869 " Writing PNG image data"); 10870 10871 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10872 " Allocating %.20g bytes of memory for pixels",(double) rowbytes); 10873 } 10874 pixel_info=AcquireVirtualMemory(rowbytes,sizeof(*ping_pixels)); 10875 if (pixel_info == (MemoryInfo *) NULL) 10876 png_error(ping,"Allocation of memory for pixels failed"); 10877 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 10878 10879 /* 10880 Initialize image scanlines. 10881 */ 10882 quantum_info=AcquireQuantumInfo(image_info,image); 10883 if (quantum_info == (QuantumInfo *) NULL) 10884 png_error(ping,"Memory allocation for quantum_info failed"); 10885 quantum_info->format=UndefinedQuantumFormat; 10886 SetQuantumDepth(image,quantum_info,image_depth); 10887 (void) SetQuantumEndian(image,quantum_info,MSBEndian); 10888 num_passes=png_set_interlace_handling(ping); 10889 10890 if ((!mng_info->write_png8 && !mng_info->write_png24 && 10891 !mng_info->write_png48 && !mng_info->write_png64 && 10892 !mng_info->write_png32) && 10893 (mng_info->IsPalette || 10894 (image_info->type == BilevelType)) && 10895 image_matte == MagickFalse && 10896 ping_have_non_bw == MagickFalse) 10897 { 10898 /* Palette, Bilevel, or Opaque Monochrome */ 10899 register const Quantum 10900 *p; 10901 10902 SetQuantumDepth(image,quantum_info,8); 10903 for (pass=0; pass < num_passes; pass++) 10904 { 10905 /* 10906 Convert PseudoClass image to a PNG monochrome image. 10907 */ 10908 for (y=0; y < (ssize_t) image->rows; y++) 10909 { 10910 if (logging != MagickFalse && y == 0) 10911 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10912 " Writing row of pixels (0)"); 10913 10914 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 10915 10916 if (p == (const Quantum *) NULL) 10917 break; 10918 10919 if (mng_info->IsPalette) 10920 { 10921 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10922 quantum_info,GrayQuantum,ping_pixels,exception); 10923 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE && 10924 mng_info->write_png_depth && 10925 mng_info->write_png_depth != old_bit_depth) 10926 { 10927 /* Undo pixel scaling */ 10928 for (i=0; i < (ssize_t) image->columns; i++) 10929 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i) 10930 >> (8-old_bit_depth)); 10931 } 10932 } 10933 10934 else 10935 { 10936 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10937 quantum_info,RedQuantum,ping_pixels,exception); 10938 } 10939 10940 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE) 10941 for (i=0; i < (ssize_t) image->columns; i++) 10942 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ? 10943 255 : 0); 10944 10945 if (logging != MagickFalse && y == 0) 10946 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10947 " Writing row of pixels (1)"); 10948 10949 png_write_row(ping,ping_pixels); 10950 10951 status=SetImageProgress(image,SaveImageTag, 10952 (MagickOffsetType) (pass * image->rows + y), 10953 num_passes * image->rows); 10954 10955 if (status == MagickFalse) 10956 break; 10957 } 10958 } 10959 } 10960 10961 else /* Not Palette, Bilevel, or Opaque Monochrome */ 10962 { 10963 if ((!mng_info->write_png8 && !mng_info->write_png24 && 10964 !mng_info->write_png48 && !mng_info->write_png64 && 10965 !mng_info->write_png32) && (image_matte != MagickFalse || 10966 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) && 10967 (mng_info->IsPalette) && ping_have_color == MagickFalse) 10968 { 10969 register const Quantum 10970 *p; 10971 10972 for (pass=0; pass < num_passes; pass++) 10973 { 10974 10975 for (y=0; y < (ssize_t) image->rows; y++) 10976 { 10977 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 10978 10979 if (p == (const Quantum *) NULL) 10980 break; 10981 10982 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 10983 { 10984 if (mng_info->IsPalette) 10985 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10986 quantum_info,GrayQuantum,ping_pixels,exception); 10987 10988 else 10989 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10990 quantum_info,RedQuantum,ping_pixels,exception); 10991 10992 if (logging != MagickFalse && y == 0) 10993 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10994 " Writing GRAY PNG pixels (2)"); 10995 } 10996 10997 else /* PNG_COLOR_TYPE_GRAY_ALPHA */ 10998 { 10999 if (logging != MagickFalse && y == 0) 11000 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11001 " Writing GRAY_ALPHA PNG pixels (2)"); 11002 11003 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11004 quantum_info,GrayAlphaQuantum,ping_pixels,exception); 11005 } 11006 11007 if (logging != MagickFalse && y == 0) 11008 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11009 " Writing row of pixels (2)"); 11010 11011 png_write_row(ping,ping_pixels); 11012 11013 status=SetImageProgress(image,SaveImageTag, 11014 (MagickOffsetType) (pass * image->rows + y), 11015 num_passes * image->rows); 11016 11017 if (status == MagickFalse) 11018 break; 11019 } 11020 } 11021 } 11022 11023 else 11024 { 11025 register const Quantum 11026 *p; 11027 11028 for (pass=0; pass < num_passes; pass++) 11029 { 11030 if ((image_depth > 8) || 11031 mng_info->write_png24 || 11032 mng_info->write_png32 || 11033 mng_info->write_png48 || 11034 mng_info->write_png64 || 11035 (!mng_info->write_png8 && !mng_info->IsPalette)) 11036 { 11037 for (y=0; y < (ssize_t) image->rows; y++) 11038 { 11039 p=GetVirtualPixels(image,0,y,image->columns,1, exception); 11040 11041 if (p == (const Quantum *) NULL) 11042 break; 11043 11044 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 11045 { 11046 if (image->storage_class == DirectClass) 11047 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11048 quantum_info,RedQuantum,ping_pixels,exception); 11049 11050 else 11051 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11052 quantum_info,GrayQuantum,ping_pixels,exception); 11053 } 11054 11055 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 11056 { 11057 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11058 quantum_info,GrayAlphaQuantum,ping_pixels, 11059 exception); 11060 11061 if (logging != MagickFalse && y == 0) 11062 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11063 " Writing GRAY_ALPHA PNG pixels (3)"); 11064 } 11065 11066 else if (image_matte != MagickFalse) 11067 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11068 quantum_info,RGBAQuantum,ping_pixels,exception); 11069 11070 else 11071 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11072 quantum_info,RGBQuantum,ping_pixels,exception); 11073 11074 if (logging != MagickFalse && y == 0) 11075 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11076 " Writing row of pixels (3)"); 11077 11078 png_write_row(ping,ping_pixels); 11079 11080 status=SetImageProgress(image,SaveImageTag, 11081 (MagickOffsetType) (pass * image->rows + y), 11082 num_passes * image->rows); 11083 11084 if (status == MagickFalse) 11085 break; 11086 } 11087 } 11088 11089 else 11090 /* not ((image_depth > 8) || 11091 mng_info->write_png24 || mng_info->write_png32 || 11092 mng_info->write_png48 || mng_info->write_png64 || 11093 (!mng_info->write_png8 && !mng_info->IsPalette)) 11094 */ 11095 { 11096 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) && 11097 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA)) 11098 { 11099 if (logging != MagickFalse) 11100 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11101 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass); 11102 11103 SetQuantumDepth(image,quantum_info,8); 11104 image_depth=8; 11105 } 11106 11107 for (y=0; y < (ssize_t) image->rows; y++) 11108 { 11109 if (logging != MagickFalse && y == 0) 11110 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11111 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass); 11112 11113 p=GetVirtualPixels(image,0,y,image->columns,1, exception); 11114 11115 if (p == (const Quantum *) NULL) 11116 break; 11117 11118 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 11119 { 11120 SetQuantumDepth(image,quantum_info,image->depth); 11121 11122 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11123 quantum_info,GrayQuantum,ping_pixels,exception); 11124 } 11125 11126 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 11127 { 11128 if (logging != MagickFalse && y == 0) 11129 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11130 " Writing GRAY_ALPHA PNG pixels (4)"); 11131 11132 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11133 quantum_info,GrayAlphaQuantum,ping_pixels, 11134 exception); 11135 } 11136 11137 else 11138 { 11139 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11140 quantum_info,IndexQuantum,ping_pixels,exception); 11141 11142 if (logging != MagickFalse && y <= 2) 11143 { 11144 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11145 " Writing row of non-gray pixels (4)"); 11146 11147 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11148 " ping_pixels[0]=%d,ping_pixels[1]=%d", 11149 (int)ping_pixels[0],(int)ping_pixels[1]); 11150 } 11151 } 11152 png_write_row(ping,ping_pixels); 11153 11154 status=SetImageProgress(image,SaveImageTag, 11155 (MagickOffsetType) (pass * image->rows + y), 11156 num_passes * image->rows); 11157 11158 if (status == MagickFalse) 11159 break; 11160 } 11161 } 11162 } 11163 } 11164 } 11165 11166 if (quantum_info != (QuantumInfo *) NULL) 11167 quantum_info=DestroyQuantumInfo(quantum_info); 11168 11169 if (logging != MagickFalse) 11170 { 11171 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11172 " Wrote PNG image data"); 11173 11174 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11175 " Width: %.20g",(double) ping_width); 11176 11177 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11178 " Height: %.20g",(double) ping_height); 11179 11180 if (mng_info->write_png_depth) 11181 { 11182 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11183 " Defined png:bit-depth: %d",mng_info->write_png_depth); 11184 } 11185 11186 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11187 " PNG bit-depth written: %d",ping_bit_depth); 11188 11189 if (mng_info->write_png_colortype) 11190 { 11191 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11192 " Defined png:color-type: %d",mng_info->write_png_colortype-1); 11193 } 11194 11195 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11196 " PNG color-type written: %d",ping_color_type); 11197 11198 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11199 " PNG Interlace method: %d",ping_interlace_method); 11200 } 11201 /* 11202 Generate text chunks after IDAT. 11203 */ 11204 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse) 11205 { 11206 ResetImagePropertyIterator(image); 11207 property=GetNextImageProperty(image); 11208 while (property != (const char *) NULL) 11209 { 11210 png_textp 11211 text; 11212 11213 value=GetImageProperty(image,property,exception); 11214 11215 /* Don't write any "png:" or "jpeg:" properties; those are just for 11216 * "identify" or for passing through to another JPEG 11217 */ 11218 if ((LocaleNCompare(property,"png:",4) != 0 && 11219 LocaleNCompare(property,"jpeg:",5) != 0) && 11220 11221 11222 /* Suppress density and units if we wrote a pHYs chunk */ 11223 (ping_exclude_pHYs != MagickFalse || 11224 LocaleCompare(property,"density") != 0 || 11225 LocaleCompare(property,"units") != 0) && 11226 11227 /* Suppress the IM-generated Date:create and Date:modify */ 11228 (ping_exclude_date == MagickFalse || 11229 LocaleNCompare(property, "Date:",5) != 0)) 11230 { 11231 if (value != (const char *) NULL) 11232 { 11233 11234#if PNG_LIBPNG_VER >= 10400 11235 text=(png_textp) png_malloc(ping, 11236 (png_alloc_size_t) sizeof(png_text)); 11237#else 11238 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); 11239#endif 11240 text[0].key=(char *) property; 11241 text[0].text=(char *) value; 11242 text[0].text_length=strlen(value); 11243 11244 if (ping_exclude_tEXt != MagickFalse) 11245 text[0].compression=PNG_TEXT_COMPRESSION_zTXt; 11246 11247 else if (ping_exclude_zTXt != MagickFalse) 11248 text[0].compression=PNG_TEXT_COMPRESSION_NONE; 11249 11250 else 11251 { 11252 text[0].compression=image_info->compression == NoCompression || 11253 (image_info->compression == UndefinedCompression && 11254 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE : 11255 PNG_TEXT_COMPRESSION_zTXt ; 11256 } 11257 11258 if (logging != MagickFalse) 11259 { 11260 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11261 " Setting up text chunk"); 11262 11263 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11264 " keyword: '%s'",text[0].key); 11265 } 11266 11267 png_set_text(ping,ping_info,text,1); 11268 png_free(ping,text); 11269 } 11270 } 11271 property=GetNextImageProperty(image); 11272 } 11273 } 11274 11275 /* write any PNG-chunk-e profiles */ 11276 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging); 11277 11278 if (logging != MagickFalse) 11279 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11280 " Writing PNG end info"); 11281 11282 png_write_end(ping,ping_info); 11283 11284 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose) 11285 { 11286 if (mng_info->page.x || mng_info->page.y || 11287 (ping_width != mng_info->page.width) || 11288 (ping_height != mng_info->page.height)) 11289 { 11290 unsigned char 11291 chunk[32]; 11292 11293 /* 11294 Write FRAM 4 with clipping boundaries followed by FRAM 1. 11295 */ 11296 (void) WriteBlobMSBULong(image,27L); /* data length=27 */ 11297 PNGType(chunk,mng_FRAM); 11298 LogPNGChunk(logging,mng_FRAM,27L); 11299 chunk[4]=4; 11300 chunk[5]=0; /* frame name separator (no name) */ 11301 chunk[6]=1; /* flag for changing delay, for next frame only */ 11302 chunk[7]=0; /* flag for changing frame timeout */ 11303 chunk[8]=1; /* flag for changing frame clipping for next frame */ 11304 chunk[9]=0; /* flag for changing frame sync_id */ 11305 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */ 11306 chunk[14]=0; /* clipping boundaries delta type */ 11307 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */ 11308 PNGLong(chunk+19, 11309 (png_uint_32) (mng_info->page.x + ping_width)); 11310 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */ 11311 PNGLong(chunk+27, 11312 (png_uint_32) (mng_info->page.y + ping_height)); 11313 (void) WriteBlob(image,31,chunk); 11314 (void) WriteBlobMSBULong(image,crc32(0,chunk,31)); 11315 mng_info->old_framing_mode=4; 11316 mng_info->framing_mode=1; 11317 } 11318 11319 else 11320 mng_info->framing_mode=3; 11321 } 11322 if (mng_info->write_mng && !mng_info->need_fram && 11323 ((int) image->dispose == 3)) 11324 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC"); 11325 11326 /* 11327 Free PNG resources. 11328 */ 11329 11330 png_destroy_write_struct(&ping,&ping_info); 11331 11332 pixel_info=RelinquishVirtualMemory(pixel_info); 11333 11334 if (ping_have_blob != MagickFalse) 11335 (void) CloseBlob(image); 11336 11337 image_info=DestroyImageInfo(image_info); 11338 image=DestroyImage(image); 11339 11340 /* Store bit depth actually written */ 11341 s[0]=(char) ping_bit_depth; 11342 s[1]='\0'; 11343 11344 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception); 11345 11346 if (logging != MagickFalse) 11347 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11348 " exit WriteOnePNGImage()"); 11349 11350#ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 11351 UnlockSemaphoreInfo(ping_semaphore); 11352#endif 11353 11354 /* } for navigation to beginning of SETJMP-protected block. Revert to 11355 * Throwing an Exception when an error occurs. 11356 */ 11357 11358 return(MagickTrue); 11359/* End write one PNG image */ 11360 11361} 11362 11363/* 11364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11365% % 11366% % 11367% % 11368% W r i t e P N G I m a g e % 11369% % 11370% % 11371% % 11372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11373% 11374% WritePNGImage() writes a Portable Network Graphics (PNG) or 11375% Multiple-image Network Graphics (MNG) image file. 11376% 11377% MNG support written by Glenn Randers-Pehrson, glennrp@image... 11378% 11379% The format of the WritePNGImage method is: 11380% 11381% MagickBooleanType WritePNGImage(const ImageInfo *image_info, 11382% Image *image,ExceptionInfo *exception) 11383% 11384% A description of each parameter follows: 11385% 11386% o image_info: the image info. 11387% 11388% o image: The image. 11389% 11390% o exception: return any errors or warnings in this structure. 11391% 11392% Returns MagickTrue on success, MagickFalse on failure. 11393% 11394% Communicating with the PNG encoder: 11395% 11396% While the datastream written is always in PNG format and normally would 11397% be given the "png" file extension, this method also writes the following 11398% pseudo-formats which are subsets of png: 11399% 11400% o PNG8: An 8-bit indexed PNG datastream is written. If the image has 11401% a depth greater than 8, the depth is reduced. If transparency 11402% is present, the tRNS chunk must only have values 0 and 255 11403% (i.e., transparency is binary: fully opaque or fully 11404% transparent). If other values are present they will be 11405% 50%-thresholded to binary transparency. If more than 256 11406% colors are present, they will be quantized to the 4-4-4-1, 11407% 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color 11408% of any resulting fully-transparent pixels is changed to 11409% the image's background color. 11410% 11411% If you want better quantization or dithering of the colors 11412% or alpha than that, you need to do it before calling the 11413% PNG encoder. The pixels contain 8-bit indices even if 11414% they could be represented with 1, 2, or 4 bits. Grayscale 11415% images will be written as indexed PNG files even though the 11416% PNG grayscale type might be slightly more efficient. Please 11417% note that writing to the PNG8 format may result in loss 11418% of color and alpha data. 11419% 11420% o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS 11421% chunk can be present to convey binary transparency by naming 11422% one of the colors as transparent. The only loss incurred 11423% is reduction of sample depth to 8. If the image has more 11424% than one transparent color, has semitransparent pixels, or 11425% has an opaque pixel with the same RGB components as the 11426% transparent color, an image is not written. 11427% 11428% o PNG32: An 8-bit per sample RGBA PNG is written. Partial 11429% transparency is permitted, i.e., the alpha sample for 11430% each pixel can have any value from 0 to 255. The alpha 11431% channel is present even if the image is fully opaque. 11432% The only loss in data is the reduction of the sample depth 11433% to 8. 11434% 11435% o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS 11436% chunk can be present to convey binary transparency by naming 11437% one of the colors as transparent. If the image has more 11438% than one transparent color, has semitransparent pixels, or 11439% has an opaque pixel with the same RGB components as the 11440% transparent color, an image is not written. 11441% 11442% o PNG64: A 16-bit per sample RGBA PNG is written. Partial 11443% transparency is permitted, i.e., the alpha sample for 11444% each pixel can have any value from 0 to 65535. The alpha 11445% channel is present even if the image is fully opaque. 11446% 11447% o PNG00: A PNG that inherits its colortype and bit-depth from the input 11448% image, if the input was a PNG, is written. If these values 11449% cannot be found, or if the pixels have been changed in a way 11450% that makes this impossible, then "PNG00" falls back to the 11451% regular "PNG" format. 11452% 11453% o -define: For more precise control of the PNG output, you can use the 11454% Image options "png:bit-depth" and "png:color-type". These 11455% can be set from the commandline with "-define" and also 11456% from the application programming interfaces. The options 11457% are case-independent and are converted to lowercase before 11458% being passed to this encoder. 11459% 11460% png:color-type can be 0, 2, 3, 4, or 6. 11461% 11462% When png:color-type is 0 (Grayscale), png:bit-depth can 11463% be 1, 2, 4, 8, or 16. 11464% 11465% When png:color-type is 2 (RGB), png:bit-depth can 11466% be 8 or 16. 11467% 11468% When png:color-type is 3 (Indexed), png:bit-depth can 11469% be 1, 2, 4, or 8. This refers to the number of bits 11470% used to store the index. The color samples always have 11471% bit-depth 8 in indexed PNG files. 11472% 11473% When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte), 11474% png:bit-depth can be 8 or 16. 11475% 11476% If the image cannot be written without loss with the 11477% requested bit-depth and color-type, a PNG file will not 11478% be written, a warning will be issued, and the encoder will 11479% return MagickFalse. 11480% 11481% Since image encoders should not be responsible for the "heavy lifting", 11482% the user should make sure that ImageMagick has already reduced the 11483% image depth and number of colors and limit transparency to binary 11484% transparency prior to attempting to write the image with depth, color, 11485% or transparency limitations. 11486% 11487% Note that another definition, "png:bit-depth-written" exists, but it 11488% is not intended for external use. It is only used internally by the 11489% PNG encoder to inform the JNG encoder of the depth of the alpha channel. 11490% 11491% It is possible to request that the PNG encoder write previously-formatted 11492% ancillary chunks in the output PNG file, using the "-profile" commandline 11493% option as shown below or by setting the profile via a programming 11494% interface: 11495% 11496% -profile PNG-chunk-x:<file> 11497% 11498% where x is a location flag and <file> is a file containing the chunk 11499% name in the first 4 bytes, then a colon (":"), followed by the chunk data. 11500% This encoder will compute the chunk length and CRC, so those must not 11501% be included in the file. 11502% 11503% "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT), 11504% or "e" (end, i.e., after IDAT). If you want to write multiple chunks 11505% of the same type, then add a short unique string after the "x" to prevent 11506% subsequent profiles from overwriting the preceding ones, e.g., 11507% 11508% -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02 11509% 11510% As of version 6.6.6 the following optimizations are always done: 11511% 11512% o 32-bit depth is reduced to 16. 11513% o 16-bit depth is reduced to 8 if all pixels contain samples whose 11514% high byte and low byte are identical. 11515% o Palette is sorted to remove unused entries and to put a 11516% transparent color first, if BUILD_PNG_PALETTE is defined. 11517% o Opaque matte channel is removed when writing an indexed PNG. 11518% o Grayscale images are reduced to 1, 2, or 4 bit depth if 11519% this can be done without loss and a larger bit depth N was not 11520% requested via the "-define png:bit-depth=N" option. 11521% o If matte channel is present but only one transparent color is 11522% present, RGB+tRNS is written instead of RGBA 11523% o Opaque matte channel is removed (or added, if color-type 4 or 6 11524% was requested when converting an opaque image). 11525% 11526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11527*/ 11528static MagickBooleanType WritePNGImage(const ImageInfo *image_info, 11529 Image *image,ExceptionInfo *exception) 11530{ 11531 MagickBooleanType 11532 excluding, 11533 logging, 11534 have_mng_structure, 11535 status; 11536 11537 MngInfo 11538 *mng_info; 11539 11540 const char 11541 *value; 11542 11543 int 11544 source; 11545 11546 /* 11547 Open image file. 11548 */ 11549 assert(image_info != (const ImageInfo *) NULL); 11550 assert(image_info->signature == MagickCoreSignature); 11551 assert(image != (Image *) NULL); 11552 assert(image->signature == MagickCoreSignature); 11553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 11554 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()"); 11555 /* 11556 Allocate a MngInfo structure. 11557 */ 11558 have_mng_structure=MagickFalse; 11559 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 11560 11561 if (mng_info == (MngInfo *) NULL) 11562 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 11563 11564 /* 11565 Initialize members of the MngInfo structure. 11566 */ 11567 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 11568 mng_info->image=image; 11569 mng_info->equal_backgrounds=MagickTrue; 11570 have_mng_structure=MagickTrue; 11571 11572 /* See if user has requested a specific PNG subformat */ 11573 11574 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; 11575 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; 11576 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; 11577 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0; 11578 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0; 11579 11580 value=GetImageOption(image_info,"png:format"); 11581 11582 if (value != (char *) NULL || LocaleCompare(image_info->magick,"PNG00") == 0) 11583 { 11584 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11585 " Format=%s",value); 11586 11587 mng_info->write_png8 = MagickFalse; 11588 mng_info->write_png24 = MagickFalse; 11589 mng_info->write_png32 = MagickFalse; 11590 mng_info->write_png48 = MagickFalse; 11591 mng_info->write_png64 = MagickFalse; 11592 11593 if (LocaleCompare(value,"png8") == 0) 11594 mng_info->write_png8 = MagickTrue; 11595 11596 else if (LocaleCompare(value,"png24") == 0) 11597 mng_info->write_png24 = MagickTrue; 11598 11599 else if (LocaleCompare(value,"png32") == 0) 11600 mng_info->write_png32 = MagickTrue; 11601 11602 else if (LocaleCompare(value,"png48") == 0) 11603 mng_info->write_png48 = MagickTrue; 11604 11605 else if (LocaleCompare(value,"png64") == 0) 11606 mng_info->write_png64 = MagickTrue; 11607 11608 else if ((LocaleCompare(value,"png00") == 0) || 11609 LocaleCompare(image_info->magick,"PNG00") == 0) 11610 { 11611 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig. */ 11612 value=GetImageProperty(image,"png:IHDR.bit-depth-orig",exception); 11613 11614 if (value != (char *) NULL) 11615 { 11616 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11617 " png00 inherited bit depth=%s",value); 11618 11619 if (LocaleCompare(value,"1") == 0) 11620 mng_info->write_png_depth = 1; 11621 11622 else if (LocaleCompare(value,"2") == 0) 11623 mng_info->write_png_depth = 2; 11624 11625 else if (LocaleCompare(value,"4") == 0) 11626 mng_info->write_png_depth = 4; 11627 11628 else if (LocaleCompare(value,"8") == 0) 11629 mng_info->write_png_depth = 8; 11630 11631 else if (LocaleCompare(value,"16") == 0) 11632 mng_info->write_png_depth = 16; 11633 } 11634 11635 value=GetImageProperty(image,"png:IHDR.color-type-orig",exception); 11636 11637 if (value != (char *) NULL) 11638 { 11639 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11640 " png00 inherited color type=%s",value); 11641 11642 if (LocaleCompare(value,"0") == 0) 11643 mng_info->write_png_colortype = 1; 11644 11645 else if (LocaleCompare(value,"2") == 0) 11646 mng_info->write_png_colortype = 3; 11647 11648 else if (LocaleCompare(value,"3") == 0) 11649 mng_info->write_png_colortype = 4; 11650 11651 else if (LocaleCompare(value,"4") == 0) 11652 mng_info->write_png_colortype = 5; 11653 11654 else if (LocaleCompare(value,"6") == 0) 11655 mng_info->write_png_colortype = 7; 11656 } 11657 } 11658 } 11659 11660 if (mng_info->write_png8) 11661 { 11662 mng_info->write_png_colortype = /* 3 */ 4; 11663 mng_info->write_png_depth = 8; 11664 image->depth = 8; 11665 } 11666 11667 if (mng_info->write_png24) 11668 { 11669 mng_info->write_png_colortype = /* 2 */ 3; 11670 mng_info->write_png_depth = 8; 11671 image->depth = 8; 11672 11673 if (image->alpha_trait != UndefinedPixelTrait) 11674 (void) SetImageType(image,TrueColorAlphaType,exception); 11675 11676 else 11677 (void) SetImageType(image,TrueColorType,exception); 11678 11679 (void) SyncImage(image,exception); 11680 } 11681 11682 if (mng_info->write_png32) 11683 { 11684 mng_info->write_png_colortype = /* 6 */ 7; 11685 mng_info->write_png_depth = 8; 11686 image->depth = 8; 11687 image->alpha_trait = BlendPixelTrait; 11688 11689 (void) SetImageType(image,TrueColorAlphaType,exception); 11690 (void) SyncImage(image,exception); 11691 } 11692 11693 if (mng_info->write_png48) 11694 { 11695 mng_info->write_png_colortype = /* 2 */ 3; 11696 mng_info->write_png_depth = 16; 11697 image->depth = 16; 11698 11699 if (image->alpha_trait != UndefinedPixelTrait) 11700 (void) SetImageType(image,TrueColorAlphaType,exception); 11701 11702 else 11703 (void) SetImageType(image,TrueColorType,exception); 11704 11705 (void) SyncImage(image,exception); 11706 } 11707 11708 if (mng_info->write_png64) 11709 { 11710 mng_info->write_png_colortype = /* 6 */ 7; 11711 mng_info->write_png_depth = 16; 11712 image->depth = 16; 11713 image->alpha_trait = BlendPixelTrait; 11714 11715 (void) SetImageType(image,TrueColorAlphaType,exception); 11716 (void) SyncImage(image,exception); 11717 } 11718 11719 value=GetImageOption(image_info,"png:bit-depth"); 11720 11721 if (value != (char *) NULL) 11722 { 11723 if (LocaleCompare(value,"1") == 0) 11724 mng_info->write_png_depth = 1; 11725 11726 else if (LocaleCompare(value,"2") == 0) 11727 mng_info->write_png_depth = 2; 11728 11729 else if (LocaleCompare(value,"4") == 0) 11730 mng_info->write_png_depth = 4; 11731 11732 else if (LocaleCompare(value,"8") == 0) 11733 mng_info->write_png_depth = 8; 11734 11735 else if (LocaleCompare(value,"16") == 0) 11736 mng_info->write_png_depth = 16; 11737 11738 else 11739 (void) ThrowMagickException(exception, 11740 GetMagickModule(),CoderWarning, 11741 "ignoring invalid defined png:bit-depth", 11742 "=%s",value); 11743 11744 if (logging != MagickFalse) 11745 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11746 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth); 11747 } 11748 11749 value=GetImageOption(image_info,"png:color-type"); 11750 11751 if (value != (char *) NULL) 11752 { 11753 /* We must store colortype+1 because 0 is a valid colortype */ 11754 if (LocaleCompare(value,"0") == 0) 11755 mng_info->write_png_colortype = 1; 11756 11757 else if (LocaleCompare(value,"1") == 0) 11758 mng_info->write_png_colortype = 2; 11759 11760 else if (LocaleCompare(value,"2") == 0) 11761 mng_info->write_png_colortype = 3; 11762 11763 else if (LocaleCompare(value,"3") == 0) 11764 mng_info->write_png_colortype = 4; 11765 11766 else if (LocaleCompare(value,"4") == 0) 11767 mng_info->write_png_colortype = 5; 11768 11769 else if (LocaleCompare(value,"6") == 0) 11770 mng_info->write_png_colortype = 7; 11771 11772 else 11773 (void) ThrowMagickException(exception, 11774 GetMagickModule(),CoderWarning, 11775 "ignoring invalid defined png:color-type", 11776 "=%s",value); 11777 11778 if (logging != MagickFalse) 11779 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11780 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1); 11781 } 11782 11783 /* Check for chunks to be excluded: 11784 * 11785 * The default is to not exclude any known chunks except for any 11786 * listed in the "unused_chunks" array, above. 11787 * 11788 * Chunks can be listed for exclusion via a "png:exclude-chunk" 11789 * define (in the image properties or in the image artifacts) 11790 * or via a mng_info member. For convenience, in addition 11791 * to or instead of a comma-separated list of chunks, the 11792 * "exclude-chunk" string can be simply "all" or "none". 11793 * 11794 * The exclude-chunk define takes priority over the mng_info. 11795 * 11796 * A "png:include-chunk" define takes priority over both the 11797 * mng_info and the "png:exclude-chunk" define. Like the 11798 * "exclude-chunk" string, it can define "all" or "none" as 11799 * well as a comma-separated list. Chunks that are unknown to 11800 * ImageMagick are always excluded, regardless of their "copy-safe" 11801 * status according to the PNG specification, and even if they 11802 * appear in the "include-chunk" list. Such defines appearing among 11803 * the image options take priority over those found among the image 11804 * artifacts. 11805 * 11806 * Finally, all chunks listed in the "unused_chunks" array are 11807 * automatically excluded, regardless of the other instructions 11808 * or lack thereof. 11809 * 11810 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk 11811 * will not be written and the gAMA chunk will only be written if it 11812 * is not between .45 and .46, or approximately (1.0/2.2). 11813 * 11814 * If you exclude tRNS and the image has transparency, the colortype 11815 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA). 11816 * 11817 * The -strip option causes StripImage() to set the png:include-chunk 11818 * artifact to "none,trns,gama". 11819 */ 11820 11821 mng_info->ping_exclude_bKGD=MagickFalse; 11822 mng_info->ping_exclude_cHRM=MagickFalse; 11823 mng_info->ping_exclude_date=MagickFalse; 11824 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */ 11825 mng_info->ping_exclude_gAMA=MagickFalse; 11826 mng_info->ping_exclude_iCCP=MagickFalse; 11827 /* mng_info->ping_exclude_iTXt=MagickFalse; */ 11828 mng_info->ping_exclude_oFFs=MagickFalse; 11829 mng_info->ping_exclude_pHYs=MagickFalse; 11830 mng_info->ping_exclude_sRGB=MagickFalse; 11831 mng_info->ping_exclude_tEXt=MagickFalse; 11832 mng_info->ping_exclude_tIME=MagickFalse; 11833 mng_info->ping_exclude_tRNS=MagickFalse; 11834 mng_info->ping_exclude_vpAg=MagickFalse; 11835 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */ 11836 mng_info->ping_exclude_zTXt=MagickFalse; 11837 11838 mng_info->ping_preserve_colormap=MagickFalse; 11839 11840 value=GetImageOption(image_info,"png:preserve-colormap"); 11841 if (value == NULL) 11842 value=GetImageArtifact(image,"png:preserve-colormap"); 11843 if (value != NULL) 11844 mng_info->ping_preserve_colormap=MagickTrue; 11845 11846 mng_info->ping_preserve_iCCP=MagickFalse; 11847 11848 value=GetImageOption(image_info,"png:preserve-iCCP"); 11849 if (value == NULL) 11850 value=GetImageArtifact(image,"png:preserve-iCCP"); 11851 if (value != NULL) 11852 mng_info->ping_preserve_iCCP=MagickTrue; 11853 11854 /* These compression-level, compression-strategy, and compression-filter 11855 * defines take precedence over values from the -quality option. 11856 */ 11857 value=GetImageOption(image_info,"png:compression-level"); 11858 if (value == NULL) 11859 value=GetImageArtifact(image,"png:compression-level"); 11860 if (value != NULL) 11861 { 11862 /* We have to add 1 to everything because 0 is a valid input, 11863 * and we want to use 0 (the default) to mean undefined. 11864 */ 11865 if (LocaleCompare(value,"0") == 0) 11866 mng_info->write_png_compression_level = 1; 11867 11868 else if (LocaleCompare(value,"1") == 0) 11869 mng_info->write_png_compression_level = 2; 11870 11871 else if (LocaleCompare(value,"2") == 0) 11872 mng_info->write_png_compression_level = 3; 11873 11874 else if (LocaleCompare(value,"3") == 0) 11875 mng_info->write_png_compression_level = 4; 11876 11877 else if (LocaleCompare(value,"4") == 0) 11878 mng_info->write_png_compression_level = 5; 11879 11880 else if (LocaleCompare(value,"5") == 0) 11881 mng_info->write_png_compression_level = 6; 11882 11883 else if (LocaleCompare(value,"6") == 0) 11884 mng_info->write_png_compression_level = 7; 11885 11886 else if (LocaleCompare(value,"7") == 0) 11887 mng_info->write_png_compression_level = 8; 11888 11889 else if (LocaleCompare(value,"8") == 0) 11890 mng_info->write_png_compression_level = 9; 11891 11892 else if (LocaleCompare(value,"9") == 0) 11893 mng_info->write_png_compression_level = 10; 11894 11895 else 11896 (void) ThrowMagickException(exception, 11897 GetMagickModule(),CoderWarning, 11898 "ignoring invalid defined png:compression-level", 11899 "=%s",value); 11900 } 11901 11902 value=GetImageOption(image_info,"png:compression-strategy"); 11903 if (value == NULL) 11904 value=GetImageArtifact(image,"png:compression-strategy"); 11905 if (value != NULL) 11906 { 11907 if (LocaleCompare(value,"0") == 0) 11908 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11909 11910 else if (LocaleCompare(value,"1") == 0) 11911 mng_info->write_png_compression_strategy = Z_FILTERED+1; 11912 11913 else if (LocaleCompare(value,"2") == 0) 11914 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1; 11915 11916 else if (LocaleCompare(value,"3") == 0) 11917#ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */ 11918 mng_info->write_png_compression_strategy = Z_RLE+1; 11919#else 11920 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11921#endif 11922 11923 else if (LocaleCompare(value,"4") == 0) 11924#ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */ 11925 mng_info->write_png_compression_strategy = Z_FIXED+1; 11926#else 11927 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11928#endif 11929 11930 else 11931 (void) ThrowMagickException(exception, 11932 GetMagickModule(),CoderWarning, 11933 "ignoring invalid defined png:compression-strategy", 11934 "=%s",value); 11935 } 11936 11937 value=GetImageOption(image_info,"png:compression-filter"); 11938 if (value == NULL) 11939 value=GetImageArtifact(image,"png:compression-filter"); 11940 if (value != NULL) 11941 { 11942 /* To do: combinations of filters allowed by libpng 11943 * masks 0x08 through 0xf8 11944 * 11945 * Implement this as a comma-separated list of 0,1,2,3,4,5 11946 * where 5 is a special case meaning PNG_ALL_FILTERS. 11947 */ 11948 11949 if (LocaleCompare(value,"0") == 0) 11950 mng_info->write_png_compression_filter = 1; 11951 11952 else if (LocaleCompare(value,"1") == 0) 11953 mng_info->write_png_compression_filter = 2; 11954 11955 else if (LocaleCompare(value,"2") == 0) 11956 mng_info->write_png_compression_filter = 3; 11957 11958 else if (LocaleCompare(value,"3") == 0) 11959 mng_info->write_png_compression_filter = 4; 11960 11961 else if (LocaleCompare(value,"4") == 0) 11962 mng_info->write_png_compression_filter = 5; 11963 11964 else if (LocaleCompare(value,"5") == 0) 11965 mng_info->write_png_compression_filter = 6; 11966 11967 else 11968 (void) ThrowMagickException(exception, 11969 GetMagickModule(),CoderWarning, 11970 "ignoring invalid defined png:compression-filter", 11971 "=%s",value); 11972 } 11973 11974 for (source=0; source<8; source++) 11975 { 11976 value = NULL; 11977 11978 if (source == 0) 11979 value=GetImageOption(image_info,"png:exclude-chunks"); 11980 11981 if (source == 1) 11982 value=GetImageArtifact(image,"png:exclude-chunks"); 11983 11984 if (source == 2) 11985 value=GetImageOption(image_info,"png:exclude-chunk"); 11986 11987 if (source == 3) 11988 value=GetImageArtifact(image,"png:exclude-chunk"); 11989 11990 if (source == 4) 11991 value=GetImageOption(image_info,"png:include-chunks"); 11992 11993 if (source == 5) 11994 value=GetImageArtifact(image,"png:include-chunks"); 11995 11996 if (source == 6) 11997 value=GetImageOption(image_info,"png:include-chunk"); 11998 11999 if (source == 7) 12000 value=GetImageArtifact(image,"png:include-chunk"); 12001 12002 if (value == NULL) 12003 continue; 12004 12005 if (source < 4) 12006 excluding = MagickTrue; 12007 else 12008 excluding = MagickFalse; 12009 12010 if (logging != MagickFalse) 12011 { 12012 if (source == 0 || source == 2) 12013 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12014 " png:exclude-chunk=%s found in image options.\n", value); 12015 else if (source == 1 || source == 3) 12016 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12017 " png:exclude-chunk=%s found in image artifacts.\n", value); 12018 else if (source == 4 || source == 6) 12019 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12020 " png:include-chunk=%s found in image options.\n", value); 12021 else /* if (source == 5 || source == 7) */ 12022 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12023 " png:include-chunk=%s found in image artifacts.\n", value); 12024 } 12025 12026 if (IsOptionMember("all",value) != MagickFalse) 12027 { 12028 mng_info->ping_exclude_bKGD=excluding; 12029 mng_info->ping_exclude_cHRM=excluding; 12030 mng_info->ping_exclude_date=excluding; 12031 mng_info->ping_exclude_EXIF=excluding; 12032 mng_info->ping_exclude_gAMA=excluding; 12033 mng_info->ping_exclude_iCCP=excluding; 12034 /* mng_info->ping_exclude_iTXt=excluding; */ 12035 mng_info->ping_exclude_oFFs=excluding; 12036 mng_info->ping_exclude_pHYs=excluding; 12037 mng_info->ping_exclude_sRGB=excluding; 12038 mng_info->ping_exclude_tEXt=excluding; 12039 mng_info->ping_exclude_tIME=excluding; 12040 mng_info->ping_exclude_tRNS=excluding; 12041 mng_info->ping_exclude_vpAg=excluding; 12042 mng_info->ping_exclude_zCCP=excluding; 12043 mng_info->ping_exclude_zTXt=excluding; 12044 } 12045 12046 if (IsOptionMember("none",value) != MagickFalse) 12047 { 12048 mng_info->ping_exclude_bKGD=excluding != MagickFalse ? MagickFalse : 12049 MagickTrue; 12050 mng_info->ping_exclude_cHRM=excluding != MagickFalse ? MagickFalse : 12051 MagickTrue; 12052 mng_info->ping_exclude_date=excluding != MagickFalse ? MagickFalse : 12053 MagickTrue; 12054 mng_info->ping_exclude_EXIF=excluding != MagickFalse ? MagickFalse : 12055 MagickTrue; 12056 mng_info->ping_exclude_gAMA=excluding != MagickFalse ? MagickFalse : 12057 MagickTrue; 12058 mng_info->ping_exclude_iCCP=excluding != MagickFalse ? MagickFalse : 12059 MagickTrue; 12060 /* mng_info->ping_exclude_iTXt=!excluding; */ 12061 mng_info->ping_exclude_oFFs=excluding != MagickFalse ? MagickFalse : 12062 MagickTrue; 12063 mng_info->ping_exclude_pHYs=excluding != MagickFalse ? MagickFalse : 12064 MagickTrue; 12065 mng_info->ping_exclude_sRGB=excluding != MagickFalse ? MagickFalse : 12066 MagickTrue; 12067 mng_info->ping_exclude_tEXt=excluding != MagickFalse ? MagickFalse : 12068 MagickTrue; 12069 mng_info->ping_exclude_tIME=excluding != MagickFalse ? MagickFalse : 12070 MagickTrue; 12071 mng_info->ping_exclude_tRNS=excluding != MagickFalse ? MagickFalse : 12072 MagickTrue; 12073 mng_info->ping_exclude_vpAg=excluding != MagickFalse ? MagickFalse : 12074 MagickTrue; 12075 mng_info->ping_exclude_zCCP=excluding != MagickFalse ? MagickFalse : 12076 MagickTrue; 12077 mng_info->ping_exclude_zTXt=excluding != MagickFalse ? MagickFalse : 12078 MagickTrue; 12079 } 12080 12081 if (IsOptionMember("bkgd",value) != MagickFalse) 12082 mng_info->ping_exclude_bKGD=excluding; 12083 12084 if (IsOptionMember("chrm",value) != MagickFalse) 12085 mng_info->ping_exclude_cHRM=excluding; 12086 12087 if (IsOptionMember("date",value) != MagickFalse) 12088 mng_info->ping_exclude_date=excluding; 12089 12090 if (IsOptionMember("exif",value) != MagickFalse) 12091 mng_info->ping_exclude_EXIF=excluding; 12092 12093 if (IsOptionMember("gama",value) != MagickFalse) 12094 mng_info->ping_exclude_gAMA=excluding; 12095 12096 if (IsOptionMember("iccp",value) != MagickFalse) 12097 mng_info->ping_exclude_iCCP=excluding; 12098 12099#if 0 12100 if (IsOptionMember("itxt",value) != MagickFalse) 12101 mng_info->ping_exclude_iTXt=excluding; 12102#endif 12103 12104 if (IsOptionMember("offs",value) != MagickFalse) 12105 mng_info->ping_exclude_oFFs=excluding; 12106 12107 if (IsOptionMember("phys",value) != MagickFalse) 12108 mng_info->ping_exclude_pHYs=excluding; 12109 12110 if (IsOptionMember("srgb",value) != MagickFalse) 12111 mng_info->ping_exclude_sRGB=excluding; 12112 12113 if (IsOptionMember("text",value) != MagickFalse) 12114 mng_info->ping_exclude_tEXt=excluding; 12115 12116 if (IsOptionMember("time",value) != MagickFalse) 12117 mng_info->ping_exclude_tIME=excluding; 12118 12119 if (IsOptionMember("trns",value) != MagickFalse) 12120 mng_info->ping_exclude_tRNS=excluding; 12121 12122 if (IsOptionMember("vpag",value) != MagickFalse) 12123 mng_info->ping_exclude_vpAg=excluding; 12124 12125 if (IsOptionMember("zccp",value) != MagickFalse) 12126 mng_info->ping_exclude_zCCP=excluding; 12127 12128 if (IsOptionMember("ztxt",value) != MagickFalse) 12129 mng_info->ping_exclude_zTXt=excluding; 12130 } 12131 12132 if (logging != MagickFalse) 12133 { 12134 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12135 " Chunks to be excluded from the output png:"); 12136 if (mng_info->ping_exclude_bKGD != MagickFalse) 12137 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12138 " bKGD"); 12139 if (mng_info->ping_exclude_cHRM != MagickFalse) 12140 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12141 " cHRM"); 12142 if (mng_info->ping_exclude_date != MagickFalse) 12143 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12144 " date"); 12145 if (mng_info->ping_exclude_EXIF != MagickFalse) 12146 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12147 " EXIF"); 12148 if (mng_info->ping_exclude_gAMA != MagickFalse) 12149 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12150 " gAMA"); 12151 if (mng_info->ping_exclude_iCCP != MagickFalse) 12152 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12153 " iCCP"); 12154#if 0 12155 if (mng_info->ping_exclude_iTXt != MagickFalse) 12156 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12157 " iTXt"); 12158#endif 12159 12160 if (mng_info->ping_exclude_oFFs != MagickFalse) 12161 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12162 " oFFs"); 12163 if (mng_info->ping_exclude_pHYs != MagickFalse) 12164 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12165 " pHYs"); 12166 if (mng_info->ping_exclude_sRGB != MagickFalse) 12167 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12168 " sRGB"); 12169 if (mng_info->ping_exclude_tEXt != MagickFalse) 12170 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12171 " tEXt"); 12172 if (mng_info->ping_exclude_tIME != MagickFalse) 12173 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12174 " tIME"); 12175 if (mng_info->ping_exclude_tRNS != MagickFalse) 12176 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12177 " tRNS"); 12178 if (mng_info->ping_exclude_vpAg != MagickFalse) 12179 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12180 " vpAg"); 12181 if (mng_info->ping_exclude_zCCP != MagickFalse) 12182 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12183 " zCCP"); 12184 if (mng_info->ping_exclude_zTXt != MagickFalse) 12185 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12186 " zTXt"); 12187 } 12188 12189 mng_info->need_blob = MagickTrue; 12190 12191 status=WriteOnePNGImage(mng_info,image_info,image,exception); 12192 12193 MngInfoFreeStruct(mng_info,&have_mng_structure); 12194 12195 if (logging != MagickFalse) 12196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()"); 12197 12198 return(status); 12199} 12200 12201#if defined(JNG_SUPPORTED) 12202 12203/* Write one JNG image */ 12204static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, 12205 const ImageInfo *image_info,Image *image,ExceptionInfo *exception) 12206{ 12207 Image 12208 *jpeg_image; 12209 12210 ImageInfo 12211 *jpeg_image_info; 12212 12213 MagickBooleanType 12214 logging, 12215 status; 12216 12217 size_t 12218 length; 12219 12220 unsigned char 12221 *blob, 12222 chunk[80], 12223 *p; 12224 12225 unsigned int 12226 jng_alpha_compression_method, 12227 jng_alpha_sample_depth, 12228 jng_color_type, 12229 transparent; 12230 12231 size_t 12232 jng_alpha_quality, 12233 jng_quality; 12234 12235 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 12236 " Enter WriteOneJNGImage()"); 12237 12238 blob=(unsigned char *) NULL; 12239 jpeg_image=(Image *) NULL; 12240 jpeg_image_info=(ImageInfo *) NULL; 12241 length=0; 12242 12243 status=MagickTrue; 12244 transparent=image_info->type==GrayscaleAlphaType || 12245 image_info->type==TrueColorAlphaType || 12246 image->alpha_trait != UndefinedPixelTrait; 12247 12248 jng_alpha_sample_depth = 0; 12249 12250 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000; 12251 12252 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0; 12253 12254 jng_alpha_quality=image_info->quality == 0UL ? 75UL : 12255 image_info->quality; 12256 12257 if (jng_alpha_quality >= 1000) 12258 jng_alpha_quality /= 1000; 12259 12260 length=0; 12261 12262 if (transparent != 0) 12263 { 12264 jng_color_type=14; 12265 12266 /* Create JPEG blob, image, and image_info */ 12267 if (logging != MagickFalse) 12268 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12269 " Creating jpeg_image_info for alpha."); 12270 12271 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); 12272 12273 if (jpeg_image_info == (ImageInfo *) NULL) 12274 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12275 12276 if (logging != MagickFalse) 12277 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12278 " Creating jpeg_image."); 12279 12280 jpeg_image=SeparateImage(image,AlphaChannel,exception); 12281 if (jpeg_image == (Image *) NULL) 12282 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12283 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12284 jpeg_image->alpha_trait=UndefinedPixelTrait; 12285 jpeg_image->quality=jng_alpha_quality; 12286 jpeg_image_info->type=GrayscaleType; 12287 (void) SetImageType(jpeg_image,GrayscaleType,exception); 12288 (void) AcquireUniqueFilename(jpeg_image->filename); 12289 (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent, 12290 "%s",jpeg_image->filename); 12291 } 12292 else 12293 { 12294 jng_alpha_compression_method=0; 12295 jng_color_type=10; 12296 jng_alpha_sample_depth=0; 12297 } 12298 12299 /* To do: check bit depth of PNG alpha channel */ 12300 12301 /* Check if image is grayscale. */ 12302 if (image_info->type != TrueColorAlphaType && image_info->type != 12303 TrueColorType && SetImageGray(image,exception)) 12304 jng_color_type-=2; 12305 12306 if (logging != MagickFalse) 12307 { 12308 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12309 " JNG Quality = %d",(int) jng_quality); 12310 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12311 " JNG Color Type = %d",jng_color_type); 12312 if (transparent != 0) 12313 { 12314 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12315 " JNG Alpha Compression = %d",jng_alpha_compression_method); 12316 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12317 " JNG Alpha Depth = %d",jng_alpha_sample_depth); 12318 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12319 " JNG Alpha Quality = %d",(int) jng_alpha_quality); 12320 } 12321 } 12322 12323 if (transparent != 0) 12324 { 12325 if (jng_alpha_compression_method==0) 12326 { 12327 const char 12328 *value; 12329 12330 /* Encode alpha as a grayscale PNG blob */ 12331 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12332 exception); 12333 if (status == MagickFalse) 12334 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12335 12336 if (logging != MagickFalse) 12337 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12338 " Creating PNG blob."); 12339 12340 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MagickPathExtent); 12341 (void) CopyMagickString(jpeg_image->magick,"PNG",MagickPathExtent); 12342 jpeg_image_info->interlace=NoInterlace; 12343 12344 /* Exclude all ancillary chunks */ 12345 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all"); 12346 12347 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image, 12348 &length,exception); 12349 12350 /* Retrieve sample depth used */ 12351 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception); 12352 if (value != (char *) NULL) 12353 jng_alpha_sample_depth= (unsigned int) value[0]; 12354 } 12355 else 12356 { 12357 /* Encode alpha as a grayscale JPEG blob */ 12358 12359 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12360 exception); 12361 if (status == MagickFalse) 12362 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12363 12364 12365 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent); 12366 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12367 jpeg_image_info->interlace=NoInterlace; 12368 if (logging != MagickFalse) 12369 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12370 " Creating blob."); 12371 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, 12372 exception); 12373 jng_alpha_sample_depth=8; 12374 12375 if (logging != MagickFalse) 12376 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12377 " Successfully read jpeg_image into a blob, length=%.20g.", 12378 (double) length); 12379 12380 } 12381 /* Destroy JPEG image and image_info */ 12382 jpeg_image=DestroyImage(jpeg_image); 12383 (void) RelinquishUniqueFileResource(jpeg_image_info->filename); 12384 jpeg_image_info=DestroyImageInfo(jpeg_image_info); 12385 } 12386 12387 /* Write JHDR chunk */ 12388 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */ 12389 PNGType(chunk,mng_JHDR); 12390 LogPNGChunk(logging,mng_JHDR,16L); 12391 PNGLong(chunk+4,(png_uint_32) image->columns); 12392 PNGLong(chunk+8,(png_uint_32) image->rows); 12393 chunk[12]=jng_color_type; 12394 chunk[13]=8; /* sample depth */ 12395 chunk[14]=8; /*jng_image_compression_method */ 12396 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8); 12397 chunk[16]=jng_alpha_sample_depth; 12398 chunk[17]=jng_alpha_compression_method; 12399 chunk[18]=0; /*jng_alpha_filter_method */ 12400 chunk[19]=0; /*jng_alpha_interlace_method */ 12401 (void) WriteBlob(image,20,chunk); 12402 (void) WriteBlobMSBULong(image,crc32(0,chunk,20)); 12403 if (logging != MagickFalse) 12404 { 12405 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12406 " JNG width:%15lu",(unsigned long) image->columns); 12407 12408 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12409 " JNG height:%14lu",(unsigned long) image->rows); 12410 12411 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12412 " JNG color type:%10d",jng_color_type); 12413 12414 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12415 " JNG sample depth:%8d",8); 12416 12417 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12418 " JNG compression:%9d",8); 12419 12420 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12421 " JNG interlace:%11d",0); 12422 12423 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12424 " JNG alpha depth:%9d",jng_alpha_sample_depth); 12425 12426 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12427 " JNG alpha compression:%3d",jng_alpha_compression_method); 12428 12429 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12430 " JNG alpha filter:%8d",0); 12431 12432 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12433 " JNG alpha interlace:%5d",0); 12434 } 12435 12436 /* Write any JNG-chunk-b profiles */ 12437 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging); 12438 12439 /* 12440 Write leading ancillary chunks 12441 */ 12442 12443 if (transparent != 0) 12444 { 12445 /* 12446 Write JNG bKGD chunk 12447 */ 12448 12449 unsigned char 12450 blue, 12451 green, 12452 red; 12453 12454 ssize_t 12455 num_bytes; 12456 12457 if (jng_color_type == 8 || jng_color_type == 12) 12458 num_bytes=6L; 12459 else 12460 num_bytes=10L; 12461 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L)); 12462 PNGType(chunk,mng_bKGD); 12463 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L)); 12464 red=ScaleQuantumToChar(image->background_color.red); 12465 green=ScaleQuantumToChar(image->background_color.green); 12466 blue=ScaleQuantumToChar(image->background_color.blue); 12467 *(chunk+4)=0; 12468 *(chunk+5)=red; 12469 *(chunk+6)=0; 12470 *(chunk+7)=green; 12471 *(chunk+8)=0; 12472 *(chunk+9)=blue; 12473 (void) WriteBlob(image,(size_t) num_bytes,chunk); 12474 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes)); 12475 } 12476 12477 if ((image->colorspace == sRGBColorspace || image->rendering_intent)) 12478 { 12479 /* 12480 Write JNG sRGB chunk 12481 */ 12482 (void) WriteBlobMSBULong(image,1L); 12483 PNGType(chunk,mng_sRGB); 12484 LogPNGChunk(logging,mng_sRGB,1L); 12485 12486 if (image->rendering_intent != UndefinedIntent) 12487 chunk[4]=(unsigned char) 12488 Magick_RenderingIntent_to_PNG_RenderingIntent( 12489 (image->rendering_intent)); 12490 12491 else 12492 chunk[4]=(unsigned char) 12493 Magick_RenderingIntent_to_PNG_RenderingIntent( 12494 (PerceptualIntent)); 12495 12496 (void) WriteBlob(image,5,chunk); 12497 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 12498 } 12499 else 12500 { 12501 if (image->gamma != 0.0) 12502 { 12503 /* 12504 Write JNG gAMA chunk 12505 */ 12506 (void) WriteBlobMSBULong(image,4L); 12507 PNGType(chunk,mng_gAMA); 12508 LogPNGChunk(logging,mng_gAMA,4L); 12509 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5)); 12510 (void) WriteBlob(image,8,chunk); 12511 (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); 12512 } 12513 12514 if ((mng_info->equal_chrms == MagickFalse) && 12515 (image->chromaticity.red_primary.x != 0.0)) 12516 { 12517 PrimaryInfo 12518 primary; 12519 12520 /* 12521 Write JNG cHRM chunk 12522 */ 12523 (void) WriteBlobMSBULong(image,32L); 12524 PNGType(chunk,mng_cHRM); 12525 LogPNGChunk(logging,mng_cHRM,32L); 12526 primary=image->chromaticity.white_point; 12527 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5)); 12528 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5)); 12529 primary=image->chromaticity.red_primary; 12530 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5)); 12531 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5)); 12532 primary=image->chromaticity.green_primary; 12533 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5)); 12534 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5)); 12535 primary=image->chromaticity.blue_primary; 12536 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5)); 12537 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5)); 12538 (void) WriteBlob(image,36,chunk); 12539 (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); 12540 } 12541 } 12542 12543 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs) 12544 { 12545 /* 12546 Write JNG pHYs chunk 12547 */ 12548 (void) WriteBlobMSBULong(image,9L); 12549 PNGType(chunk,mng_pHYs); 12550 LogPNGChunk(logging,mng_pHYs,9L); 12551 if (image->units == PixelsPerInchResolution) 12552 { 12553 PNGLong(chunk+4,(png_uint_32) 12554 (image->resolution.x*100.0/2.54+0.5)); 12555 12556 PNGLong(chunk+8,(png_uint_32) 12557 (image->resolution.y*100.0/2.54+0.5)); 12558 12559 chunk[12]=1; 12560 } 12561 12562 else 12563 { 12564 if (image->units == PixelsPerCentimeterResolution) 12565 { 12566 PNGLong(chunk+4,(png_uint_32) 12567 (image->resolution.x*100.0+0.5)); 12568 12569 PNGLong(chunk+8,(png_uint_32) 12570 (image->resolution.y*100.0+0.5)); 12571 12572 chunk[12]=1; 12573 } 12574 12575 else 12576 { 12577 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5)); 12578 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5)); 12579 chunk[12]=0; 12580 } 12581 } 12582 (void) WriteBlob(image,13,chunk); 12583 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12584 } 12585 12586 if (mng_info->write_mng == 0 && (image->page.x || image->page.y)) 12587 { 12588 /* 12589 Write JNG oFFs chunk 12590 */ 12591 (void) WriteBlobMSBULong(image,9L); 12592 PNGType(chunk,mng_oFFs); 12593 LogPNGChunk(logging,mng_oFFs,9L); 12594 PNGsLong(chunk+4,(ssize_t) (image->page.x)); 12595 PNGsLong(chunk+8,(ssize_t) (image->page.y)); 12596 chunk[12]=0; 12597 (void) WriteBlob(image,13,chunk); 12598 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12599 } 12600 if (mng_info->write_mng == 0 && (image->page.width || image->page.height)) 12601 { 12602 (void) WriteBlobMSBULong(image,9L); /* data length=8 */ 12603 PNGType(chunk,mng_vpAg); 12604 LogPNGChunk(logging,mng_vpAg,9L); 12605 PNGLong(chunk+4,(png_uint_32) image->page.width); 12606 PNGLong(chunk+8,(png_uint_32) image->page.height); 12607 chunk[12]=0; /* unit = pixels */ 12608 (void) WriteBlob(image,13,chunk); 12609 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12610 } 12611 12612 if (transparent != 0) 12613 { 12614 if (jng_alpha_compression_method==0) 12615 { 12616 register ssize_t 12617 i; 12618 12619 size_t 12620 len; 12621 12622 /* Write IDAT chunk header */ 12623 if (logging != MagickFalse) 12624 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12625 " Write IDAT chunks from blob, length=%.20g.",(double) 12626 length); 12627 12628 /* Copy IDAT chunks */ 12629 len=0; 12630 p=blob+8; 12631 for (i=8; i<(ssize_t) length; i+=len+12) 12632 { 12633 len=(size_t) (*p) << 24; 12634 len|=(size_t) (*(p+1)) << 16; 12635 len|=(size_t) (*(p+2)) << 8; 12636 len|=(size_t) (*(p+3)); 12637 p+=4; 12638 12639 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */ 12640 { 12641 /* Found an IDAT chunk. */ 12642 (void) WriteBlobMSBULong(image,len); 12643 LogPNGChunk(logging,mng_IDAT,len); 12644 (void) WriteBlob(image,len+4,p); 12645 (void) WriteBlobMSBULong(image, crc32(0,p,(uInt) len+4)); 12646 } 12647 12648 else 12649 { 12650 if (logging != MagickFalse) 12651 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12652 " Skipping %c%c%c%c chunk, length=%.20g.", 12653 *(p),*(p+1),*(p+2),*(p+3),(double) len); 12654 } 12655 p+=(8+len); 12656 } 12657 } 12658 else if (length != 0) 12659 { 12660 /* Write JDAA chunk header */ 12661 if (logging != MagickFalse) 12662 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12663 " Write JDAA chunk, length=%.20g.",(double) length); 12664 (void) WriteBlobMSBULong(image,(size_t) length); 12665 PNGType(chunk,mng_JDAA); 12666 LogPNGChunk(logging,mng_JDAA,length); 12667 /* Write JDAT chunk(s) data */ 12668 (void) WriteBlob(image,4,chunk); 12669 (void) WriteBlob(image,length,blob); 12670 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob, 12671 (uInt) length)); 12672 } 12673 blob=(unsigned char *) RelinquishMagickMemory(blob); 12674 } 12675 12676 /* Encode image as a JPEG blob */ 12677 if (logging != MagickFalse) 12678 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12679 " Creating jpeg_image_info."); 12680 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); 12681 if (jpeg_image_info == (ImageInfo *) NULL) 12682 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12683 12684 if (logging != MagickFalse) 12685 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12686 " Creating jpeg_image."); 12687 12688 jpeg_image=CloneImage(image,0,0,MagickTrue,exception); 12689 if (jpeg_image == (Image *) NULL) 12690 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12691 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12692 12693 (void) AcquireUniqueFilename(jpeg_image->filename); 12694 (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,"%s", 12695 jpeg_image->filename); 12696 12697 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12698 exception); 12699 12700 if (logging != MagickFalse) 12701 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12702 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns, 12703 (double) jpeg_image->rows); 12704 12705 if (status == MagickFalse) 12706 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12707 12708 if (jng_color_type == 8 || jng_color_type == 12) 12709 jpeg_image_info->type=GrayscaleType; 12710 12711 jpeg_image_info->quality=jng_quality; 12712 jpeg_image->quality=jng_quality; 12713 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent); 12714 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12715 12716 if (logging != MagickFalse) 12717 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12718 " Creating blob."); 12719 12720 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, 12721 exception); 12722 12723 if (logging != MagickFalse) 12724 { 12725 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12726 " Successfully read jpeg_image into a blob, length=%.20g.", 12727 (double) length); 12728 12729 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12730 " Write JDAT chunk, length=%.20g.",(double) length); 12731 } 12732 12733 /* Write JDAT chunk(s) */ 12734 (void) WriteBlobMSBULong(image,(size_t) length); 12735 PNGType(chunk,mng_JDAT); 12736 LogPNGChunk(logging,mng_JDAT,length); 12737 (void) WriteBlob(image,4,chunk); 12738 (void) WriteBlob(image,length,blob); 12739 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length)); 12740 12741 jpeg_image=DestroyImage(jpeg_image); 12742 (void) RelinquishUniqueFileResource(jpeg_image_info->filename); 12743 jpeg_image_info=DestroyImageInfo(jpeg_image_info); 12744 blob=(unsigned char *) RelinquishMagickMemory(blob); 12745 12746 /* Write any JNG-chunk-e profiles */ 12747 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging); 12748 12749 /* Write IEND chunk */ 12750 (void) WriteBlobMSBULong(image,0L); 12751 PNGType(chunk,mng_IEND); 12752 LogPNGChunk(logging,mng_IEND,0); 12753 (void) WriteBlob(image,4,chunk); 12754 (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); 12755 12756 if (logging != MagickFalse) 12757 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12758 " exit WriteOneJNGImage()"); 12759 12760 return(status); 12761} 12762 12763 12764/* 12765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12766% % 12767% % 12768% % 12769% W r i t e J N G I m a g e % 12770% % 12771% % 12772% % 12773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12774% 12775% WriteJNGImage() writes a JPEG Network Graphics (JNG) image file. 12776% 12777% JNG support written by Glenn Randers-Pehrson, glennrp@image... 12778% 12779% The format of the WriteJNGImage method is: 12780% 12781% MagickBooleanType WriteJNGImage(const ImageInfo *image_info, 12782% Image *image,ExceptionInfo *exception) 12783% 12784% A description of each parameter follows: 12785% 12786% o image_info: the image info. 12787% 12788% o image: The image. 12789% 12790% o exception: return any errors or warnings in this structure. 12791% 12792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12793*/ 12794static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image, 12795 ExceptionInfo *exception) 12796{ 12797 MagickBooleanType 12798 have_mng_structure, 12799 logging, 12800 status; 12801 12802 MngInfo 12803 *mng_info; 12804 12805 /* 12806 Open image file. 12807 */ 12808 assert(image_info != (const ImageInfo *) NULL); 12809 assert(image_info->signature == MagickCoreSignature); 12810 assert(image != (Image *) NULL); 12811 assert(image->signature == MagickCoreSignature); 12812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 12813 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()"); 12814 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 12815 if (status == MagickFalse) 12816 return(status); 12817 if ((image->columns > 65535UL) || (image->rows > 65535UL)) 12818 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 12819 12820 /* 12821 Allocate a MngInfo structure. 12822 */ 12823 have_mng_structure=MagickFalse; 12824 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 12825 if (mng_info == (MngInfo *) NULL) 12826 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12827 /* 12828 Initialize members of the MngInfo structure. 12829 */ 12830 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 12831 mng_info->image=image; 12832 have_mng_structure=MagickTrue; 12833 12834 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n"); 12835 12836 status=WriteOneJNGImage(mng_info,image_info,image,exception); 12837 (void) CloseBlob(image); 12838 12839 (void) CatchImageException(image); 12840 MngInfoFreeStruct(mng_info,&have_mng_structure); 12841 if (logging != MagickFalse) 12842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()"); 12843 return(status); 12844} 12845#endif 12846 12847static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image, 12848 ExceptionInfo *exception) 12849{ 12850 const char 12851 *option; 12852 12853 Image 12854 *next_image; 12855 12856 MagickBooleanType 12857 have_mng_structure, 12858 status; 12859 12860 volatile MagickBooleanType 12861 logging; 12862 12863 MngInfo 12864 *mng_info; 12865 12866 int 12867 image_count, 12868 need_iterations, 12869 need_matte; 12870 12871 volatile int 12872#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 12873 defined(PNG_MNG_FEATURES_SUPPORTED) 12874 need_local_plte, 12875#endif 12876 all_images_are_gray, 12877 need_defi, 12878 use_global_plte; 12879 12880 register ssize_t 12881 i; 12882 12883 unsigned char 12884 chunk[800]; 12885 12886 volatile unsigned int 12887 write_jng, 12888 write_mng; 12889 12890 volatile size_t 12891 scene; 12892 12893 size_t 12894 final_delay=0, 12895 initial_delay; 12896 12897#if (PNG_LIBPNG_VER < 10200) 12898 if (image_info->verbose) 12899 printf("Your PNG library (libpng-%s) is rather old.\n", 12900 PNG_LIBPNG_VER_STRING); 12901#endif 12902 12903 /* 12904 Open image file. 12905 */ 12906 assert(image_info != (const ImageInfo *) NULL); 12907 assert(image_info->signature == MagickCoreSignature); 12908 assert(image != (Image *) NULL); 12909 assert(image->signature == MagickCoreSignature); 12910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 12911 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()"); 12912 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 12913 if (status == MagickFalse) 12914 return(status); 12915 12916 /* 12917 Allocate a MngInfo structure. 12918 */ 12919 have_mng_structure=MagickFalse; 12920 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 12921 if (mng_info == (MngInfo *) NULL) 12922 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12923 /* 12924 Initialize members of the MngInfo structure. 12925 */ 12926 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 12927 mng_info->image=image; 12928 have_mng_structure=MagickTrue; 12929 write_mng=LocaleCompare(image_info->magick,"MNG") == 0; 12930 12931 /* 12932 * See if user has requested a specific PNG subformat to be used 12933 * for all of the PNGs in the MNG being written, e.g., 12934 * 12935 * convert *.png png8:animation.mng 12936 * 12937 * To do: check -define png:bit_depth and png:color_type as well, 12938 * or perhaps use mng:bit_depth and mng:color_type instead for 12939 * global settings. 12940 */ 12941 12942 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; 12943 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; 12944 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; 12945 12946 write_jng=MagickFalse; 12947 if (image_info->compression == JPEGCompression) 12948 write_jng=MagickTrue; 12949 12950 mng_info->adjoin=image_info->adjoin && 12951 (GetNextImageInList(image) != (Image *) NULL) && write_mng; 12952 12953 if (logging != MagickFalse) 12954 { 12955 /* Log some info about the input */ 12956 Image 12957 *p; 12958 12959 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12960 " Checking input image(s)\n" 12961 " Image_info depth: %.20g, Type: %d", 12962 (double) image_info->depth, image_info->type); 12963 12964 scene=0; 12965 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p)) 12966 { 12967 12968 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12969 " Scene: %.20g\n, Image depth: %.20g", 12970 (double) scene++, (double) p->depth); 12971 12972 if (p->alpha_trait != UndefinedPixelTrait) 12973 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12974 " Matte: True"); 12975 12976 else 12977 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12978 " Matte: False"); 12979 12980 if (p->storage_class == PseudoClass) 12981 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12982 " Storage class: PseudoClass"); 12983 12984 else 12985 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12986 " Storage class: DirectClass"); 12987 12988 if (p->colors) 12989 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12990 " Number of colors: %.20g",(double) p->colors); 12991 12992 else 12993 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12994 " Number of colors: unspecified"); 12995 12996 if (mng_info->adjoin == MagickFalse) 12997 break; 12998 } 12999 } 13000 13001 use_global_plte=MagickFalse; 13002 all_images_are_gray=MagickFalse; 13003#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13004 need_local_plte=MagickTrue; 13005#endif 13006 need_defi=MagickFalse; 13007 need_matte=MagickFalse; 13008 mng_info->framing_mode=1; 13009 mng_info->old_framing_mode=1; 13010 13011 if (write_mng) 13012 if (image_info->page != (char *) NULL) 13013 { 13014 /* 13015 Determine image bounding box. 13016 */ 13017 SetGeometry(image,&mng_info->page); 13018 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x, 13019 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height); 13020 } 13021 if (write_mng) 13022 { 13023 unsigned int 13024 need_geom; 13025 13026 unsigned short 13027 red, 13028 green, 13029 blue; 13030 13031 mng_info->page=image->page; 13032 need_geom=MagickTrue; 13033 if (mng_info->page.width || mng_info->page.height) 13034 need_geom=MagickFalse; 13035 /* 13036 Check all the scenes. 13037 */ 13038 initial_delay=image->delay; 13039 need_iterations=MagickFalse; 13040 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0; 13041 mng_info->equal_physs=MagickTrue, 13042 mng_info->equal_gammas=MagickTrue; 13043 mng_info->equal_srgbs=MagickTrue; 13044 mng_info->equal_backgrounds=MagickTrue; 13045 image_count=0; 13046#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13047 defined(PNG_MNG_FEATURES_SUPPORTED) 13048 all_images_are_gray=MagickTrue; 13049 mng_info->equal_palettes=MagickFalse; 13050 need_local_plte=MagickFalse; 13051#endif 13052 for (next_image=image; next_image != (Image *) NULL; ) 13053 { 13054 if (need_geom) 13055 { 13056 if ((next_image->columns+next_image->page.x) > mng_info->page.width) 13057 mng_info->page.width=next_image->columns+next_image->page.x; 13058 13059 if ((next_image->rows+next_image->page.y) > mng_info->page.height) 13060 mng_info->page.height=next_image->rows+next_image->page.y; 13061 } 13062 13063 if (next_image->page.x || next_image->page.y) 13064 need_defi=MagickTrue; 13065 13066 if (next_image->alpha_trait != UndefinedPixelTrait) 13067 need_matte=MagickTrue; 13068 13069 if ((int) next_image->dispose >= BackgroundDispose) 13070 if ((next_image->alpha_trait != UndefinedPixelTrait) || 13071 next_image->page.x || next_image->page.y || 13072 ((next_image->columns < mng_info->page.width) && 13073 (next_image->rows < mng_info->page.height))) 13074 mng_info->need_fram=MagickTrue; 13075 13076 if (next_image->iterations) 13077 need_iterations=MagickTrue; 13078 13079 final_delay=next_image->delay; 13080 13081 if (final_delay != initial_delay || final_delay > 1UL* 13082 next_image->ticks_per_second) 13083 mng_info->need_fram=1; 13084 13085#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13086 defined(PNG_MNG_FEATURES_SUPPORTED) 13087 /* 13088 check for global palette possibility. 13089 */ 13090 if (image->alpha_trait != UndefinedPixelTrait) 13091 need_local_plte=MagickTrue; 13092 13093 if (need_local_plte == 0) 13094 { 13095 if (SetImageGray(image,exception) == MagickFalse) 13096 all_images_are_gray=MagickFalse; 13097 mng_info->equal_palettes=PalettesAreEqual(image,next_image); 13098 if (use_global_plte == 0) 13099 use_global_plte=mng_info->equal_palettes; 13100 need_local_plte=!mng_info->equal_palettes; 13101 } 13102#endif 13103 if (GetNextImageInList(next_image) != (Image *) NULL) 13104 { 13105 if (next_image->background_color.red != 13106 next_image->next->background_color.red || 13107 next_image->background_color.green != 13108 next_image->next->background_color.green || 13109 next_image->background_color.blue != 13110 next_image->next->background_color.blue) 13111 mng_info->equal_backgrounds=MagickFalse; 13112 13113 if (next_image->gamma != next_image->next->gamma) 13114 mng_info->equal_gammas=MagickFalse; 13115 13116 if (next_image->rendering_intent != 13117 next_image->next->rendering_intent) 13118 mng_info->equal_srgbs=MagickFalse; 13119 13120 if ((next_image->units != next_image->next->units) || 13121 (next_image->resolution.x != next_image->next->resolution.x) || 13122 (next_image->resolution.y != next_image->next->resolution.y)) 13123 mng_info->equal_physs=MagickFalse; 13124 13125 if (mng_info->equal_chrms) 13126 { 13127 if (next_image->chromaticity.red_primary.x != 13128 next_image->next->chromaticity.red_primary.x || 13129 next_image->chromaticity.red_primary.y != 13130 next_image->next->chromaticity.red_primary.y || 13131 next_image->chromaticity.green_primary.x != 13132 next_image->next->chromaticity.green_primary.x || 13133 next_image->chromaticity.green_primary.y != 13134 next_image->next->chromaticity.green_primary.y || 13135 next_image->chromaticity.blue_primary.x != 13136 next_image->next->chromaticity.blue_primary.x || 13137 next_image->chromaticity.blue_primary.y != 13138 next_image->next->chromaticity.blue_primary.y || 13139 next_image->chromaticity.white_point.x != 13140 next_image->next->chromaticity.white_point.x || 13141 next_image->chromaticity.white_point.y != 13142 next_image->next->chromaticity.white_point.y) 13143 mng_info->equal_chrms=MagickFalse; 13144 } 13145 } 13146 image_count++; 13147 next_image=GetNextImageInList(next_image); 13148 } 13149 if (image_count < 2) 13150 { 13151 mng_info->equal_backgrounds=MagickFalse; 13152 mng_info->equal_chrms=MagickFalse; 13153 mng_info->equal_gammas=MagickFalse; 13154 mng_info->equal_srgbs=MagickFalse; 13155 mng_info->equal_physs=MagickFalse; 13156 use_global_plte=MagickFalse; 13157#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13158 need_local_plte=MagickTrue; 13159#endif 13160 need_iterations=MagickFalse; 13161 } 13162 13163 if (mng_info->need_fram == MagickFalse) 13164 { 13165 /* 13166 Only certain framing rates 100/n are exactly representable without 13167 the FRAM chunk but we'll allow some slop in VLC files 13168 */ 13169 if (final_delay == 0) 13170 { 13171 if (need_iterations != MagickFalse) 13172 { 13173 /* 13174 It's probably a GIF with loop; don't run it *too* fast. 13175 */ 13176 if (mng_info->adjoin) 13177 { 13178 final_delay=10; 13179 (void) ThrowMagickException(exception,GetMagickModule(), 13180 CoderWarning, 13181 "input has zero delay between all frames; assuming", 13182 " 10 cs `%s'",""); 13183 } 13184 } 13185 else 13186 mng_info->ticks_per_second=0; 13187 } 13188 if (final_delay != 0) 13189 mng_info->ticks_per_second=(png_uint_32) 13190 (image->ticks_per_second/final_delay); 13191 if (final_delay > 50) 13192 mng_info->ticks_per_second=2; 13193 13194 if (final_delay > 75) 13195 mng_info->ticks_per_second=1; 13196 13197 if (final_delay > 125) 13198 mng_info->need_fram=MagickTrue; 13199 13200 if (need_defi && final_delay > 2 && (final_delay != 4) && 13201 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) && 13202 (final_delay != 25) && (final_delay != 50) && 13203 (final_delay != (size_t) image->ticks_per_second)) 13204 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */ 13205 } 13206 13207 if (mng_info->need_fram != MagickFalse) 13208 mng_info->ticks_per_second=image->ticks_per_second; 13209 /* 13210 If pseudocolor, we should also check to see if all the 13211 palettes are identical and write a global PLTE if they are. 13212 ../glennrp Feb 99. 13213 */ 13214 /* 13215 Write the MNG version 1.0 signature and MHDR chunk. 13216 */ 13217 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n"); 13218 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */ 13219 PNGType(chunk,mng_MHDR); 13220 LogPNGChunk(logging,mng_MHDR,28L); 13221 PNGLong(chunk+4,(png_uint_32) mng_info->page.width); 13222 PNGLong(chunk+8,(png_uint_32) mng_info->page.height); 13223 PNGLong(chunk+12,mng_info->ticks_per_second); 13224 PNGLong(chunk+16,0L); /* layer count=unknown */ 13225 PNGLong(chunk+20,0L); /* frame count=unknown */ 13226 PNGLong(chunk+24,0L); /* play time=unknown */ 13227 if (write_jng) 13228 { 13229 if (need_matte) 13230 { 13231 if (need_defi || mng_info->need_fram || use_global_plte) 13232 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */ 13233 13234 else 13235 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */ 13236 } 13237 13238 else 13239 { 13240 if (need_defi || mng_info->need_fram || use_global_plte) 13241 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */ 13242 13243 else 13244 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */ 13245 } 13246 } 13247 13248 else 13249 { 13250 if (need_matte) 13251 { 13252 if (need_defi || mng_info->need_fram || use_global_plte) 13253 PNGLong(chunk+28,11L); /* simplicity=LC */ 13254 13255 else 13256 PNGLong(chunk+28,9L); /* simplicity=VLC */ 13257 } 13258 13259 else 13260 { 13261 if (need_defi || mng_info->need_fram || use_global_plte) 13262 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */ 13263 13264 else 13265 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */ 13266 } 13267 } 13268 (void) WriteBlob(image,32,chunk); 13269 (void) WriteBlobMSBULong(image,crc32(0,chunk,32)); 13270 option=GetImageOption(image_info,"mng:need-cacheoff"); 13271 if (option != (const char *) NULL) 13272 { 13273 size_t 13274 length; 13275 13276 /* 13277 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG. 13278 */ 13279 PNGType(chunk,mng_nEED); 13280 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20); 13281 (void) WriteBlobMSBULong(image,(size_t) length); 13282 LogPNGChunk(logging,mng_nEED,(size_t) length); 13283 length+=4; 13284 (void) WriteBlob(image,length,chunk); 13285 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length)); 13286 } 13287 if ((GetPreviousImageInList(image) == (Image *) NULL) && 13288 (GetNextImageInList(image) != (Image *) NULL) && 13289 (image->iterations != 1)) 13290 { 13291 /* 13292 Write MNG TERM chunk 13293 */ 13294 (void) WriteBlobMSBULong(image,10L); /* data length=10 */ 13295 PNGType(chunk,mng_TERM); 13296 LogPNGChunk(logging,mng_TERM,10L); 13297 chunk[4]=3; /* repeat animation */ 13298 chunk[5]=0; /* show last frame when done */ 13299 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second* 13300 final_delay/MagickMax(image->ticks_per_second,1))); 13301 13302 if (image->iterations == 0) 13303 PNGLong(chunk+10,PNG_UINT_31_MAX); 13304 13305 else 13306 PNGLong(chunk+10,(png_uint_32) image->iterations); 13307 13308 if (logging != MagickFalse) 13309 { 13310 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13311 " TERM delay: %.20g",(double) (mng_info->ticks_per_second* 13312 final_delay/MagickMax(image->ticks_per_second,1))); 13313 13314 if (image->iterations == 0) 13315 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13316 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX); 13317 13318 else 13319 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13320 " Image iterations: %.20g",(double) image->iterations); 13321 } 13322 (void) WriteBlob(image,14,chunk); 13323 (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); 13324 } 13325 /* 13326 To do: check for cHRM+gAMA == sRGB, and write sRGB instead. 13327 */ 13328 if ((image->colorspace == sRGBColorspace || image->rendering_intent) && 13329 mng_info->equal_srgbs) 13330 { 13331 /* 13332 Write MNG sRGB chunk 13333 */ 13334 (void) WriteBlobMSBULong(image,1L); 13335 PNGType(chunk,mng_sRGB); 13336 LogPNGChunk(logging,mng_sRGB,1L); 13337 13338 if (image->rendering_intent != UndefinedIntent) 13339 chunk[4]=(unsigned char) 13340 Magick_RenderingIntent_to_PNG_RenderingIntent( 13341 (image->rendering_intent)); 13342 13343 else 13344 chunk[4]=(unsigned char) 13345 Magick_RenderingIntent_to_PNG_RenderingIntent( 13346 (PerceptualIntent)); 13347 13348 (void) WriteBlob(image,5,chunk); 13349 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 13350 mng_info->have_write_global_srgb=MagickTrue; 13351 } 13352 13353 else 13354 { 13355 if (image->gamma && mng_info->equal_gammas) 13356 { 13357 /* 13358 Write MNG gAMA chunk 13359 */ 13360 (void) WriteBlobMSBULong(image,4L); 13361 PNGType(chunk,mng_gAMA); 13362 LogPNGChunk(logging,mng_gAMA,4L); 13363 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5)); 13364 (void) WriteBlob(image,8,chunk); 13365 (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); 13366 mng_info->have_write_global_gama=MagickTrue; 13367 } 13368 if (mng_info->equal_chrms) 13369 { 13370 PrimaryInfo 13371 primary; 13372 13373 /* 13374 Write MNG cHRM chunk 13375 */ 13376 (void) WriteBlobMSBULong(image,32L); 13377 PNGType(chunk,mng_cHRM); 13378 LogPNGChunk(logging,mng_cHRM,32L); 13379 primary=image->chromaticity.white_point; 13380 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5)); 13381 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5)); 13382 primary=image->chromaticity.red_primary; 13383 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5)); 13384 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5)); 13385 primary=image->chromaticity.green_primary; 13386 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5)); 13387 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5)); 13388 primary=image->chromaticity.blue_primary; 13389 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5)); 13390 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5)); 13391 (void) WriteBlob(image,36,chunk); 13392 (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); 13393 mng_info->have_write_global_chrm=MagickTrue; 13394 } 13395 } 13396 if (image->resolution.x && image->resolution.y && mng_info->equal_physs) 13397 { 13398 /* 13399 Write MNG pHYs chunk 13400 */ 13401 (void) WriteBlobMSBULong(image,9L); 13402 PNGType(chunk,mng_pHYs); 13403 LogPNGChunk(logging,mng_pHYs,9L); 13404 13405 if (image->units == PixelsPerInchResolution) 13406 { 13407 PNGLong(chunk+4,(png_uint_32) 13408 (image->resolution.x*100.0/2.54+0.5)); 13409 13410 PNGLong(chunk+8,(png_uint_32) 13411 (image->resolution.y*100.0/2.54+0.5)); 13412 13413 chunk[12]=1; 13414 } 13415 13416 else 13417 { 13418 if (image->units == PixelsPerCentimeterResolution) 13419 { 13420 PNGLong(chunk+4,(png_uint_32) 13421 (image->resolution.x*100.0+0.5)); 13422 13423 PNGLong(chunk+8,(png_uint_32) 13424 (image->resolution.y*100.0+0.5)); 13425 13426 chunk[12]=1; 13427 } 13428 13429 else 13430 { 13431 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5)); 13432 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5)); 13433 chunk[12]=0; 13434 } 13435 } 13436 (void) WriteBlob(image,13,chunk); 13437 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 13438 } 13439 /* 13440 Write MNG BACK chunk and global bKGD chunk, if the image is transparent 13441 or does not cover the entire frame. 13442 */ 13443 if (write_mng && ((image->alpha_trait != UndefinedPixelTrait) || 13444 image->page.x > 0 || image->page.y > 0 || (image->page.width && 13445 (image->page.width+image->page.x < mng_info->page.width)) 13446 || (image->page.height && (image->page.height+image->page.y 13447 < mng_info->page.height)))) 13448 { 13449 (void) WriteBlobMSBULong(image,6L); 13450 PNGType(chunk,mng_BACK); 13451 LogPNGChunk(logging,mng_BACK,6L); 13452 red=ScaleQuantumToShort(image->background_color.red); 13453 green=ScaleQuantumToShort(image->background_color.green); 13454 blue=ScaleQuantumToShort(image->background_color.blue); 13455 PNGShort(chunk+4,red); 13456 PNGShort(chunk+6,green); 13457 PNGShort(chunk+8,blue); 13458 (void) WriteBlob(image,10,chunk); 13459 (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); 13460 if (mng_info->equal_backgrounds) 13461 { 13462 (void) WriteBlobMSBULong(image,6L); 13463 PNGType(chunk,mng_bKGD); 13464 LogPNGChunk(logging,mng_bKGD,6L); 13465 (void) WriteBlob(image,10,chunk); 13466 (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); 13467 } 13468 } 13469 13470#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13471 if ((need_local_plte == MagickFalse) && 13472 (image->storage_class == PseudoClass) && 13473 (all_images_are_gray == MagickFalse)) 13474 { 13475 size_t 13476 data_length; 13477 13478 /* 13479 Write MNG PLTE chunk 13480 */ 13481 data_length=3*image->colors; 13482 (void) WriteBlobMSBULong(image,data_length); 13483 PNGType(chunk,mng_PLTE); 13484 LogPNGChunk(logging,mng_PLTE,data_length); 13485 13486 for (i=0; i < (ssize_t) image->colors; i++) 13487 { 13488 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar( 13489 image->colormap[i].red) & 0xff); 13490 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar( 13491 image->colormap[i].green) & 0xff); 13492 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar( 13493 image->colormap[i].blue) & 0xff); 13494 } 13495 13496 (void) WriteBlob(image,data_length+4,chunk); 13497 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4))); 13498 mng_info->have_write_global_plte=MagickTrue; 13499 } 13500#endif 13501 } 13502 scene=0; 13503 mng_info->delay=0; 13504#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13505 defined(PNG_MNG_FEATURES_SUPPORTED) 13506 mng_info->equal_palettes=MagickFalse; 13507#endif 13508 do 13509 { 13510 if (mng_info->adjoin) 13511 { 13512#if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13513 defined(PNG_MNG_FEATURES_SUPPORTED) 13514 /* 13515 If we aren't using a global palette for the entire MNG, check to 13516 see if we can use one for two or more consecutive images. 13517 */ 13518 if (need_local_plte && use_global_plte && !all_images_are_gray) 13519 { 13520 if (mng_info->IsPalette) 13521 { 13522 /* 13523 When equal_palettes is true, this image has the same palette 13524 as the previous PseudoClass image 13525 */ 13526 mng_info->have_write_global_plte=mng_info->equal_palettes; 13527 mng_info->equal_palettes=PalettesAreEqual(image,image->next); 13528 if (mng_info->equal_palettes && !mng_info->have_write_global_plte) 13529 { 13530 /* 13531 Write MNG PLTE chunk 13532 */ 13533 size_t 13534 data_length; 13535 13536 data_length=3*image->colors; 13537 (void) WriteBlobMSBULong(image,data_length); 13538 PNGType(chunk,mng_PLTE); 13539 LogPNGChunk(logging,mng_PLTE,data_length); 13540 13541 for (i=0; i < (ssize_t) image->colors; i++) 13542 { 13543 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red); 13544 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green); 13545 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue); 13546 } 13547 13548 (void) WriteBlob(image,data_length+4,chunk); 13549 (void) WriteBlobMSBULong(image,crc32(0,chunk, 13550 (uInt) (data_length+4))); 13551 mng_info->have_write_global_plte=MagickTrue; 13552 } 13553 } 13554 else 13555 mng_info->have_write_global_plte=MagickFalse; 13556 } 13557#endif 13558 if (need_defi) 13559 { 13560 ssize_t 13561 previous_x, 13562 previous_y; 13563 13564 if (scene) 13565 { 13566 previous_x=mng_info->page.x; 13567 previous_y=mng_info->page.y; 13568 } 13569 else 13570 { 13571 previous_x=0; 13572 previous_y=0; 13573 } 13574 mng_info->page=image->page; 13575 if ((mng_info->page.x != previous_x) || 13576 (mng_info->page.y != previous_y)) 13577 { 13578 (void) WriteBlobMSBULong(image,12L); /* data length=12 */ 13579 PNGType(chunk,mng_DEFI); 13580 LogPNGChunk(logging,mng_DEFI,12L); 13581 chunk[4]=0; /* object 0 MSB */ 13582 chunk[5]=0; /* object 0 LSB */ 13583 chunk[6]=0; /* visible */ 13584 chunk[7]=0; /* abstract */ 13585 PNGLong(chunk+8,(png_uint_32) mng_info->page.x); 13586 PNGLong(chunk+12,(png_uint_32) mng_info->page.y); 13587 (void) WriteBlob(image,16,chunk); 13588 (void) WriteBlobMSBULong(image,crc32(0,chunk,16)); 13589 } 13590 } 13591 } 13592 13593 mng_info->write_mng=write_mng; 13594 13595 if ((int) image->dispose >= 3) 13596 mng_info->framing_mode=3; 13597 13598 if (mng_info->need_fram && mng_info->adjoin && 13599 ((image->delay != mng_info->delay) || 13600 (mng_info->framing_mode != mng_info->old_framing_mode))) 13601 { 13602 if (image->delay == mng_info->delay) 13603 { 13604 /* 13605 Write a MNG FRAM chunk with the new framing mode. 13606 */ 13607 (void) WriteBlobMSBULong(image,1L); /* data length=1 */ 13608 PNGType(chunk,mng_FRAM); 13609 LogPNGChunk(logging,mng_FRAM,1L); 13610 chunk[4]=(unsigned char) mng_info->framing_mode; 13611 (void) WriteBlob(image,5,chunk); 13612 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 13613 } 13614 else 13615 { 13616 /* 13617 Write a MNG FRAM chunk with the delay. 13618 */ 13619 (void) WriteBlobMSBULong(image,10L); /* data length=10 */ 13620 PNGType(chunk,mng_FRAM); 13621 LogPNGChunk(logging,mng_FRAM,10L); 13622 chunk[4]=(unsigned char) mng_info->framing_mode; 13623 chunk[5]=0; /* frame name separator (no name) */ 13624 chunk[6]=2; /* flag for changing default delay */ 13625 chunk[7]=0; /* flag for changing frame timeout */ 13626 chunk[8]=0; /* flag for changing frame clipping */ 13627 chunk[9]=0; /* flag for changing frame sync_id */ 13628 PNGLong(chunk+10,(png_uint_32) 13629 ((mng_info->ticks_per_second* 13630 image->delay)/MagickMax(image->ticks_per_second,1))); 13631 (void) WriteBlob(image,14,chunk); 13632 (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); 13633 mng_info->delay=(png_uint_32) image->delay; 13634 } 13635 mng_info->old_framing_mode=mng_info->framing_mode; 13636 } 13637 13638#if defined(JNG_SUPPORTED) 13639 if (image_info->compression == JPEGCompression) 13640 { 13641 ImageInfo 13642 *write_info; 13643 13644 if (logging != MagickFalse) 13645 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13646 " Writing JNG object."); 13647 /* To do: specify the desired alpha compression method. */ 13648 write_info=CloneImageInfo(image_info); 13649 write_info->compression=UndefinedCompression; 13650 status=WriteOneJNGImage(mng_info,write_info,image,exception); 13651 write_info=DestroyImageInfo(write_info); 13652 } 13653 else 13654#endif 13655 { 13656 if (logging != MagickFalse) 13657 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13658 " Writing PNG object."); 13659 13660 mng_info->need_blob = MagickFalse; 13661 mng_info->ping_preserve_colormap = MagickFalse; 13662 13663 /* We don't want any ancillary chunks written */ 13664 mng_info->ping_exclude_bKGD=MagickTrue; 13665 mng_info->ping_exclude_cHRM=MagickTrue; 13666 mng_info->ping_exclude_date=MagickTrue; 13667 mng_info->ping_exclude_EXIF=MagickTrue; 13668 mng_info->ping_exclude_gAMA=MagickTrue; 13669 mng_info->ping_exclude_iCCP=MagickTrue; 13670 /* mng_info->ping_exclude_iTXt=MagickTrue; */ 13671 mng_info->ping_exclude_oFFs=MagickTrue; 13672 mng_info->ping_exclude_pHYs=MagickTrue; 13673 mng_info->ping_exclude_sRGB=MagickTrue; 13674 mng_info->ping_exclude_tEXt=MagickTrue; 13675 mng_info->ping_exclude_tRNS=MagickTrue; 13676 mng_info->ping_exclude_vpAg=MagickTrue; 13677 mng_info->ping_exclude_zCCP=MagickTrue; 13678 mng_info->ping_exclude_zTXt=MagickTrue; 13679 13680 status=WriteOnePNGImage(mng_info,image_info,image,exception); 13681 } 13682 13683 if (status == MagickFalse) 13684 { 13685 MngInfoFreeStruct(mng_info,&have_mng_structure); 13686 (void) CloseBlob(image); 13687 return(MagickFalse); 13688 } 13689 (void) CatchImageException(image); 13690 if (GetNextImageInList(image) == (Image *) NULL) 13691 break; 13692 image=SyncNextImageInList(image); 13693 status=SetImageProgress(image,SaveImagesTag,scene++, 13694 GetImageListLength(image)); 13695 13696 if (status == MagickFalse) 13697 break; 13698 13699 } while (mng_info->adjoin); 13700 13701 if (write_mng) 13702 { 13703 while (GetPreviousImageInList(image) != (Image *) NULL) 13704 image=GetPreviousImageInList(image); 13705 /* 13706 Write the MEND chunk. 13707 */ 13708 (void) WriteBlobMSBULong(image,0x00000000L); 13709 PNGType(chunk,mng_MEND); 13710 LogPNGChunk(logging,mng_MEND,0L); 13711 (void) WriteBlob(image,4,chunk); 13712 (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); 13713 } 13714 /* 13715 Relinquish resources. 13716 */ 13717 (void) CloseBlob(image); 13718 MngInfoFreeStruct(mng_info,&have_mng_structure); 13719 13720 if (logging != MagickFalse) 13721 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()"); 13722 13723 return(MagickTrue); 13724} 13725#else /* PNG_LIBPNG_VER > 10011 */ 13726 13727static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image) 13728{ 13729 (void) image; 13730 printf("Your PNG library is too old: You have libpng-%s\n", 13731 PNG_LIBPNG_VER_STRING); 13732 13733 ThrowBinaryException(CoderError,"PNG library is too old", 13734 image_info->filename); 13735} 13736 13737static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) 13738{ 13739 return(WritePNGImage(image_info,image)); 13740} 13741#endif /* PNG_LIBPNG_VER > 10011 */ 13742#endif 13743