1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP N N GGGG % 7 % P P NN N G % 8 % PPPP N N N G GG % 9 % P N NN G G % 10 % P N N GGG % 11 % % 12 % % 13 % Read/Write Portable Network Graphics Image Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % Glenn Randers-Pehrson % 18 % November 1997 % 19 % % 20 % % 21 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 22 % dedicated to making software imaging solutions freely available. % 23 % % 24 % You may not use this file except in compliance with the License. You may % 25 % obtain a copy of the License at % 26 % % 27 % http://www.imagemagick.org/script/license.php % 28 % % 29 % Unless required by applicable law or agreed to in writing, software % 30 % distributed under the License is distributed on an "AS IS" BASIS, % 31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 32 % See the License for the specific language governing permissions and % 33 % limitations under the License. % 34 % % 35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 % 37 % 38 */ 39 40 41 /* 43 Include declarations. 44 */ 45 #include "MagickCore/studio.h" 46 #include "MagickCore/artifact.h" 47 #include "MagickCore/attribute.h" 48 #include "MagickCore/blob.h" 49 #include "MagickCore/blob-private.h" 50 #include "MagickCore/cache.h" 51 #include "MagickCore/channel.h" 52 #include "MagickCore/color.h" 53 #include "MagickCore/color-private.h" 54 #include "MagickCore/colormap.h" 55 #include "MagickCore/colorspace.h" 56 #include "MagickCore/colorspace-private.h" 57 #include "MagickCore/constitute.h" 58 #include "MagickCore/enhance.h" 59 #include "MagickCore/exception.h" 60 #include "MagickCore/exception-private.h" 61 #include "MagickCore/geometry.h" 62 #include "MagickCore/histogram.h" 63 #include "MagickCore/image.h" 64 #include "MagickCore/image-private.h" 65 #include "MagickCore/layer.h" 66 #include "MagickCore/list.h" 67 #include "MagickCore/log.h" 68 #include "MagickCore/MagickCore.h" 69 #include "MagickCore/memory_.h" 70 #include "MagickCore/module.h" 71 #include "MagickCore/monitor.h" 72 #include "MagickCore/monitor-private.h" 73 #include "MagickCore/option.h" 74 #include "MagickCore/pixel.h" 75 #include "MagickCore/pixel-accessor.h" 76 #include "MagickCore/profile.h" 77 #include "MagickCore/property.h" 78 #include "MagickCore/quantum-private.h" 79 #include "MagickCore/resource_.h" 80 #include "MagickCore/semaphore.h" 81 #include "MagickCore/quantum-private.h" 82 #include "MagickCore/static.h" 83 #include "MagickCore/statistic.h" 84 #include "MagickCore/string_.h" 85 #include "MagickCore/string-private.h" 86 #include "MagickCore/transform.h" 87 #include "MagickCore/utility.h" 88 #if defined(MAGICKCORE_PNG_DELEGATE) 89 90 /* Suppress libpng pedantic warnings that were added in 91 * libpng-1.2.41 and libpng-1.4.0. If you are working on 92 * migration to libpng-1.5, remove these defines and then 93 * fix any code that generates warnings. 94 */ 95 /* #define PNG_DEPRECATED Use of this function is deprecated */ 96 /* #define PNG_USE_RESULT The result of this function must be checked */ 97 /* #define PNG_NORETURN This function does not return */ 98 /* #define PNG_ALLOCATED The result of the function is new memory */ 99 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */ 100 101 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */ 102 #define PNG_PTR_NORETURN 103 104 #include "png.h" 105 #include "zlib.h" 106 107 /* ImageMagick differences */ 109 #define first_scene scene 110 111 #if PNG_LIBPNG_VER > 10011 112 /* 113 Optional declarations. Define or undefine them as you like. 114 */ 115 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */ 116 117 /* 118 Features under construction. Define these to work on them. 119 */ 120 #undef MNG_OBJECT_BUFFERS 121 #undef MNG_BASI_SUPPORTED 122 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */ 123 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */ 124 #if defined(MAGICKCORE_JPEG_DELEGATE) 125 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */ 126 #endif 127 #if !defined(RGBColorMatchExact) 128 #define IsPNGColorEqual(color,target) \ 129 (((color).red == (target).red) && \ 130 ((color).green == (target).green) && \ 131 ((color).blue == (target).blue)) 132 #endif 133 134 /* Table of recognized sRGB ICC profiles */ 135 struct sRGB_info_struct 136 { 137 png_uint_32 len; 138 png_uint_32 crc; 139 png_byte intent; 140 }; 141 142 const struct sRGB_info_struct sRGB_info[] = 143 { 144 /* ICC v2 perceptual sRGB_IEC61966-2-1_black_scaled.icc */ 145 { 3048, 0x3b8772b9UL, 0}, 146 147 /* ICC v2 relative sRGB_IEC61966-2-1_no_black_scaling.icc */ 148 { 3052, 0x427ebb21UL, 1}, 149 150 /* ICC v4 perceptual sRGB_v4_ICC_preference_displayclass.icc */ 151 {60988, 0x306fd8aeUL, 0}, 152 153 /* ICC v4 perceptual sRGB_v4_ICC_preference.icc perceptual */ 154 {60960, 0xbbef7812UL, 0}, 155 156 /* HP? sRGB v2 media-relative sRGB_IEC61966-2-1_noBPC.icc */ 157 { 3024, 0x5d5129ceUL, 1}, 158 159 /* HP-Microsoft sRGB v2 perceptual */ 160 { 3144, 0x182ea552UL, 0}, 161 162 /* HP-Microsoft sRGB v2 media-relative */ 163 { 3144, 0xf29e526dUL, 1}, 164 165 /* Facebook's "2012/01/25 03:41:57", 524, "TINYsRGB.icc" */ 166 { 524, 0xd4938c39UL, 0}, 167 168 /* "2012/11/28 22:35:21", 3212, "Argyll_sRGB.icm") */ 169 { 3212, 0x034af5a1UL, 0}, 170 171 /* Not recognized */ 172 { 0, 0x00000000UL, 0}, 173 }; 174 175 /* Macros for left-bit-replication to ensure that pixels 176 * and PixelInfos all have the same image->depth, and for use 177 * in PNG8 quantization. 178 */ 179 180 /* LBR01: Replicate top bit */ 181 182 #define LBR01PacketRed(pixelpacket) \ 183 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \ 184 0 : QuantumRange); 185 186 #define LBR01PacketGreen(pixelpacket) \ 187 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \ 188 0 : QuantumRange); 189 190 #define LBR01PacketBlue(pixelpacket) \ 191 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \ 192 0 : QuantumRange); 193 194 #define LBR01PacketAlpha(pixelpacket) \ 195 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \ 196 0 : QuantumRange); 197 198 #define LBR01PacketRGB(pixelpacket) \ 199 { \ 200 LBR01PacketRed((pixelpacket)); \ 201 LBR01PacketGreen((pixelpacket)); \ 202 LBR01PacketBlue((pixelpacket)); \ 203 } 204 205 #define LBR01PacketRGBO(pixelpacket) \ 206 { \ 207 LBR01PacketRGB((pixelpacket)); \ 208 LBR01PacketAlpha((pixelpacket)); \ 209 } 210 211 #define LBR01PixelRed(pixel) \ 212 (SetPixelRed(image, \ 213 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \ 214 0 : QuantumRange,(pixel))); 215 216 #define LBR01PixelGreen(pixel) \ 217 (SetPixelGreen(image, \ 218 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \ 219 0 : QuantumRange,(pixel))); 220 221 #define LBR01PixelBlue(pixel) \ 222 (SetPixelBlue(image, \ 223 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \ 224 0 : QuantumRange,(pixel))); 225 226 #define LBR01PixelAlpha(pixel) \ 227 (SetPixelAlpha(image, \ 228 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \ 229 0 : QuantumRange,(pixel))); 230 231 #define LBR01PixelRGB(pixel) \ 232 { \ 233 LBR01PixelRed((pixel)); \ 234 LBR01PixelGreen((pixel)); \ 235 LBR01PixelBlue((pixel)); \ 236 } 237 238 #define LBR01PixelRGBA(pixel) \ 239 { \ 240 LBR01PixelRGB((pixel)); \ 241 LBR01PixelAlpha((pixel)); \ 242 } 243 244 /* LBR02: Replicate top 2 bits */ 245 246 #define LBR02PacketRed(pixelpacket) \ 247 { \ 248 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \ 249 (pixelpacket).red=ScaleCharToQuantum( \ 250 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 251 } 252 #define LBR02PacketGreen(pixelpacket) \ 253 { \ 254 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \ 255 (pixelpacket).green=ScaleCharToQuantum( \ 256 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 257 } 258 #define LBR02PacketBlue(pixelpacket) \ 259 { \ 260 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \ 261 (pixelpacket).blue=ScaleCharToQuantum( \ 262 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 263 } 264 #define LBR02PacketAlpha(pixelpacket) \ 265 { \ 266 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \ 267 (pixelpacket).alpha=ScaleCharToQuantum( \ 268 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \ 269 } 270 271 #define LBR02PacketRGB(pixelpacket) \ 272 { \ 273 LBR02PacketRed((pixelpacket)); \ 274 LBR02PacketGreen((pixelpacket)); \ 275 LBR02PacketBlue((pixelpacket)); \ 276 } 277 278 #define LBR02PacketRGBO(pixelpacket) \ 279 { \ 280 LBR02PacketRGB((pixelpacket)); \ 281 LBR02PacketAlpha((pixelpacket)); \ 282 } 283 284 #define LBR02PixelRed(pixel) \ 285 { \ 286 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 287 & 0xc0; \ 288 SetPixelRed(image, ScaleCharToQuantum( \ 289 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 290 (pixel)); \ 291 } 292 #define LBR02PixelGreen(pixel) \ 293 { \ 294 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 295 & 0xc0; \ 296 SetPixelGreen(image, ScaleCharToQuantum( \ 297 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 298 (pixel)); \ 299 } 300 #define LBR02PixelBlue(pixel) \ 301 { \ 302 unsigned char lbr_bits= \ 303 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \ 304 SetPixelBlue(image, ScaleCharToQuantum( \ 305 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 306 (pixel)); \ 307 } 308 #define LBR02PixelAlpha(pixel) \ 309 { \ 310 unsigned char lbr_bits= \ 311 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \ 312 SetPixelAlpha(image, ScaleCharToQuantum( \ 313 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \ 314 (pixel) ); \ 315 } 316 317 #define LBR02PixelRGB(pixel) \ 318 { \ 319 LBR02PixelRed((pixel)); \ 320 LBR02PixelGreen((pixel)); \ 321 LBR02PixelBlue((pixel)); \ 322 } 323 324 #define LBR02PixelRGBA(pixel) \ 325 { \ 326 LBR02PixelRGB((pixel)); \ 327 LBR02PixelAlpha((pixel)); \ 328 } 329 330 /* LBR03: Replicate top 3 bits (only used with opaque pixels during 331 PNG8 quantization) */ 332 333 #define LBR03PacketRed(pixelpacket) \ 334 { \ 335 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \ 336 (pixelpacket).red=ScaleCharToQuantum( \ 337 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 338 } 339 #define LBR03PacketGreen(pixelpacket) \ 340 { \ 341 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \ 342 (pixelpacket).green=ScaleCharToQuantum( \ 343 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 344 } 345 #define LBR03PacketBlue(pixelpacket) \ 346 { \ 347 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \ 348 (pixelpacket).blue=ScaleCharToQuantum( \ 349 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \ 350 } 351 352 #define LBR03PacketRGB(pixelpacket) \ 353 { \ 354 LBR03PacketRed((pixelpacket)); \ 355 LBR03PacketGreen((pixelpacket)); \ 356 LBR03PacketBlue((pixelpacket)); \ 357 } 358 359 #define LBR03PixelRed(pixel) \ 360 { \ 361 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 362 & 0xe0; \ 363 SetPixelRed(image, ScaleCharToQuantum( \ 364 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 365 } 366 #define LBR03Green(pixel) \ 367 { \ 368 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 369 & 0xe0; \ 370 SetPixelGreen(image, ScaleCharToQuantum( \ 371 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 372 } 373 #define LBR03Blue(pixel) \ 374 { \ 375 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \ 376 & 0xe0; \ 377 SetPixelBlue(image, ScaleCharToQuantum( \ 378 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \ 379 } 380 381 #define LBR03RGB(pixel) \ 382 { \ 383 LBR03PixelRed((pixel)); \ 384 LBR03Green((pixel)); \ 385 LBR03Blue((pixel)); \ 386 } 387 388 /* LBR04: Replicate top 4 bits */ 389 390 #define LBR04PacketRed(pixelpacket) \ 391 { \ 392 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \ 393 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 394 } 395 #define LBR04PacketGreen(pixelpacket) \ 396 { \ 397 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \ 398 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 399 } 400 #define LBR04PacketBlue(pixelpacket) \ 401 { \ 402 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \ 403 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 404 } 405 #define LBR04PacketAlpha(pixelpacket) \ 406 { \ 407 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \ 408 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \ 409 } 410 411 #define LBR04PacketRGB(pixelpacket) \ 412 { \ 413 LBR04PacketRed((pixelpacket)); \ 414 LBR04PacketGreen((pixelpacket)); \ 415 LBR04PacketBlue((pixelpacket)); \ 416 } 417 418 #define LBR04PacketRGBO(pixelpacket) \ 419 { \ 420 LBR04PacketRGB((pixelpacket)); \ 421 LBR04PacketAlpha((pixelpacket)); \ 422 } 423 424 #define LBR04PixelRed(pixel) \ 425 { \ 426 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \ 427 & 0xf0; \ 428 SetPixelRed(image,\ 429 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 430 } 431 #define LBR04PixelGreen(pixel) \ 432 { \ 433 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\ 434 & 0xf0; \ 435 SetPixelGreen(image,\ 436 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 437 } 438 #define LBR04PixelBlue(pixel) \ 439 { \ 440 unsigned char lbr_bits= \ 441 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \ 442 SetPixelBlue(image,\ 443 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 444 } 445 #define LBR04PixelAlpha(pixel) \ 446 { \ 447 unsigned char lbr_bits= \ 448 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \ 449 SetPixelAlpha(image,\ 450 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \ 451 } 452 453 #define LBR04PixelRGB(pixel) \ 454 { \ 455 LBR04PixelRed((pixel)); \ 456 LBR04PixelGreen((pixel)); \ 457 LBR04PixelBlue((pixel)); \ 458 } 459 460 #define LBR04PixelRGBA(pixel) \ 461 { \ 462 LBR04PixelRGB((pixel)); \ 463 LBR04PixelAlpha((pixel)); \ 464 } 465 466 /* 467 Establish thread safety. 468 setjmp/longjmp is claimed to be safe on these platforms: 469 setjmp/longjmp is alleged to be unsafe on these platforms: 470 */ 471 #ifdef PNG_SETJMP_SUPPORTED 472 # ifndef IMPNG_SETJMP_IS_THREAD_SAFE 473 # define IMPNG_SETJMP_NOT_THREAD_SAFE 474 # endif 475 476 # ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 477 static SemaphoreInfo 478 *ping_semaphore = (SemaphoreInfo *) NULL; 479 # endif 480 #endif 481 482 /* 483 This temporary until I set up malloc'ed object attributes array. 484 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but 485 waste more memory. 486 */ 487 #define MNG_MAX_OBJECTS 256 488 489 /* 490 If this not defined, spec is interpreted strictly. If it is 491 defined, an attempt will be made to recover from some errors, 492 including 493 o global PLTE too short 494 */ 495 #undef MNG_LOOSE 496 497 /* 498 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure 499 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work 500 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8, 501 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in 502 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here. 503 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and 504 will be enabled by default in libpng-1.2.0. 505 */ 506 #ifdef PNG_MNG_FEATURES_SUPPORTED 507 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 508 # define PNG_READ_EMPTY_PLTE_SUPPORTED 509 # endif 510 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED 511 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED 512 # endif 513 #endif 514 515 /* 516 Maximum valid size_t in PNG/MNG chunks is (2^31)-1 517 This macro is only defined in libpng-1.0.3 and later. 518 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6 519 */ 520 #ifndef PNG_UINT_31_MAX 521 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL 522 #endif 523 524 /* 525 Constant strings for known chunk types. If you need to add a chunk, 526 add a string holding the name here. To make the code more 527 portable, we use ASCII numbers like this, not characters. 528 */ 529 530 static const png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'}; 531 static const png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'}; 532 static const png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'}; 533 static const png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'}; 534 static const png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'}; 535 static const png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'}; 536 static const png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'}; 537 static const png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'}; 538 static const png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'}; 539 static const png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'}; 540 static const png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'}; 541 static const png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'}; 542 static const png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'}; 543 static const png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'}; 544 static const png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'}; 545 static const png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'}; 546 static const png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'}; 547 static const png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'}; 548 static const png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'}; 549 static const png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'}; 550 static const png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'}; 551 static const png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'}; 552 static const png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'}; 553 static const png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'}; 554 static const png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'}; 555 static const png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'}; 556 static const png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'}; 557 static const png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'}; 558 static const png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'}; 559 static const png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; 560 static const png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'}; 561 static const png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'}; 562 static const png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'}; 563 static const png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'}; 564 565 #if defined(JNG_SUPPORTED) 566 static const png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'}; 567 static const png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'}; 568 static const png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'}; 569 static const png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'}; 570 static const png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'}; 571 static const png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'}; 572 #endif 573 574 #if 0 575 /* Other known chunks that are not yet supported by ImageMagick: */ 576 static const png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'}; 577 static const png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'}; 578 static const png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'}; 579 static const png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'}; 580 static const png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'}; 581 static const png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'}; 582 static const png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'}; 583 #endif 584 585 typedef struct _MngBox 586 { 587 long 588 left, 589 right, 590 top, 591 bottom; 592 } MngBox; 593 594 typedef struct _MngPair 595 { 596 volatile long 597 a, 598 b; 599 } MngPair; 600 601 #ifdef MNG_OBJECT_BUFFERS 602 typedef struct _MngBuffer 603 { 604 605 size_t 606 height, 607 width; 608 609 Image 610 *image; 611 612 png_color 613 plte[256]; 614 615 int 616 reference_count; 617 618 unsigned char 619 alpha_sample_depth, 620 compression_method, 621 color_type, 622 concrete, 623 filter_method, 624 frozen, 625 image_type, 626 interlace_method, 627 pixel_sample_depth, 628 plte_length, 629 sample_depth, 630 viewable; 631 } MngBuffer; 632 #endif 633 634 typedef struct _MngInfo 635 { 636 637 #ifdef MNG_OBJECT_BUFFERS 638 MngBuffer 639 *ob[MNG_MAX_OBJECTS]; 640 #endif 641 642 Image * 643 image; 644 645 RectangleInfo 646 page; 647 648 int 649 adjoin, 650 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 651 bytes_in_read_buffer, 652 found_empty_plte, 653 #endif 654 equal_backgrounds, 655 equal_chrms, 656 equal_gammas, 657 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 658 defined(PNG_MNG_FEATURES_SUPPORTED) 659 equal_palettes, 660 #endif 661 equal_physs, 662 equal_srgbs, 663 framing_mode, 664 have_global_bkgd, 665 have_global_chrm, 666 have_global_gama, 667 have_global_phys, 668 have_global_sbit, 669 have_global_srgb, 670 have_saved_bkgd_index, 671 have_write_global_chrm, 672 have_write_global_gama, 673 have_write_global_plte, 674 have_write_global_srgb, 675 need_fram, 676 object_id, 677 old_framing_mode, 678 saved_bkgd_index; 679 680 int 681 new_number_colors; 682 683 ssize_t 684 image_found, 685 loop_count[256], 686 loop_iteration[256], 687 scenes_found, 688 x_off[MNG_MAX_OBJECTS], 689 y_off[MNG_MAX_OBJECTS]; 690 691 MngBox 692 clip, 693 frame, 694 image_box, 695 object_clip[MNG_MAX_OBJECTS]; 696 697 unsigned char 698 /* These flags could be combined into one byte */ 699 exists[MNG_MAX_OBJECTS], 700 frozen[MNG_MAX_OBJECTS], 701 loop_active[256], 702 invisible[MNG_MAX_OBJECTS], 703 viewable[MNG_MAX_OBJECTS]; 704 705 MagickOffsetType 706 loop_jump[256]; 707 708 png_colorp 709 global_plte; 710 711 png_color_8 712 global_sbit; 713 714 png_byte 715 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 716 read_buffer[8], 717 #endif 718 global_trns[256]; 719 720 float 721 global_gamma; 722 723 ChromaticityInfo 724 global_chrm; 725 726 RenderingIntent 727 global_srgb_intent; 728 729 unsigned int 730 delay, 731 global_plte_length, 732 global_trns_length, 733 global_x_pixels_per_unit, 734 global_y_pixels_per_unit, 735 mng_width, 736 mng_height, 737 ticks_per_second; 738 739 MagickBooleanType 740 need_blob; 741 742 unsigned int 743 IsPalette, 744 global_phys_unit_type, 745 basi_warning, 746 clon_warning, 747 dhdr_warning, 748 jhdr_warning, 749 magn_warning, 750 past_warning, 751 phyg_warning, 752 phys_warning, 753 sbit_warning, 754 show_warning, 755 mng_type, 756 write_mng, 757 write_png_colortype, 758 write_png_depth, 759 write_png_compression_level, 760 write_png_compression_strategy, 761 write_png_compression_filter, 762 write_png8, 763 write_png24, 764 write_png32, 765 write_png48, 766 write_png64; 767 768 #ifdef MNG_BASI_SUPPORTED 769 size_t 770 basi_width, 771 basi_height; 772 773 unsigned int 774 basi_depth, 775 basi_color_type, 776 basi_compression_method, 777 basi_filter_type, 778 basi_interlace_method, 779 basi_red, 780 basi_green, 781 basi_blue, 782 basi_alpha, 783 basi_viewable; 784 #endif 785 786 png_uint_16 787 magn_first, 788 magn_last, 789 magn_mb, 790 magn_ml, 791 magn_mr, 792 magn_mt, 793 magn_mx, 794 magn_my, 795 magn_methx, 796 magn_methy; 797 798 PixelInfo 799 mng_global_bkgd; 800 801 /* Added at version 6.6.6-7 */ 802 MagickBooleanType 803 ping_exclude_bKGD, 804 ping_exclude_cHRM, 805 ping_exclude_date, 806 ping_exclude_EXIF, 807 ping_exclude_gAMA, 808 ping_exclude_iCCP, 809 /* ping_exclude_iTXt, */ 810 ping_exclude_oFFs, 811 ping_exclude_pHYs, 812 ping_exclude_sRGB, 813 ping_exclude_tEXt, 814 ping_exclude_tRNS, 815 ping_exclude_vpAg, 816 ping_exclude_zCCP, /* hex-encoded iCCP */ 817 ping_exclude_zTXt, 818 ping_preserve_colormap, 819 /* Added at version 6.8.5-7 */ 820 ping_preserve_iCCP, 821 /* Added at version 6.8.9-9 */ 822 ping_exclude_tIME; 823 824 } MngInfo; 825 #endif /* VER */ 826 827 /* 829 Forward declarations. 830 */ 831 static MagickBooleanType 832 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *); 833 834 static MagickBooleanType 835 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *); 836 837 #if defined(JNG_SUPPORTED) 838 static MagickBooleanType 839 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *); 840 #endif 841 842 #if PNG_LIBPNG_VER > 10011 843 844 845 #if (MAGICKCORE_QUANTUM_DEPTH >= 16) 846 static MagickBooleanType 847 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception) 848 { 849 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8. 850 * 851 * This is true if the high byte and the next highest byte of 852 * each sample of the image, the colormap, and the background color 853 * are equal to each other. We check this by seeing if the samples 854 * are unchanged when we scale them down to 8 and back up to Quantum. 855 * 856 * We don't use the method GetImageDepth() because it doesn't check 857 * background and doesn't handle PseudoClass specially. 858 */ 859 860 #define QuantumToCharToQuantumEqQuantum(quantum) \ 861 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum) 862 863 MagickBooleanType 864 ok_to_reduce=MagickFalse; 865 866 if (image->depth >= 16) 867 { 868 869 const Quantum 870 *p; 871 872 ok_to_reduce= 873 QuantumToCharToQuantumEqQuantum(image->background_color.red) && 874 QuantumToCharToQuantumEqQuantum(image->background_color.green) && 875 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ? 876 MagickTrue : MagickFalse; 877 878 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass) 879 { 880 int indx; 881 882 for (indx=0; indx < (ssize_t) image->colors; indx++) 883 { 884 ok_to_reduce=( 885 QuantumToCharToQuantumEqQuantum( 886 image->colormap[indx].red) && 887 QuantumToCharToQuantumEqQuantum( 888 image->colormap[indx].green) && 889 QuantumToCharToQuantumEqQuantum( 890 image->colormap[indx].blue)) ? 891 MagickTrue : MagickFalse; 892 893 if (ok_to_reduce == MagickFalse) 894 break; 895 } 896 } 897 898 if ((ok_to_reduce != MagickFalse) && 899 (image->storage_class != PseudoClass)) 900 { 901 ssize_t 902 y; 903 904 register ssize_t 905 x; 906 907 for (y=0; y < (ssize_t) image->rows; y++) 908 { 909 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 910 911 if (p == (const Quantum *) NULL) 912 { 913 ok_to_reduce = MagickFalse; 914 break; 915 } 916 917 for (x=(ssize_t) image->columns-1; x >= 0; x--) 918 { 919 ok_to_reduce= 920 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) && 921 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) && 922 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ? 923 MagickTrue : MagickFalse; 924 925 if (ok_to_reduce == MagickFalse) 926 break; 927 928 p+=GetPixelChannels(image); 929 } 930 if (x >= 0) 931 break; 932 } 933 } 934 935 if (ok_to_reduce != MagickFalse) 936 { 937 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 938 " OK to reduce PNG bit depth to 8 without loss of info"); 939 } 940 else 941 { 942 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 943 " Not OK to reduce PNG bit depth to 8 without loss of info"); 944 } 945 } 946 947 return ok_to_reduce; 948 } 949 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */ 950 951 static const char* PngColorTypeToString(const unsigned int color_type) 952 { 953 const char 954 *result = "Unknown"; 955 956 switch (color_type) 957 { 958 case PNG_COLOR_TYPE_GRAY: 959 result = "Gray"; 960 break; 961 case PNG_COLOR_TYPE_GRAY_ALPHA: 962 result = "Gray+Alpha"; 963 break; 964 case PNG_COLOR_TYPE_PALETTE: 965 result = "Palette"; 966 break; 967 case PNG_COLOR_TYPE_RGB: 968 result = "RGB"; 969 break; 970 case PNG_COLOR_TYPE_RGB_ALPHA: 971 result = "RGB+Alpha"; 972 break; 973 } 974 975 return result; 976 } 977 978 static int 979 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent) 980 { 981 switch (intent) 982 { 983 case PerceptualIntent: 984 return 0; 985 986 case RelativeIntent: 987 return 1; 988 989 case SaturationIntent: 990 return 2; 991 992 case AbsoluteIntent: 993 return 3; 994 995 default: 996 return -1; 997 } 998 } 999 1000 static RenderingIntent 1001 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent) 1002 { 1003 switch (ping_intent) 1004 { 1005 case 0: 1006 return PerceptualIntent; 1007 1008 case 1: 1009 return RelativeIntent; 1010 1011 case 2: 1012 return SaturationIntent; 1013 1014 case 3: 1015 return AbsoluteIntent; 1016 1017 default: 1018 return UndefinedIntent; 1019 } 1020 } 1021 1022 static const char * 1023 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent) 1024 { 1025 switch (ping_intent) 1026 { 1027 case 0: 1028 return "Perceptual Intent"; 1029 1030 case 1: 1031 return "Relative Intent"; 1032 1033 case 2: 1034 return "Saturation Intent"; 1035 1036 case 3: 1037 return "Absolute Intent"; 1038 1039 default: 1040 return "Undefined Intent"; 1041 } 1042 } 1043 1044 static const char * 1045 Magick_ColorType_from_PNG_ColorType(const int ping_colortype) 1046 { 1047 switch (ping_colortype) 1048 { 1049 case 0: 1050 return "Grayscale"; 1051 1052 case 2: 1053 return "Truecolor"; 1054 1055 case 3: 1056 return "Indexed"; 1057 1058 case 4: 1059 return "GrayAlpha"; 1060 1061 case 6: 1062 return "RGBA"; 1063 1064 default: 1065 return "UndefinedColorType"; 1066 } 1067 } 1068 1069 #endif /* PNG_LIBPNG_VER > 10011 */ 1070 #endif /* MAGICKCORE_PNG_DELEGATE */ 1071 1072 /* 1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1075 % % 1076 % % 1077 % % 1078 % I s M N G % 1079 % % 1080 % % 1081 % % 1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1083 % 1084 % IsMNG() returns MagickTrue if the image format type, identified by the 1085 % magick string, is MNG. 1086 % 1087 % The format of the IsMNG method is: 1088 % 1089 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length) 1090 % 1091 % A description of each parameter follows: 1092 % 1093 % o magick: compare image format pattern against these bytes. 1094 % 1095 % o length: Specifies the length of the magick string. 1096 % 1097 % 1098 */ 1099 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length) 1100 { 1101 if (length < 8) 1102 return(MagickFalse); 1103 1104 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0) 1105 return(MagickTrue); 1106 1107 return(MagickFalse); 1108 } 1109 1110 /* 1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1113 % % 1114 % % 1115 % % 1116 % I s J N G % 1117 % % 1118 % % 1119 % % 1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1121 % 1122 % IsJNG() returns MagickTrue if the image format type, identified by the 1123 % magick string, is JNG. 1124 % 1125 % The format of the IsJNG method is: 1126 % 1127 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length) 1128 % 1129 % A description of each parameter follows: 1130 % 1131 % o magick: compare image format pattern against these bytes. 1132 % 1133 % o length: Specifies the length of the magick string. 1134 % 1135 % 1136 */ 1137 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length) 1138 { 1139 if (length < 8) 1140 return(MagickFalse); 1141 1142 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0) 1143 return(MagickTrue); 1144 1145 return(MagickFalse); 1146 } 1147 1148 /* 1150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1151 % % 1152 % % 1153 % % 1154 % I s P N G % 1155 % % 1156 % % 1157 % % 1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1159 % 1160 % IsPNG() returns MagickTrue if the image format type, identified by the 1161 % magick string, is PNG. 1162 % 1163 % The format of the IsPNG method is: 1164 % 1165 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length) 1166 % 1167 % A description of each parameter follows: 1168 % 1169 % o magick: compare image format pattern against these bytes. 1170 % 1171 % o length: Specifies the length of the magick string. 1172 % 1173 */ 1174 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length) 1175 { 1176 if (length < 8) 1177 return(MagickFalse); 1178 1179 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0) 1180 return(MagickTrue); 1181 1182 return(MagickFalse); 1183 } 1184 1185 #if defined(MAGICKCORE_PNG_DELEGATE) 1187 #if defined(__cplusplus) || defined(c_plusplus) 1188 extern "C" { 1189 #endif 1190 1191 #if (PNG_LIBPNG_VER > 10011) 1192 static size_t WriteBlobMSBULong(Image *image,const size_t value) 1193 { 1194 unsigned char 1195 buffer[4]; 1196 1197 assert(image != (Image *) NULL); 1198 assert(image->signature == MagickCoreSignature); 1199 buffer[0]=(unsigned char) (value >> 24); 1200 buffer[1]=(unsigned char) (value >> 16); 1201 buffer[2]=(unsigned char) (value >> 8); 1202 buffer[3]=(unsigned char) value; 1203 return((size_t) WriteBlob(image,4,buffer)); 1204 } 1205 1206 static void PNGLong(png_bytep p,png_uint_32 value) 1207 { 1208 *p++=(png_byte) ((value >> 24) & 0xff); 1209 *p++=(png_byte) ((value >> 16) & 0xff); 1210 *p++=(png_byte) ((value >> 8) & 0xff); 1211 *p++=(png_byte) (value & 0xff); 1212 } 1213 1214 #if defined(JNG_SUPPORTED) 1215 static void PNGsLong(png_bytep p,png_int_32 value) 1216 { 1217 *p++=(png_byte) ((value >> 24) & 0xff); 1218 *p++=(png_byte) ((value >> 16) & 0xff); 1219 *p++=(png_byte) ((value >> 8) & 0xff); 1220 *p++=(png_byte) (value & 0xff); 1221 } 1222 #endif 1223 1224 static void PNGShort(png_bytep p,png_uint_16 value) 1225 { 1226 *p++=(png_byte) ((value >> 8) & 0xff); 1227 *p++=(png_byte) (value & 0xff); 1228 } 1229 1230 static void PNGType(png_bytep p,const png_byte *type) 1231 { 1232 (void) CopyMagickMemory(p,type,4*sizeof(png_byte)); 1233 } 1234 1235 static void LogPNGChunk(MagickBooleanType logging, const png_byte *type, 1236 size_t length) 1237 { 1238 if (logging != MagickFalse) 1239 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1240 " Writing %c%c%c%c chunk, length: %.20g", 1241 type[0],type[1],type[2],type[3],(double) length); 1242 } 1243 #endif /* PNG_LIBPNG_VER > 10011 */ 1244 1245 #if defined(__cplusplus) || defined(c_plusplus) 1246 } 1247 #endif 1248 1249 #if PNG_LIBPNG_VER > 10011 1250 /* 1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1252 % % 1253 % % 1254 % % 1255 % R e a d P N G I m a g e % 1256 % % 1257 % % 1258 % % 1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1260 % 1261 % ReadPNGImage() reads a Portable Network Graphics (PNG) or 1262 % Multiple-image Network Graphics (MNG) image file and returns it. It 1263 % allocates the memory necessary for the new Image structure and returns a 1264 % pointer to the new image or set of images. 1265 % 1266 % MNG support written by Glenn Randers-Pehrson, glennrp (at) image... 1267 % 1268 % The format of the ReadPNGImage method is: 1269 % 1270 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 1271 % 1272 % A description of each parameter follows: 1273 % 1274 % o image_info: the image info. 1275 % 1276 % o exception: return any errors or warnings in this structure. 1277 % 1278 % To do, more or less in chronological order (as of version 5.5.2, 1279 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage): 1280 % 1281 % Get 16-bit cheap transparency working. 1282 % 1283 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance) 1284 % 1285 % Preserve all unknown and not-yet-handled known chunks found in input 1286 % PNG file and copy them into output PNG files according to the PNG 1287 % copying rules. 1288 % 1289 % (At this point, PNG encoding should be in full MNG compliance) 1290 % 1291 % Provide options for choice of background to use when the MNG BACK 1292 % chunk is not present or is not mandatory (i.e., leave transparent, 1293 % user specified, MNG BACK, PNG bKGD) 1294 % 1295 % Implement LOOP/ENDL [done, but could do discretionary loops more 1296 % efficiently by linking in the duplicate frames.]. 1297 % 1298 % Decode and act on the MHDR simplicity profile (offer option to reject 1299 % files or attempt to process them anyway when the profile isn't LC or VLC). 1300 % 1301 % Upgrade to full MNG without Delta-PNG. 1302 % 1303 % o BACK [done a while ago except for background image ID] 1304 % o MOVE [done 15 May 1999] 1305 % o CLIP [done 15 May 1999] 1306 % o DISC [done 19 May 1999] 1307 % o SAVE [partially done 19 May 1999 (marks objects frozen)] 1308 % o SEEK [partially done 19 May 1999 (discard function only)] 1309 % o SHOW 1310 % o PAST 1311 % o BASI 1312 % o MNG-level tEXt/iTXt/zTXt 1313 % o pHYg 1314 % o pHYs 1315 % o sBIT 1316 % o bKGD 1317 % o iTXt (wait for libpng implementation). 1318 % 1319 % Use the scene signature to discover when an identical scene is 1320 % being reused, and just point to the original image->exception instead 1321 % of storing another set of pixels. This not specific to MNG 1322 % but could be applied generally. 1323 % 1324 % Upgrade to full MNG with Delta-PNG. 1325 % 1326 % JNG tEXt/iTXt/zTXt 1327 % 1328 % We will not attempt to read files containing the CgBI chunk. 1329 % They are really Xcode files meant for display on the iPhone. 1330 % These are not valid PNG files and it is impossible to recover 1331 % the original PNG from files that have been converted to Xcode-PNG, 1332 % since irretrievable loss of color data has occurred due to the 1333 % use of premultiplied alpha. 1334 */ 1335 1336 #if defined(__cplusplus) || defined(c_plusplus) 1337 extern "C" { 1338 #endif 1339 1340 /* 1341 This the function that does the actual reading of data. It is 1342 the same as the one supplied in libpng, except that it receives the 1343 datastream from the ReadBlob() function instead of standard input. 1344 */ 1345 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length) 1346 { 1347 Image 1348 *image; 1349 1350 image=(Image *) png_get_io_ptr(png_ptr); 1351 if (length != 0) 1352 { 1353 png_size_t 1354 check; 1355 1356 check=(png_size_t) ReadBlob(image,(size_t) length,data); 1357 if (check != length) 1358 { 1359 char 1360 msg[MagickPathExtent]; 1361 1362 (void) FormatLocaleString(msg,MagickPathExtent, 1363 "Expected %.20g bytes; found %.20g bytes",(double) length, 1364 (double) check); 1365 png_warning(png_ptr,msg); 1366 png_error(png_ptr,"Read Exception"); 1367 } 1368 } 1369 } 1370 1371 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \ 1372 !defined(PNG_MNG_FEATURES_SUPPORTED) 1373 /* We use mng_get_data() instead of png_get_data() if we have a libpng 1374 * older than libpng-1.0.3a, which was the first to allow the empty 1375 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was 1376 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was 1377 * encountered after an empty PLTE, so we have to look ahead for bKGD 1378 * chunks and remove them from the datastream that is passed to libpng, 1379 * and store their contents for later use. 1380 */ 1381 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length) 1382 { 1383 MngInfo 1384 *mng_info; 1385 1386 Image 1387 *image; 1388 1389 png_size_t 1390 check; 1391 1392 register ssize_t 1393 i; 1394 1395 i=0; 1396 mng_info=(MngInfo *) png_get_io_ptr(png_ptr); 1397 image=(Image *) mng_info->image; 1398 while (mng_info->bytes_in_read_buffer && length) 1399 { 1400 data[i]=mng_info->read_buffer[i]; 1401 mng_info->bytes_in_read_buffer--; 1402 length--; 1403 i++; 1404 } 1405 if (length != 0) 1406 { 1407 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data); 1408 1409 if (check != length) 1410 png_error(png_ptr,"Read Exception"); 1411 1412 if (length == 4) 1413 { 1414 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && 1415 (data[3] == 0)) 1416 { 1417 check=(png_size_t) ReadBlob(image,(size_t) length, 1418 (char *) mng_info->read_buffer); 1419 mng_info->read_buffer[4]=0; 1420 mng_info->bytes_in_read_buffer=4; 1421 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0) 1422 mng_info->found_empty_plte=MagickTrue; 1423 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0) 1424 { 1425 mng_info->found_empty_plte=MagickFalse; 1426 mng_info->have_saved_bkgd_index=MagickFalse; 1427 } 1428 } 1429 1430 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && 1431 (data[3] == 1)) 1432 { 1433 check=(png_size_t) ReadBlob(image,(size_t) length, 1434 (char *) mng_info->read_buffer); 1435 mng_info->read_buffer[4]=0; 1436 mng_info->bytes_in_read_buffer=4; 1437 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0) 1438 if (mng_info->found_empty_plte) 1439 { 1440 /* 1441 Skip the bKGD data byte and CRC. 1442 */ 1443 check=(png_size_t) 1444 ReadBlob(image,5,(char *) mng_info->read_buffer); 1445 check=(png_size_t) ReadBlob(image,(size_t) length, 1446 (char *) mng_info->read_buffer); 1447 mng_info->saved_bkgd_index=mng_info->read_buffer[0]; 1448 mng_info->have_saved_bkgd_index=MagickTrue; 1449 mng_info->bytes_in_read_buffer=0; 1450 } 1451 } 1452 } 1453 } 1454 } 1455 #endif 1456 1457 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length) 1458 { 1459 Image 1460 *image; 1461 1462 image=(Image *) png_get_io_ptr(png_ptr); 1463 if (length != 0) 1464 { 1465 png_size_t 1466 check; 1467 1468 check=(png_size_t) WriteBlob(image,(size_t) length,data); 1469 1470 if (check != length) 1471 png_error(png_ptr,"WriteBlob Failed"); 1472 } 1473 } 1474 1475 static void png_flush_data(png_structp png_ptr) 1476 { 1477 (void) png_ptr; 1478 } 1479 1480 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 1481 static int PalettesAreEqual(Image *a,Image *b) 1482 { 1483 ssize_t 1484 i; 1485 1486 if ((a == (Image *) NULL) || (b == (Image *) NULL)) 1487 return((int) MagickFalse); 1488 1489 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass) 1490 return((int) MagickFalse); 1491 1492 if (a->colors != b->colors) 1493 return((int) MagickFalse); 1494 1495 for (i=0; i < (ssize_t) a->colors; i++) 1496 { 1497 if ((a->colormap[i].red != b->colormap[i].red) || 1498 (a->colormap[i].green != b->colormap[i].green) || 1499 (a->colormap[i].blue != b->colormap[i].blue)) 1500 return((int) MagickFalse); 1501 } 1502 1503 return((int) MagickTrue); 1504 } 1505 #endif 1506 1507 static void MngInfoDiscardObject(MngInfo *mng_info,int i) 1508 { 1509 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) && 1510 mng_info->exists[i] && !mng_info->frozen[i]) 1511 { 1512 #ifdef MNG_OBJECT_BUFFERS 1513 if (mng_info->ob[i] != (MngBuffer *) NULL) 1514 { 1515 if (mng_info->ob[i]->reference_count > 0) 1516 mng_info->ob[i]->reference_count--; 1517 1518 if (mng_info->ob[i]->reference_count == 0) 1519 { 1520 if (mng_info->ob[i]->image != (Image *) NULL) 1521 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image); 1522 1523 mng_info->ob[i]=DestroyString(mng_info->ob[i]); 1524 } 1525 } 1526 mng_info->ob[i]=(MngBuffer *) NULL; 1527 #endif 1528 mng_info->exists[i]=MagickFalse; 1529 mng_info->invisible[i]=MagickFalse; 1530 mng_info->viewable[i]=MagickFalse; 1531 mng_info->frozen[i]=MagickFalse; 1532 mng_info->x_off[i]=0; 1533 mng_info->y_off[i]=0; 1534 mng_info->object_clip[i].left=0; 1535 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX; 1536 mng_info->object_clip[i].top=0; 1537 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX; 1538 } 1539 } 1540 1541 static void MngInfoFreeStruct(MngInfo *mng_info, 1542 MagickBooleanType *have_mng_structure) 1543 { 1544 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL)) 1545 { 1546 register ssize_t 1547 i; 1548 1549 for (i=1; i < MNG_MAX_OBJECTS; i++) 1550 MngInfoDiscardObject(mng_info,i); 1551 1552 if (mng_info->global_plte != (png_colorp) NULL) 1553 mng_info->global_plte=(png_colorp) 1554 RelinquishMagickMemory(mng_info->global_plte); 1555 1556 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info); 1557 *have_mng_structure=MagickFalse; 1558 } 1559 } 1560 1561 static MngBox mng_minimum_box(MngBox box1,MngBox box2) 1562 { 1563 MngBox 1564 box; 1565 1566 box=box1; 1567 if (box.left < box2.left) 1568 box.left=box2.left; 1569 1570 if (box.top < box2.top) 1571 box.top=box2.top; 1572 1573 if (box.right > box2.right) 1574 box.right=box2.right; 1575 1576 if (box.bottom > box2.bottom) 1577 box.bottom=box2.bottom; 1578 1579 return box; 1580 } 1581 1582 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p) 1583 { 1584 MngBox 1585 box; 1586 1587 /* 1588 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk. 1589 */ 1590 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 1591 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); 1592 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]); 1593 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]); 1594 if (delta_type != 0) 1595 { 1596 box.left+=previous_box.left; 1597 box.right+=previous_box.right; 1598 box.top+=previous_box.top; 1599 box.bottom+=previous_box.bottom; 1600 } 1601 1602 return(box); 1603 } 1604 1605 static MngPair mng_read_pair(MngPair previous_pair,int delta_type, 1606 unsigned char *p) 1607 { 1608 MngPair 1609 pair; 1610 /* 1611 Read two ssize_ts from CLON, MOVE or PAST chunk 1612 */ 1613 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 1614 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); 1615 1616 if (delta_type != 0) 1617 { 1618 pair.a+=previous_pair.a; 1619 pair.b+=previous_pair.b; 1620 } 1621 1622 return(pair); 1623 } 1624 1625 static long mng_get_long(unsigned char *p) 1626 { 1627 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])); 1628 } 1629 1630 typedef struct _PNGErrorInfo 1631 { 1632 Image 1633 *image; 1634 1635 ExceptionInfo 1636 *exception; 1637 } PNGErrorInfo; 1638 1639 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message) 1640 { 1641 ExceptionInfo 1642 *exception; 1643 1644 Image 1645 *image; 1646 1647 PNGErrorInfo 1648 *error_info; 1649 1650 error_info=(PNGErrorInfo *) png_get_error_ptr(ping); 1651 image=error_info->image; 1652 exception=error_info->exception; 1653 1654 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1655 " libpng-%s error: %s", png_get_libpng_ver(NULL),message); 1656 1657 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message, 1658 "`%s'",image->filename); 1659 1660 #if (PNG_LIBPNG_VER < 10500) 1661 /* A warning about deprecated use of jmpbuf here is unavoidable if you 1662 * are building with libpng-1.4.x and can be ignored. 1663 */ 1664 longjmp(ping->jmpbuf,1); 1665 #else 1666 png_longjmp(ping,1); 1667 #endif 1668 } 1669 1670 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message) 1671 { 1672 ExceptionInfo 1673 *exception; 1674 1675 Image 1676 *image; 1677 1678 PNGErrorInfo 1679 *error_info; 1680 1681 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0) 1682 png_error(ping, message); 1683 1684 error_info=(PNGErrorInfo *) png_get_error_ptr(ping); 1685 image=error_info->image; 1686 exception=error_info->exception; 1687 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1688 " libpng-%s warning: %s", png_get_libpng_ver(NULL),message); 1689 1690 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, 1691 message,"`%s'",image->filename); 1692 } 1693 1694 #ifdef PNG_USER_MEM_SUPPORTED 1695 #if PNG_LIBPNG_VER >= 10400 1696 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size) 1697 #else 1698 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size) 1699 #endif 1700 { 1701 (void) png_ptr; 1702 return((png_voidp) AcquireMagickMemory((size_t) size)); 1703 } 1704 1705 /* 1706 Free a pointer. It is removed from the list at the same time. 1707 */ 1708 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr) 1709 { 1710 (void) png_ptr; 1711 ptr=RelinquishMagickMemory(ptr); 1712 return((png_free_ptr) NULL); 1713 } 1714 #endif 1715 1716 #if defined(__cplusplus) || defined(c_plusplus) 1717 } 1718 #endif 1719 1720 static int 1721 Magick_png_read_raw_profile(png_struct *ping,Image *image, 1722 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception) 1723 { 1724 register ssize_t 1725 i; 1726 1727 register unsigned char 1728 *dp; 1729 1730 register png_charp 1731 sp; 1732 1733 png_uint_32 1734 length, 1735 nibbles; 1736 1737 StringInfo 1738 *profile; 1739 1740 const unsigned char 1741 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1742 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1743 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0, 1744 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 1745 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12, 1746 13,14,15}; 1747 1748 sp=text[ii].text+1; 1749 /* look for newline */ 1750 while (*sp != '\n') 1751 sp++; 1752 1753 /* look for length */ 1754 while (*sp == '\0' || *sp == ' ' || *sp == '\n') 1755 sp++; 1756 1757 length=(png_uint_32) StringToLong(sp); 1758 1759 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1760 " length: %lu",(unsigned long) length); 1761 1762 while (*sp != ' ' && *sp != '\n') 1763 sp++; 1764 1765 /* allocate space */ 1766 if (length == 0) 1767 { 1768 png_warning(ping,"invalid profile length"); 1769 return(MagickFalse); 1770 } 1771 1772 profile=BlobToStringInfo((const void *) NULL,length); 1773 1774 if (profile == (StringInfo *) NULL) 1775 { 1776 png_warning(ping, "unable to copy profile"); 1777 return(MagickFalse); 1778 } 1779 1780 /* copy profile, skipping white space and column 1 "=" signs */ 1781 dp=GetStringInfoDatum(profile); 1782 nibbles=length*2; 1783 1784 for (i=0; i < (ssize_t) nibbles; i++) 1785 { 1786 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f') 1787 { 1788 if (*sp == '\0') 1789 { 1790 png_warning(ping, "ran out of profile data"); 1791 profile=DestroyStringInfo(profile); 1792 return(MagickFalse); 1793 } 1794 sp++; 1795 } 1796 1797 if (i%2 == 0) 1798 *dp=(unsigned char) (16*unhex[(int) *sp++]); 1799 1800 else 1801 (*dp++)+=unhex[(int) *sp++]; 1802 } 1803 /* 1804 We have already read "Raw profile type. 1805 */ 1806 (void) SetImageProfile(image,&text[ii].key[17],profile,exception); 1807 profile=DestroyStringInfo(profile); 1808 1809 if (image_info->verbose) 1810 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]); 1811 1812 return MagickTrue; 1813 } 1814 1815 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 1816 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) 1817 { 1818 Image 1819 *image; 1820 1821 1822 /* The unknown chunk structure contains the chunk data: 1823 png_byte name[5]; 1824 png_byte *data; 1825 png_size_t size; 1826 1827 Note that libpng has already taken care of the CRC handling. 1828 */ 1829 1830 LogMagickEvent(CoderEvent,GetMagickModule(), 1831 " read_vpag_chunk: found %c%c%c%c chunk", 1832 chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]); 1833 1834 if (chunk->name[0] != 118 || chunk->name[1] != 112 || 1835 chunk->name[2] != 65 ||chunk-> name[3] != 103) 1836 return(0); /* Did not recognize */ 1837 1838 /* recognized vpAg */ 1839 1840 if (chunk->size != 9) 1841 return(-1); /* Error return */ 1842 1843 if (chunk->data[8] != 0) 1844 return(0); /* ImageMagick requires pixel units */ 1845 1846 image=(Image *) png_get_user_chunk_ptr(ping); 1847 1848 image->page.width=(size_t) ((chunk->data[0] << 24) | 1849 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]); 1850 1851 image->page.height=(size_t) ((chunk->data[4] << 24) | 1852 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]); 1853 1854 /* Return one of the following: */ 1855 /* return(-n); chunk had an error */ 1856 /* return(0); did not recognize */ 1857 /* return(n); success */ 1858 1859 return(1); 1860 1861 } 1862 #endif 1863 1864 #if defined(PNG_tIME_SUPPORTED) 1865 static void read_tIME_chunk(Image *image,png_struct *ping,png_info *info, 1866 ExceptionInfo *exception) 1867 { 1868 png_timep 1869 time; 1870 1871 if (png_get_tIME(ping,info,&time)) 1872 { 1873 char 1874 timestamp[21]; 1875 1876 FormatLocaleString(timestamp,21,"%04d-%02d-%02dT%02d:%02d:%02dZ", 1877 time->year,time->month,time->day,time->hour,time->minute,time->second); 1878 SetImageProperty(image,"png:tIME",timestamp,exception); 1879 } 1880 } 1881 #endif 1882 1883 /* 1884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1885 % % 1886 % % 1887 % % 1888 % R e a d O n e P N G I m a g e % 1889 % % 1890 % % 1891 % % 1892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1893 % 1894 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file 1895 % (minus the 8-byte signature) and returns it. It allocates the memory 1896 % necessary for the new Image structure and returns a pointer to the new 1897 % image. 1898 % 1899 % The format of the ReadOnePNGImage method is: 1900 % 1901 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info, 1902 % ExceptionInfo *exception) 1903 % 1904 % A description of each parameter follows: 1905 % 1906 % o mng_info: Specifies a pointer to a MngInfo structure. 1907 % 1908 % o image_info: the image info. 1909 % 1910 % o exception: return any errors or warnings in this structure. 1911 % 1912 */ 1913 static Image *ReadOnePNGImage(MngInfo *mng_info, 1914 const ImageInfo *image_info, ExceptionInfo *exception) 1915 { 1916 /* Read one PNG image */ 1917 1918 /* To do: Read the tEXt/Creation Time chunk into the date:create property */ 1919 1920 Image 1921 *image; 1922 1923 char 1924 im_vers[32], 1925 libpng_runv[32], 1926 libpng_vers[32], 1927 zlib_runv[32], 1928 zlib_vers[32]; 1929 1930 int 1931 intent, /* "PNG Rendering intent", which is ICC intent + 1 */ 1932 num_raw_profiles, 1933 num_text, 1934 num_text_total, 1935 num_passes, 1936 number_colors, 1937 pass, 1938 ping_bit_depth, 1939 ping_color_type, 1940 ping_file_depth, 1941 ping_interlace_method, 1942 ping_compression_method, 1943 ping_filter_method, 1944 ping_num_trans, 1945 unit_type; 1946 1947 double 1948 file_gamma; 1949 1950 MagickBooleanType 1951 logging, 1952 ping_found_cHRM, 1953 ping_found_gAMA, 1954 ping_found_iCCP, 1955 ping_found_sRGB, 1956 ping_found_sRGB_cHRM, 1957 ping_preserve_iCCP, 1958 status; 1959 1960 MemoryInfo 1961 *volatile pixel_info; 1962 1963 PixelInfo 1964 transparent_color; 1965 1966 PNGErrorInfo 1967 error_info; 1968 1969 png_bytep 1970 ping_trans_alpha; 1971 1972 png_color_16p 1973 ping_background, 1974 ping_trans_color; 1975 1976 png_info 1977 *end_info, 1978 *ping_info; 1979 1980 png_struct 1981 *ping; 1982 1983 png_textp 1984 text; 1985 1986 png_uint_32 1987 ping_height, 1988 ping_width, 1989 x_resolution, 1990 y_resolution; 1991 1992 QuantumInfo 1993 *quantum_info; 1994 1995 ssize_t 1996 ping_rowbytes, 1997 y; 1998 1999 register unsigned char 2000 *p; 2001 2002 register ssize_t 2003 i, 2004 x; 2005 2006 register Quantum 2007 *q; 2008 2009 size_t 2010 length, 2011 row_offset; 2012 2013 ssize_t 2014 j; 2015 2016 unsigned char 2017 *ping_pixels; 2018 2019 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED 2020 png_byte unused_chunks[]= 2021 { 2022 104, 73, 83, 84, (png_byte) '\0', /* hIST */ 2023 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ 2024 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ 2025 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ 2026 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ 2027 #if !defined(PNG_tIME_SUPPORTED) 2028 116, 73, 77, 69, (png_byte) '\0', /* tIME */ 2029 #endif 2030 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */ 2031 /* ignore the APNG chunks */ 2032 97, 99, 84, 76, (png_byte) '\0', /* acTL */ 2033 102, 99, 84, 76, (png_byte) '\0', /* fcTL */ 2034 102, 100, 65, 84, (png_byte) '\0', /* fdAT */ 2035 #endif 2036 }; 2037 #endif 2038 2039 /* Define these outside of the following "if logging()" block so they will 2040 * show in debuggers. 2041 */ 2042 *im_vers='\0'; 2043 (void) ConcatenateMagickString(im_vers, 2044 MagickLibVersionText,32); 2045 (void) ConcatenateMagickString(im_vers, 2046 MagickLibAddendum,32); 2047 2048 *libpng_vers='\0'; 2049 (void) ConcatenateMagickString(libpng_vers, 2050 PNG_LIBPNG_VER_STRING,32); 2051 *libpng_runv='\0'; 2052 (void) ConcatenateMagickString(libpng_runv, 2053 png_get_libpng_ver(NULL),32); 2054 2055 *zlib_vers='\0'; 2056 (void) ConcatenateMagickString(zlib_vers, 2057 ZLIB_VERSION,32); 2058 *zlib_runv='\0'; 2059 (void) ConcatenateMagickString(zlib_runv, 2060 zlib_version,32); 2061 2062 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 2063 " Enter ReadOnePNGImage()\n" 2064 " IM version = %s\n" 2065 " Libpng version = %s", 2066 im_vers, libpng_vers); 2067 2068 if (logging != MagickFalse) 2069 { 2070 if (LocaleCompare(libpng_vers,libpng_runv) != 0) 2071 { 2072 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 2073 libpng_runv); 2074 } 2075 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s", 2076 zlib_vers); 2077 if (LocaleCompare(zlib_vers,zlib_runv) != 0) 2078 { 2079 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 2080 zlib_runv); 2081 } 2082 } 2083 2084 #if (PNG_LIBPNG_VER < 10200) 2085 if (image_info->verbose) 2086 printf("Your PNG library (libpng-%s) is rather old.\n", 2087 PNG_LIBPNG_VER_STRING); 2088 #endif 2089 2090 #if (PNG_LIBPNG_VER >= 10400) 2091 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */ 2092 if (image_info->verbose) 2093 { 2094 printf("Your PNG library (libpng-%s) is an old beta version.\n", 2095 PNG_LIBPNG_VER_STRING); 2096 printf("Please update it.\n"); 2097 } 2098 # endif 2099 #endif 2100 2101 2102 quantum_info = (QuantumInfo *) NULL; 2103 image=mng_info->image; 2104 2105 if (logging != MagickFalse) 2106 { 2107 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2108 " Before reading:\n" 2109 " image->alpha_trait=%d" 2110 " image->rendering_intent=%d\n" 2111 " image->colorspace=%d\n" 2112 " image->gamma=%f", 2113 (int) image->alpha_trait, (int) image->rendering_intent, 2114 (int) image->colorspace, image->gamma); 2115 } 2116 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent); 2117 2118 /* Set to an out-of-range color unless tRNS chunk is present */ 2119 transparent_color.red=65537; 2120 transparent_color.green=65537; 2121 transparent_color.blue=65537; 2122 transparent_color.alpha=65537; 2123 2124 number_colors=0; 2125 num_text = 0; 2126 num_text_total = 0; 2127 num_raw_profiles = 0; 2128 2129 ping_found_cHRM = MagickFalse; 2130 ping_found_gAMA = MagickFalse; 2131 ping_found_iCCP = MagickFalse; 2132 ping_found_sRGB = MagickFalse; 2133 ping_found_sRGB_cHRM = MagickFalse; 2134 ping_preserve_iCCP = MagickFalse; 2135 2136 2137 /* 2138 Allocate the PNG structures 2139 */ 2140 #ifdef PNG_USER_MEM_SUPPORTED 2141 error_info.image=image; 2142 error_info.exception=exception; 2143 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info, 2144 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL, 2145 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free); 2146 #else 2147 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info, 2148 MagickPNGErrorHandler,MagickPNGWarningHandler); 2149 #endif 2150 if (ping == (png_struct *) NULL) 2151 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2152 2153 ping_info=png_create_info_struct(ping); 2154 2155 if (ping_info == (png_info *) NULL) 2156 { 2157 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL); 2158 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2159 } 2160 2161 end_info=png_create_info_struct(ping); 2162 2163 if (end_info == (png_info *) NULL) 2164 { 2165 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL); 2166 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2167 } 2168 2169 pixel_info=(MemoryInfo *) NULL; 2170 2171 if (setjmp(png_jmpbuf(ping))) 2172 { 2173 /* 2174 PNG image is corrupt. 2175 */ 2176 png_destroy_read_struct(&ping,&ping_info,&end_info); 2177 2178 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 2179 UnlockSemaphoreInfo(ping_semaphore); 2180 #endif 2181 2182 if (pixel_info != (MemoryInfo *) NULL) 2183 pixel_info=RelinquishVirtualMemory(pixel_info); 2184 2185 if (logging != MagickFalse) 2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2187 " exit ReadOnePNGImage() with error."); 2188 2189 if (image != (Image *) NULL) 2190 { 2191 const char 2192 *option; 2193 2194 option=GetImageOption(image_info,"png:preserve-corrupt-image"); 2195 if (IsStringTrue(option) == MagickFalse) 2196 image->columns=0; 2197 } 2198 2199 return(GetFirstImageInList(image)); 2200 } 2201 2202 /* { For navigation to end of SETJMP-protected block. Within this 2203 * block, use png_error() instead of Throwing an Exception, to ensure 2204 * that libpng is able to clean up, and that the semaphore is unlocked. 2205 */ 2206 2207 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 2208 LockSemaphoreInfo(ping_semaphore); 2209 #endif 2210 2211 #ifdef PNG_BENIGN_ERRORS_SUPPORTED 2212 /* Allow benign errors */ 2213 png_set_benign_errors(ping, 1); 2214 #endif 2215 2216 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 2217 /* Reject images with too many rows or columns */ 2218 png_set_user_limits(ping, 2219 (png_uint_32) MagickMin(0x7fffffffL, 2220 GetMagickResourceLimit(WidthResource)), 2221 (png_uint_32) MagickMin(0x7fffffffL, 2222 GetMagickResourceLimit(HeightResource))); 2223 #endif /* PNG_SET_USER_LIMITS_SUPPORTED */ 2224 2225 /* 2226 Prepare PNG for reading. 2227 */ 2228 2229 mng_info->image_found++; 2230 png_set_sig_bytes(ping,8); 2231 2232 if (LocaleCompare(image_info->magick,"MNG") == 0) 2233 { 2234 #if defined(PNG_MNG_FEATURES_SUPPORTED) 2235 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); 2236 png_set_read_fn(ping,image,png_get_data); 2237 #else 2238 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) 2239 png_permit_empty_plte(ping,MagickTrue); 2240 png_set_read_fn(ping,image,png_get_data); 2241 #else 2242 mng_info->image=image; 2243 mng_info->bytes_in_read_buffer=0; 2244 mng_info->found_empty_plte=MagickFalse; 2245 mng_info->have_saved_bkgd_index=MagickFalse; 2246 png_set_read_fn(ping,mng_info,mng_get_data); 2247 #endif 2248 #endif 2249 } 2250 2251 else 2252 png_set_read_fn(ping,image,png_get_data); 2253 2254 { 2255 const char 2256 *value; 2257 2258 value=GetImageOption(image_info,"profile:skip"); 2259 2260 if (IsOptionMember("ICC",value) == MagickFalse) 2261 { 2262 2263 value=GetImageOption(image_info,"png:preserve-iCCP"); 2264 2265 if (value == NULL) 2266 value=GetImageArtifact(image,"png:preserve-iCCP"); 2267 2268 if (value != NULL) 2269 ping_preserve_iCCP=MagickTrue; 2270 2271 #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED) 2272 /* Don't let libpng check for ICC/sRGB profile because we're going 2273 * to do that anyway. This feature was added at libpng-1.6.12. 2274 * If logging, go ahead and check and issue a warning as appropriate. 2275 */ 2276 if (logging == MagickFalse) 2277 png_set_option(ping, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); 2278 #endif 2279 } 2280 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 2281 else 2282 { 2283 png_set_keep_unknown_chunks(ping, 1, mng_iCCP, 1); 2284 } 2285 #endif 2286 } 2287 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 2288 /* Ignore unused chunks and all unknown chunks except for vpAg */ 2289 #if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */ 2290 png_set_keep_unknown_chunks(ping, 2, NULL, 0); 2291 #else 2292 png_set_keep_unknown_chunks(ping, 1, NULL, 0); 2293 #endif 2294 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1); 2295 png_set_keep_unknown_chunks(ping, 1, unused_chunks, 2296 (int)sizeof(unused_chunks)/5); 2297 /* Callback for other unknown chunks */ 2298 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback); 2299 #endif 2300 2301 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 2302 # if (PNG_LIBPNG_VER >= 10400) 2303 /* Limit the size of the chunk storage cache used for sPLT, text, 2304 * and unknown chunks. 2305 */ 2306 png_set_chunk_cache_max(ping, 32767); 2307 # endif 2308 #endif 2309 2310 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED 2311 /* Disable new libpng-1.5.10 feature */ 2312 png_set_check_for_invalid_index (ping, 0); 2313 #endif 2314 2315 #if (PNG_LIBPNG_VER < 10400) 2316 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ 2317 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__) 2318 /* Disable thread-unsafe features of pnggccrd */ 2319 if (png_access_version_number() >= 10200) 2320 { 2321 png_uint_32 mmx_disable_mask=0; 2322 png_uint_32 asm_flags; 2323 2324 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ 2325 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ 2326 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ 2327 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); 2328 asm_flags=png_get_asm_flags(ping); 2329 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask); 2330 } 2331 # endif 2332 #endif 2333 2334 png_read_info(ping,ping_info); 2335 2336 png_get_IHDR(ping,ping_info,&ping_width,&ping_height, 2337 &ping_bit_depth,&ping_color_type, 2338 &ping_interlace_method,&ping_compression_method, 2339 &ping_filter_method); 2340 2341 ping_file_depth = ping_bit_depth; 2342 2343 /* Swap bytes if requested */ 2344 if (ping_file_depth == 16) 2345 { 2346 const char 2347 *value; 2348 2349 value=GetImageOption(image_info,"png:swap-bytes"); 2350 2351 if (value == NULL) 2352 value=GetImageArtifact(image,"png:swap-bytes"); 2353 2354 if (value != NULL) 2355 png_set_swap(ping); 2356 } 2357 2358 /* Save bit-depth and color-type in case we later want to write a PNG00 */ 2359 { 2360 char 2361 msg[MagickPathExtent]; 2362 2363 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_color_type); 2364 (void) SetImageProperty(image,"png:IHDR.color-type-orig",msg,exception); 2365 2366 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_bit_depth); 2367 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig",msg,exception); 2368 } 2369 2370 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans, 2371 &ping_trans_color); 2372 2373 (void) png_get_bKGD(ping, ping_info, &ping_background); 2374 2375 if (ping_bit_depth < 8) 2376 { 2377 png_set_packing(ping); 2378 ping_bit_depth = 8; 2379 } 2380 2381 image->depth=ping_bit_depth; 2382 image->depth=GetImageQuantumDepth(image,MagickFalse); 2383 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace; 2384 2385 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 2386 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) 2387 { 2388 image->rendering_intent=UndefinedIntent; 2389 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent); 2390 (void) ResetMagickMemory(&image->chromaticity,0, 2391 sizeof(image->chromaticity)); 2392 } 2393 2394 if (logging != MagickFalse) 2395 { 2396 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2397 " PNG width: %.20g, height: %.20g\n" 2398 " PNG color_type: %d, bit_depth: %d\n" 2399 " PNG compression_method: %d\n" 2400 " PNG interlace_method: %d, filter_method: %d", 2401 (double) ping_width, (double) ping_height, 2402 ping_color_type, ping_bit_depth, 2403 ping_compression_method, 2404 ping_interlace_method,ping_filter_method); 2405 2406 } 2407 2408 if (png_get_valid(ping,ping_info, PNG_INFO_iCCP)) 2409 { 2410 ping_found_iCCP=MagickTrue; 2411 if (logging != MagickFalse) 2412 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2413 " Found PNG iCCP chunk."); 2414 } 2415 2416 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA)) 2417 { 2418 ping_found_gAMA=MagickTrue; 2419 if (logging != MagickFalse) 2420 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2421 " Found PNG gAMA chunk."); 2422 } 2423 2424 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2425 { 2426 ping_found_cHRM=MagickTrue; 2427 if (logging != MagickFalse) 2428 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2429 " Found PNG cHRM chunk."); 2430 } 2431 2432 if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info, 2433 PNG_INFO_sRGB)) 2434 { 2435 ping_found_sRGB=MagickTrue; 2436 if (logging != MagickFalse) 2437 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2438 " Found PNG sRGB chunk."); 2439 } 2440 2441 #ifdef PNG_READ_iCCP_SUPPORTED 2442 if (ping_found_iCCP !=MagickTrue && 2443 ping_found_sRGB != MagickTrue && 2444 png_get_valid(ping,ping_info, PNG_INFO_iCCP)) 2445 { 2446 ping_found_iCCP=MagickTrue; 2447 if (logging != MagickFalse) 2448 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2449 " Found PNG iCCP chunk."); 2450 } 2451 2452 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP)) 2453 { 2454 int 2455 compression; 2456 2457 #if (PNG_LIBPNG_VER < 10500) 2458 png_charp 2459 info; 2460 #else 2461 png_bytep 2462 info; 2463 #endif 2464 2465 png_charp 2466 name; 2467 2468 png_uint_32 2469 profile_length; 2470 2471 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info, 2472 &profile_length); 2473 2474 if (profile_length != 0) 2475 { 2476 StringInfo 2477 *profile; 2478 2479 if (logging != MagickFalse) 2480 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2481 " Reading PNG iCCP chunk."); 2482 2483 profile=BlobToStringInfo(info,profile_length); 2484 2485 if (profile == (StringInfo *) NULL) 2486 { 2487 png_warning(ping, "ICC profile is NULL"); 2488 profile=DestroyStringInfo(profile); 2489 } 2490 else 2491 { 2492 if (ping_preserve_iCCP == MagickFalse) 2493 { 2494 int 2495 icheck, 2496 got_crc=0; 2497 2498 2499 png_uint_32 2500 length, 2501 profile_crc=0; 2502 2503 unsigned char 2504 *data; 2505 2506 length=(png_uint_32) GetStringInfoLength(profile); 2507 2508 for (icheck=0; sRGB_info[icheck].len > 0; icheck++) 2509 { 2510 if (length == sRGB_info[icheck].len) 2511 { 2512 if (got_crc == 0) 2513 { 2514 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2515 " Got a %lu-byte ICC profile (potentially sRGB)", 2516 (unsigned long) length); 2517 2518 data=GetStringInfoDatum(profile); 2519 profile_crc=crc32(0,data,length); 2520 2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2522 " with crc=%8x",(unsigned int) profile_crc); 2523 got_crc++; 2524 } 2525 2526 if (profile_crc == sRGB_info[icheck].crc) 2527 { 2528 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2529 " It is sRGB with rendering intent = %s", 2530 Magick_RenderingIntentString_from_PNG_RenderingIntent( 2531 sRGB_info[icheck].intent)); 2532 if (image->rendering_intent==UndefinedIntent) 2533 { 2534 image->rendering_intent= 2535 Magick_RenderingIntent_from_PNG_RenderingIntent( 2536 sRGB_info[icheck].intent); 2537 } 2538 break; 2539 } 2540 } 2541 } 2542 if (sRGB_info[icheck].len == 0) 2543 { 2544 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2545 " Got a %lu-byte ICC profile not recognized as sRGB", 2546 (unsigned long) length); 2547 (void) SetImageProfile(image,"icc",profile,exception); 2548 } 2549 } 2550 else /* Preserve-iCCP */ 2551 { 2552 (void) SetImageProfile(image,"icc",profile,exception); 2553 } 2554 2555 profile=DestroyStringInfo(profile); 2556 } 2557 } 2558 } 2559 #endif 2560 2561 #if defined(PNG_READ_sRGB_SUPPORTED) 2562 { 2563 if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info, 2564 PNG_INFO_sRGB)) 2565 { 2566 if (png_get_sRGB(ping,ping_info,&intent)) 2567 { 2568 if (image->rendering_intent == UndefinedIntent) 2569 image->rendering_intent= 2570 Magick_RenderingIntent_from_PNG_RenderingIntent (intent); 2571 2572 if (logging != MagickFalse) 2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2574 " Reading PNG sRGB chunk: rendering_intent: %d",intent); 2575 } 2576 } 2577 2578 else if (mng_info->have_global_srgb) 2579 { 2580 if (image->rendering_intent == UndefinedIntent) 2581 image->rendering_intent= 2582 Magick_RenderingIntent_from_PNG_RenderingIntent 2583 (mng_info->global_srgb_intent); 2584 } 2585 } 2586 #endif 2587 2588 2589 { 2590 if (!png_get_gAMA(ping,ping_info,&file_gamma)) 2591 if (mng_info->have_global_gama) 2592 png_set_gAMA(ping,ping_info,mng_info->global_gamma); 2593 2594 if (png_get_gAMA(ping,ping_info,&file_gamma)) 2595 { 2596 image->gamma=(float) file_gamma; 2597 if (logging != MagickFalse) 2598 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2599 " Reading PNG gAMA chunk: gamma: %f",file_gamma); 2600 } 2601 } 2602 2603 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2604 { 2605 if (mng_info->have_global_chrm != MagickFalse) 2606 { 2607 (void) png_set_cHRM(ping,ping_info, 2608 mng_info->global_chrm.white_point.x, 2609 mng_info->global_chrm.white_point.y, 2610 mng_info->global_chrm.red_primary.x, 2611 mng_info->global_chrm.red_primary.y, 2612 mng_info->global_chrm.green_primary.x, 2613 mng_info->global_chrm.green_primary.y, 2614 mng_info->global_chrm.blue_primary.x, 2615 mng_info->global_chrm.blue_primary.y); 2616 } 2617 } 2618 2619 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM)) 2620 { 2621 (void) png_get_cHRM(ping,ping_info, 2622 &image->chromaticity.white_point.x, 2623 &image->chromaticity.white_point.y, 2624 &image->chromaticity.red_primary.x, 2625 &image->chromaticity.red_primary.y, 2626 &image->chromaticity.green_primary.x, 2627 &image->chromaticity.green_primary.y, 2628 &image->chromaticity.blue_primary.x, 2629 &image->chromaticity.blue_primary.y); 2630 2631 ping_found_cHRM=MagickTrue; 2632 2633 if (image->chromaticity.red_primary.x>0.6399f && 2634 image->chromaticity.red_primary.x<0.6401f && 2635 image->chromaticity.red_primary.y>0.3299f && 2636 image->chromaticity.red_primary.y<0.3301f && 2637 image->chromaticity.green_primary.x>0.2999f && 2638 image->chromaticity.green_primary.x<0.3001f && 2639 image->chromaticity.green_primary.y>0.5999f && 2640 image->chromaticity.green_primary.y<0.6001f && 2641 image->chromaticity.blue_primary.x>0.1499f && 2642 image->chromaticity.blue_primary.x<0.1501f && 2643 image->chromaticity.blue_primary.y>0.0599f && 2644 image->chromaticity.blue_primary.y<0.0601f && 2645 image->chromaticity.white_point.x>0.3126f && 2646 image->chromaticity.white_point.x<0.3128f && 2647 image->chromaticity.white_point.y>0.3289f && 2648 image->chromaticity.white_point.y<0.3291f) 2649 ping_found_sRGB_cHRM=MagickTrue; 2650 } 2651 2652 if (image->rendering_intent != UndefinedIntent) 2653 { 2654 if (ping_found_sRGB != MagickTrue && 2655 (ping_found_gAMA != MagickTrue || 2656 (image->gamma > .45 && image->gamma < .46)) && 2657 (ping_found_cHRM != MagickTrue || 2658 ping_found_sRGB_cHRM != MagickFalse) && 2659 ping_found_iCCP != MagickTrue) 2660 { 2661 png_set_sRGB(ping,ping_info, 2662 Magick_RenderingIntent_to_PNG_RenderingIntent 2663 (image->rendering_intent)); 2664 file_gamma=1.000f/2.200f; 2665 ping_found_sRGB=MagickTrue; 2666 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2667 " Setting sRGB as if in input"); 2668 } 2669 } 2670 2671 #if defined(PNG_oFFs_SUPPORTED) 2672 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs)) 2673 { 2674 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info); 2675 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info); 2676 2677 if (logging != MagickFalse) 2678 if (image->page.x || image->page.y) 2679 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2680 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double) 2681 image->page.x,(double) image->page.y); 2682 } 2683 #endif 2684 #if defined(PNG_pHYs_SUPPORTED) 2685 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 2686 { 2687 if (mng_info->have_global_phys) 2688 { 2689 png_set_pHYs(ping,ping_info, 2690 mng_info->global_x_pixels_per_unit, 2691 mng_info->global_y_pixels_per_unit, 2692 mng_info->global_phys_unit_type); 2693 } 2694 } 2695 2696 x_resolution=0; 2697 y_resolution=0; 2698 unit_type=0; 2699 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 2700 { 2701 /* 2702 Set image resolution. 2703 */ 2704 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution, 2705 &unit_type); 2706 image->resolution.x=(double) x_resolution; 2707 image->resolution.y=(double) y_resolution; 2708 2709 if (unit_type == PNG_RESOLUTION_METER) 2710 { 2711 image->units=PixelsPerCentimeterResolution; 2712 image->resolution.x=(double) x_resolution/100.0; 2713 image->resolution.y=(double) y_resolution/100.0; 2714 } 2715 2716 if (logging != MagickFalse) 2717 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2718 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.", 2719 (double) x_resolution,(double) y_resolution,unit_type); 2720 } 2721 #endif 2722 2723 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE)) 2724 { 2725 png_colorp 2726 palette; 2727 2728 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 2729 2730 if ((number_colors == 0) && 2731 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)) 2732 { 2733 if (mng_info->global_plte_length) 2734 { 2735 png_set_PLTE(ping,ping_info,mng_info->global_plte, 2736 (int) mng_info->global_plte_length); 2737 2738 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 2739 { 2740 if (mng_info->global_trns_length) 2741 { 2742 png_warning(ping, 2743 "global tRNS has more entries than global PLTE"); 2744 } 2745 else 2746 { 2747 png_set_tRNS(ping,ping_info,mng_info->global_trns, 2748 (int) mng_info->global_trns_length,NULL); 2749 } 2750 } 2751 #ifdef PNG_READ_bKGD_SUPPORTED 2752 if ( 2753 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 2754 mng_info->have_saved_bkgd_index || 2755 #endif 2756 png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 2757 { 2758 png_color_16 2759 background; 2760 2761 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 2762 if (mng_info->have_saved_bkgd_index) 2763 background.index=mng_info->saved_bkgd_index; 2764 #endif 2765 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD)) 2766 background.index=ping_background->index; 2767 2768 background.red=(png_uint_16) 2769 mng_info->global_plte[background.index].red; 2770 2771 background.green=(png_uint_16) 2772 mng_info->global_plte[background.index].green; 2773 2774 background.blue=(png_uint_16) 2775 mng_info->global_plte[background.index].blue; 2776 2777 background.gray=(png_uint_16) 2778 mng_info->global_plte[background.index].green; 2779 2780 png_set_bKGD(ping,ping_info,&background); 2781 } 2782 #endif 2783 } 2784 else 2785 png_error(ping,"No global PLTE in file"); 2786 } 2787 } 2788 2789 #ifdef PNG_READ_bKGD_SUPPORTED 2790 if (mng_info->have_global_bkgd && 2791 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD))) 2792 image->background_color=mng_info->mng_global_bkgd; 2793 2794 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 2795 { 2796 unsigned int 2797 bkgd_scale; 2798 2799 /* Set image background color. 2800 * Scale background components to 16-bit, then scale 2801 * to quantum depth 2802 */ 2803 2804 bkgd_scale = 1; 2805 2806 if (ping_file_depth == 1) 2807 bkgd_scale = 255; 2808 2809 else if (ping_file_depth == 2) 2810 bkgd_scale = 85; 2811 2812 else if (ping_file_depth == 4) 2813 bkgd_scale = 17; 2814 2815 if (ping_file_depth <= 8) 2816 bkgd_scale *= 257; 2817 2818 ping_background->red *= bkgd_scale; 2819 ping_background->green *= bkgd_scale; 2820 ping_background->blue *= bkgd_scale; 2821 2822 if (logging != MagickFalse) 2823 { 2824 if (logging != MagickFalse) 2825 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2826 " Reading PNG bKGD chunk, raw ping_background=(%d,%d,%d).\n" 2827 " bkgd_scale=%d. ping_background=(%d,%d,%d).", 2828 ping_background->red,ping_background->green, 2829 ping_background->blue, 2830 bkgd_scale,ping_background->red, 2831 ping_background->green,ping_background->blue); 2832 } 2833 2834 image->background_color.red= 2835 ScaleShortToQuantum(ping_background->red); 2836 2837 image->background_color.green= 2838 ScaleShortToQuantum(ping_background->green); 2839 2840 image->background_color.blue= 2841 ScaleShortToQuantum(ping_background->blue); 2842 2843 image->background_color.alpha=OpaqueAlpha; 2844 2845 if (logging != MagickFalse) 2846 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2847 " image->background_color=(%.20g,%.20g,%.20g).", 2848 (double) image->background_color.red, 2849 (double) image->background_color.green, 2850 (double) image->background_color.blue); 2851 } 2852 #endif /* PNG_READ_bKGD_SUPPORTED */ 2853 2854 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 2855 { 2856 /* 2857 Image has a tRNS chunk. 2858 */ 2859 int 2860 max_sample; 2861 2862 size_t 2863 one=1; 2864 2865 if (logging != MagickFalse) 2866 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2867 " Reading PNG tRNS chunk."); 2868 2869 max_sample = (int) ((one << ping_file_depth) - 1); 2870 2871 if ((ping_color_type == PNG_COLOR_TYPE_GRAY && 2872 (int)ping_trans_color->gray > max_sample) || 2873 (ping_color_type == PNG_COLOR_TYPE_RGB && 2874 ((int)ping_trans_color->red > max_sample || 2875 (int)ping_trans_color->green > max_sample || 2876 (int)ping_trans_color->blue > max_sample))) 2877 { 2878 if (logging != MagickFalse) 2879 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2880 " Ignoring PNG tRNS chunk with out-of-range sample."); 2881 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0); 2882 png_set_invalid(ping,ping_info,PNG_INFO_tRNS); 2883 image->alpha_trait=UndefinedPixelTrait; 2884 } 2885 else 2886 { 2887 int 2888 scale_to_short; 2889 2890 scale_to_short = 65535L/((1UL << ping_file_depth)-1); 2891 2892 /* Scale transparent_color to short */ 2893 transparent_color.red= scale_to_short*ping_trans_color->red; 2894 transparent_color.green= scale_to_short*ping_trans_color->green; 2895 transparent_color.blue= scale_to_short*ping_trans_color->blue; 2896 transparent_color.alpha= scale_to_short*ping_trans_color->gray; 2897 2898 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 2899 { 2900 if (logging != MagickFalse) 2901 { 2902 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2903 " Raw tRNS graylevel = %d, scaled graylevel = %d.", 2904 (int) ping_trans_color->gray,(int) transparent_color.alpha); 2905 2906 } 2907 transparent_color.red=transparent_color.alpha; 2908 transparent_color.green=transparent_color.alpha; 2909 transparent_color.blue=transparent_color.alpha; 2910 } 2911 } 2912 } 2913 #if defined(PNG_READ_sBIT_SUPPORTED) 2914 if (mng_info->have_global_sbit) 2915 { 2916 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT)) 2917 png_set_sBIT(ping,ping_info,&mng_info->global_sbit); 2918 } 2919 #endif 2920 num_passes=png_set_interlace_handling(ping); 2921 2922 png_read_update_info(ping,ping_info); 2923 2924 ping_rowbytes=png_get_rowbytes(ping,ping_info); 2925 2926 /* 2927 Initialize image structure. 2928 */ 2929 mng_info->image_box.left=0; 2930 mng_info->image_box.right=(ssize_t) ping_width; 2931 mng_info->image_box.top=0; 2932 mng_info->image_box.bottom=(ssize_t) ping_height; 2933 if (mng_info->mng_type == 0) 2934 { 2935 mng_info->mng_width=ping_width; 2936 mng_info->mng_height=ping_height; 2937 mng_info->frame=mng_info->image_box; 2938 mng_info->clip=mng_info->image_box; 2939 } 2940 2941 else 2942 { 2943 image->page.y=mng_info->y_off[mng_info->object_id]; 2944 } 2945 2946 image->compression=ZipCompression; 2947 image->columns=ping_width; 2948 image->rows=ping_height; 2949 2950 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 2951 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) 2952 { 2953 double 2954 image_gamma = image->gamma; 2955 2956 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2957 " image->gamma=%f",(float) image_gamma); 2958 2959 if (image_gamma > 0.75) 2960 { 2961 /* Set image->rendering_intent to Undefined, 2962 * image->colorspace to GRAY, and reset image->chromaticity. 2963 */ 2964 image->intensity = Rec709LuminancePixelIntensityMethod; 2965 SetImageColorspace(image,GRAYColorspace,exception); 2966 } 2967 else 2968 { 2969 RenderingIntent 2970 save_rendering_intent = image->rendering_intent; 2971 ChromaticityInfo 2972 save_chromaticity = image->chromaticity; 2973 2974 SetImageColorspace(image,GRAYColorspace,exception); 2975 image->rendering_intent = save_rendering_intent; 2976 image->chromaticity = save_chromaticity; 2977 } 2978 2979 image->gamma = image_gamma; 2980 } 2981 2982 (void)LogMagickEvent(CoderEvent,GetMagickModule(), 2983 " image->colorspace=%d",(int) image->colorspace); 2984 2985 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) || 2986 ((int) ping_bit_depth < 16 && 2987 (int) ping_color_type == PNG_COLOR_TYPE_GRAY)) 2988 { 2989 size_t 2990 one; 2991 2992 image->storage_class=PseudoClass; 2993 one=1; 2994 image->colors=one << ping_file_depth; 2995 #if (MAGICKCORE_QUANTUM_DEPTH == 8) 2996 if (image->colors > 256) 2997 image->colors=256; 2998 #else 2999 if (image->colors > 65536L) 3000 image->colors=65536L; 3001 #endif 3002 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3003 { 3004 png_colorp 3005 palette; 3006 3007 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 3008 image->colors=(size_t) number_colors; 3009 3010 if (logging != MagickFalse) 3011 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3012 " Reading PNG PLTE chunk: number_colors: %d.",number_colors); 3013 } 3014 } 3015 3016 if (image->storage_class == PseudoClass) 3017 { 3018 /* 3019 Initialize image colormap. 3020 */ 3021 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 3022 png_error(ping,"Memory allocation failed"); 3023 3024 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3025 { 3026 png_colorp 3027 palette; 3028 3029 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); 3030 3031 for (i=0; i < (ssize_t) number_colors; i++) 3032 { 3033 image->colormap[i].red=ScaleCharToQuantum(palette[i].red); 3034 image->colormap[i].green=ScaleCharToQuantum(palette[i].green); 3035 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue); 3036 } 3037 3038 for ( ; i < (ssize_t) image->colors; i++) 3039 { 3040 image->colormap[i].red=0; 3041 image->colormap[i].green=0; 3042 image->colormap[i].blue=0; 3043 } 3044 } 3045 3046 else 3047 { 3048 Quantum 3049 scale; 3050 3051 scale = (Quantum) ((65535UL)/((1UL << ping_file_depth)-1)); 3052 3053 #if (MAGICKCORE_QUANTUM_DEPTH > 16) 3054 scale = ScaleShortToQuantum(scale); 3055 #endif 3056 3057 for (i=0; i < (ssize_t) image->colors; i++) 3058 { 3059 image->colormap[i].red=(Quantum) (i*scale); 3060 image->colormap[i].green=(Quantum) (i*scale); 3061 image->colormap[i].blue=(Quantum) (i*scale); 3062 } 3063 } 3064 } 3065 3066 /* Set some properties for reporting by "identify" */ 3067 { 3068 char 3069 msg[MagickPathExtent]; 3070 3071 /* encode ping_width, ping_height, ping_file_depth, ping_color_type, 3072 ping_interlace_method in value */ 3073 3074 (void) FormatLocaleString(msg,MagickPathExtent, 3075 "%d, %d",(int) ping_width, (int) ping_height); 3076 (void) SetImageProperty(image,"png:IHDR.width,height",msg,exception); 3077 3078 (void) FormatLocaleString(msg,MagickPathExtent,"%d",(int) ping_file_depth); 3079 (void) SetImageProperty(image,"png:IHDR.bit_depth",msg,exception); 3080 3081 (void) FormatLocaleString(msg,MagickPathExtent,"%d (%s)", 3082 (int) ping_color_type, 3083 Magick_ColorType_from_PNG_ColorType((int)ping_color_type)); 3084 (void) SetImageProperty(image,"png:IHDR.color_type",msg,exception); 3085 3086 if (ping_interlace_method == 0) 3087 { 3088 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Not interlaced)", 3089 (int) ping_interlace_method); 3090 } 3091 else if (ping_interlace_method == 1) 3092 { 3093 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Adam7 method)", 3094 (int) ping_interlace_method); 3095 } 3096 else 3097 { 3098 (void) FormatLocaleString(msg,MagickPathExtent,"%d (Unknown method)", 3099 (int) ping_interlace_method); 3100 } 3101 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception); 3102 3103 if (number_colors != 0) 3104 { 3105 (void) FormatLocaleString(msg,MagickPathExtent,"%d", 3106 (int) number_colors); 3107 (void) SetImageProperty(image,"png:PLTE.number_colors",msg, 3108 exception); 3109 } 3110 } 3111 #if defined(PNG_tIME_SUPPORTED) 3112 read_tIME_chunk(image,ping,ping_info,exception); 3113 #endif 3114 3115 3116 /* 3117 Read image scanlines. 3118 */ 3119 if (image->delay != 0) 3120 mng_info->scenes_found++; 3121 3122 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || ( 3123 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t) 3124 (image_info->first_scene+image_info->number_scenes)))) 3125 { 3126 /* This happens later in non-ping decodes */ 3127 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3128 image->storage_class=DirectClass; 3129 image->alpha_trait= 3130 (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3131 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3132 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3133 BlendPixelTrait : UndefinedPixelTrait; 3134 3135 if (logging != MagickFalse) 3136 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3137 " Skipping PNG image data for scene %.20g",(double) 3138 mng_info->scenes_found-1); 3139 png_destroy_read_struct(&ping,&ping_info,&end_info); 3140 3141 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3142 UnlockSemaphoreInfo(ping_semaphore); 3143 #endif 3144 3145 if (logging != MagickFalse) 3146 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3147 " exit ReadOnePNGImage()."); 3148 3149 return(image); 3150 } 3151 3152 if (logging != MagickFalse) 3153 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3154 " Reading PNG IDAT chunk(s)"); 3155 3156 status=SetImageExtent(image,image->columns,image->rows,exception); 3157 if (status == MagickFalse) 3158 return(DestroyImageList(image)); 3159 3160 if (num_passes > 1) 3161 pixel_info=AcquireVirtualMemory(image->rows,ping_rowbytes* 3162 sizeof(*ping_pixels)); 3163 else 3164 pixel_info=AcquireVirtualMemory(ping_rowbytes,sizeof(*ping_pixels)); 3165 3166 if (pixel_info == (MemoryInfo *) NULL) 3167 png_error(ping,"Memory allocation failed"); 3168 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 3169 3170 if (logging != MagickFalse) 3171 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3172 " Converting PNG pixels to pixel packets"); 3173 /* 3174 Convert PNG pixels to pixel packets. 3175 */ 3176 quantum_info=AcquireQuantumInfo(image_info,image); 3177 3178 if (quantum_info == (QuantumInfo *) NULL) 3179 png_error(ping,"Failed to allocate quantum_info"); 3180 3181 (void) SetQuantumEndian(image,quantum_info,MSBEndian); 3182 3183 { 3184 3185 MagickBooleanType 3186 found_transparent_pixel; 3187 3188 found_transparent_pixel=MagickFalse; 3189 3190 if (image->storage_class == DirectClass) 3191 { 3192 for (pass=0; pass < num_passes; pass++) 3193 { 3194 /* 3195 Convert image to DirectClass pixel packets. 3196 */ 3197 image->alpha_trait= 3198 (((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3199 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3200 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3201 BlendPixelTrait : UndefinedPixelTrait; 3202 3203 for (y=0; y < (ssize_t) image->rows; y++) 3204 { 3205 if (num_passes > 1) 3206 row_offset=ping_rowbytes*y; 3207 3208 else 3209 row_offset=0; 3210 3211 png_read_row(ping,ping_pixels+row_offset,NULL); 3212 3213 if (pass < num_passes-1) 3214 continue; 3215 3216 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3217 3218 if (q == (Quantum *) NULL) 3219 break; 3220 3221 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY) 3222 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3223 GrayQuantum,ping_pixels+row_offset,exception); 3224 3225 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 3226 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3227 GrayAlphaQuantum,ping_pixels+row_offset,exception); 3228 3229 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 3230 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3231 RGBAQuantum,ping_pixels+row_offset,exception); 3232 3233 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3234 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3235 IndexQuantum,ping_pixels+row_offset,exception); 3236 3237 else /* ping_color_type == PNG_COLOR_TYPE_RGB */ 3238 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 3239 RGBQuantum,ping_pixels+row_offset,exception); 3240 3241 if (found_transparent_pixel == MagickFalse) 3242 { 3243 /* Is there a transparent pixel in the row? */ 3244 if (y== 0 && logging != MagickFalse) 3245 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3246 " Looking for cheap transparent pixel"); 3247 3248 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3249 { 3250 if ((ping_color_type == PNG_COLOR_TYPE_RGBA || 3251 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && 3252 (GetPixelAlpha(image,q) != OpaqueAlpha)) 3253 { 3254 if (logging != MagickFalse) 3255 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3256 " ...got one."); 3257 3258 found_transparent_pixel = MagickTrue; 3259 break; 3260 } 3261 if ((ping_color_type == PNG_COLOR_TYPE_RGB || 3262 ping_color_type == PNG_COLOR_TYPE_GRAY) && 3263 (ScaleQuantumToShort(GetPixelRed(image,q)) == 3264 transparent_color.red && 3265 ScaleQuantumToShort(GetPixelGreen(image,q)) == 3266 transparent_color.green && 3267 ScaleQuantumToShort(GetPixelBlue(image,q)) == 3268 transparent_color.blue)) 3269 { 3270 if (logging != MagickFalse) 3271 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3272 " ...got one."); 3273 found_transparent_pixel = MagickTrue; 3274 break; 3275 } 3276 q+=GetPixelChannels(image); 3277 } 3278 } 3279 3280 if (num_passes == 1) 3281 { 3282 status=SetImageProgress(image,LoadImageTag, 3283 (MagickOffsetType) y, image->rows); 3284 3285 if (status == MagickFalse) 3286 break; 3287 } 3288 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3289 break; 3290 } 3291 3292 if (num_passes != 1) 3293 { 3294 status=SetImageProgress(image,LoadImageTag,pass,num_passes); 3295 if (status == MagickFalse) 3296 break; 3297 } 3298 } 3299 } 3300 3301 else /* image->storage_class != DirectClass */ 3302 3303 for (pass=0; pass < num_passes; pass++) 3304 { 3305 Quantum 3306 *quantum_scanline; 3307 3308 register Quantum 3309 *r; 3310 3311 /* 3312 Convert grayscale image to PseudoClass pixel packets. 3313 */ 3314 if (logging != MagickFalse) 3315 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3316 " Converting grayscale pixels to pixel packets"); 3317 3318 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ? 3319 BlendPixelTrait : UndefinedPixelTrait; 3320 3321 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns, 3322 (image->alpha_trait == BlendPixelTrait? 2 : 1)* 3323 sizeof(*quantum_scanline)); 3324 3325 if (quantum_scanline == (Quantum *) NULL) 3326 png_error(ping,"Memory allocation failed"); 3327 3328 for (y=0; y < (ssize_t) image->rows; y++) 3329 { 3330 Quantum 3331 alpha; 3332 3333 if (num_passes > 1) 3334 row_offset=ping_rowbytes*y; 3335 3336 else 3337 row_offset=0; 3338 3339 png_read_row(ping,ping_pixels+row_offset,NULL); 3340 3341 if (pass < num_passes-1) 3342 continue; 3343 3344 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 3345 3346 if (q == (Quantum *) NULL) 3347 break; 3348 3349 p=ping_pixels+row_offset; 3350 r=quantum_scanline; 3351 3352 switch (ping_bit_depth) 3353 { 3354 case 8: 3355 { 3356 3357 if (ping_color_type == 4) 3358 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3359 { 3360 *r++=*p++; 3361 3362 alpha=ScaleCharToQuantum((unsigned char)*p++); 3363 3364 SetPixelAlpha(image,alpha,q); 3365 3366 if (alpha != OpaqueAlpha) 3367 found_transparent_pixel = MagickTrue; 3368 3369 q+=GetPixelChannels(image); 3370 } 3371 3372 else 3373 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3374 *r++=*p++; 3375 3376 break; 3377 } 3378 3379 case 16: 3380 { 3381 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3382 { 3383 #if (MAGICKCORE_QUANTUM_DEPTH >= 16) 3384 unsigned short 3385 quantum; 3386 3387 if (image->colors > 256) 3388 quantum=((*p++) << 8); 3389 3390 else 3391 quantum=0; 3392 3393 quantum|=(*p++); 3394 *r=ScaleShortToQuantum(quantum); 3395 r++; 3396 3397 if (ping_color_type == 4) 3398 { 3399 if (image->colors > 256) 3400 quantum=((*p++) << 8); 3401 else 3402 quantum=0; 3403 3404 quantum|=(*p++); 3405 3406 alpha=ScaleShortToQuantum(quantum); 3407 SetPixelAlpha(image,alpha,q); 3408 3409 if (alpha != OpaqueAlpha) 3410 found_transparent_pixel = MagickTrue; 3411 3412 q+=GetPixelChannels(image); 3413 } 3414 3415 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */ 3416 *r++=(*p++); 3417 p++; /* strip low byte */ 3418 3419 if (ping_color_type == 4) 3420 { 3421 SetPixelAlpha(image,*p++,q); 3422 3423 if (GetPixelAlpha(image,q) != OpaqueAlpha) 3424 found_transparent_pixel = MagickTrue; 3425 3426 p++; 3427 q+=GetPixelChannels(image); 3428 } 3429 #endif 3430 } 3431 3432 break; 3433 } 3434 3435 default: 3436 break; 3437 } 3438 3439 /* 3440 Transfer image scanline. 3441 */ 3442 r=quantum_scanline; 3443 3444 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3445 3446 if (q == (Quantum *) NULL) 3447 break; 3448 for (x=0; x < (ssize_t) image->columns; x++) 3449 { 3450 SetPixelIndex(image,*r++,q); 3451 q+=GetPixelChannels(image); 3452 } 3453 3454 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3455 break; 3456 3457 if (num_passes == 1) 3458 { 3459 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 3460 image->rows); 3461 3462 if (status == MagickFalse) 3463 break; 3464 } 3465 } 3466 3467 if (num_passes != 1) 3468 { 3469 status=SetImageProgress(image,LoadImageTag,pass,num_passes); 3470 3471 if (status == MagickFalse) 3472 break; 3473 } 3474 3475 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline); 3476 } 3477 3478 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait : 3479 UndefinedPixelTrait; 3480 3481 if (logging != MagickFalse) 3482 { 3483 if (found_transparent_pixel != MagickFalse) 3484 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3485 " Found transparent pixel"); 3486 else 3487 { 3488 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3489 " No transparent pixel was found"); 3490 3491 ping_color_type&=0x03; 3492 } 3493 } 3494 } 3495 3496 if (quantum_info != (QuantumInfo *) NULL) 3497 quantum_info=DestroyQuantumInfo(quantum_info); 3498 3499 if (image->storage_class == PseudoClass) 3500 { 3501 PixelTrait 3502 alpha_trait; 3503 3504 alpha_trait=image->alpha_trait; 3505 image->alpha_trait=UndefinedPixelTrait; 3506 (void) SyncImage(image,exception); 3507 image->alpha_trait=alpha_trait; 3508 } 3509 3510 png_read_end(ping,end_info); 3511 3512 if (logging != MagickFalse) 3513 { 3514 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3515 " image->storage_class=%d\n",(int) image->storage_class); 3516 } 3517 3518 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 < 3519 (ssize_t) image_info->first_scene && image->delay != 0) 3520 { 3521 png_destroy_read_struct(&ping,&ping_info,&end_info); 3522 pixel_info=RelinquishVirtualMemory(pixel_info); 3523 image->colors=2; 3524 (void) SetImageBackgroundColor(image,exception); 3525 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3526 UnlockSemaphoreInfo(ping_semaphore); 3527 #endif 3528 if (logging != MagickFalse) 3529 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3530 " exit ReadOnePNGImage() early."); 3531 return(image); 3532 } 3533 3534 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3535 { 3536 ClassType 3537 storage_class; 3538 3539 /* 3540 Image has a transparent background. 3541 */ 3542 storage_class=image->storage_class; 3543 image->alpha_trait=BlendPixelTrait; 3544 3545 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */ 3546 3547 if (storage_class == PseudoClass) 3548 { 3549 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 3550 { 3551 for (x=0; x < ping_num_trans; x++) 3552 { 3553 image->colormap[x].alpha_trait=BlendPixelTrait; 3554 image->colormap[x].alpha = 3555 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]); 3556 } 3557 } 3558 3559 else if (ping_color_type == PNG_COLOR_TYPE_GRAY) 3560 { 3561 for (x=0; x < (int) image->colors; x++) 3562 { 3563 if (ScaleQuantumToShort(image->colormap[x].red) == 3564 transparent_color.alpha) 3565 { 3566 image->colormap[x].alpha_trait=BlendPixelTrait; 3567 image->colormap[x].alpha = (Quantum) TransparentAlpha; 3568 } 3569 } 3570 } 3571 (void) SyncImage(image,exception); 3572 } 3573 3574 #if 1 /* Should have already been done above, but glennrp problem P10 3575 * needs this. 3576 */ 3577 else 3578 { 3579 for (y=0; y < (ssize_t) image->rows; y++) 3580 { 3581 image->storage_class=storage_class; 3582 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 3583 3584 if (q == (Quantum *) NULL) 3585 break; 3586 3587 3588 /* Caution: on a Q8 build, this does not distinguish between 3589 * 16-bit colors that differ only in the low byte 3590 */ 3591 for (x=(ssize_t) image->columns-1; x >= 0; x--) 3592 { 3593 if (ScaleQuantumToShort(GetPixelRed(image,q)) == 3594 transparent_color.red && 3595 ScaleQuantumToShort(GetPixelGreen(image,q)) == 3596 transparent_color.green && 3597 ScaleQuantumToShort(GetPixelBlue(image,q)) == 3598 transparent_color.blue) 3599 { 3600 SetPixelAlpha(image,TransparentAlpha,q); 3601 } 3602 3603 #if 0 /* I have not found a case where this is needed. */ 3604 else 3605 { 3606 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha; 3607 } 3608 #endif 3609 3610 q+=GetPixelChannels(image); 3611 } 3612 3613 if (SyncAuthenticPixels(image,exception) == MagickFalse) 3614 break; 3615 } 3616 } 3617 #endif 3618 3619 image->storage_class=DirectClass; 3620 } 3621 3622 for (j = 0; j < 2; j++) 3623 { 3624 if (j == 0) 3625 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ? 3626 MagickTrue : MagickFalse; 3627 else 3628 status = png_get_text(ping,end_info,&text,&num_text) != 0 ? 3629 MagickTrue : MagickFalse; 3630 3631 if (status != MagickFalse) 3632 for (i=0; i < (ssize_t) num_text; i++) 3633 { 3634 /* Check for a profile */ 3635 3636 if (logging != MagickFalse) 3637 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3638 " Reading PNG text chunk"); 3639 3640 if (strlen(text[i].key) > 16 && 3641 memcmp(text[i].key, "Raw profile type ",17) == 0) 3642 { 3643 const char 3644 *value; 3645 3646 value=GetImageOption(image_info,"profile:skip"); 3647 3648 if (IsOptionMember(text[i].key+17,value) == MagickFalse) 3649 { 3650 (void) Magick_png_read_raw_profile(ping,image,image_info,text, 3651 (int) i,exception); 3652 num_raw_profiles++; 3653 if (logging != MagickFalse) 3654 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3655 " Read raw profile %s",text[i].key+17); 3656 } 3657 else 3658 { 3659 if (logging != MagickFalse) 3660 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3661 " Skipping raw profile %s",text[i].key+17); 3662 } 3663 } 3664 3665 else 3666 { 3667 char 3668 *value; 3669 3670 length=text[i].text_length; 3671 value=(char *) AcquireQuantumMemory(length+MagickPathExtent, 3672 sizeof(*value)); 3673 if (value == (char *) NULL) 3674 { 3675 png_error(ping,"Memory allocation failed"); 3676 break; 3677 } 3678 *value='\0'; 3679 (void) ConcatenateMagickString(value,text[i].text,length+2); 3680 3681 /* Don't save "density" or "units" property if we have a pHYs 3682 * chunk 3683 */ 3684 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) || 3685 (LocaleCompare(text[i].key,"density") != 0 && 3686 LocaleCompare(text[i].key,"units") != 0)) 3687 (void) SetImageProperty(image,text[i].key,value,exception); 3688 3689 if (logging != MagickFalse) 3690 { 3691 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3692 " length: %lu\n" 3693 " Keyword: %s", 3694 (unsigned long) length, 3695 text[i].key); 3696 } 3697 3698 value=DestroyString(value); 3699 } 3700 } 3701 num_text_total += num_text; 3702 } 3703 3704 #ifdef MNG_OBJECT_BUFFERS 3705 /* 3706 Store the object if necessary. 3707 */ 3708 if (object_id && !mng_info->frozen[object_id]) 3709 { 3710 if (mng_info->ob[object_id] == (MngBuffer *) NULL) 3711 { 3712 /* 3713 create a new object buffer. 3714 */ 3715 mng_info->ob[object_id]=(MngBuffer *) 3716 AcquireMagickMemory(sizeof(MngBuffer)); 3717 3718 if (mng_info->ob[object_id] != (MngBuffer *) NULL) 3719 { 3720 mng_info->ob[object_id]->image=(Image *) NULL; 3721 mng_info->ob[object_id]->reference_count=1; 3722 } 3723 } 3724 3725 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) || 3726 mng_info->ob[object_id]->frozen) 3727 { 3728 if (mng_info->ob[object_id] == (MngBuffer *) NULL) 3729 png_error(ping,"Memory allocation failed"); 3730 3731 if (mng_info->ob[object_id]->frozen) 3732 png_error(ping,"Cannot overwrite frozen MNG object buffer"); 3733 } 3734 3735 else 3736 { 3737 3738 if (mng_info->ob[object_id]->image != (Image *) NULL) 3739 mng_info->ob[object_id]->image=DestroyImage 3740 (mng_info->ob[object_id]->image); 3741 3742 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue, 3743 exception); 3744 3745 if (mng_info->ob[object_id]->image != (Image *) NULL) 3746 mng_info->ob[object_id]->image->file=(FILE *) NULL; 3747 3748 else 3749 png_error(ping, "Cloning image for object buffer failed"); 3750 3751 if (ping_width > 250000L || ping_height > 250000L) 3752 png_error(ping,"PNG Image dimensions are too large."); 3753 3754 mng_info->ob[object_id]->width=ping_width; 3755 mng_info->ob[object_id]->height=ping_height; 3756 mng_info->ob[object_id]->color_type=ping_color_type; 3757 mng_info->ob[object_id]->sample_depth=ping_bit_depth; 3758 mng_info->ob[object_id]->interlace_method=ping_interlace_method; 3759 mng_info->ob[object_id]->compression_method= 3760 ping_compression_method; 3761 mng_info->ob[object_id]->filter_method=ping_filter_method; 3762 3763 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE)) 3764 { 3765 png_colorp 3766 plte; 3767 3768 /* 3769 Copy the PLTE to the object buffer. 3770 */ 3771 png_get_PLTE(ping,ping_info,&plte,&number_colors); 3772 mng_info->ob[object_id]->plte_length=number_colors; 3773 3774 for (i=0; i < number_colors; i++) 3775 { 3776 mng_info->ob[object_id]->plte[i]=plte[i]; 3777 } 3778 } 3779 3780 else 3781 mng_info->ob[object_id]->plte_length=0; 3782 } 3783 } 3784 #endif 3785 3786 /* Set image->alpha_trait to MagickTrue if the input colortype supports 3787 * alpha or if a valid tRNS chunk is present, no matter whether there 3788 * is actual transparency present. 3789 */ 3790 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) || 3791 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || 3792 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ? 3793 BlendPixelTrait : UndefinedPixelTrait; 3794 3795 #if 0 /* I'm not sure what's wrong here but it does not work. */ 3796 if (image->alpha_trait != UndefinedPixelTrait) 3797 { 3798 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 3799 (void) SetImageType(image,GrayscaleAlphaType,exception); 3800 3801 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 3802 (void) SetImageType(image,PaletteAlphaType,exception); 3803 3804 else 3805 (void) SetImageType(image,TrueColorAlphaType,exception); 3806 } 3807 3808 else 3809 { 3810 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 3811 (void) SetImageType(image,GrayscaleType,exception); 3812 3813 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 3814 (void) SetImageType(image,PaletteType,exception); 3815 3816 else 3817 (void) SetImageType(image,TrueColorType,exception); 3818 } 3819 #endif 3820 3821 /* Set more properties for identify to retrieve */ 3822 { 3823 char 3824 msg[MagickPathExtent]; 3825 3826 if (num_text_total != 0) 3827 { 3828 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */ 3829 (void) FormatLocaleString(msg,MagickPathExtent, 3830 "%d tEXt/zTXt/iTXt chunks were found", num_text_total); 3831 (void) SetImageProperty(image,"png:text",msg, 3832 exception); 3833 } 3834 3835 if (num_raw_profiles != 0) 3836 { 3837 (void) FormatLocaleString(msg,MagickPathExtent, 3838 "%d were found", num_raw_profiles); 3839 (void) SetImageProperty(image,"png:text-encoded profiles",msg, 3840 exception); 3841 } 3842 3843 if (ping_found_cHRM != MagickFalse) 3844 { 3845 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3846 "chunk was found (see Chromaticity, above)"); 3847 (void) SetImageProperty(image,"png:cHRM",msg, 3848 exception); 3849 } 3850 3851 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD)) 3852 { 3853 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3854 "chunk was found (see Background color, above)"); 3855 (void) SetImageProperty(image,"png:bKGD",msg, 3856 exception); 3857 } 3858 3859 (void) FormatLocaleString(msg,MagickPathExtent,"%s", 3860 "chunk was found"); 3861 3862 #if defined(PNG_iCCP_SUPPORTED) 3863 if (ping_found_iCCP != MagickFalse) 3864 (void) SetImageProperty(image,"png:iCCP",msg, 3865 exception); 3866 #endif 3867 3868 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS)) 3869 (void) SetImageProperty(image,"png:tRNS",msg, 3870 exception); 3871 3872 #if defined(PNG_sRGB_SUPPORTED) 3873 if (ping_found_sRGB != MagickFalse) 3874 { 3875 (void) FormatLocaleString(msg,MagickPathExtent, 3876 "intent=%d (%s)", 3877 (int) intent, 3878 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent)); 3879 (void) SetImageProperty(image,"png:sRGB",msg, 3880 exception); 3881 } 3882 #endif 3883 3884 if (ping_found_gAMA != MagickFalse) 3885 { 3886 (void) FormatLocaleString(msg,MagickPathExtent, 3887 "gamma=%.8g (See Gamma, above)", 3888 file_gamma); 3889 (void) SetImageProperty(image,"png:gAMA",msg, 3890 exception); 3891 } 3892 3893 #if defined(PNG_pHYs_SUPPORTED) 3894 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs)) 3895 { 3896 (void) FormatLocaleString(msg,MagickPathExtent, 3897 "x_res=%.10g, y_res=%.10g, units=%d", 3898 (double) x_resolution,(double) y_resolution, unit_type); 3899 (void) SetImageProperty(image,"png:pHYs",msg, 3900 exception); 3901 } 3902 #endif 3903 3904 #if defined(PNG_oFFs_SUPPORTED) 3905 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs)) 3906 { 3907 (void) FormatLocaleString(msg,MagickPathExtent,"x_off=%.20g, y_off=%.20g", 3908 (double) image->page.x,(double) image->page.y); 3909 (void) SetImageProperty(image,"png:oFFs",msg, 3910 exception); 3911 } 3912 #endif 3913 3914 #if defined(PNG_tIME_SUPPORTED) 3915 read_tIME_chunk(image,ping,end_info,exception); 3916 #endif 3917 3918 if ((image->page.width != 0 && image->page.width != image->columns) || 3919 (image->page.height != 0 && image->page.height != image->rows)) 3920 { 3921 (void) FormatLocaleString(msg,MagickPathExtent, 3922 "width=%.20g, height=%.20g", 3923 (double) image->page.width,(double) image->page.height); 3924 (void) SetImageProperty(image,"png:vpAg",msg, 3925 exception); 3926 } 3927 } 3928 3929 /* 3930 Relinquish resources. 3931 */ 3932 png_destroy_read_struct(&ping,&ping_info,&end_info); 3933 3934 pixel_info=RelinquishVirtualMemory(pixel_info); 3935 3936 if (logging != MagickFalse) 3937 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 3938 " exit ReadOnePNGImage()"); 3939 3940 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 3941 UnlockSemaphoreInfo(ping_semaphore); 3942 #endif 3943 3944 /* } for navigation to beginning of SETJMP-protected block, revert to 3945 * Throwing an Exception when an error occurs. 3946 */ 3947 3948 return(image); 3949 3950 /* end of reading one PNG image */ 3951 } 3952 3953 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 3954 { 3955 Image 3956 *image; 3957 3958 MagickBooleanType 3959 have_mng_structure, 3960 logging, 3961 status; 3962 3963 MngInfo 3964 *mng_info; 3965 3966 char 3967 magic_number[MagickPathExtent]; 3968 3969 ssize_t 3970 count; 3971 3972 /* 3973 Open image file. 3974 */ 3975 assert(image_info != (const ImageInfo *) NULL); 3976 assert(image_info->signature == MagickCoreSignature); 3977 3978 if (image_info->debug != MagickFalse) 3979 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 3980 image_info->filename); 3981 3982 assert(exception != (ExceptionInfo *) NULL); 3983 assert(exception->signature == MagickCoreSignature); 3984 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()"); 3985 image=AcquireImage(image_info,exception); 3986 mng_info=(MngInfo *) NULL; 3987 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 3988 3989 if (status == MagickFalse) 3990 ThrowReaderException(FileOpenError,"UnableToOpenFile"); 3991 3992 /* 3993 Verify PNG signature. 3994 */ 3995 count=ReadBlob(image,8,(unsigned char *) magic_number); 3996 3997 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0) 3998 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 3999 4000 /* 4001 Allocate a MngInfo structure. 4002 */ 4003 have_mng_structure=MagickFalse; 4004 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 4005 4006 if (mng_info == (MngInfo *) NULL) 4007 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4008 4009 /* 4010 Initialize members of the MngInfo structure. 4011 */ 4012 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 4013 mng_info->image=image; 4014 have_mng_structure=MagickTrue; 4015 4016 image=ReadOnePNGImage(mng_info,image_info,exception); 4017 MngInfoFreeStruct(mng_info,&have_mng_structure); 4018 4019 if (image == (Image *) NULL) 4020 { 4021 if (logging != MagickFalse) 4022 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4023 "exit ReadPNGImage() with error"); 4024 4025 return((Image *) NULL); 4026 } 4027 4028 (void) CloseBlob(image); 4029 4030 if ((image->columns == 0) || (image->rows == 0)) 4031 { 4032 if (logging != MagickFalse) 4033 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4034 "exit ReadPNGImage() with error."); 4035 4036 ThrowReaderException(CorruptImageError,"CorruptImage"); 4037 } 4038 4039 if ((IssRGBColorspace(image->colorspace) != MagickFalse) && 4040 ((image->gamma < .45) || (image->gamma > .46)) && 4041 !(image->chromaticity.red_primary.x>0.6399f && 4042 image->chromaticity.red_primary.x<0.6401f && 4043 image->chromaticity.red_primary.y>0.3299f && 4044 image->chromaticity.red_primary.y<0.3301f && 4045 image->chromaticity.green_primary.x>0.2999f && 4046 image->chromaticity.green_primary.x<0.3001f && 4047 image->chromaticity.green_primary.y>0.5999f && 4048 image->chromaticity.green_primary.y<0.6001f && 4049 image->chromaticity.blue_primary.x>0.1499f && 4050 image->chromaticity.blue_primary.x<0.1501f && 4051 image->chromaticity.blue_primary.y>0.0599f && 4052 image->chromaticity.blue_primary.y<0.0601f && 4053 image->chromaticity.white_point.x>0.3126f && 4054 image->chromaticity.white_point.x<0.3128f && 4055 image->chromaticity.white_point.y>0.3289f && 4056 image->chromaticity.white_point.y<0.3291f)) 4057 { 4058 SetImageColorspace(image,RGBColorspace,exception); 4059 } 4060 4061 if (logging != MagickFalse) 4062 { 4063 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4064 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.", 4065 (double) image->page.width,(double) image->page.height, 4066 (double) image->page.x,(double) image->page.y); 4067 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4068 " image->colorspace: %d", (int) image->colorspace); 4069 } 4070 4071 if (logging != MagickFalse) 4072 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()"); 4073 4074 return(image); 4075 } 4076 4077 4078 4079 #if defined(JNG_SUPPORTED) 4080 /* 4081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4082 % % 4083 % % 4084 % % 4085 % R e a d O n e J N G I m a g e % 4086 % % 4087 % % 4088 % % 4089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4090 % 4091 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file 4092 % (minus the 8-byte signature) and returns it. It allocates the memory 4093 % necessary for the new Image structure and returns a pointer to the new 4094 % image. 4095 % 4096 % JNG support written by Glenn Randers-Pehrson, glennrp (at) image... 4097 % 4098 % The format of the ReadOneJNGImage method is: 4099 % 4100 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info, 4101 % ExceptionInfo *exception) 4102 % 4103 % A description of each parameter follows: 4104 % 4105 % o mng_info: Specifies a pointer to a MngInfo structure. 4106 % 4107 % o image_info: the image info. 4108 % 4109 % o exception: return any errors or warnings in this structure. 4110 % 4111 */ 4112 static Image *ReadOneJNGImage(MngInfo *mng_info, 4113 const ImageInfo *image_info, ExceptionInfo *exception) 4114 { 4115 Image 4116 *alpha_image, 4117 *color_image, 4118 *image, 4119 *jng_image; 4120 4121 ImageInfo 4122 *alpha_image_info, 4123 *color_image_info; 4124 4125 MagickBooleanType 4126 logging; 4127 4128 ssize_t 4129 y; 4130 4131 MagickBooleanType 4132 status; 4133 4134 png_uint_32 4135 jng_height, 4136 jng_width; 4137 4138 png_byte 4139 jng_color_type, 4140 jng_image_sample_depth, 4141 jng_image_compression_method, 4142 jng_image_interlace_method, 4143 jng_alpha_sample_depth, 4144 jng_alpha_compression_method, 4145 jng_alpha_filter_method, 4146 jng_alpha_interlace_method; 4147 4148 register const Quantum 4149 *s; 4150 4151 register ssize_t 4152 i, 4153 x; 4154 4155 register Quantum 4156 *q; 4157 4158 register unsigned char 4159 *p; 4160 4161 unsigned int 4162 read_JSEP, 4163 reading_idat; 4164 4165 size_t 4166 length; 4167 4168 jng_alpha_compression_method=0; 4169 jng_alpha_sample_depth=8; 4170 jng_color_type=0; 4171 jng_height=0; 4172 jng_width=0; 4173 alpha_image=(Image *) NULL; 4174 color_image=(Image *) NULL; 4175 alpha_image_info=(ImageInfo *) NULL; 4176 color_image_info=(ImageInfo *) NULL; 4177 4178 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 4179 " Enter ReadOneJNGImage()"); 4180 4181 image=mng_info->image; 4182 4183 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 4184 { 4185 /* 4186 Allocate next image structure. 4187 */ 4188 if (logging != MagickFalse) 4189 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4190 " AcquireNextImage()"); 4191 4192 AcquireNextImage(image_info,image,exception); 4193 4194 if (GetNextImageInList(image) == (Image *) NULL) 4195 return((Image *) NULL); 4196 4197 image=SyncNextImageInList(image); 4198 } 4199 mng_info->image=image; 4200 4201 /* 4202 Signature bytes have already been read. 4203 */ 4204 4205 read_JSEP=MagickFalse; 4206 reading_idat=MagickFalse; 4207 for (;;) 4208 { 4209 char 4210 type[MagickPathExtent]; 4211 4212 unsigned char 4213 *chunk; 4214 4215 unsigned int 4216 count; 4217 4218 /* 4219 Read a new JNG chunk. 4220 */ 4221 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 4222 2*GetBlobSize(image)); 4223 4224 if (status == MagickFalse) 4225 break; 4226 4227 type[0]='\0'; 4228 (void) ConcatenateMagickString(type,"errr",MagickPathExtent); 4229 length=ReadBlobMSBLong(image); 4230 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type); 4231 4232 if (logging != MagickFalse) 4233 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4234 " Reading JNG chunk type %c%c%c%c, length: %.20g", 4235 type[0],type[1],type[2],type[3],(double) length); 4236 4237 if (length > PNG_UINT_31_MAX || count == 0) 4238 ThrowReaderException(CorruptImageError,"CorruptImage"); 4239 4240 p=NULL; 4241 chunk=(unsigned char *) NULL; 4242 4243 if (length != 0) 4244 { 4245 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); 4246 4247 if (chunk == (unsigned char *) NULL) 4248 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4249 4250 for (i=0; i < (ssize_t) length; i++) 4251 chunk[i]=(unsigned char) ReadBlobByte(image); 4252 4253 p=chunk; 4254 } 4255 4256 (void) ReadBlobMSBLong(image); /* read crc word */ 4257 4258 if (memcmp(type,mng_JHDR,4) == 0) 4259 { 4260 if (length == 16) 4261 { 4262 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 4263 (p[2] << 8) | p[3]); 4264 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 4265 (p[6] << 8) | p[7]); 4266 if ((jng_width == 0) || (jng_height == 0)) 4267 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 4268 jng_color_type=p[8]; 4269 jng_image_sample_depth=p[9]; 4270 jng_image_compression_method=p[10]; 4271 jng_image_interlace_method=p[11]; 4272 4273 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace : 4274 NoInterlace; 4275 4276 jng_alpha_sample_depth=p[12]; 4277 jng_alpha_compression_method=p[13]; 4278 jng_alpha_filter_method=p[14]; 4279 jng_alpha_interlace_method=p[15]; 4280 4281 if (logging != MagickFalse) 4282 { 4283 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4284 " jng_width: %16lu, jng_height: %16lu\n" 4285 " jng_color_type: %16d, jng_image_sample_depth: %3d\n" 4286 " jng_image_compression_method:%3d", 4287 (unsigned long) jng_width, (unsigned long) jng_height, 4288 jng_color_type, jng_image_sample_depth, 4289 jng_image_compression_method); 4290 4291 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4292 " jng_image_interlace_method: %3d" 4293 " jng_alpha_sample_depth: %3d", 4294 jng_image_interlace_method, 4295 jng_alpha_sample_depth); 4296 4297 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4298 " jng_alpha_compression_method:%3d\n" 4299 " jng_alpha_filter_method: %3d\n" 4300 " jng_alpha_interlace_method: %3d", 4301 jng_alpha_compression_method, 4302 jng_alpha_filter_method, 4303 jng_alpha_interlace_method); 4304 } 4305 } 4306 4307 if (length != 0) 4308 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4309 4310 continue; 4311 } 4312 4313 4314 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) && 4315 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) || 4316 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0))) 4317 { 4318 /* 4319 o create color_image 4320 o open color_blob, attached to color_image 4321 o if (color type has alpha) 4322 open alpha_blob, attached to alpha_image 4323 */ 4324 4325 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo)); 4326 4327 if (color_image_info == (ImageInfo *) NULL) 4328 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4329 4330 GetImageInfo(color_image_info); 4331 color_image=AcquireImage(color_image_info,exception); 4332 4333 if (color_image == (Image *) NULL) 4334 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4335 4336 if (logging != MagickFalse) 4337 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4338 " Creating color_blob."); 4339 4340 (void) AcquireUniqueFilename(color_image->filename); 4341 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode, 4342 exception); 4343 4344 if (status == MagickFalse) 4345 return((Image *) NULL); 4346 4347 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12)) 4348 { 4349 alpha_image_info=(ImageInfo *) 4350 AcquireMagickMemory(sizeof(ImageInfo)); 4351 4352 if (alpha_image_info == (ImageInfo *) NULL) 4353 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4354 4355 GetImageInfo(alpha_image_info); 4356 alpha_image=AcquireImage(alpha_image_info,exception); 4357 4358 if (alpha_image == (Image *) NULL) 4359 { 4360 alpha_image=DestroyImage(alpha_image); 4361 ThrowReaderException(ResourceLimitError, 4362 "MemoryAllocationFailed"); 4363 } 4364 4365 if (logging != MagickFalse) 4366 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4367 " Creating alpha_blob."); 4368 4369 (void) AcquireUniqueFilename(alpha_image->filename); 4370 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode, 4371 exception); 4372 4373 if (status == MagickFalse) 4374 return((Image *) NULL); 4375 4376 if (jng_alpha_compression_method == 0) 4377 { 4378 unsigned char 4379 data[18]; 4380 4381 if (logging != MagickFalse) 4382 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4383 " Writing IHDR chunk to alpha_blob."); 4384 4385 (void) WriteBlob(alpha_image,8,(const unsigned char *) 4386 "\211PNG\r\n\032\n"); 4387 4388 (void) WriteBlobMSBULong(alpha_image,13L); 4389 PNGType(data,mng_IHDR); 4390 LogPNGChunk(logging,mng_IHDR,13L); 4391 PNGLong(data+4,jng_width); 4392 PNGLong(data+8,jng_height); 4393 data[12]=jng_alpha_sample_depth; 4394 data[13]=0; /* color_type gray */ 4395 data[14]=0; /* compression method 0 */ 4396 data[15]=0; /* filter_method 0 */ 4397 data[16]=0; /* interlace_method 0 */ 4398 (void) WriteBlob(alpha_image,17,data); 4399 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17)); 4400 } 4401 } 4402 reading_idat=MagickTrue; 4403 } 4404 4405 if (memcmp(type,mng_JDAT,4) == 0) 4406 { 4407 /* Copy chunk to color_image->blob */ 4408 4409 if (logging != MagickFalse) 4410 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4411 " Copying JDAT chunk data to color_blob."); 4412 4413 (void) WriteBlob(color_image,length,chunk); 4414 4415 if (length != 0) 4416 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4417 4418 continue; 4419 } 4420 4421 if (memcmp(type,mng_IDAT,4) == 0) 4422 { 4423 png_byte 4424 data[5]; 4425 4426 /* Copy IDAT header and chunk data to alpha_image->blob */ 4427 4428 if (alpha_image != NULL && image_info->ping == MagickFalse) 4429 { 4430 if (logging != MagickFalse) 4431 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4432 " Copying IDAT chunk data to alpha_blob."); 4433 4434 (void) WriteBlobMSBULong(alpha_image,(size_t) length); 4435 PNGType(data,mng_IDAT); 4436 LogPNGChunk(logging,mng_IDAT,length); 4437 (void) WriteBlob(alpha_image,4,data); 4438 (void) WriteBlob(alpha_image,length,chunk); 4439 (void) WriteBlobMSBULong(alpha_image, 4440 crc32(crc32(0,data,4),chunk,(uInt) length)); 4441 } 4442 4443 if (length != 0) 4444 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4445 4446 continue; 4447 } 4448 4449 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0)) 4450 { 4451 /* Copy chunk data to alpha_image->blob */ 4452 4453 if (alpha_image != NULL && image_info->ping == MagickFalse) 4454 { 4455 if (logging != MagickFalse) 4456 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4457 " Copying JDAA chunk data to alpha_blob."); 4458 4459 (void) WriteBlob(alpha_image,length,chunk); 4460 } 4461 4462 if (length != 0) 4463 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4464 4465 continue; 4466 } 4467 4468 if (memcmp(type,mng_JSEP,4) == 0) 4469 { 4470 read_JSEP=MagickTrue; 4471 4472 if (length != 0) 4473 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4474 4475 continue; 4476 } 4477 4478 if (memcmp(type,mng_bKGD,4) == 0) 4479 { 4480 if (length == 2) 4481 { 4482 image->background_color.red=ScaleCharToQuantum(p[1]); 4483 image->background_color.green=image->background_color.red; 4484 image->background_color.blue=image->background_color.red; 4485 } 4486 4487 if (length == 6) 4488 { 4489 image->background_color.red=ScaleCharToQuantum(p[1]); 4490 image->background_color.green=ScaleCharToQuantum(p[3]); 4491 image->background_color.blue=ScaleCharToQuantum(p[5]); 4492 } 4493 4494 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4495 continue; 4496 } 4497 4498 if (memcmp(type,mng_gAMA,4) == 0) 4499 { 4500 if (length == 4) 4501 image->gamma=((float) mng_get_long(p))*0.00001; 4502 4503 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4504 continue; 4505 } 4506 4507 if (memcmp(type,mng_cHRM,4) == 0) 4508 { 4509 if (length == 32) 4510 { 4511 image->chromaticity.white_point.x=0.00001*mng_get_long(p); 4512 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]); 4513 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]); 4514 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]); 4515 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]); 4516 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]); 4517 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]); 4518 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]); 4519 } 4520 4521 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4522 continue; 4523 } 4524 4525 if (memcmp(type,mng_sRGB,4) == 0) 4526 { 4527 if (length == 1) 4528 { 4529 image->rendering_intent= 4530 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]); 4531 image->gamma=1.000f/2.200f; 4532 image->chromaticity.red_primary.x=0.6400f; 4533 image->chromaticity.red_primary.y=0.3300f; 4534 image->chromaticity.green_primary.x=0.3000f; 4535 image->chromaticity.green_primary.y=0.6000f; 4536 image->chromaticity.blue_primary.x=0.1500f; 4537 image->chromaticity.blue_primary.y=0.0600f; 4538 image->chromaticity.white_point.x=0.3127f; 4539 image->chromaticity.white_point.y=0.3290f; 4540 } 4541 4542 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4543 continue; 4544 } 4545 4546 if (memcmp(type,mng_oFFs,4) == 0) 4547 { 4548 if (length > 8) 4549 { 4550 image->page.x=(ssize_t) mng_get_long(p); 4551 image->page.y=(ssize_t) mng_get_long(&p[4]); 4552 4553 if ((int) p[8] != 0) 4554 { 4555 image->page.x/=10000; 4556 image->page.y/=10000; 4557 } 4558 } 4559 4560 if (length != 0) 4561 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4562 4563 continue; 4564 } 4565 4566 if (memcmp(type,mng_pHYs,4) == 0) 4567 { 4568 if (length > 8) 4569 { 4570 image->resolution.x=(double) mng_get_long(p); 4571 image->resolution.y=(double) mng_get_long(&p[4]); 4572 if ((int) p[8] == PNG_RESOLUTION_METER) 4573 { 4574 image->units=PixelsPerCentimeterResolution; 4575 image->resolution.x=image->resolution.x/100.0f; 4576 image->resolution.y=image->resolution.y/100.0f; 4577 } 4578 } 4579 4580 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4581 continue; 4582 } 4583 4584 #if 0 4585 if (memcmp(type,mng_iCCP,4) == 0) 4586 { 4587 /* To do: */ 4588 if (length != 0) 4589 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4590 4591 continue; 4592 } 4593 #endif 4594 4595 if (length != 0) 4596 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 4597 4598 if (memcmp(type,mng_IEND,4)) 4599 continue; 4600 4601 break; 4602 } 4603 4604 4605 /* IEND found */ 4606 4607 /* 4608 Finish up reading image data: 4609 4610 o read main image from color_blob. 4611 4612 o close color_blob. 4613 4614 o if (color_type has alpha) 4615 if alpha_encoding is PNG 4616 read secondary image from alpha_blob via ReadPNG 4617 if alpha_encoding is JPEG 4618 read secondary image from alpha_blob via ReadJPEG 4619 4620 o close alpha_blob. 4621 4622 o copy intensity of secondary image into 4623 alpha samples of main image. 4624 4625 o destroy the secondary image. 4626 */ 4627 4628 if (color_image_info == (ImageInfo *) NULL) 4629 { 4630 assert(color_image == (Image *) NULL); 4631 assert(alpha_image == (Image *) NULL); 4632 return((Image *) NULL); 4633 } 4634 4635 if (color_image == (Image *) NULL) 4636 { 4637 assert(alpha_image == (Image *) NULL); 4638 return((Image *) NULL); 4639 } 4640 4641 (void) SeekBlob(color_image,0,SEEK_SET); 4642 4643 if (logging != MagickFalse) 4644 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4645 " Reading jng_image from color_blob."); 4646 4647 assert(color_image_info != (ImageInfo *) NULL); 4648 (void) FormatLocaleString(color_image_info->filename,MagickPathExtent,"%s", 4649 color_image->filename); 4650 4651 color_image_info->ping=MagickFalse; /* To do: avoid this */ 4652 jng_image=ReadImage(color_image_info,exception); 4653 4654 (void) RelinquishUniqueFileResource(color_image->filename); 4655 color_image=DestroyImage(color_image); 4656 color_image_info=DestroyImageInfo(color_image_info); 4657 4658 if (jng_image == (Image *) NULL) 4659 return((Image *) NULL); 4660 4661 if (logging != MagickFalse) 4662 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4663 " Copying jng_image pixels to main image."); 4664 4665 image->rows=jng_height; 4666 image->columns=jng_width; 4667 4668 status=SetImageExtent(image,image->columns,image->rows,exception); 4669 if (status == MagickFalse) 4670 return(DestroyImageList(image)); 4671 4672 for (y=0; y < (ssize_t) image->rows; y++) 4673 { 4674 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception); 4675 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 4676 for (x=(ssize_t) image->columns; x != 0; x--) 4677 { 4678 SetPixelRed(image,GetPixelRed(jng_image,s),q); 4679 SetPixelGreen(image,GetPixelGreen(jng_image,s),q); 4680 SetPixelBlue(image,GetPixelBlue(jng_image,s),q); 4681 q+=GetPixelChannels(image); 4682 s+=GetPixelChannels(jng_image); 4683 } 4684 4685 if (SyncAuthenticPixels(image,exception) == MagickFalse) 4686 break; 4687 } 4688 4689 jng_image=DestroyImage(jng_image); 4690 4691 if (image_info->ping == MagickFalse) 4692 { 4693 if (jng_color_type >= 12) 4694 { 4695 if (jng_alpha_compression_method == 0) 4696 { 4697 png_byte 4698 data[5]; 4699 (void) WriteBlobMSBULong(alpha_image,0x00000000L); 4700 PNGType(data,mng_IEND); 4701 LogPNGChunk(logging,mng_IEND,0L); 4702 (void) WriteBlob(alpha_image,4,data); 4703 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4)); 4704 } 4705 4706 (void) CloseBlob(alpha_image); 4707 4708 if (logging != MagickFalse) 4709 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4710 " Reading alpha from alpha_blob."); 4711 4712 (void) FormatLocaleString(alpha_image_info->filename,MagickPathExtent, 4713 "%s",alpha_image->filename); 4714 4715 jng_image=ReadImage(alpha_image_info,exception); 4716 4717 if (jng_image != (Image *) NULL) 4718 for (y=0; y < (ssize_t) image->rows; y++) 4719 { 4720 s=GetVirtualPixels(jng_image,0,y,image->columns,1, 4721 exception); 4722 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 4723 4724 if (image->alpha_trait != UndefinedPixelTrait) 4725 for (x=(ssize_t) image->columns; x != 0; x--) 4726 { 4727 SetPixelAlpha(image,GetPixelRed(jng_image,s),q); 4728 q+=GetPixelChannels(image); 4729 s+=GetPixelChannels(jng_image); 4730 } 4731 4732 else 4733 for (x=(ssize_t) image->columns; x != 0; x--) 4734 { 4735 SetPixelAlpha(image,GetPixelRed(jng_image,s),q); 4736 if (GetPixelAlpha(image,q) != OpaqueAlpha) 4737 image->alpha_trait=BlendPixelTrait; 4738 q+=GetPixelChannels(image); 4739 s+=GetPixelChannels(jng_image); 4740 } 4741 4742 if (SyncAuthenticPixels(image,exception) == MagickFalse) 4743 break; 4744 } 4745 (void) RelinquishUniqueFileResource(alpha_image->filename); 4746 alpha_image=DestroyImage(alpha_image); 4747 alpha_image_info=DestroyImageInfo(alpha_image_info); 4748 if (jng_image != (Image *) NULL) 4749 jng_image=DestroyImage(jng_image); 4750 } 4751 } 4752 4753 /* Read the JNG image. */ 4754 4755 if (mng_info->mng_type == 0) 4756 { 4757 mng_info->mng_width=jng_width; 4758 mng_info->mng_height=jng_height; 4759 } 4760 4761 if (image->page.width == 0 && image->page.height == 0) 4762 { 4763 image->page.width=jng_width; 4764 image->page.height=jng_height; 4765 } 4766 4767 if (image->page.x == 0 && image->page.y == 0) 4768 { 4769 image->page.x=mng_info->x_off[mng_info->object_id]; 4770 image->page.y=mng_info->y_off[mng_info->object_id]; 4771 } 4772 4773 else 4774 { 4775 image->page.y=mng_info->y_off[mng_info->object_id]; 4776 } 4777 4778 mng_info->image_found++; 4779 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image), 4780 2*GetBlobSize(image)); 4781 4782 if (status == MagickFalse) 4783 return((Image *) NULL); 4784 4785 if (logging != MagickFalse) 4786 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4787 " exit ReadOneJNGImage()"); 4788 4789 return(image); 4790 } 4791 4792 /* 4793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4794 % % 4795 % % 4796 % % 4797 % R e a d J N G I m a g e % 4798 % % 4799 % % 4800 % % 4801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4802 % 4803 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file 4804 % (including the 8-byte signature) and returns it. It allocates the memory 4805 % necessary for the new Image structure and returns a pointer to the new 4806 % image. 4807 % 4808 % JNG support written by Glenn Randers-Pehrson, glennrp (at) image... 4809 % 4810 % The format of the ReadJNGImage method is: 4811 % 4812 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo 4813 % *exception) 4814 % 4815 % A description of each parameter follows: 4816 % 4817 % o image_info: the image info. 4818 % 4819 % o exception: return any errors or warnings in this structure. 4820 % 4821 */ 4822 4823 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 4824 { 4825 Image 4826 *image; 4827 4828 MagickBooleanType 4829 have_mng_structure, 4830 logging, 4831 status; 4832 4833 MngInfo 4834 *mng_info; 4835 4836 char 4837 magic_number[MagickPathExtent]; 4838 4839 size_t 4840 count; 4841 4842 /* 4843 Open image file. 4844 */ 4845 assert(image_info != (const ImageInfo *) NULL); 4846 assert(image_info->signature == MagickCoreSignature); 4847 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename); 4848 assert(exception != (ExceptionInfo *) NULL); 4849 assert(exception->signature == MagickCoreSignature); 4850 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()"); 4851 image=AcquireImage(image_info,exception); 4852 mng_info=(MngInfo *) NULL; 4853 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 4854 4855 if (status == MagickFalse) 4856 return((Image *) NULL); 4857 4858 if (LocaleCompare(image_info->magick,"JNG") != 0) 4859 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 4860 4861 /* Verify JNG signature. */ 4862 4863 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number); 4864 4865 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0) 4866 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 4867 4868 /* Allocate a MngInfo structure. */ 4869 4870 have_mng_structure=MagickFalse; 4871 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info)); 4872 4873 if (mng_info == (MngInfo *) NULL) 4874 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 4875 4876 /* Initialize members of the MngInfo structure. */ 4877 4878 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 4879 have_mng_structure=MagickTrue; 4880 4881 mng_info->image=image; 4882 image=ReadOneJNGImage(mng_info,image_info,exception); 4883 MngInfoFreeStruct(mng_info,&have_mng_structure); 4884 4885 if (image == (Image *) NULL) 4886 { 4887 if (logging != MagickFalse) 4888 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4889 "exit ReadJNGImage() with error"); 4890 4891 return((Image *) NULL); 4892 } 4893 (void) CloseBlob(image); 4894 4895 if (image->columns == 0 || image->rows == 0) 4896 { 4897 if (logging != MagickFalse) 4898 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 4899 "exit ReadJNGImage() with error"); 4900 4901 ThrowReaderException(CorruptImageError,"CorruptImage"); 4902 } 4903 4904 if (logging != MagickFalse) 4905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()"); 4906 4907 return(image); 4908 } 4909 #endif 4910 4911 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 4912 { 4913 char 4914 page_geometry[MagickPathExtent]; 4915 4916 Image 4917 *image; 4918 4919 MagickBooleanType 4920 logging, 4921 have_mng_structure; 4922 4923 volatile int 4924 first_mng_object, 4925 object_id, 4926 term_chunk_found, 4927 skip_to_iend; 4928 4929 volatile ssize_t 4930 image_count=0; 4931 4932 MagickBooleanType 4933 status; 4934 4935 MagickOffsetType 4936 offset; 4937 4938 MngInfo 4939 *mng_info; 4940 4941 MngBox 4942 default_fb, 4943 fb, 4944 previous_fb; 4945 4946 #if defined(MNG_INSERT_LAYERS) 4947 PixelInfo 4948 mng_background_color; 4949 #endif 4950 4951 register unsigned char 4952 *p; 4953 4954 register ssize_t 4955 i; 4956 4957 size_t 4958 count; 4959 4960 ssize_t 4961 loop_level; 4962 4963 volatile short 4964 skipping_loop; 4965 4966 #if defined(MNG_INSERT_LAYERS) 4967 unsigned int 4968 mandatory_back=0; 4969 #endif 4970 4971 volatile unsigned int 4972 #ifdef MNG_OBJECT_BUFFERS 4973 mng_background_object=0, 4974 #endif 4975 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */ 4976 4977 size_t 4978 default_frame_timeout, 4979 frame_timeout, 4980 #if defined(MNG_INSERT_LAYERS) 4981 image_height, 4982 image_width, 4983 #endif 4984 length; 4985 4986 /* These delays are all measured in image ticks_per_second, 4987 * not in MNG ticks_per_second 4988 */ 4989 volatile size_t 4990 default_frame_delay, 4991 final_delay, 4992 final_image_delay, 4993 frame_delay, 4994 #if defined(MNG_INSERT_LAYERS) 4995 insert_layers, 4996 #endif 4997 mng_iterations=1, 4998 simplicity=0, 4999 subframe_height=0, 5000 subframe_width=0; 5001 5002 previous_fb.top=0; 5003 previous_fb.bottom=0; 5004 previous_fb.left=0; 5005 previous_fb.right=0; 5006 default_fb.top=0; 5007 default_fb.bottom=0; 5008 default_fb.left=0; 5009 default_fb.right=0; 5010 5011 /* Open image file. */ 5012 5013 assert(image_info != (const ImageInfo *) NULL); 5014 assert(image_info->signature == MagickCoreSignature); 5015 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename); 5016 assert(exception != (ExceptionInfo *) NULL); 5017 assert(exception->signature == MagickCoreSignature); 5018 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()"); 5019 image=AcquireImage(image_info,exception); 5020 mng_info=(MngInfo *) NULL; 5021 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 5022 5023 if (status == MagickFalse) 5024 return((Image *) NULL); 5025 5026 first_mng_object=MagickFalse; 5027 skipping_loop=(-1); 5028 have_mng_structure=MagickFalse; 5029 5030 /* Allocate a MngInfo structure. */ 5031 5032 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 5033 5034 if (mng_info == (MngInfo *) NULL) 5035 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 5036 5037 /* Initialize members of the MngInfo structure. */ 5038 5039 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 5040 mng_info->image=image; 5041 have_mng_structure=MagickTrue; 5042 5043 if (LocaleCompare(image_info->magick,"MNG") == 0) 5044 { 5045 char 5046 magic_number[MagickPathExtent]; 5047 5048 /* Verify MNG signature. */ 5049 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number); 5050 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0) 5051 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 5052 5053 /* Initialize some nonzero members of the MngInfo structure. */ 5054 for (i=0; i < MNG_MAX_OBJECTS; i++) 5055 { 5056 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX; 5057 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX; 5058 } 5059 mng_info->exists[0]=MagickTrue; 5060 } 5061 5062 first_mng_object=MagickTrue; 5063 mng_type=0; 5064 #if defined(MNG_INSERT_LAYERS) 5065 insert_layers=MagickFalse; /* should be False when converting or mogrifying */ 5066 #endif 5067 default_frame_delay=0; 5068 default_frame_timeout=0; 5069 frame_delay=0; 5070 final_delay=1; 5071 mng_info->ticks_per_second=1UL*image->ticks_per_second; 5072 object_id=0; 5073 skip_to_iend=MagickFalse; 5074 term_chunk_found=MagickFalse; 5075 mng_info->framing_mode=1; 5076 #if defined(MNG_INSERT_LAYERS) 5077 mandatory_back=MagickFalse; 5078 #endif 5079 #if defined(MNG_INSERT_LAYERS) 5080 mng_background_color=image->background_color; 5081 #endif 5082 default_fb=mng_info->frame; 5083 previous_fb=mng_info->frame; 5084 do 5085 { 5086 char 5087 type[MagickPathExtent]; 5088 5089 if (LocaleCompare(image_info->magick,"MNG") == 0) 5090 { 5091 unsigned char 5092 *chunk; 5093 5094 /* 5095 Read a new chunk. 5096 */ 5097 type[0]='\0'; 5098 (void) ConcatenateMagickString(type,"errr",MagickPathExtent); 5099 length=ReadBlobMSBLong(image); 5100 count=(size_t) ReadBlob(image,4,(unsigned char *) type); 5101 5102 if (logging != MagickFalse) 5103 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5104 " Reading MNG chunk type %c%c%c%c, length: %.20g", 5105 type[0],type[1],type[2],type[3],(double) length); 5106 5107 if (length > PNG_UINT_31_MAX) 5108 { 5109 status=MagickFalse; 5110 break; 5111 } 5112 5113 if (count == 0) 5114 ThrowReaderException(CorruptImageError,"CorruptImage"); 5115 5116 p=NULL; 5117 chunk=(unsigned char *) NULL; 5118 5119 if (length != 0) 5120 { 5121 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); 5122 5123 if (chunk == (unsigned char *) NULL) 5124 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 5125 5126 for (i=0; i < (ssize_t) length; i++) 5127 chunk[i]=(unsigned char) ReadBlobByte(image); 5128 5129 p=chunk; 5130 } 5131 5132 (void) ReadBlobMSBLong(image); /* read crc word */ 5133 5134 #if !defined(JNG_SUPPORTED) 5135 if (memcmp(type,mng_JHDR,4) == 0) 5136 { 5137 skip_to_iend=MagickTrue; 5138 5139 if (mng_info->jhdr_warning == 0) 5140 (void) ThrowMagickException(exception,GetMagickModule(), 5141 CoderError,"JNGCompressNotSupported","`%s'",image->filename); 5142 5143 mng_info->jhdr_warning++; 5144 } 5145 #endif 5146 if (memcmp(type,mng_DHDR,4) == 0) 5147 { 5148 skip_to_iend=MagickTrue; 5149 5150 if (mng_info->dhdr_warning == 0) 5151 (void) ThrowMagickException(exception,GetMagickModule(), 5152 CoderError,"DeltaPNGNotSupported","`%s'",image->filename); 5153 5154 mng_info->dhdr_warning++; 5155 } 5156 if (memcmp(type,mng_MEND,4) == 0) 5157 break; 5158 5159 if (skip_to_iend) 5160 { 5161 if (memcmp(type,mng_IEND,4) == 0) 5162 skip_to_iend=MagickFalse; 5163 5164 if (length != 0) 5165 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5166 5167 if (logging != MagickFalse) 5168 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5169 " Skip to IEND."); 5170 5171 continue; 5172 } 5173 5174 if (memcmp(type,mng_MHDR,4) == 0) 5175 { 5176 if (length != 28) 5177 { 5178 if (chunk) 5179 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5180 ThrowReaderException(CorruptImageError,"CorruptImage"); 5181 } 5182 5183 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 5184 (p[2] << 8) | p[3]); 5185 5186 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 5187 (p[6] << 8) | p[7]); 5188 5189 if (logging != MagickFalse) 5190 { 5191 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5192 " MNG width: %.20g",(double) mng_info->mng_width); 5193 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5194 " MNG height: %.20g",(double) mng_info->mng_height); 5195 } 5196 5197 p+=8; 5198 mng_info->ticks_per_second=(size_t) mng_get_long(p); 5199 5200 if (mng_info->ticks_per_second == 0) 5201 default_frame_delay=0; 5202 5203 else 5204 default_frame_delay=1UL*image->ticks_per_second/ 5205 mng_info->ticks_per_second; 5206 5207 frame_delay=default_frame_delay; 5208 simplicity=0; 5209 5210 p+=16; 5211 simplicity=(size_t) mng_get_long(p); 5212 5213 mng_type=1; /* Full MNG */ 5214 5215 if ((simplicity != 0) && ((simplicity | 11) == 11)) 5216 mng_type=2; /* LC */ 5217 5218 if ((simplicity != 0) && ((simplicity | 9) == 9)) 5219 mng_type=3; /* VLC */ 5220 5221 #if defined(MNG_INSERT_LAYERS) 5222 if (mng_type != 3) 5223 insert_layers=MagickTrue; 5224 #endif 5225 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 5226 { 5227 /* Allocate next image structure. */ 5228 AcquireNextImage(image_info,image,exception); 5229 5230 if (GetNextImageInList(image) == (Image *) NULL) 5231 return((Image *) NULL); 5232 5233 image=SyncNextImageInList(image); 5234 mng_info->image=image; 5235 } 5236 5237 if ((mng_info->mng_width > 65535L) || 5238 (mng_info->mng_height > 65535L)) 5239 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit"); 5240 5241 (void) FormatLocaleString(page_geometry,MagickPathExtent, 5242 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double) 5243 mng_info->mng_height); 5244 5245 mng_info->frame.left=0; 5246 mng_info->frame.right=(ssize_t) mng_info->mng_width; 5247 mng_info->frame.top=0; 5248 mng_info->frame.bottom=(ssize_t) mng_info->mng_height; 5249 mng_info->clip=default_fb=previous_fb=mng_info->frame; 5250 5251 for (i=0; i < MNG_MAX_OBJECTS; i++) 5252 mng_info->object_clip[i]=mng_info->frame; 5253 5254 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5255 continue; 5256 } 5257 5258 if (memcmp(type,mng_TERM,4) == 0) 5259 { 5260 int 5261 repeat=0; 5262 5263 if (length != 0) 5264 repeat=p[0]; 5265 5266 if (repeat == 3) 5267 { 5268 final_delay=(png_uint_32) mng_get_long(&p[2]); 5269 mng_iterations=(png_uint_32) mng_get_long(&p[6]); 5270 5271 if (mng_iterations == PNG_UINT_31_MAX) 5272 mng_iterations=0; 5273 5274 image->iterations=mng_iterations; 5275 term_chunk_found=MagickTrue; 5276 } 5277 5278 if (logging != MagickFalse) 5279 { 5280 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5281 " repeat=%d, final_delay=%.20g, iterations=%.20g", 5282 repeat,(double) final_delay, (double) image->iterations); 5283 } 5284 5285 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5286 continue; 5287 } 5288 if (memcmp(type,mng_DEFI,4) == 0) 5289 { 5290 if (mng_type == 3) 5291 (void) ThrowMagickException(exception,GetMagickModule(), 5292 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'", 5293 image->filename); 5294 5295 if (length < 2) 5296 { 5297 if (chunk) 5298 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5299 ThrowReaderException(CorruptImageError,"CorruptImage"); 5300 } 5301 5302 object_id=(p[0] << 8) | p[1]; 5303 5304 if (mng_type == 2 && object_id != 0) 5305 (void) ThrowMagickException(exception,GetMagickModule(), 5306 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'", 5307 image->filename); 5308 5309 if (object_id > MNG_MAX_OBJECTS) 5310 { 5311 /* 5312 Instead of using a warning we should allocate a larger 5313 MngInfo structure and continue. 5314 */ 5315 (void) ThrowMagickException(exception,GetMagickModule(), 5316 CoderError,"object id too large","`%s'",image->filename); 5317 object_id=MNG_MAX_OBJECTS; 5318 } 5319 5320 if (mng_info->exists[object_id]) 5321 if (mng_info->frozen[object_id]) 5322 { 5323 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5324 (void) ThrowMagickException(exception, 5325 GetMagickModule(),CoderError, 5326 "DEFI cannot redefine a frozen MNG object","`%s'", 5327 image->filename); 5328 continue; 5329 } 5330 5331 mng_info->exists[object_id]=MagickTrue; 5332 5333 if (length > 2) 5334 mng_info->invisible[object_id]=p[2]; 5335 5336 /* 5337 Extract object offset info. 5338 */ 5339 if (length > 11) 5340 { 5341 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) | 5342 (p[5] << 16) | (p[6] << 8) | p[7]); 5343 5344 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) | 5345 (p[9] << 16) | (p[10] << 8) | p[11]); 5346 5347 if (logging != MagickFalse) 5348 { 5349 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5350 " x_off[%d]: %.20g, y_off[%d]: %.20g", 5351 object_id,(double) mng_info->x_off[object_id], 5352 object_id,(double) mng_info->y_off[object_id]); 5353 } 5354 } 5355 5356 /* 5357 Extract object clipping info. 5358 */ 5359 if (length > 27) 5360 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0, 5361 &p[12]); 5362 5363 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5364 continue; 5365 } 5366 if (memcmp(type,mng_bKGD,4) == 0) 5367 { 5368 mng_info->have_global_bkgd=MagickFalse; 5369 5370 if (length > 5) 5371 { 5372 mng_info->mng_global_bkgd.red= 5373 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); 5374 5375 mng_info->mng_global_bkgd.green= 5376 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); 5377 5378 mng_info->mng_global_bkgd.blue= 5379 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); 5380 5381 mng_info->have_global_bkgd=MagickTrue; 5382 } 5383 5384 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5385 continue; 5386 } 5387 if (memcmp(type,mng_BACK,4) == 0) 5388 { 5389 #if defined(MNG_INSERT_LAYERS) 5390 if (length > 6) 5391 mandatory_back=p[6]; 5392 5393 else 5394 mandatory_back=0; 5395 5396 if (mandatory_back && length > 5) 5397 { 5398 mng_background_color.red= 5399 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); 5400 5401 mng_background_color.green= 5402 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); 5403 5404 mng_background_color.blue= 5405 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); 5406 5407 mng_background_color.alpha=OpaqueAlpha; 5408 } 5409 5410 #ifdef MNG_OBJECT_BUFFERS 5411 if (length > 8) 5412 mng_background_object=(p[7] << 8) | p[8]; 5413 #endif 5414 #endif 5415 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5416 continue; 5417 } 5418 5419 if (memcmp(type,mng_PLTE,4) == 0) 5420 { 5421 /* Read global PLTE. */ 5422 5423 if (length && (length < 769)) 5424 { 5425 if (mng_info->global_plte == (png_colorp) NULL) 5426 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256, 5427 sizeof(*mng_info->global_plte)); 5428 5429 for (i=0; i < (ssize_t) (length/3); i++) 5430 { 5431 mng_info->global_plte[i].red=p[3*i]; 5432 mng_info->global_plte[i].green=p[3*i+1]; 5433 mng_info->global_plte[i].blue=p[3*i+2]; 5434 } 5435 5436 mng_info->global_plte_length=(unsigned int) (length/3); 5437 } 5438 #ifdef MNG_LOOSE 5439 for ( ; i < 256; i++) 5440 { 5441 mng_info->global_plte[i].red=i; 5442 mng_info->global_plte[i].green=i; 5443 mng_info->global_plte[i].blue=i; 5444 } 5445 5446 if (length != 0) 5447 mng_info->global_plte_length=256; 5448 #endif 5449 else 5450 mng_info->global_plte_length=0; 5451 5452 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5453 continue; 5454 } 5455 5456 if (memcmp(type,mng_tRNS,4) == 0) 5457 { 5458 /* read global tRNS */ 5459 5460 if (length > 0 && length < 257) 5461 for (i=0; i < (ssize_t) length; i++) 5462 mng_info->global_trns[i]=p[i]; 5463 5464 #ifdef MNG_LOOSE 5465 for ( ; i < 256; i++) 5466 mng_info->global_trns[i]=255; 5467 #endif 5468 mng_info->global_trns_length=(unsigned int) length; 5469 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5470 continue; 5471 } 5472 if (memcmp(type,mng_gAMA,4) == 0) 5473 { 5474 if (length == 4) 5475 { 5476 ssize_t 5477 igamma; 5478 5479 igamma=mng_get_long(p); 5480 mng_info->global_gamma=((float) igamma)*0.00001; 5481 mng_info->have_global_gama=MagickTrue; 5482 } 5483 5484 else 5485 mng_info->have_global_gama=MagickFalse; 5486 5487 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5488 continue; 5489 } 5490 5491 if (memcmp(type,mng_cHRM,4) == 0) 5492 { 5493 /* Read global cHRM */ 5494 5495 if (length == 32) 5496 { 5497 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p); 5498 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]); 5499 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]); 5500 mng_info->global_chrm.red_primary.y=0.00001* 5501 mng_get_long(&p[12]); 5502 mng_info->global_chrm.green_primary.x=0.00001* 5503 mng_get_long(&p[16]); 5504 mng_info->global_chrm.green_primary.y=0.00001* 5505 mng_get_long(&p[20]); 5506 mng_info->global_chrm.blue_primary.x=0.00001* 5507 mng_get_long(&p[24]); 5508 mng_info->global_chrm.blue_primary.y=0.00001* 5509 mng_get_long(&p[28]); 5510 mng_info->have_global_chrm=MagickTrue; 5511 } 5512 else 5513 mng_info->have_global_chrm=MagickFalse; 5514 5515 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5516 continue; 5517 } 5518 5519 if (memcmp(type,mng_sRGB,4) == 0) 5520 { 5521 /* 5522 Read global sRGB. 5523 */ 5524 if (length != 0) 5525 { 5526 mng_info->global_srgb_intent= 5527 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]); 5528 mng_info->have_global_srgb=MagickTrue; 5529 } 5530 else 5531 mng_info->have_global_srgb=MagickFalse; 5532 5533 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5534 continue; 5535 } 5536 5537 if (memcmp(type,mng_iCCP,4) == 0) 5538 { 5539 /* To do: */ 5540 5541 /* 5542 Read global iCCP. 5543 */ 5544 if (length != 0) 5545 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5546 5547 continue; 5548 } 5549 5550 if (memcmp(type,mng_FRAM,4) == 0) 5551 { 5552 if (mng_type == 3) 5553 (void) ThrowMagickException(exception,GetMagickModule(), 5554 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'", 5555 image->filename); 5556 5557 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4)) 5558 image->delay=frame_delay; 5559 5560 frame_delay=default_frame_delay; 5561 frame_timeout=default_frame_timeout; 5562 fb=default_fb; 5563 5564 if (length != 0) 5565 if (p[0]) 5566 mng_info->framing_mode=p[0]; 5567 5568 if (logging != MagickFalse) 5569 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5570 " Framing_mode=%d",mng_info->framing_mode); 5571 5572 if (length > 6) 5573 { 5574 /* Note the delay and frame clipping boundaries. */ 5575 5576 p++; /* framing mode */ 5577 5578 while (*p && ((p-chunk) < (ssize_t) length)) 5579 p++; /* frame name */ 5580 5581 p++; /* frame name terminator */ 5582 5583 if ((p-chunk) < (ssize_t) (length-4)) 5584 { 5585 int 5586 change_delay, 5587 change_timeout, 5588 change_clipping; 5589 5590 change_delay=(*p++); 5591 change_timeout=(*p++); 5592 change_clipping=(*p++); 5593 p++; /* change_sync */ 5594 5595 if (change_delay) 5596 { 5597 frame_delay=1UL*image->ticks_per_second* 5598 mng_get_long(p); 5599 5600 if (mng_info->ticks_per_second != 0) 5601 frame_delay/=mng_info->ticks_per_second; 5602 5603 else 5604 frame_delay=PNG_UINT_31_MAX; 5605 5606 if (change_delay == 2) 5607 default_frame_delay=frame_delay; 5608 5609 p+=4; 5610 5611 if (logging != MagickFalse) 5612 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5613 " Framing_delay=%.20g",(double) frame_delay); 5614 } 5615 5616 if (change_timeout) 5617 { 5618 frame_timeout=1UL*image->ticks_per_second* 5619 mng_get_long(p); 5620 5621 if (mng_info->ticks_per_second != 0) 5622 frame_timeout/=mng_info->ticks_per_second; 5623 5624 else 5625 frame_timeout=PNG_UINT_31_MAX; 5626 5627 if (change_timeout == 2) 5628 default_frame_timeout=frame_timeout; 5629 5630 p+=4; 5631 5632 if (logging != MagickFalse) 5633 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5634 " Framing_timeout=%.20g",(double) frame_timeout); 5635 } 5636 5637 if (change_clipping) 5638 { 5639 fb=mng_read_box(previous_fb,(char) p[0],&p[1]); 5640 p+=17; 5641 previous_fb=fb; 5642 5643 if (logging != MagickFalse) 5644 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5645 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g", 5646 (double) fb.left,(double) fb.right,(double) fb.top, 5647 (double) fb.bottom); 5648 5649 if (change_clipping == 2) 5650 default_fb=fb; 5651 } 5652 } 5653 } 5654 mng_info->clip=fb; 5655 mng_info->clip=mng_minimum_box(fb,mng_info->frame); 5656 5657 subframe_width=(size_t) (mng_info->clip.right 5658 -mng_info->clip.left); 5659 5660 subframe_height=(size_t) (mng_info->clip.bottom 5661 -mng_info->clip.top); 5662 /* 5663 Insert a background layer behind the frame if framing_mode is 4. 5664 */ 5665 #if defined(MNG_INSERT_LAYERS) 5666 if (logging != MagickFalse) 5667 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5668 " subframe_width=%.20g, subframe_height=%.20g",(double) 5669 subframe_width,(double) subframe_height); 5670 5671 if (insert_layers && (mng_info->framing_mode == 4) && 5672 (subframe_width) && (subframe_height)) 5673 { 5674 /* Allocate next image structure. */ 5675 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 5676 { 5677 AcquireNextImage(image_info,image,exception); 5678 5679 if (GetNextImageInList(image) == (Image *) NULL) 5680 { 5681 image=DestroyImageList(image); 5682 MngInfoFreeStruct(mng_info,&have_mng_structure); 5683 return((Image *) NULL); 5684 } 5685 5686 image=SyncNextImageInList(image); 5687 } 5688 5689 mng_info->image=image; 5690 5691 if (term_chunk_found) 5692 { 5693 image->start_loop=MagickTrue; 5694 image->iterations=mng_iterations; 5695 term_chunk_found=MagickFalse; 5696 } 5697 5698 else 5699 image->start_loop=MagickFalse; 5700 5701 image->columns=subframe_width; 5702 image->rows=subframe_height; 5703 image->page.width=subframe_width; 5704 image->page.height=subframe_height; 5705 image->page.x=mng_info->clip.left; 5706 image->page.y=mng_info->clip.top; 5707 image->background_color=mng_background_color; 5708 image->alpha_trait=UndefinedPixelTrait; 5709 image->delay=0; 5710 (void) SetImageBackgroundColor(image,exception); 5711 5712 if (logging != MagickFalse) 5713 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5714 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", 5715 (double) mng_info->clip.left,(double) mng_info->clip.right, 5716 (double) mng_info->clip.top,(double) mng_info->clip.bottom); 5717 } 5718 #endif 5719 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5720 continue; 5721 } 5722 5723 if (memcmp(type,mng_CLIP,4) == 0) 5724 { 5725 unsigned int 5726 first_object, 5727 last_object; 5728 5729 /* 5730 Read CLIP. 5731 */ 5732 if (length > 3) 5733 { 5734 first_object=(p[0] << 8) | p[1]; 5735 last_object=(p[2] << 8) | p[3]; 5736 p+=4; 5737 5738 for (i=(int) first_object; i <= (int) last_object; i++) 5739 { 5740 if (mng_info->exists[i] && !mng_info->frozen[i]) 5741 { 5742 MngBox 5743 box; 5744 5745 box=mng_info->object_clip[i]; 5746 if ((p-chunk) < (ssize_t) (length-17)) 5747 mng_info->object_clip[i]= 5748 mng_read_box(box,(char) p[0],&p[1]); 5749 } 5750 } 5751 5752 } 5753 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5754 continue; 5755 } 5756 5757 if (memcmp(type,mng_SAVE,4) == 0) 5758 { 5759 for (i=1; i < MNG_MAX_OBJECTS; i++) 5760 if (mng_info->exists[i]) 5761 { 5762 mng_info->frozen[i]=MagickTrue; 5763 #ifdef MNG_OBJECT_BUFFERS 5764 if (mng_info->ob[i] != (MngBuffer *) NULL) 5765 mng_info->ob[i]->frozen=MagickTrue; 5766 #endif 5767 } 5768 5769 if (length != 0) 5770 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5771 5772 continue; 5773 } 5774 5775 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0)) 5776 { 5777 /* Read DISC or SEEK. */ 5778 5779 if ((length == 0) || !memcmp(type,mng_SEEK,4)) 5780 { 5781 for (i=1; i < MNG_MAX_OBJECTS; i++) 5782 MngInfoDiscardObject(mng_info,i); 5783 } 5784 5785 else 5786 { 5787 register ssize_t 5788 j; 5789 5790 for (j=1; j < (ssize_t) length; j+=2) 5791 { 5792 i=p[j-1] << 8 | p[j]; 5793 MngInfoDiscardObject(mng_info,i); 5794 } 5795 } 5796 5797 if (length != 0) 5798 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5799 5800 continue; 5801 } 5802 5803 if (memcmp(type,mng_MOVE,4) == 0) 5804 { 5805 size_t 5806 first_object, 5807 last_object; 5808 5809 /* read MOVE */ 5810 5811 if (length > 3) 5812 { 5813 first_object=(p[0] << 8) | p[1]; 5814 last_object=(p[2] << 8) | p[3]; 5815 p+=4; 5816 5817 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++) 5818 { 5819 if (mng_info->exists[i] && !mng_info->frozen[i] && 5820 (p-chunk) < (ssize_t) (length-8)) 5821 { 5822 MngPair 5823 new_pair; 5824 5825 MngPair 5826 old_pair; 5827 5828 old_pair.a=mng_info->x_off[i]; 5829 old_pair.b=mng_info->y_off[i]; 5830 new_pair=mng_read_pair(old_pair,(int) p[0],&p[1]); 5831 mng_info->x_off[i]=new_pair.a; 5832 mng_info->y_off[i]=new_pair.b; 5833 } 5834 } 5835 } 5836 5837 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5838 continue; 5839 } 5840 5841 if (memcmp(type,mng_LOOP,4) == 0) 5842 { 5843 ssize_t loop_iters=1; 5844 if (length > 4) 5845 { 5846 loop_level=chunk[0]; 5847 mng_info->loop_active[loop_level]=1; /* mark loop active */ 5848 5849 /* Record starting point. */ 5850 loop_iters=mng_get_long(&chunk[1]); 5851 5852 if (logging != MagickFalse) 5853 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5854 " LOOP level %.20g has %.20g iterations ", 5855 (double) loop_level, (double) loop_iters); 5856 5857 if (loop_iters == 0) 5858 skipping_loop=loop_level; 5859 5860 else 5861 { 5862 mng_info->loop_jump[loop_level]=TellBlob(image); 5863 mng_info->loop_count[loop_level]=loop_iters; 5864 } 5865 5866 mng_info->loop_iteration[loop_level]=0; 5867 } 5868 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5869 continue; 5870 } 5871 5872 if (memcmp(type,mng_ENDL,4) == 0) 5873 { 5874 if (length > 0) 5875 { 5876 loop_level=chunk[0]; 5877 5878 if (skipping_loop > 0) 5879 { 5880 if (skipping_loop == loop_level) 5881 { 5882 /* 5883 Found end of zero-iteration loop. 5884 */ 5885 skipping_loop=(-1); 5886 mng_info->loop_active[loop_level]=0; 5887 } 5888 } 5889 5890 else 5891 { 5892 if (mng_info->loop_active[loop_level] == 1) 5893 { 5894 mng_info->loop_count[loop_level]--; 5895 mng_info->loop_iteration[loop_level]++; 5896 5897 if (logging != MagickFalse) 5898 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 5899 " ENDL: LOOP level %.20g has %.20g remaining iters ", 5900 (double) loop_level,(double) 5901 mng_info->loop_count[loop_level]); 5902 5903 if (mng_info->loop_count[loop_level] != 0) 5904 { 5905 offset= 5906 SeekBlob(image,mng_info->loop_jump[loop_level], 5907 SEEK_SET); 5908 5909 if (offset < 0) 5910 ThrowReaderException(CorruptImageError, 5911 "ImproperImageHeader"); 5912 } 5913 5914 else 5915 { 5916 short 5917 last_level; 5918 5919 /* 5920 Finished loop. 5921 */ 5922 mng_info->loop_active[loop_level]=0; 5923 last_level=(-1); 5924 for (i=0; i < loop_level; i++) 5925 if (mng_info->loop_active[i] == 1) 5926 last_level=(short) i; 5927 loop_level=last_level; 5928 } 5929 } 5930 } 5931 } 5932 5933 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 5934 continue; 5935 } 5936 5937 if (memcmp(type,mng_CLON,4) == 0) 5938 { 5939 if (mng_info->clon_warning == 0) 5940 (void) ThrowMagickException(exception,GetMagickModule(), 5941 CoderError,"CLON is not implemented yet","`%s'", 5942 image->filename); 5943 5944 mng_info->clon_warning++; 5945 } 5946 5947 if (memcmp(type,mng_MAGN,4) == 0) 5948 { 5949 png_uint_16 5950 magn_first, 5951 magn_last, 5952 magn_mb, 5953 magn_ml, 5954 magn_mr, 5955 magn_mt, 5956 magn_mx, 5957 magn_my, 5958 magn_methx, 5959 magn_methy; 5960 5961 if (length > 1) 5962 magn_first=(p[0] << 8) | p[1]; 5963 5964 else 5965 magn_first=0; 5966 5967 if (length > 3) 5968 magn_last=(p[2] << 8) | p[3]; 5969 5970 else 5971 magn_last=magn_first; 5972 #ifndef MNG_OBJECT_BUFFERS 5973 if (magn_first || magn_last) 5974 if (mng_info->magn_warning == 0) 5975 { 5976 (void) ThrowMagickException(exception, 5977 GetMagickModule(),CoderError, 5978 "MAGN is not implemented yet for nonzero objects", 5979 "`%s'",image->filename); 5980 5981 mng_info->magn_warning++; 5982 } 5983 #endif 5984 if (length > 4) 5985 magn_methx=p[4]; 5986 5987 else 5988 magn_methx=0; 5989 5990 if (length > 6) 5991 magn_mx=(p[5] << 8) | p[6]; 5992 5993 else 5994 magn_mx=1; 5995 5996 if (magn_mx == 0) 5997 magn_mx=1; 5998 5999 if (length > 8) 6000 magn_my=(p[7] << 8) | p[8]; 6001 6002 else 6003 magn_my=magn_mx; 6004 6005 if (magn_my == 0) 6006 magn_my=1; 6007 6008 if (length > 10) 6009 magn_ml=(p[9] << 8) | p[10]; 6010 6011 else 6012 magn_ml=magn_mx; 6013 6014 if (magn_ml == 0) 6015 magn_ml=1; 6016 6017 if (length > 12) 6018 magn_mr=(p[11] << 8) | p[12]; 6019 6020 else 6021 magn_mr=magn_mx; 6022 6023 if (magn_mr == 0) 6024 magn_mr=1; 6025 6026 if (length > 14) 6027 magn_mt=(p[13] << 8) | p[14]; 6028 6029 else 6030 magn_mt=magn_my; 6031 6032 if (magn_mt == 0) 6033 magn_mt=1; 6034 6035 if (length > 16) 6036 magn_mb=(p[15] << 8) | p[16]; 6037 6038 else 6039 magn_mb=magn_my; 6040 6041 if (magn_mb == 0) 6042 magn_mb=1; 6043 6044 if (length > 17) 6045 magn_methy=p[17]; 6046 6047 else 6048 magn_methy=magn_methx; 6049 6050 6051 if (magn_methx > 5 || magn_methy > 5) 6052 if (mng_info->magn_warning == 0) 6053 { 6054 (void) ThrowMagickException(exception, 6055 GetMagickModule(),CoderError, 6056 "Unknown MAGN method in MNG datastream","`%s'", 6057 image->filename); 6058 6059 mng_info->magn_warning++; 6060 } 6061 #ifdef MNG_OBJECT_BUFFERS 6062 /* Magnify existing objects in the range magn_first to magn_last */ 6063 #endif 6064 if (magn_first == 0 || magn_last == 0) 6065 { 6066 /* Save the magnification factors for object 0 */ 6067 mng_info->magn_mb=magn_mb; 6068 mng_info->magn_ml=magn_ml; 6069 mng_info->magn_mr=magn_mr; 6070 mng_info->magn_mt=magn_mt; 6071 mng_info->magn_mx=magn_mx; 6072 mng_info->magn_my=magn_my; 6073 mng_info->magn_methx=magn_methx; 6074 mng_info->magn_methy=magn_methy; 6075 } 6076 } 6077 6078 if (memcmp(type,mng_PAST,4) == 0) 6079 { 6080 if (mng_info->past_warning == 0) 6081 (void) ThrowMagickException(exception,GetMagickModule(), 6082 CoderError,"PAST is not implemented yet","`%s'", 6083 image->filename); 6084 6085 mng_info->past_warning++; 6086 } 6087 6088 if (memcmp(type,mng_SHOW,4) == 0) 6089 { 6090 if (mng_info->show_warning == 0) 6091 (void) ThrowMagickException(exception,GetMagickModule(), 6092 CoderError,"SHOW is not implemented yet","`%s'", 6093 image->filename); 6094 6095 mng_info->show_warning++; 6096 } 6097 6098 if (memcmp(type,mng_sBIT,4) == 0) 6099 { 6100 if (length < 4) 6101 mng_info->have_global_sbit=MagickFalse; 6102 6103 else 6104 { 6105 mng_info->global_sbit.gray=p[0]; 6106 mng_info->global_sbit.red=p[0]; 6107 mng_info->global_sbit.green=p[1]; 6108 mng_info->global_sbit.blue=p[2]; 6109 mng_info->global_sbit.alpha=p[3]; 6110 mng_info->have_global_sbit=MagickTrue; 6111 } 6112 } 6113 if (memcmp(type,mng_pHYs,4) == 0) 6114 { 6115 if (length > 8) 6116 { 6117 mng_info->global_x_pixels_per_unit= 6118 (size_t) mng_get_long(p); 6119 mng_info->global_y_pixels_per_unit= 6120 (size_t) mng_get_long(&p[4]); 6121 mng_info->global_phys_unit_type=p[8]; 6122 mng_info->have_global_phys=MagickTrue; 6123 } 6124 6125 else 6126 mng_info->have_global_phys=MagickFalse; 6127 } 6128 if (memcmp(type,mng_pHYg,4) == 0) 6129 { 6130 if (mng_info->phyg_warning == 0) 6131 (void) ThrowMagickException(exception,GetMagickModule(), 6132 CoderError,"pHYg is not implemented.","`%s'",image->filename); 6133 6134 mng_info->phyg_warning++; 6135 } 6136 if (memcmp(type,mng_BASI,4) == 0) 6137 { 6138 skip_to_iend=MagickTrue; 6139 6140 if (mng_info->basi_warning == 0) 6141 (void) ThrowMagickException(exception,GetMagickModule(), 6142 CoderError,"BASI is not implemented yet","`%s'", 6143 image->filename); 6144 6145 mng_info->basi_warning++; 6146 #ifdef MNG_BASI_SUPPORTED 6147 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) | 6148 (p[2] << 8) | p[3]); 6149 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) | 6150 (p[6] << 8) | p[7]); 6151 basi_color_type=p[8]; 6152 basi_compression_method=p[9]; 6153 basi_filter_type=p[10]; 6154 basi_interlace_method=p[11]; 6155 if (length > 11) 6156 basi_red=(p[12] << 8) & p[13]; 6157 6158 else 6159 basi_red=0; 6160 6161 if (length > 13) 6162 basi_green=(p[14] << 8) & p[15]; 6163 6164 else 6165 basi_green=0; 6166 6167 if (length > 15) 6168 basi_blue=(p[16] << 8) & p[17]; 6169 6170 else 6171 basi_blue=0; 6172 6173 if (length > 17) 6174 basi_alpha=(p[18] << 8) & p[19]; 6175 6176 else 6177 { 6178 if (basi_sample_depth == 16) 6179 basi_alpha=65535L; 6180 else 6181 basi_alpha=255; 6182 } 6183 6184 if (length > 19) 6185 basi_viewable=p[20]; 6186 6187 else 6188 basi_viewable=0; 6189 6190 #endif 6191 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6192 continue; 6193 } 6194 6195 if (memcmp(type,mng_IHDR,4) 6196 #if defined(JNG_SUPPORTED) 6197 && memcmp(type,mng_JHDR,4) 6198 #endif 6199 ) 6200 { 6201 /* Not an IHDR or JHDR chunk */ 6202 if (length != 0) 6203 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6204 6205 continue; 6206 } 6207 /* Process IHDR */ 6208 if (logging != MagickFalse) 6209 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6210 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]); 6211 6212 mng_info->exists[object_id]=MagickTrue; 6213 mng_info->viewable[object_id]=MagickTrue; 6214 6215 if (mng_info->invisible[object_id]) 6216 { 6217 if (logging != MagickFalse) 6218 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6219 " Skipping invisible object"); 6220 6221 skip_to_iend=MagickTrue; 6222 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6223 continue; 6224 } 6225 #if defined(MNG_INSERT_LAYERS) 6226 if (length < 8) 6227 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 6228 6229 image_width=(size_t) mng_get_long(p); 6230 image_height=(size_t) mng_get_long(&p[4]); 6231 #endif 6232 chunk=(unsigned char *) RelinquishMagickMemory(chunk); 6233 6234 /* 6235 Insert a transparent background layer behind the entire animation 6236 if it is not full screen. 6237 */ 6238 #if defined(MNG_INSERT_LAYERS) 6239 if (insert_layers && mng_type && first_mng_object) 6240 { 6241 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) || 6242 (image_width < mng_info->mng_width) || 6243 (mng_info->clip.right < (ssize_t) mng_info->mng_width) || 6244 (image_height < mng_info->mng_height) || 6245 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height)) 6246 { 6247 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6248 { 6249 /* 6250 Allocate next image structure. 6251 */ 6252 AcquireNextImage(image_info,image,exception); 6253 6254 if (GetNextImageInList(image) == (Image *) NULL) 6255 { 6256 image=DestroyImageList(image); 6257 MngInfoFreeStruct(mng_info,&have_mng_structure); 6258 return((Image *) NULL); 6259 } 6260 6261 image=SyncNextImageInList(image); 6262 } 6263 mng_info->image=image; 6264 6265 if (term_chunk_found) 6266 { 6267 image->start_loop=MagickTrue; 6268 image->iterations=mng_iterations; 6269 term_chunk_found=MagickFalse; 6270 } 6271 6272 else 6273 image->start_loop=MagickFalse; 6274 6275 /* Make a background rectangle. */ 6276 6277 image->delay=0; 6278 image->columns=mng_info->mng_width; 6279 image->rows=mng_info->mng_height; 6280 image->page.width=mng_info->mng_width; 6281 image->page.height=mng_info->mng_height; 6282 image->page.x=0; 6283 image->page.y=0; 6284 image->background_color=mng_background_color; 6285 (void) SetImageBackgroundColor(image,exception); 6286 if (logging != MagickFalse) 6287 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6288 " Inserted transparent background layer, W=%.20g, H=%.20g", 6289 (double) mng_info->mng_width,(double) mng_info->mng_height); 6290 } 6291 } 6292 /* 6293 Insert a background layer behind the upcoming image if 6294 framing_mode is 3, and we haven't already inserted one. 6295 */ 6296 if (insert_layers && (mng_info->framing_mode == 3) && 6297 (subframe_width) && (subframe_height) && (simplicity == 0 || 6298 (simplicity & 0x08))) 6299 { 6300 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6301 { 6302 /* 6303 Allocate next image structure. 6304 */ 6305 AcquireNextImage(image_info,image,exception); 6306 6307 if (GetNextImageInList(image) == (Image *) NULL) 6308 { 6309 image=DestroyImageList(image); 6310 MngInfoFreeStruct(mng_info,&have_mng_structure); 6311 return((Image *) NULL); 6312 } 6313 6314 image=SyncNextImageInList(image); 6315 } 6316 6317 mng_info->image=image; 6318 6319 if (term_chunk_found) 6320 { 6321 image->start_loop=MagickTrue; 6322 image->iterations=mng_iterations; 6323 term_chunk_found=MagickFalse; 6324 } 6325 6326 else 6327 image->start_loop=MagickFalse; 6328 6329 image->delay=0; 6330 image->columns=subframe_width; 6331 image->rows=subframe_height; 6332 image->page.width=subframe_width; 6333 image->page.height=subframe_height; 6334 image->page.x=mng_info->clip.left; 6335 image->page.y=mng_info->clip.top; 6336 image->background_color=mng_background_color; 6337 image->alpha_trait=UndefinedPixelTrait; 6338 (void) SetImageBackgroundColor(image,exception); 6339 6340 if (logging != MagickFalse) 6341 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6342 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", 6343 (double) mng_info->clip.left,(double) mng_info->clip.right, 6344 (double) mng_info->clip.top,(double) mng_info->clip.bottom); 6345 } 6346 #endif /* MNG_INSERT_LAYERS */ 6347 first_mng_object=MagickFalse; 6348 6349 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 6350 { 6351 /* 6352 Allocate next image structure. 6353 */ 6354 AcquireNextImage(image_info,image,exception); 6355 6356 if (GetNextImageInList(image) == (Image *) NULL) 6357 { 6358 image=DestroyImageList(image); 6359 MngInfoFreeStruct(mng_info,&have_mng_structure); 6360 return((Image *) NULL); 6361 } 6362 6363 image=SyncNextImageInList(image); 6364 } 6365 mng_info->image=image; 6366 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 6367 GetBlobSize(image)); 6368 6369 if (status == MagickFalse) 6370 break; 6371 6372 if (term_chunk_found) 6373 { 6374 image->start_loop=MagickTrue; 6375 term_chunk_found=MagickFalse; 6376 } 6377 6378 else 6379 image->start_loop=MagickFalse; 6380 6381 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3) 6382 { 6383 image->delay=frame_delay; 6384 frame_delay=default_frame_delay; 6385 } 6386 6387 else 6388 image->delay=0; 6389 6390 image->page.width=mng_info->mng_width; 6391 image->page.height=mng_info->mng_height; 6392 image->page.x=mng_info->x_off[object_id]; 6393 image->page.y=mng_info->y_off[object_id]; 6394 image->iterations=mng_iterations; 6395 6396 /* 6397 Seek back to the beginning of the IHDR or JHDR chunk's length field. 6398 */ 6399 6400 if (logging != MagickFalse) 6401 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6402 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1], 6403 type[2],type[3]); 6404 6405 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR); 6406 6407 if (offset < 0) 6408 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 6409 } 6410 6411 mng_info->image=image; 6412 mng_info->mng_type=mng_type; 6413 mng_info->object_id=object_id; 6414 6415 if (memcmp(type,mng_IHDR,4) == 0) 6416 image=ReadOnePNGImage(mng_info,image_info,exception); 6417 6418 #if defined(JNG_SUPPORTED) 6419 else 6420 image=ReadOneJNGImage(mng_info,image_info,exception); 6421 #endif 6422 6423 if (image == (Image *) NULL) 6424 { 6425 if (logging != MagickFalse) 6426 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6427 "exit ReadJNGImage() with error"); 6428 6429 MngInfoFreeStruct(mng_info,&have_mng_structure); 6430 return((Image *) NULL); 6431 } 6432 6433 if (image->columns == 0 || image->rows == 0) 6434 { 6435 (void) CloseBlob(image); 6436 image=DestroyImageList(image); 6437 MngInfoFreeStruct(mng_info,&have_mng_structure); 6438 return((Image *) NULL); 6439 } 6440 6441 mng_info->image=image; 6442 6443 if (mng_type) 6444 { 6445 MngBox 6446 crop_box; 6447 6448 if (mng_info->magn_methx || mng_info->magn_methy) 6449 { 6450 png_uint_32 6451 magnified_height, 6452 magnified_width; 6453 6454 if (logging != MagickFalse) 6455 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6456 " Processing MNG MAGN chunk"); 6457 6458 if (mng_info->magn_methx == 1) 6459 { 6460 magnified_width=mng_info->magn_ml; 6461 6462 if (image->columns > 1) 6463 magnified_width += mng_info->magn_mr; 6464 6465 if (image->columns > 2) 6466 magnified_width += (png_uint_32) 6467 ((image->columns-2)*(mng_info->magn_mx)); 6468 } 6469 6470 else 6471 { 6472 magnified_width=(png_uint_32) image->columns; 6473 6474 if (image->columns > 1) 6475 magnified_width += mng_info->magn_ml-1; 6476 6477 if (image->columns > 2) 6478 magnified_width += mng_info->magn_mr-1; 6479 6480 if (image->columns > 3) 6481 magnified_width += (png_uint_32) 6482 ((image->columns-3)*(mng_info->magn_mx-1)); 6483 } 6484 6485 if (mng_info->magn_methy == 1) 6486 { 6487 magnified_height=mng_info->magn_mt; 6488 6489 if (image->rows > 1) 6490 magnified_height += mng_info->magn_mb; 6491 6492 if (image->rows > 2) 6493 magnified_height += (png_uint_32) 6494 ((image->rows-2)*(mng_info->magn_my)); 6495 } 6496 6497 else 6498 { 6499 magnified_height=(png_uint_32) image->rows; 6500 6501 if (image->rows > 1) 6502 magnified_height += mng_info->magn_mt-1; 6503 6504 if (image->rows > 2) 6505 magnified_height += mng_info->magn_mb-1; 6506 6507 if (image->rows > 3) 6508 magnified_height += (png_uint_32) 6509 ((image->rows-3)*(mng_info->magn_my-1)); 6510 } 6511 6512 if (magnified_height > image->rows || 6513 magnified_width > image->columns) 6514 { 6515 Image 6516 *large_image; 6517 6518 int 6519 yy; 6520 6521 Quantum 6522 *next, 6523 *prev; 6524 6525 png_uint_16 6526 magn_methx, 6527 magn_methy; 6528 6529 ssize_t 6530 m, 6531 y; 6532 6533 register Quantum 6534 *n, 6535 *q; 6536 6537 register ssize_t 6538 x; 6539 6540 /* Allocate next image structure. */ 6541 6542 if (logging != MagickFalse) 6543 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6544 " Allocate magnified image"); 6545 6546 AcquireNextImage(image_info,image,exception); 6547 6548 if (GetNextImageInList(image) == (Image *) NULL) 6549 { 6550 image=DestroyImageList(image); 6551 MngInfoFreeStruct(mng_info,&have_mng_structure); 6552 return((Image *) NULL); 6553 } 6554 6555 large_image=SyncNextImageInList(image); 6556 6557 large_image->columns=magnified_width; 6558 large_image->rows=magnified_height; 6559 6560 magn_methx=mng_info->magn_methx; 6561 magn_methy=mng_info->magn_methy; 6562 6563 #if (MAGICKCORE_QUANTUM_DEPTH > 16) 6564 #define QM unsigned short 6565 if (magn_methx != 1 || magn_methy != 1) 6566 { 6567 /* 6568 Scale pixels to unsigned shorts to prevent 6569 overflow of intermediate values of interpolations 6570 */ 6571 for (y=0; y < (ssize_t) image->rows; y++) 6572 { 6573 q=GetAuthenticPixels(image,0,y,image->columns,1, 6574 exception); 6575 6576 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6577 { 6578 SetPixelRed(image,ScaleQuantumToShort( 6579 GetPixelRed(image,q)),q); 6580 SetPixelGreen(image,ScaleQuantumToShort( 6581 GetPixelGreen(image,q)),q); 6582 SetPixelBlue(image,ScaleQuantumToShort( 6583 GetPixelBlue(image,q)),q); 6584 SetPixelAlpha(image,ScaleQuantumToShort( 6585 GetPixelAlpha(image,q)),q); 6586 q+=GetPixelChannels(image); 6587 } 6588 6589 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6590 break; 6591 } 6592 } 6593 #else 6594 #define QM Quantum 6595 #endif 6596 6597 if (image->alpha_trait != UndefinedPixelTrait) 6598 (void) SetImageBackgroundColor(large_image,exception); 6599 6600 else 6601 { 6602 large_image->background_color.alpha=OpaqueAlpha; 6603 (void) SetImageBackgroundColor(large_image,exception); 6604 6605 if (magn_methx == 4) 6606 magn_methx=2; 6607 6608 if (magn_methx == 5) 6609 magn_methx=3; 6610 6611 if (magn_methy == 4) 6612 magn_methy=2; 6613 6614 if (magn_methy == 5) 6615 magn_methy=3; 6616 } 6617 6618 /* magnify the rows into the right side of the large image */ 6619 6620 if (logging != MagickFalse) 6621 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6622 " Magnify the rows to %.20g",(double) large_image->rows); 6623 m=(ssize_t) mng_info->magn_mt; 6624 yy=0; 6625 length=(size_t) GetPixelChannels(image)*image->columns; 6626 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next)); 6627 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev)); 6628 6629 if ((prev == (Quantum *) NULL) || 6630 (next == (Quantum *) NULL)) 6631 { 6632 image=DestroyImageList(image); 6633 MngInfoFreeStruct(mng_info,&have_mng_structure); 6634 ThrowReaderException(ResourceLimitError, 6635 "MemoryAllocationFailed"); 6636 } 6637 6638 n=GetAuthenticPixels(image,0,0,image->columns,1,exception); 6639 (void) CopyMagickMemory(next,n,length); 6640 6641 for (y=0; y < (ssize_t) image->rows; y++) 6642 { 6643 if (y == 0) 6644 m=(ssize_t) mng_info->magn_mt; 6645 6646 else if (magn_methy > 1 && y == (ssize_t) image->rows-2) 6647 m=(ssize_t) mng_info->magn_mb; 6648 6649 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1) 6650 m=(ssize_t) mng_info->magn_mb; 6651 6652 else if (magn_methy > 1 && y == (ssize_t) image->rows-1) 6653 m=1; 6654 6655 else 6656 m=(ssize_t) mng_info->magn_my; 6657 6658 n=prev; 6659 prev=next; 6660 next=n; 6661 6662 if (y < (ssize_t) image->rows-1) 6663 { 6664 n=GetAuthenticPixels(image,0,y+1,image->columns,1, 6665 exception); 6666 (void) CopyMagickMemory(next,n,length); 6667 } 6668 6669 for (i=0; i < m; i++, yy++) 6670 { 6671 register Quantum 6672 *pixels; 6673 6674 assert(yy < (ssize_t) large_image->rows); 6675 pixels=prev; 6676 n=next; 6677 q=GetAuthenticPixels(large_image,0,yy,large_image->columns, 6678 1,exception); 6679 q+=(large_image->columns-image->columns)* 6680 GetPixelChannels(large_image); 6681 6682 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6683 { 6684 /* To do: get color as function of indexes[x] */ 6685 /* 6686 if (image->storage_class == PseudoClass) 6687 { 6688 } 6689 */ 6690 6691 if (magn_methy <= 1) 6692 { 6693 /* replicate previous */ 6694 SetPixelRed(large_image,GetPixelRed(image,pixels),q); 6695 SetPixelGreen(large_image,GetPixelGreen(image, 6696 pixels),q); 6697 SetPixelBlue(large_image,GetPixelBlue(image, 6698 pixels),q); 6699 SetPixelAlpha(large_image,GetPixelAlpha(image, 6700 pixels),q); 6701 } 6702 6703 else if (magn_methy == 2 || magn_methy == 4) 6704 { 6705 if (i == 0) 6706 { 6707 SetPixelRed(large_image,GetPixelRed(image, 6708 pixels),q); 6709 SetPixelGreen(large_image,GetPixelGreen(image, 6710 pixels),q); 6711 SetPixelBlue(large_image,GetPixelBlue(image, 6712 pixels),q); 6713 SetPixelAlpha(large_image,GetPixelAlpha(image, 6714 pixels),q); 6715 } 6716 6717 else 6718 { 6719 /* Interpolate */ 6720 SetPixelRed(large_image,((QM) (((ssize_t) 6721 (2*i*(GetPixelRed(image,n) 6722 -GetPixelRed(image,pixels)+m))/ 6723 ((ssize_t) (m*2)) 6724 +GetPixelRed(image,pixels)))),q); 6725 SetPixelGreen(large_image,((QM) (((ssize_t) 6726 (2*i*(GetPixelGreen(image,n) 6727 -GetPixelGreen(image,pixels)+m))/ 6728 ((ssize_t) (m*2)) 6729 +GetPixelGreen(image,pixels)))),q); 6730 SetPixelBlue(large_image,((QM) (((ssize_t) 6731 (2*i*(GetPixelBlue(image,n) 6732 -GetPixelBlue(image,pixels)+m))/ 6733 ((ssize_t) (m*2)) 6734 +GetPixelBlue(image,pixels)))),q); 6735 6736 if (image->alpha_trait != UndefinedPixelTrait) 6737 SetPixelAlpha(large_image, ((QM) (((ssize_t) 6738 (2*i*(GetPixelAlpha(image,n) 6739 -GetPixelAlpha(image,pixels)+m)) 6740 /((ssize_t) (m*2))+ 6741 GetPixelAlpha(image,pixels)))),q); 6742 } 6743 6744 if (magn_methy == 4) 6745 { 6746 /* Replicate nearest */ 6747 if (i <= ((m+1) << 1)) 6748 SetPixelAlpha(large_image,GetPixelAlpha(image, 6749 pixels),q); 6750 else 6751 SetPixelAlpha(large_image,GetPixelAlpha(image, 6752 n),q); 6753 } 6754 } 6755 6756 else /* if (magn_methy == 3 || magn_methy == 5) */ 6757 { 6758 /* Replicate nearest */ 6759 if (i <= ((m+1) << 1)) 6760 { 6761 SetPixelRed(large_image,GetPixelRed(image, 6762 pixels),q); 6763 SetPixelGreen(large_image,GetPixelGreen(image, 6764 pixels),q); 6765 SetPixelBlue(large_image,GetPixelBlue(image, 6766 pixels),q); 6767 SetPixelAlpha(large_image,GetPixelAlpha(image, 6768 pixels),q); 6769 } 6770 6771 else 6772 { 6773 SetPixelRed(large_image,GetPixelRed(image,n),q); 6774 SetPixelGreen(large_image,GetPixelGreen(image,n), 6775 q); 6776 SetPixelBlue(large_image,GetPixelBlue(image,n), 6777 q); 6778 SetPixelAlpha(large_image,GetPixelAlpha(image,n), 6779 q); 6780 } 6781 6782 if (magn_methy == 5) 6783 { 6784 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i* 6785 (GetPixelAlpha(image,n) 6786 -GetPixelAlpha(image,pixels)) 6787 +m))/((ssize_t) (m*2)) 6788 +GetPixelAlpha(image,pixels)),q); 6789 } 6790 } 6791 n+=GetPixelChannels(image); 6792 q+=GetPixelChannels(large_image); 6793 pixels+=GetPixelChannels(image); 6794 } /* x */ 6795 6796 if (SyncAuthenticPixels(large_image,exception) == 0) 6797 break; 6798 6799 } /* i */ 6800 } /* y */ 6801 6802 prev=(Quantum *) RelinquishMagickMemory(prev); 6803 next=(Quantum *) RelinquishMagickMemory(next); 6804 6805 length=image->columns; 6806 6807 if (logging != MagickFalse) 6808 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6809 " Delete original image"); 6810 6811 DeleteImageFromList(&image); 6812 6813 image=large_image; 6814 6815 mng_info->image=image; 6816 6817 /* magnify the columns */ 6818 if (logging != MagickFalse) 6819 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6820 " Magnify the columns to %.20g",(double) image->columns); 6821 6822 for (y=0; y < (ssize_t) image->rows; y++) 6823 { 6824 register Quantum 6825 *pixels; 6826 6827 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 6828 pixels=q+(image->columns-length)*GetPixelChannels(image); 6829 n=pixels+GetPixelChannels(image); 6830 6831 for (x=(ssize_t) (image->columns-length); 6832 x < (ssize_t) image->columns; x++) 6833 { 6834 /* To do: Rewrite using Get/Set***PixelChannel() */ 6835 6836 if (x == (ssize_t) (image->columns-length)) 6837 m=(ssize_t) mng_info->magn_ml; 6838 6839 else if (magn_methx > 1 && x == (ssize_t) image->columns-2) 6840 m=(ssize_t) mng_info->magn_mr; 6841 6842 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1) 6843 m=(ssize_t) mng_info->magn_mr; 6844 6845 else if (magn_methx > 1 && x == (ssize_t) image->columns-1) 6846 m=1; 6847 6848 else 6849 m=(ssize_t) mng_info->magn_mx; 6850 6851 for (i=0; i < m; i++) 6852 { 6853 if (magn_methx <= 1) 6854 { 6855 /* replicate previous */ 6856 SetPixelRed(image,GetPixelRed(image,pixels),q); 6857 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6858 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6859 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6860 } 6861 6862 else if (magn_methx == 2 || magn_methx == 4) 6863 { 6864 if (i == 0) 6865 { 6866 SetPixelRed(image,GetPixelRed(image,pixels),q); 6867 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6868 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6869 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6870 } 6871 6872 /* To do: Rewrite using Get/Set***PixelChannel() */ 6873 else 6874 { 6875 /* Interpolate */ 6876 SetPixelRed(image,(QM) ((2*i*( 6877 GetPixelRed(image,n) 6878 -GetPixelRed(image,pixels))+m) 6879 /((ssize_t) (m*2))+ 6880 GetPixelRed(image,pixels)),q); 6881 6882 SetPixelGreen(image,(QM) ((2*i*( 6883 GetPixelGreen(image,n) 6884 -GetPixelGreen(image,pixels))+m) 6885 /((ssize_t) (m*2))+ 6886 GetPixelGreen(image,pixels)),q); 6887 6888 SetPixelBlue(image,(QM) ((2*i*( 6889 GetPixelBlue(image,n) 6890 -GetPixelBlue(image,pixels))+m) 6891 /((ssize_t) (m*2))+ 6892 GetPixelBlue(image,pixels)),q); 6893 if (image->alpha_trait != UndefinedPixelTrait) 6894 SetPixelAlpha(image,(QM) ((2*i*( 6895 GetPixelAlpha(image,n) 6896 -GetPixelAlpha(image,pixels))+m) 6897 /((ssize_t) (m*2))+ 6898 GetPixelAlpha(image,pixels)),q); 6899 } 6900 6901 if (magn_methx == 4) 6902 { 6903 /* Replicate nearest */ 6904 if (i <= ((m+1) << 1)) 6905 { 6906 SetPixelAlpha(image, 6907 GetPixelAlpha(image,pixels)+0,q); 6908 } 6909 else 6910 { 6911 SetPixelAlpha(image, 6912 GetPixelAlpha(image,n)+0,q); 6913 } 6914 } 6915 } 6916 6917 else /* if (magn_methx == 3 || magn_methx == 5) */ 6918 { 6919 /* Replicate nearest */ 6920 if (i <= ((m+1) << 1)) 6921 { 6922 SetPixelRed(image,GetPixelRed(image,pixels),q); 6923 SetPixelGreen(image,GetPixelGreen(image,pixels),q); 6924 SetPixelBlue(image,GetPixelBlue(image,pixels),q); 6925 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q); 6926 } 6927 6928 else 6929 { 6930 SetPixelRed(image,GetPixelRed(image,n),q); 6931 SetPixelGreen(image,GetPixelGreen(image,n),q); 6932 SetPixelBlue(image,GetPixelBlue(image,n),q); 6933 SetPixelAlpha(image,GetPixelAlpha(image,n),q); 6934 } 6935 6936 if (magn_methx == 5) 6937 { 6938 /* Interpolate */ 6939 SetPixelAlpha(image, 6940 (QM) ((2*i*( GetPixelAlpha(image,n) 6941 -GetPixelAlpha(image,pixels))+m)/ 6942 ((ssize_t) (m*2)) 6943 +GetPixelAlpha(image,pixels)),q); 6944 } 6945 } 6946 q+=GetPixelChannels(image); 6947 } 6948 n+=GetPixelChannels(image); 6949 } 6950 6951 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6952 break; 6953 } 6954 #if (MAGICKCORE_QUANTUM_DEPTH > 16) 6955 if (magn_methx != 1 || magn_methy != 1) 6956 { 6957 /* 6958 Rescale pixels to Quantum 6959 */ 6960 for (y=0; y < (ssize_t) image->rows; y++) 6961 { 6962 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 6963 6964 for (x=(ssize_t) image->columns-1; x >= 0; x--) 6965 { 6966 SetPixelRed(image,ScaleShortToQuantum( 6967 GetPixelRed(image,q)),q); 6968 SetPixelGreen(image,ScaleShortToQuantum( 6969 GetPixelGreen(image,q)),q); 6970 SetPixelBlue(image,ScaleShortToQuantum( 6971 GetPixelBlue(image,q)),q); 6972 SetPixelAlpha(image,ScaleShortToQuantum( 6973 GetPixelAlpha(image,q)),q); 6974 q+=GetPixelChannels(image); 6975 } 6976 6977 if (SyncAuthenticPixels(image,exception) == MagickFalse) 6978 break; 6979 } 6980 } 6981 #endif 6982 if (logging != MagickFalse) 6983 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 6984 " Finished MAGN processing"); 6985 } 6986 } 6987 6988 /* 6989 Crop_box is with respect to the upper left corner of the MNG. 6990 */ 6991 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id]; 6992 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id]; 6993 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id]; 6994 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id]; 6995 crop_box=mng_minimum_box(crop_box,mng_info->clip); 6996 crop_box=mng_minimum_box(crop_box,mng_info->frame); 6997 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]); 6998 if ((crop_box.left != (mng_info->image_box.left 6999 +mng_info->x_off[object_id])) || 7000 (crop_box.right != (mng_info->image_box.right 7001 +mng_info->x_off[object_id])) || 7002 (crop_box.top != (mng_info->image_box.top 7003 +mng_info->y_off[object_id])) || 7004 (crop_box.bottom != (mng_info->image_box.bottom 7005 +mng_info->y_off[object_id]))) 7006 { 7007 if (logging != MagickFalse) 7008 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7009 " Crop the PNG image"); 7010 7011 if ((crop_box.left < crop_box.right) && 7012 (crop_box.top < crop_box.bottom)) 7013 { 7014 Image 7015 *im; 7016 7017 RectangleInfo 7018 crop_info; 7019 7020 /* 7021 Crop_info is with respect to the upper left corner of 7022 the image. 7023 */ 7024 crop_info.x=(crop_box.left-mng_info->x_off[object_id]); 7025 crop_info.y=(crop_box.top-mng_info->y_off[object_id]); 7026 crop_info.width=(size_t) (crop_box.right-crop_box.left); 7027 crop_info.height=(size_t) (crop_box.bottom-crop_box.top); 7028 image->page.width=image->columns; 7029 image->page.height=image->rows; 7030 image->page.x=0; 7031 image->page.y=0; 7032 im=CropImage(image,&crop_info,exception); 7033 7034 if (im != (Image *) NULL) 7035 { 7036 image->columns=im->columns; 7037 image->rows=im->rows; 7038 im=DestroyImage(im); 7039 image->page.width=image->columns; 7040 image->page.height=image->rows; 7041 image->page.x=crop_box.left; 7042 image->page.y=crop_box.top; 7043 } 7044 } 7045 7046 else 7047 { 7048 /* 7049 No pixels in crop area. The MNG spec still requires 7050 a layer, though, so make a single transparent pixel in 7051 the top left corner. 7052 */ 7053 image->columns=1; 7054 image->rows=1; 7055 image->colors=2; 7056 (void) SetImageBackgroundColor(image,exception); 7057 image->page.width=1; 7058 image->page.height=1; 7059 image->page.x=0; 7060 image->page.y=0; 7061 } 7062 } 7063 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED 7064 image=mng_info->image; 7065 #endif 7066 } 7067 7068 #if (MAGICKCORE_QUANTUM_DEPTH > 16) 7069 /* PNG does not handle depths greater than 16 so reduce it even 7070 * if lossy. 7071 */ 7072 if (image->depth > 16) 7073 image->depth=16; 7074 #endif 7075 7076 #if (MAGICKCORE_QUANTUM_DEPTH > 8) 7077 if (image->depth > 8) 7078 { 7079 /* To do: fill low byte properly */ 7080 image->depth=16; 7081 } 7082 7083 if (LosslessReduceDepthOK(image,exception) != MagickFalse) 7084 image->depth = 8; 7085 #endif 7086 7087 if (image_info->number_scenes != 0) 7088 { 7089 if (mng_info->scenes_found > 7090 (ssize_t) (image_info->first_scene+image_info->number_scenes)) 7091 break; 7092 } 7093 7094 if (logging != MagickFalse) 7095 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7096 " Finished reading image datastream."); 7097 7098 } while (LocaleCompare(image_info->magick,"MNG") == 0); 7099 7100 (void) CloseBlob(image); 7101 7102 if (logging != MagickFalse) 7103 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7104 " Finished reading all image datastreams."); 7105 7106 #if defined(MNG_INSERT_LAYERS) 7107 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) && 7108 (mng_info->mng_height)) 7109 { 7110 /* 7111 Insert a background layer if nothing else was found. 7112 */ 7113 if (logging != MagickFalse) 7114 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7115 " No images found. Inserting a background layer."); 7116 7117 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL) 7118 { 7119 /* 7120 Allocate next image structure. 7121 */ 7122 AcquireNextImage(image_info,image,exception); 7123 if (GetNextImageInList(image) == (Image *) NULL) 7124 { 7125 image=DestroyImageList(image); 7126 MngInfoFreeStruct(mng_info,&have_mng_structure); 7127 7128 if (logging != MagickFalse) 7129 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7130 " Allocation failed, returning NULL."); 7131 7132 return((Image *) NULL); 7133 } 7134 image=SyncNextImageInList(image); 7135 } 7136 image->columns=mng_info->mng_width; 7137 image->rows=mng_info->mng_height; 7138 image->page.width=mng_info->mng_width; 7139 image->page.height=mng_info->mng_height; 7140 image->page.x=0; 7141 image->page.y=0; 7142 image->background_color=mng_background_color; 7143 image->alpha_trait=UndefinedPixelTrait; 7144 7145 if (image_info->ping == MagickFalse) 7146 (void) SetImageBackgroundColor(image,exception); 7147 7148 mng_info->image_found++; 7149 } 7150 #endif 7151 image->iterations=mng_iterations; 7152 7153 if (mng_iterations == 1) 7154 image->start_loop=MagickTrue; 7155 7156 while (GetPreviousImageInList(image) != (Image *) NULL) 7157 { 7158 image_count++; 7159 if (image_count > 10*mng_info->image_found) 7160 { 7161 if (logging != MagickFalse) 7162 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning"); 7163 7164 (void) ThrowMagickException(exception,GetMagickModule(), 7165 CoderError,"Linked list is corrupted, beginning of list not found", 7166 "`%s'",image_info->filename); 7167 7168 return((Image *) NULL); 7169 } 7170 7171 image=GetPreviousImageInList(image); 7172 7173 if (GetNextImageInList(image) == (Image *) NULL) 7174 { 7175 if (logging != MagickFalse) 7176 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list"); 7177 7178 (void) ThrowMagickException(exception,GetMagickModule(), 7179 CoderError,"Linked list is corrupted; next_image is NULL","`%s'", 7180 image_info->filename); 7181 } 7182 } 7183 7184 if (mng_info->ticks_per_second && mng_info->image_found > 1 && 7185 GetNextImageInList(image) == 7186 (Image *) NULL) 7187 { 7188 if (logging != MagickFalse) 7189 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7190 " First image null"); 7191 7192 (void) ThrowMagickException(exception,GetMagickModule(), 7193 CoderError,"image->next for first image is NULL but shouldn't be.", 7194 "`%s'",image_info->filename); 7195 } 7196 7197 if (mng_info->image_found == 0) 7198 { 7199 if (logging != MagickFalse) 7200 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7201 " No visible images found."); 7202 7203 (void) ThrowMagickException(exception,GetMagickModule(), 7204 CoderError,"No visible images in file","`%s'",image_info->filename); 7205 7206 if (image != (Image *) NULL) 7207 image=DestroyImageList(image); 7208 7209 MngInfoFreeStruct(mng_info,&have_mng_structure); 7210 return((Image *) NULL); 7211 } 7212 7213 if (mng_info->ticks_per_second) 7214 final_delay=1UL*MagickMax(image->ticks_per_second,1L)* 7215 final_delay/mng_info->ticks_per_second; 7216 7217 else 7218 image->start_loop=MagickTrue; 7219 7220 /* Find final nonzero image delay */ 7221 final_image_delay=0; 7222 7223 while (GetNextImageInList(image) != (Image *) NULL) 7224 { 7225 if (image->delay) 7226 final_image_delay=image->delay; 7227 7228 image=GetNextImageInList(image); 7229 } 7230 7231 if (final_delay < final_image_delay) 7232 final_delay=final_image_delay; 7233 7234 image->delay=final_delay; 7235 7236 if (logging != MagickFalse) 7237 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7238 " image->delay=%.20g, final_delay=%.20g",(double) image->delay, 7239 (double) final_delay); 7240 7241 if (logging != MagickFalse) 7242 { 7243 int 7244 scene; 7245 7246 scene=0; 7247 image=GetFirstImageInList(image); 7248 7249 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7250 " Before coalesce:"); 7251 7252 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7253 " scene 0 delay=%.20g",(double) image->delay); 7254 7255 while (GetNextImageInList(image) != (Image *) NULL) 7256 { 7257 image=GetNextImageInList(image); 7258 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7259 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay); 7260 } 7261 } 7262 7263 image=GetFirstImageInList(image); 7264 #ifdef MNG_COALESCE_LAYERS 7265 if (insert_layers) 7266 { 7267 Image 7268 *next_image, 7269 *next; 7270 7271 size_t 7272 scene; 7273 7274 if (logging != MagickFalse) 7275 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images"); 7276 7277 scene=image->scene; 7278 next_image=CoalesceImages(image,exception); 7279 7280 if (next_image == (Image *) NULL) 7281 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 7282 7283 image=DestroyImageList(image); 7284 image=next_image; 7285 7286 for (next=image; next != (Image *) NULL; next=next_image) 7287 { 7288 next->page.width=mng_info->mng_width; 7289 next->page.height=mng_info->mng_height; 7290 next->page.x=0; 7291 next->page.y=0; 7292 next->scene=scene++; 7293 next_image=GetNextImageInList(next); 7294 7295 if (next_image == (Image *) NULL) 7296 break; 7297 7298 if (next->delay == 0) 7299 { 7300 scene--; 7301 next_image->previous=GetPreviousImageInList(next); 7302 if (GetPreviousImageInList(next) == (Image *) NULL) 7303 image=next_image; 7304 else 7305 next->previous->next=next_image; 7306 next=DestroyImage(next); 7307 } 7308 } 7309 } 7310 #endif 7311 7312 while (GetNextImageInList(image) != (Image *) NULL) 7313 image=GetNextImageInList(image); 7314 7315 image->dispose=BackgroundDispose; 7316 7317 if (logging != MagickFalse) 7318 { 7319 int 7320 scene; 7321 7322 scene=0; 7323 image=GetFirstImageInList(image); 7324 7325 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7326 " After coalesce:"); 7327 7328 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7329 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay, 7330 (double) image->dispose); 7331 7332 while (GetNextImageInList(image) != (Image *) NULL) 7333 { 7334 image=GetNextImageInList(image); 7335 7336 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7337 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++, 7338 (double) image->delay,(double) image->dispose); 7339 } 7340 } 7341 7342 image=GetFirstImageInList(image); 7343 MngInfoFreeStruct(mng_info,&have_mng_structure); 7344 have_mng_structure=MagickFalse; 7345 7346 if (logging != MagickFalse) 7347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()"); 7348 7349 return(GetFirstImageInList(image)); 7350 } 7351 #else /* PNG_LIBPNG_VER > 10011 */ 7352 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 7353 { 7354 printf("Your PNG library is too old: You have libpng-%s\n", 7355 PNG_LIBPNG_VER_STRING); 7356 7357 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 7358 "PNG library is too old","`%s'",image_info->filename); 7359 7360 return(Image *) NULL; 7361 } 7362 7363 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) 7364 { 7365 return(ReadPNGImage(image_info,exception)); 7366 } 7367 #endif /* PNG_LIBPNG_VER > 10011 */ 7368 #endif 7369 7370 /* 7372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7373 % % 7374 % % 7375 % % 7376 % R e g i s t e r P N G I m a g e % 7377 % % 7378 % % 7379 % % 7380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7381 % 7382 % RegisterPNGImage() adds properties for the PNG image format to 7383 % the list of supported formats. The properties include the image format 7384 % tag, a method to read and/or write the format, whether the format 7385 % supports the saving of more than one frame to the same file or blob, 7386 % whether the format supports native in-memory I/O, and a brief 7387 % description of the format. 7388 % 7389 % The format of the RegisterPNGImage method is: 7390 % 7391 % size_t RegisterPNGImage(void) 7392 % 7393 */ 7394 ModuleExport size_t RegisterPNGImage(void) 7395 { 7396 char 7397 version[MagickPathExtent]; 7398 7399 MagickInfo 7400 *entry; 7401 7402 static const char 7403 *PNGNote= 7404 { 7405 "See http://www.libpng.org/ for details about the PNG format." 7406 }, 7407 7408 *JNGNote= 7409 { 7410 "See http://www.libpng.org/pub/mng/ for details about the JNG\n" 7411 "format." 7412 }, 7413 7414 *MNGNote= 7415 { 7416 "See http://www.libpng.org/pub/mng/ for details about the MNG\n" 7417 "format." 7418 }; 7419 7420 *version='\0'; 7421 7422 #if defined(PNG_LIBPNG_VER_STRING) 7423 (void) ConcatenateMagickString(version,"libpng ",MagickPathExtent); 7424 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MagickPathExtent); 7425 7426 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0) 7427 { 7428 (void) ConcatenateMagickString(version,",",MagickPathExtent); 7429 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL), 7430 MagickPathExtent); 7431 } 7432 #endif 7433 7434 entry=AcquireMagickInfo("PNG","MNG","Multiple-image Network Graphics"); 7435 entry->flags|=CoderSeekableStreamFlag; /* To do: eliminate this. */ 7436 7437 #if defined(MAGICKCORE_PNG_DELEGATE) 7438 entry->decoder=(DecodeImageHandler *) ReadMNGImage; 7439 entry->encoder=(EncodeImageHandler *) WriteMNGImage; 7440 #endif 7441 7442 entry->magick=(IsImageFormatHandler *) IsMNG; 7443 7444 if (*version != '\0') 7445 entry->version=ConstantString(version); 7446 7447 entry->mime_type=ConstantString("video/x-mng"); 7448 entry->note=ConstantString(MNGNote); 7449 (void) RegisterMagickInfo(entry); 7450 7451 entry=AcquireMagickInfo("PNG","PNG","Portable Network Graphics"); 7452 7453 #if defined(MAGICKCORE_PNG_DELEGATE) 7454 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7455 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7456 #endif 7457 7458 entry->magick=(IsImageFormatHandler *) IsPNG; 7459 entry->flags^=CoderAdjoinFlag; 7460 entry->mime_type=ConstantString("image/png"); 7461 7462 if (*version != '\0') 7463 entry->version=ConstantString(version); 7464 7465 entry->note=ConstantString(PNGNote); 7466 (void) RegisterMagickInfo(entry); 7467 7468 entry=AcquireMagickInfo("PNG","PNG8", 7469 "8-bit indexed with optional binary transparency"); 7470 7471 #if defined(MAGICKCORE_PNG_DELEGATE) 7472 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7473 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7474 #endif 7475 7476 entry->magick=(IsImageFormatHandler *) IsPNG; 7477 entry->flags^=CoderAdjoinFlag; 7478 entry->mime_type=ConstantString("image/png"); 7479 (void) RegisterMagickInfo(entry); 7480 7481 entry=AcquireMagickInfo("PNG","PNG24", 7482 "opaque or binary transparent 24-bit RGB"); 7483 *version='\0'; 7484 7485 #if defined(ZLIB_VERSION) 7486 (void) ConcatenateMagickString(version,"zlib ",MagickPathExtent); 7487 (void) ConcatenateMagickString(version,ZLIB_VERSION,MagickPathExtent); 7488 7489 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0) 7490 { 7491 (void) ConcatenateMagickString(version,",",MagickPathExtent); 7492 (void) ConcatenateMagickString(version,zlib_version,MagickPathExtent); 7493 } 7494 #endif 7495 7496 if (*version != '\0') 7497 entry->version=ConstantString(version); 7498 7499 #if defined(MAGICKCORE_PNG_DELEGATE) 7500 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7501 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7502 #endif 7503 7504 entry->magick=(IsImageFormatHandler *) IsPNG; 7505 entry->flags^=CoderAdjoinFlag; 7506 entry->mime_type=ConstantString("image/png"); 7507 (void) RegisterMagickInfo(entry); 7508 7509 entry=AcquireMagickInfo("PNG","PNG32","opaque or transparent 32-bit RGBA"); 7510 7511 #if defined(MAGICKCORE_PNG_DELEGATE) 7512 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7513 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7514 #endif 7515 7516 entry->magick=(IsImageFormatHandler *) IsPNG; 7517 entry->flags^=CoderAdjoinFlag; 7518 entry->mime_type=ConstantString("image/png"); 7519 (void) RegisterMagickInfo(entry); 7520 7521 entry=AcquireMagickInfo("PNG","PNG48", 7522 "opaque or binary transparent 48-bit RGB"); 7523 7524 #if defined(MAGICKCORE_PNG_DELEGATE) 7525 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7526 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7527 #endif 7528 7529 entry->magick=(IsImageFormatHandler *) IsPNG; 7530 entry->flags^=CoderAdjoinFlag; 7531 entry->mime_type=ConstantString("image/png"); 7532 (void) RegisterMagickInfo(entry); 7533 7534 entry=AcquireMagickInfo("PNG","PNG64","opaque or transparent 64-bit RGBA"); 7535 7536 #if defined(MAGICKCORE_PNG_DELEGATE) 7537 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7538 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7539 #endif 7540 7541 entry->magick=(IsImageFormatHandler *) IsPNG; 7542 entry->flags^=CoderAdjoinFlag; 7543 entry->mime_type=ConstantString("image/png"); 7544 (void) RegisterMagickInfo(entry); 7545 7546 entry=AcquireMagickInfo("PNG","PNG00", 7547 "PNG inheriting bit-depth, color-type from original, if possible"); 7548 7549 #if defined(MAGICKCORE_PNG_DELEGATE) 7550 entry->decoder=(DecodeImageHandler *) ReadPNGImage; 7551 entry->encoder=(EncodeImageHandler *) WritePNGImage; 7552 #endif 7553 7554 entry->magick=(IsImageFormatHandler *) IsPNG; 7555 entry->flags^=CoderAdjoinFlag; 7556 entry->mime_type=ConstantString("image/png"); 7557 (void) RegisterMagickInfo(entry); 7558 7559 entry=AcquireMagickInfo("PNG","JNG","JPEG Network Graphics"); 7560 7561 #if defined(JNG_SUPPORTED) 7562 #if defined(MAGICKCORE_PNG_DELEGATE) 7563 entry->decoder=(DecodeImageHandler *) ReadJNGImage; 7564 entry->encoder=(EncodeImageHandler *) WriteJNGImage; 7565 #endif 7566 #endif 7567 7568 entry->magick=(IsImageFormatHandler *) IsJNG; 7569 entry->flags^=CoderAdjoinFlag; 7570 entry->mime_type=ConstantString("image/x-jng"); 7571 entry->note=ConstantString(JNGNote); 7572 (void) RegisterMagickInfo(entry); 7573 7574 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 7575 ping_semaphore=AcquireSemaphoreInfo(); 7576 #endif 7577 7578 return(MagickImageCoderSignature); 7579 } 7580 7581 /* 7583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7584 % % 7585 % % 7586 % % 7587 % U n r e g i s t e r P N G I m a g e % 7588 % % 7589 % % 7590 % % 7591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7592 % 7593 % UnregisterPNGImage() removes format registrations made by the 7594 % PNG module from the list of supported formats. 7595 % 7596 % The format of the UnregisterPNGImage method is: 7597 % 7598 % UnregisterPNGImage(void) 7599 % 7600 */ 7601 ModuleExport void UnregisterPNGImage(void) 7602 { 7603 (void) UnregisterMagickInfo("MNG"); 7604 (void) UnregisterMagickInfo("PNG"); 7605 (void) UnregisterMagickInfo("PNG8"); 7606 (void) UnregisterMagickInfo("PNG24"); 7607 (void) UnregisterMagickInfo("PNG32"); 7608 (void) UnregisterMagickInfo("PNG48"); 7609 (void) UnregisterMagickInfo("PNG64"); 7610 (void) UnregisterMagickInfo("PNG00"); 7611 (void) UnregisterMagickInfo("JNG"); 7612 7613 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 7614 if (ping_semaphore != (SemaphoreInfo *) NULL) 7615 RelinquishSemaphoreInfo(&ping_semaphore); 7616 #endif 7617 } 7618 7619 #if defined(MAGICKCORE_PNG_DELEGATE) 7621 #if PNG_LIBPNG_VER > 10011 7622 /* 7623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7624 % % 7625 % % 7626 % % 7627 % W r i t e M N G I m a g e % 7628 % % 7629 % % 7630 % % 7631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7632 % 7633 % WriteMNGImage() writes an image in the Portable Network Graphics 7634 % Group's "Multiple-image Network Graphics" encoded image format. 7635 % 7636 % MNG support written by Glenn Randers-Pehrson, glennrp (at) image... 7637 % 7638 % The format of the WriteMNGImage method is: 7639 % 7640 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info, 7641 % Image *image,ExceptionInfo *exception) 7642 % 7643 % A description of each parameter follows. 7644 % 7645 % o image_info: the image info. 7646 % 7647 % o image: The image. 7648 % 7649 % o exception: return any errors or warnings in this structure. 7650 % 7651 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also 7652 % "To do" under ReadPNGImage): 7653 % 7654 % Preserve all unknown and not-yet-handled known chunks found in input 7655 % PNG file and copy them into output PNG files according to the PNG 7656 % copying rules. 7657 % 7658 % Write the iCCP chunk at MNG level when (icc profile length > 0) 7659 % 7660 % Improve selection of color type (use indexed-colour or indexed-colour 7661 % with tRNS when 256 or fewer unique RGBA values are present). 7662 % 7663 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3) 7664 % This will be complicated if we limit ourselves to generating MNG-LC 7665 % files. For now we ignore disposal method 3 and simply overlay the next 7666 % image on it. 7667 % 7668 % Check for identical PLTE's or PLTE/tRNS combinations and use a 7669 % global MNG PLTE or PLTE/tRNS combination when appropriate. 7670 % [mostly done 15 June 1999 but still need to take care of tRNS] 7671 % 7672 % Check for identical sRGB and replace with a global sRGB (and remove 7673 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and 7674 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace 7675 % local gAMA/cHRM with local sRGB if appropriate). 7676 % 7677 % Check for identical sBIT chunks and write global ones. 7678 % 7679 % Provide option to skip writing the signature tEXt chunks. 7680 % 7681 % Use signatures to detect identical objects and reuse the first 7682 % instance of such objects instead of writing duplicate objects. 7683 % 7684 % Use a smaller-than-32k value of compression window size when 7685 % appropriate. 7686 % 7687 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write 7688 % ancillary text chunks and save profiles. 7689 % 7690 % Provide an option to force LC files (to ensure exact framing rate) 7691 % instead of VLC. 7692 % 7693 % Provide an option to force VLC files instead of LC, even when offsets 7694 % are present. This will involve expanding the embedded images with a 7695 % transparent region at the top and/or left. 7696 */ 7697 7698 static void 7699 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping, 7700 png_info *ping_info, unsigned char *profile_type, unsigned char 7701 *profile_description, unsigned char *profile_data, png_uint_32 length) 7702 { 7703 png_textp 7704 text; 7705 7706 register ssize_t 7707 i; 7708 7709 unsigned char 7710 *sp; 7711 7712 png_charp 7713 dp; 7714 7715 png_uint_32 7716 allocated_length, 7717 description_length; 7718 7719 unsigned char 7720 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 7721 7722 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0) 7723 return; 7724 7725 if (image_info->verbose) 7726 { 7727 (void) printf("writing raw profile: type=%s, length=%.20g\n", 7728 (char *) profile_type, (double) length); 7729 } 7730 7731 #if PNG_LIBPNG_VER >= 10400 7732 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text)); 7733 #else 7734 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); 7735 #endif 7736 description_length=(png_uint_32) strlen((const char *) profile_description); 7737 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20 7738 + description_length); 7739 #if PNG_LIBPNG_VER >= 10400 7740 text[0].text=(png_charp) png_malloc(ping, 7741 (png_alloc_size_t) allocated_length); 7742 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80); 7743 #else 7744 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length); 7745 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80); 7746 #endif 7747 text[0].key[0]='\0'; 7748 (void) ConcatenateMagickString(text[0].key, 7749 "Raw profile type ",MagickPathExtent); 7750 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62); 7751 sp=profile_data; 7752 dp=text[0].text; 7753 *dp++='\n'; 7754 (void) CopyMagickString(dp,(const char *) profile_description, 7755 allocated_length); 7756 dp+=description_length; 7757 *dp++='\n'; 7758 (void) FormatLocaleString(dp,allocated_length- 7759 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length); 7760 dp+=8; 7761 7762 for (i=0; i < (ssize_t) length; i++) 7763 { 7764 if (i%36 == 0) 7765 *dp++='\n'; 7766 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)]; 7767 *(dp++)=(char) hex[((*sp++ ) & 0x0f)]; 7768 } 7769 7770 *dp++='\n'; 7771 *dp='\0'; 7772 text[0].text_length=(png_size_t) (dp-text[0].text); 7773 text[0].compression=image_info->compression == NoCompression || 7774 (image_info->compression == UndefinedCompression && 7775 text[0].text_length < 128) ? -1 : 0; 7776 7777 if (text[0].text_length <= allocated_length) 7778 png_set_text(ping,ping_info,text,1); 7779 7780 png_free(ping,text[0].text); 7781 png_free(ping,text[0].key); 7782 png_free(ping,text); 7783 } 7784 7785 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image, 7786 const char *string, MagickBooleanType logging) 7787 { 7788 char 7789 *name; 7790 7791 const StringInfo 7792 *profile; 7793 7794 unsigned char 7795 *data; 7796 7797 png_uint_32 length; 7798 7799 ResetImageProfileIterator(image); 7800 7801 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 7802 { 7803 profile=GetImageProfile(image,name); 7804 7805 if (profile != (const StringInfo *) NULL) 7806 { 7807 StringInfo 7808 *ping_profile; 7809 7810 if (LocaleNCompare(name,string,11) == 0) 7811 { 7812 if (logging != MagickFalse) 7813 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 7814 " Found %s profile",name); 7815 7816 ping_profile=CloneStringInfo(profile); 7817 data=GetStringInfoDatum(ping_profile), 7818 length=(png_uint_32) GetStringInfoLength(ping_profile); 7819 data[4]=data[3]; 7820 data[3]=data[2]; 7821 data[2]=data[1]; 7822 data[1]=data[0]; 7823 (void) WriteBlobMSBULong(image,length-5); /* data length */ 7824 (void) WriteBlob(image,length-1,data+1); 7825 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1)); 7826 ping_profile=DestroyStringInfo(ping_profile); 7827 } 7828 } 7829 7830 name=GetNextImageProfile(image); 7831 } 7832 7833 return(MagickTrue); 7834 } 7835 7836 static inline MagickBooleanType Magick_png_color_equal(const Image *image, 7837 const Quantum *p, const PixelInfo *q) 7838 { 7839 MagickRealType 7840 value; 7841 7842 value=(MagickRealType) p[image->channel_map[RedPixelChannel].offset]; 7843 if (AbsolutePixelValue(value-q->red) >= MagickEpsilon) 7844 return(MagickFalse); 7845 value=(MagickRealType) p[image->channel_map[GreenPixelChannel].offset]; 7846 if (AbsolutePixelValue(value-q->green) >= MagickEpsilon) 7847 return(MagickFalse); 7848 value=(MagickRealType) p[image->channel_map[BluePixelChannel].offset]; 7849 if (AbsolutePixelValue(value-q->blue) >= MagickEpsilon) 7850 return(MagickFalse); 7851 7852 return(MagickTrue); 7853 } 7854 7855 #if defined(PNG_tIME_SUPPORTED) 7856 static void write_tIME_chunk(Image *image,png_struct *ping,png_info *info, 7857 const char *date,ExceptionInfo *exception) 7858 { 7859 unsigned int 7860 day, 7861 hour, 7862 minute, 7863 month, 7864 second, 7865 year; 7866 7867 png_time 7868 ptime; 7869 7870 time_t 7871 ttime; 7872 7873 if (date != (const char *) NULL) 7874 { 7875 if (sscanf(date,"%d-%d-%dT%d:%d:%dZ",&year,&month,&day,&hour,&minute, 7876 &second) != 6) 7877 { 7878 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 7879 "Invalid date format specified for png:tIME","`%s'", 7880 image->filename); 7881 return; 7882 } 7883 ptime.year=(png_uint_16) year; 7884 ptime.month=(png_byte) month; 7885 ptime.day=(png_byte) day; 7886 ptime.hour=(png_byte) hour; 7887 ptime.minute=(png_byte) minute; 7888 ptime.second=(png_byte) second; 7889 } 7890 else 7891 { 7892 time(&ttime); 7893 png_convert_from_time_t(&ptime,ttime); 7894 } 7895 png_set_tIME(ping,info,&ptime); 7896 } 7897 #endif 7898 7899 /* Write one PNG image */ 7900 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, 7901 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception) 7902 { 7903 char 7904 im_vers[32], 7905 libpng_runv[32], 7906 libpng_vers[32], 7907 zlib_runv[32], 7908 zlib_vers[32]; 7909 7910 Image 7911 *image; 7912 7913 ImageInfo 7914 *image_info; 7915 7916 char 7917 s[2]; 7918 7919 const char 7920 *name, 7921 *property, 7922 *value; 7923 7924 const StringInfo 7925 *profile; 7926 7927 int 7928 num_passes, 7929 pass; 7930 7931 png_byte 7932 ping_trans_alpha[256]; 7933 7934 png_color 7935 palette[257]; 7936 7937 png_color_16 7938 ping_background, 7939 ping_trans_color; 7940 7941 png_info 7942 *ping_info; 7943 7944 png_struct 7945 *ping; 7946 7947 png_uint_32 7948 ping_height, 7949 ping_width; 7950 7951 ssize_t 7952 y; 7953 7954 MagickBooleanType 7955 image_matte, 7956 logging, 7957 matte, 7958 7959 ping_have_blob, 7960 ping_have_cheap_transparency, 7961 ping_have_color, 7962 ping_have_non_bw, 7963 ping_have_PLTE, 7964 ping_have_bKGD, 7965 ping_have_iCCP, 7966 ping_have_pHYs, 7967 ping_have_sRGB, 7968 ping_have_tRNS, 7969 7970 ping_exclude_bKGD, 7971 ping_exclude_cHRM, 7972 ping_exclude_date, 7973 /* ping_exclude_EXIF, */ 7974 ping_exclude_gAMA, 7975 ping_exclude_iCCP, 7976 /* ping_exclude_iTXt, */ 7977 ping_exclude_oFFs, 7978 ping_exclude_pHYs, 7979 ping_exclude_sRGB, 7980 ping_exclude_tEXt, 7981 ping_exclude_tIME, 7982 /* ping_exclude_tRNS, */ 7983 ping_exclude_vpAg, 7984 ping_exclude_zCCP, /* hex-encoded iCCP */ 7985 ping_exclude_zTXt, 7986 7987 ping_preserve_colormap, 7988 ping_preserve_iCCP, 7989 ping_need_colortype_warning, 7990 7991 status, 7992 tried_332, 7993 tried_333, 7994 tried_444; 7995 7996 MemoryInfo 7997 *volatile pixel_info; 7998 7999 QuantumInfo 8000 *quantum_info; 8001 8002 PNGErrorInfo 8003 error_info; 8004 8005 register ssize_t 8006 i, 8007 x; 8008 8009 unsigned char 8010 *ping_pixels; 8011 8012 volatile int 8013 image_colors, 8014 ping_bit_depth, 8015 ping_color_type, 8016 ping_interlace_method, 8017 ping_compression_method, 8018 ping_filter_method, 8019 ping_num_trans; 8020 8021 volatile size_t 8022 image_depth, 8023 old_bit_depth; 8024 8025 size_t 8026 quality, 8027 rowbytes, 8028 save_image_depth; 8029 8030 int 8031 j, 8032 number_colors, 8033 number_opaque, 8034 number_semitransparent, 8035 number_transparent, 8036 ping_pHYs_unit_type; 8037 8038 png_uint_32 8039 ping_pHYs_x_resolution, 8040 ping_pHYs_y_resolution; 8041 8042 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 8043 " Enter WriteOnePNGImage()"); 8044 8045 image = CloneImage(IMimage,0,0,MagickFalse,exception); 8046 image_info=(ImageInfo *) CloneImageInfo(IMimage_info); 8047 if (image_info == (ImageInfo *) NULL) 8048 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed"); 8049 8050 /* Define these outside of the following "if logging()" block so they will 8051 * show in debuggers. 8052 */ 8053 *im_vers='\0'; 8054 (void) ConcatenateMagickString(im_vers, 8055 MagickLibVersionText,MagickPathExtent); 8056 (void) ConcatenateMagickString(im_vers, 8057 MagickLibAddendum,MagickPathExtent); 8058 8059 *libpng_vers='\0'; 8060 (void) ConcatenateMagickString(libpng_vers, 8061 PNG_LIBPNG_VER_STRING,32); 8062 *libpng_runv='\0'; 8063 (void) ConcatenateMagickString(libpng_runv, 8064 png_get_libpng_ver(NULL),32); 8065 8066 *zlib_vers='\0'; 8067 (void) ConcatenateMagickString(zlib_vers, 8068 ZLIB_VERSION,32); 8069 *zlib_runv='\0'; 8070 (void) ConcatenateMagickString(zlib_runv, 8071 zlib_version,32); 8072 8073 if (logging != MagickFalse) 8074 { 8075 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s", 8076 im_vers); 8077 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s", 8078 libpng_vers); 8079 if (LocaleCompare(libpng_vers,libpng_runv) != 0) 8080 { 8081 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 8082 libpng_runv); 8083 } 8084 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s", 8085 zlib_vers); 8086 if (LocaleCompare(zlib_vers,zlib_runv) != 0) 8087 { 8088 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s", 8089 zlib_runv); 8090 } 8091 } 8092 8093 /* Initialize some stuff */ 8094 ping_bit_depth=0, 8095 ping_color_type=0, 8096 ping_interlace_method=0, 8097 ping_compression_method=0, 8098 ping_filter_method=0, 8099 ping_num_trans = 0; 8100 8101 ping_background.red = 0; 8102 ping_background.green = 0; 8103 ping_background.blue = 0; 8104 ping_background.gray = 0; 8105 ping_background.index = 0; 8106 8107 ping_trans_color.red=0; 8108 ping_trans_color.green=0; 8109 ping_trans_color.blue=0; 8110 ping_trans_color.gray=0; 8111 8112 ping_pHYs_unit_type = 0; 8113 ping_pHYs_x_resolution = 0; 8114 ping_pHYs_y_resolution = 0; 8115 8116 ping_have_blob=MagickFalse; 8117 ping_have_cheap_transparency=MagickFalse; 8118 ping_have_color=MagickTrue; 8119 ping_have_non_bw=MagickTrue; 8120 ping_have_PLTE=MagickFalse; 8121 ping_have_bKGD=MagickFalse; 8122 ping_have_iCCP=MagickFalse; 8123 ping_have_pHYs=MagickFalse; 8124 ping_have_sRGB=MagickFalse; 8125 ping_have_tRNS=MagickFalse; 8126 8127 ping_exclude_bKGD=mng_info->ping_exclude_bKGD; 8128 ping_exclude_cHRM=mng_info->ping_exclude_cHRM; 8129 ping_exclude_date=mng_info->ping_exclude_date; 8130 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */ 8131 ping_exclude_gAMA=mng_info->ping_exclude_gAMA; 8132 ping_exclude_iCCP=mng_info->ping_exclude_iCCP; 8133 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */ 8134 ping_exclude_oFFs=mng_info->ping_exclude_oFFs; 8135 ping_exclude_pHYs=mng_info->ping_exclude_pHYs; 8136 ping_exclude_sRGB=mng_info->ping_exclude_sRGB; 8137 ping_exclude_tEXt=mng_info->ping_exclude_tEXt; 8138 ping_exclude_tIME=mng_info->ping_exclude_tIME; 8139 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */ 8140 ping_exclude_vpAg=mng_info->ping_exclude_vpAg; 8141 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */ 8142 ping_exclude_zTXt=mng_info->ping_exclude_zTXt; 8143 8144 ping_preserve_colormap = mng_info->ping_preserve_colormap; 8145 ping_preserve_iCCP = mng_info->ping_preserve_iCCP; 8146 ping_need_colortype_warning = MagickFalse; 8147 8148 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk, 8149 * i.e., eliminate the ICC profile and set image->rendering_intent. 8150 * Note that this will not involve any changes to the actual pixels 8151 * but merely passes information to applications that read the resulting 8152 * PNG image. 8153 * 8154 * To do: recognize other variants of the sRGB profile, using the CRC to 8155 * verify all recognized variants including the 7 already known. 8156 * 8157 * Work around libpng16+ rejecting some "known invalid sRGB profiles". 8158 * 8159 * Use something other than image->rendering_intent to record the fact 8160 * that the sRGB profile was found. 8161 * 8162 * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC 8163 * profile. Record the Blackpoint Compensation, if any. 8164 */ 8165 if (ping_exclude_sRGB == MagickFalse && ping_preserve_iCCP == MagickFalse) 8166 { 8167 char 8168 *name; 8169 8170 const StringInfo 8171 *profile; 8172 8173 ResetImageProfileIterator(image); 8174 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 8175 { 8176 profile=GetImageProfile(image,name); 8177 8178 if (profile != (StringInfo *) NULL) 8179 { 8180 if ((LocaleCompare(name,"ICC") == 0) || 8181 (LocaleCompare(name,"ICM") == 0)) 8182 8183 { 8184 int 8185 icheck, 8186 got_crc=0; 8187 8188 8189 png_uint_32 8190 length, 8191 profile_crc=0; 8192 8193 unsigned char 8194 *data; 8195 8196 length=(png_uint_32) GetStringInfoLength(profile); 8197 8198 for (icheck=0; sRGB_info[icheck].len > 0; icheck++) 8199 { 8200 if (length == sRGB_info[icheck].len) 8201 { 8202 if (got_crc == 0) 8203 { 8204 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8205 " Got a %lu-byte ICC profile (potentially sRGB)", 8206 (unsigned long) length); 8207 8208 data=GetStringInfoDatum(profile); 8209 profile_crc=crc32(0,data,length); 8210 8211 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8212 " with crc=%8x",(unsigned int) profile_crc); 8213 got_crc++; 8214 } 8215 8216 if (profile_crc == sRGB_info[icheck].crc) 8217 { 8218 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8219 " It is sRGB with rendering intent = %s", 8220 Magick_RenderingIntentString_from_PNG_RenderingIntent( 8221 sRGB_info[icheck].intent)); 8222 if (image->rendering_intent==UndefinedIntent) 8223 { 8224 image->rendering_intent= 8225 Magick_RenderingIntent_from_PNG_RenderingIntent( 8226 sRGB_info[icheck].intent); 8227 } 8228 ping_exclude_iCCP = MagickTrue; 8229 ping_exclude_zCCP = MagickTrue; 8230 ping_have_sRGB = MagickTrue; 8231 break; 8232 } 8233 } 8234 } 8235 if (sRGB_info[icheck].len == 0) 8236 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8237 " Got a %lu-byte ICC profile not recognized as sRGB", 8238 (unsigned long) length); 8239 } 8240 } 8241 name=GetNextImageProfile(image); 8242 } 8243 } 8244 8245 number_opaque = 0; 8246 number_semitransparent = 0; 8247 number_transparent = 0; 8248 8249 if (logging != MagickFalse) 8250 { 8251 if (image->storage_class == UndefinedClass) 8252 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8253 " image->storage_class=UndefinedClass"); 8254 if (image->storage_class == DirectClass) 8255 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8256 " image->storage_class=DirectClass"); 8257 if (image->storage_class == PseudoClass) 8258 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8259 " image->storage_class=PseudoClass"); 8260 (void) LogMagickEvent(CoderEvent,GetMagickModule(), image->taint ? 8261 " image->taint=MagickTrue": 8262 " image->taint=MagickFalse"); 8263 } 8264 8265 if (image->storage_class == PseudoClass && 8266 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 || 8267 mng_info->write_png48 || mng_info->write_png64 || 8268 (mng_info->write_png_colortype != 1 && 8269 mng_info->write_png_colortype != 5))) 8270 { 8271 (void) SyncImage(image,exception); 8272 image->storage_class = DirectClass; 8273 } 8274 8275 if (ping_preserve_colormap == MagickFalse) 8276 { 8277 if (image->storage_class != PseudoClass && image->colormap != NULL) 8278 { 8279 /* Free the bogus colormap; it can cause trouble later */ 8280 if (logging != MagickFalse) 8281 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8282 " Freeing bogus colormap"); 8283 (void) RelinquishMagickMemory(image->colormap); 8284 image->colormap=NULL; 8285 } 8286 } 8287 8288 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 8289 (void) TransformImageColorspace(image,sRGBColorspace,exception); 8290 8291 /* 8292 Sometimes we get PseudoClass images whose RGB values don't match 8293 the colors in the colormap. This code syncs the RGB values. 8294 */ 8295 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass) 8296 (void) SyncImage(image,exception); 8297 8298 #if (MAGICKCORE_QUANTUM_DEPTH == 8) 8299 if (image->depth > 8) 8300 { 8301 if (logging != MagickFalse) 8302 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8303 " Reducing PNG bit depth to 8 since this is a Q8 build."); 8304 8305 image->depth=8; 8306 } 8307 #endif 8308 8309 /* Respect the -depth option */ 8310 if (image->depth < 4) 8311 { 8312 register Quantum 8313 *r; 8314 8315 if (image->depth > 2) 8316 { 8317 /* Scale to 4-bit */ 8318 LBR04PacketRGBO(image->background_color); 8319 8320 for (y=0; y < (ssize_t) image->rows; y++) 8321 { 8322 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8323 8324 if (r == (Quantum *) NULL) 8325 break; 8326 8327 for (x=0; x < (ssize_t) image->columns; x++) 8328 { 8329 LBR04PixelRGBA(r); 8330 r+=GetPixelChannels(image); 8331 } 8332 8333 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8334 break; 8335 } 8336 8337 if (image->storage_class == PseudoClass && image->colormap != NULL) 8338 { 8339 for (i=0; i < (ssize_t) image->colors; i++) 8340 { 8341 LBR04PacketRGBO(image->colormap[i]); 8342 } 8343 } 8344 } 8345 else if (image->depth > 1) 8346 { 8347 /* Scale to 2-bit */ 8348 LBR02PacketRGBO(image->background_color); 8349 8350 for (y=0; y < (ssize_t) image->rows; y++) 8351 { 8352 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8353 8354 if (r == (Quantum *) NULL) 8355 break; 8356 8357 for (x=0; x < (ssize_t) image->columns; x++) 8358 { 8359 LBR02PixelRGBA(r); 8360 r+=GetPixelChannels(image); 8361 } 8362 8363 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8364 break; 8365 } 8366 8367 if (image->storage_class == PseudoClass && image->colormap != NULL) 8368 { 8369 for (i=0; i < (ssize_t) image->colors; i++) 8370 { 8371 LBR02PacketRGBO(image->colormap[i]); 8372 } 8373 } 8374 } 8375 else 8376 { 8377 /* Scale to 1-bit */ 8378 LBR01PacketRGBO(image->background_color); 8379 8380 for (y=0; y < (ssize_t) image->rows; y++) 8381 { 8382 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8383 8384 if (r == (Quantum *) NULL) 8385 break; 8386 8387 for (x=0; x < (ssize_t) image->columns; x++) 8388 { 8389 LBR01PixelRGBA(r); 8390 r+=GetPixelChannels(image); 8391 } 8392 8393 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8394 break; 8395 } 8396 8397 if (image->storage_class == PseudoClass && image->colormap != NULL) 8398 { 8399 for (i=0; i < (ssize_t) image->colors; i++) 8400 { 8401 LBR01PacketRGBO(image->colormap[i]); 8402 } 8403 } 8404 } 8405 } 8406 8407 /* To do: set to next higher multiple of 8 */ 8408 if (image->depth < 8) 8409 image->depth=8; 8410 8411 #if (MAGICKCORE_QUANTUM_DEPTH > 16) 8412 /* PNG does not handle depths greater than 16 so reduce it even 8413 * if lossy 8414 */ 8415 if (image->depth > 8) 8416 image->depth=16; 8417 #endif 8418 8419 #if (MAGICKCORE_QUANTUM_DEPTH > 8) 8420 if (image->depth > 8) 8421 { 8422 /* To do: fill low byte properly */ 8423 image->depth=16; 8424 } 8425 8426 if (image->depth == 16 && mng_info->write_png_depth != 16) 8427 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse) 8428 image->depth = 8; 8429 #endif 8430 8431 image_colors = (int) image->colors; 8432 number_opaque = (int) image->colors; 8433 number_transparent = 0; 8434 number_semitransparent = 0; 8435 8436 if (mng_info->write_png_colortype && 8437 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 && 8438 mng_info->write_png_colortype < 4 && 8439 image->alpha_trait == UndefinedPixelTrait))) 8440 { 8441 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we 8442 * are not going to need the result. 8443 */ 8444 if (mng_info->write_png_colortype == 1 || 8445 mng_info->write_png_colortype == 5) 8446 ping_have_color=MagickFalse; 8447 8448 if (image->alpha_trait != UndefinedPixelTrait) 8449 { 8450 number_transparent = 2; 8451 number_semitransparent = 1; 8452 } 8453 } 8454 8455 if (mng_info->write_png_colortype < 7) 8456 { 8457 /* BUILD_PALETTE 8458 * 8459 * Normally we run this just once, but in the case of writing PNG8 8460 * we reduce the transparency to binary and run again, then if there 8461 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1 8462 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA 8463 * palette. Then (To do) we take care of a final reduction that is only 8464 * needed if there are still 256 colors present and one of them has both 8465 * transparent and opaque instances. 8466 */ 8467 8468 tried_332 = MagickFalse; 8469 tried_333 = MagickFalse; 8470 tried_444 = MagickFalse; 8471 8472 for (j=0; j<6; j++) 8473 { 8474 /* 8475 * Sometimes we get DirectClass images that have 256 colors or fewer. 8476 * This code will build a colormap. 8477 * 8478 * Also, sometimes we get PseudoClass images with an out-of-date 8479 * colormap. This code will replace the colormap with a new one. 8480 * Sometimes we get PseudoClass images that have more than 256 colors. 8481 * This code will delete the colormap and change the image to 8482 * DirectClass. 8483 * 8484 * If image->alpha_trait is MagickFalse, we ignore the alpha channel 8485 * even though it sometimes contains left-over non-opaque values. 8486 * 8487 * Also we gather some information (number of opaque, transparent, 8488 * and semitransparent pixels, and whether the image has any non-gray 8489 * pixels or only black-and-white pixels) that we might need later. 8490 * 8491 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6) 8492 * we need to check for bogus non-opaque values, at least. 8493 */ 8494 8495 int 8496 n; 8497 8498 PixelInfo 8499 opaque[260], 8500 semitransparent[260], 8501 transparent[260]; 8502 8503 register const Quantum 8504 *s; 8505 8506 register Quantum 8507 *q, 8508 *r; 8509 8510 if (logging != MagickFalse) 8511 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8512 " Enter BUILD_PALETTE:"); 8513 8514 if (logging != MagickFalse) 8515 { 8516 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8517 " image->columns=%.20g",(double) image->columns); 8518 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8519 " image->rows=%.20g",(double) image->rows); 8520 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8521 " image->alpha_trait=%.20g",(double) image->alpha_trait); 8522 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8523 " image->depth=%.20g",(double) image->depth); 8524 8525 if (image->storage_class == PseudoClass && image->colormap != NULL) 8526 { 8527 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8528 " Original colormap:"); 8529 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8530 " i (red,green,blue,alpha)"); 8531 8532 for (i=0; i < 256; i++) 8533 { 8534 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8535 " %d (%d,%d,%d,%d)", 8536 (int) i, 8537 (int) image->colormap[i].red, 8538 (int) image->colormap[i].green, 8539 (int) image->colormap[i].blue, 8540 (int) image->colormap[i].alpha); 8541 } 8542 8543 for (i=image->colors - 10; i < (ssize_t) image->colors; i++) 8544 { 8545 if (i > 255) 8546 { 8547 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8548 " %d (%d,%d,%d,%d)", 8549 (int) i, 8550 (int) image->colormap[i].red, 8551 (int) image->colormap[i].green, 8552 (int) image->colormap[i].blue, 8553 (int) image->colormap[i].alpha); 8554 } 8555 } 8556 } 8557 8558 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8559 " image->colors=%d",(int) image->colors); 8560 8561 if (image->colors == 0) 8562 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8563 " (zero means unknown)"); 8564 8565 if (ping_preserve_colormap == MagickFalse) 8566 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8567 " Regenerate the colormap"); 8568 } 8569 8570 image_colors=0; 8571 number_opaque = 0; 8572 number_semitransparent = 0; 8573 number_transparent = 0; 8574 8575 for (y=0; y < (ssize_t) image->rows; y++) 8576 { 8577 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8578 8579 if (q == (Quantum *) NULL) 8580 break; 8581 8582 for (x=0; x < (ssize_t) image->columns; x++) 8583 { 8584 if (image->alpha_trait == UndefinedPixelTrait || 8585 GetPixelAlpha(image,q) == OpaqueAlpha) 8586 { 8587 if (number_opaque < 259) 8588 { 8589 if (number_opaque == 0) 8590 { 8591 GetPixelInfoPixel(image, q, opaque); 8592 opaque[0].alpha=OpaqueAlpha; 8593 number_opaque=1; 8594 } 8595 8596 for (i=0; i< (ssize_t) number_opaque; i++) 8597 { 8598 if (Magick_png_color_equal(image,q,opaque+i)) 8599 break; 8600 } 8601 8602 if (i == (ssize_t) number_opaque && number_opaque < 259) 8603 { 8604 number_opaque++; 8605 GetPixelInfoPixel(image, q, opaque+i); 8606 opaque[i].alpha=OpaqueAlpha; 8607 } 8608 } 8609 } 8610 else if (GetPixelAlpha(image,q) == TransparentAlpha) 8611 { 8612 if (number_transparent < 259) 8613 { 8614 if (number_transparent == 0) 8615 { 8616 GetPixelInfoPixel(image, q, transparent); 8617 ping_trans_color.red=(unsigned short) 8618 GetPixelRed(image,q); 8619 ping_trans_color.green=(unsigned short) 8620 GetPixelGreen(image,q); 8621 ping_trans_color.blue=(unsigned short) 8622 GetPixelBlue(image,q); 8623 ping_trans_color.gray=(unsigned short) 8624 GetPixelGray(image,q); 8625 number_transparent = 1; 8626 } 8627 8628 for (i=0; i< (ssize_t) number_transparent; i++) 8629 { 8630 if (Magick_png_color_equal(image,q,transparent+i)) 8631 break; 8632 } 8633 8634 if (i == (ssize_t) number_transparent && 8635 number_transparent < 259) 8636 { 8637 number_transparent++; 8638 GetPixelInfoPixel(image,q,transparent+i); 8639 } 8640 } 8641 } 8642 else 8643 { 8644 if (number_semitransparent < 259) 8645 { 8646 if (number_semitransparent == 0) 8647 { 8648 GetPixelInfoPixel(image,q,semitransparent); 8649 number_semitransparent = 1; 8650 } 8651 8652 for (i=0; i< (ssize_t) number_semitransparent; i++) 8653 { 8654 if (Magick_png_color_equal(image,q,semitransparent+i) 8655 && GetPixelAlpha(image,q) == 8656 semitransparent[i].alpha) 8657 break; 8658 } 8659 8660 if (i == (ssize_t) number_semitransparent && 8661 number_semitransparent < 259) 8662 { 8663 number_semitransparent++; 8664 GetPixelInfoPixel(image, q, semitransparent+i); 8665 } 8666 } 8667 } 8668 q+=GetPixelChannels(image); 8669 } 8670 } 8671 8672 if (mng_info->write_png8 == MagickFalse && 8673 ping_exclude_bKGD == MagickFalse) 8674 { 8675 /* Add the background color to the palette, if it 8676 * isn't already there. 8677 */ 8678 if (logging != MagickFalse) 8679 { 8680 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8681 " Check colormap for background (%d,%d,%d)", 8682 (int) image->background_color.red, 8683 (int) image->background_color.green, 8684 (int) image->background_color.blue); 8685 } 8686 for (i=0; i<number_opaque; i++) 8687 { 8688 if (opaque[i].red == image->background_color.red && 8689 opaque[i].green == image->background_color.green && 8690 opaque[i].blue == image->background_color.blue) 8691 break; 8692 } 8693 if (number_opaque < 259 && i == number_opaque) 8694 { 8695 opaque[i] = image->background_color; 8696 ping_background.index = i; 8697 number_opaque++; 8698 if (logging != MagickFalse) 8699 { 8700 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8701 " background_color index is %d",(int) i); 8702 } 8703 8704 } 8705 else if (logging != MagickFalse) 8706 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8707 " No room in the colormap to add background color"); 8708 } 8709 8710 image_colors=number_opaque+number_transparent+number_semitransparent; 8711 8712 if (logging != MagickFalse) 8713 { 8714 if (image_colors > 256) 8715 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8716 " image has more than 256 colors"); 8717 8718 else 8719 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8720 " image has %d colors",image_colors); 8721 } 8722 8723 if (ping_preserve_colormap != MagickFalse) 8724 break; 8725 8726 if (mng_info->write_png_colortype != 7) /* We won't need this info */ 8727 { 8728 ping_have_color=MagickFalse; 8729 ping_have_non_bw=MagickFalse; 8730 8731 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 8732 { 8733 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8734 "incompatible colorspace"); 8735 ping_have_color=MagickTrue; 8736 ping_have_non_bw=MagickTrue; 8737 } 8738 8739 if(image_colors > 256) 8740 { 8741 for (y=0; y < (ssize_t) image->rows; y++) 8742 { 8743 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8744 8745 if (q == (Quantum *) NULL) 8746 break; 8747 8748 s=q; 8749 for (x=0; x < (ssize_t) image->columns; x++) 8750 { 8751 if (GetPixelRed(image,s) != GetPixelGreen(image,s) || 8752 GetPixelRed(image,s) != GetPixelBlue(image,s)) 8753 { 8754 ping_have_color=MagickTrue; 8755 ping_have_non_bw=MagickTrue; 8756 break; 8757 } 8758 s+=GetPixelChannels(image); 8759 } 8760 8761 if (ping_have_color != MagickFalse) 8762 break; 8763 8764 /* Worst case is black-and-white; we are looking at every 8765 * pixel twice. 8766 */ 8767 8768 if (ping_have_non_bw == MagickFalse) 8769 { 8770 s=q; 8771 for (x=0; x < (ssize_t) image->columns; x++) 8772 { 8773 if (GetPixelRed(image,s) != 0 && 8774 GetPixelRed(image,s) != QuantumRange) 8775 { 8776 ping_have_non_bw=MagickTrue; 8777 break; 8778 } 8779 s+=GetPixelChannels(image); 8780 } 8781 } 8782 } 8783 } 8784 } 8785 8786 if (image_colors < 257) 8787 { 8788 PixelInfo 8789 colormap[260]; 8790 8791 /* 8792 * Initialize image colormap. 8793 */ 8794 8795 if (logging != MagickFalse) 8796 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8797 " Sort the new colormap"); 8798 8799 /* Sort palette, transparent first */; 8800 8801 n = 0; 8802 8803 for (i=0; i<number_transparent; i++) 8804 colormap[n++] = transparent[i]; 8805 8806 for (i=0; i<number_semitransparent; i++) 8807 colormap[n++] = semitransparent[i]; 8808 8809 for (i=0; i<number_opaque; i++) 8810 colormap[n++] = opaque[i]; 8811 8812 ping_background.index += 8813 (number_transparent + number_semitransparent); 8814 8815 /* image_colors < 257; search the colormap instead of the pixels 8816 * to get ping_have_color and ping_have_non_bw 8817 */ 8818 for (i=0; i<n; i++) 8819 { 8820 if (ping_have_color == MagickFalse) 8821 { 8822 if (colormap[i].red != colormap[i].green || 8823 colormap[i].red != colormap[i].blue) 8824 { 8825 ping_have_color=MagickTrue; 8826 ping_have_non_bw=MagickTrue; 8827 break; 8828 } 8829 } 8830 8831 if (ping_have_non_bw == MagickFalse) 8832 { 8833 if (colormap[i].red != 0 && colormap[i].red != QuantumRange) 8834 ping_have_non_bw=MagickTrue; 8835 } 8836 } 8837 8838 if ((mng_info->ping_exclude_tRNS == MagickFalse || 8839 (number_transparent == 0 && number_semitransparent == 0)) && 8840 (((mng_info->write_png_colortype-1) == 8841 PNG_COLOR_TYPE_PALETTE) || 8842 (mng_info->write_png_colortype == 0))) 8843 { 8844 if (logging != MagickFalse) 8845 { 8846 if (n != (ssize_t) image_colors) 8847 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8848 " image_colors (%d) and n (%d) don't match", 8849 image_colors, n); 8850 8851 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8852 " AcquireImageColormap"); 8853 } 8854 8855 image->colors = image_colors; 8856 8857 if (AcquireImageColormap(image,image_colors,exception) == 8858 MagickFalse) 8859 ThrowWriterException(ResourceLimitError, 8860 "MemoryAllocationFailed"); 8861 8862 for (i=0; i< (ssize_t) image_colors; i++) 8863 image->colormap[i] = colormap[i]; 8864 8865 if (logging != MagickFalse) 8866 { 8867 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8868 " image->colors=%d (%d)", 8869 (int) image->colors, image_colors); 8870 8871 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8872 " Update the pixel indexes"); 8873 } 8874 8875 /* Sync the pixel indices with the new colormap */ 8876 8877 for (y=0; y < (ssize_t) image->rows; y++) 8878 { 8879 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8880 8881 if (q == (Quantum *) NULL) 8882 break; 8883 8884 for (x=0; x < (ssize_t) image->columns; x++) 8885 { 8886 for (i=0; i< (ssize_t) image_colors; i++) 8887 { 8888 if ((image->alpha_trait == UndefinedPixelTrait || 8889 image->colormap[i].alpha == GetPixelAlpha(image,q)) && 8890 image->colormap[i].red == GetPixelRed(image,q) && 8891 image->colormap[i].green == GetPixelGreen(image,q) && 8892 image->colormap[i].blue == GetPixelBlue(image,q)) 8893 { 8894 SetPixelIndex(image,i,q); 8895 break; 8896 } 8897 } 8898 q+=GetPixelChannels(image); 8899 } 8900 8901 if (SyncAuthenticPixels(image,exception) == MagickFalse) 8902 break; 8903 } 8904 } 8905 } 8906 8907 if (logging != MagickFalse) 8908 { 8909 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8910 " image->colors=%d", (int) image->colors); 8911 8912 if (image->colormap != NULL) 8913 { 8914 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8915 " i (red,green,blue,alpha)"); 8916 8917 for (i=0; i < (ssize_t) image->colors; i++) 8918 { 8919 if (i < 300 || i >= (ssize_t) image->colors - 10) 8920 { 8921 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8922 " %d (%d,%d,%d,%d)", 8923 (int) i, 8924 (int) image->colormap[i].red, 8925 (int) image->colormap[i].green, 8926 (int) image->colormap[i].blue, 8927 (int) image->colormap[i].alpha); 8928 } 8929 } 8930 } 8931 8932 if (number_transparent < 257) 8933 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8934 " number_transparent = %d", 8935 number_transparent); 8936 else 8937 8938 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8939 " number_transparent > 256"); 8940 8941 if (number_opaque < 257) 8942 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8943 " number_opaque = %d", 8944 number_opaque); 8945 8946 else 8947 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8948 " number_opaque > 256"); 8949 8950 if (number_semitransparent < 257) 8951 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8952 " number_semitransparent = %d", 8953 number_semitransparent); 8954 8955 else 8956 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8957 " number_semitransparent > 256"); 8958 8959 if (ping_have_non_bw == MagickFalse) 8960 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8961 " All pixels and the background are black or white"); 8962 8963 else if (ping_have_color == MagickFalse) 8964 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8965 " All pixels and the background are gray"); 8966 8967 else 8968 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8969 " At least one pixel or the background is non-gray"); 8970 8971 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8972 " Exit BUILD_PALETTE:"); 8973 } 8974 8975 if (mng_info->write_png8 == MagickFalse) 8976 break; 8977 8978 /* Make any reductions necessary for the PNG8 format */ 8979 if (image_colors <= 256 && 8980 image_colors != 0 && image->colormap != NULL && 8981 number_semitransparent == 0 && 8982 number_transparent <= 1) 8983 break; 8984 8985 /* PNG8 can't have semitransparent colors so we threshold the 8986 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one 8987 * transparent color so if more than one is transparent we merge 8988 * them into image->background_color. 8989 */ 8990 if (number_semitransparent != 0 || number_transparent > 1) 8991 { 8992 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 8993 " Thresholding the alpha channel to binary"); 8994 8995 for (y=0; y < (ssize_t) image->rows; y++) 8996 { 8997 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 8998 8999 if (r == (Quantum *) NULL) 9000 break; 9001 9002 for (x=0; x < (ssize_t) image->columns; x++) 9003 { 9004 if (GetPixelAlpha(image,r) < OpaqueAlpha/2) 9005 { 9006 SetPixelViaPixelInfo(image,&image->background_color,r); 9007 SetPixelAlpha(image,TransparentAlpha,r); 9008 } 9009 else 9010 SetPixelAlpha(image,OpaqueAlpha,r); 9011 r+=GetPixelChannels(image); 9012 } 9013 9014 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9015 break; 9016 9017 if (image_colors != 0 && image_colors <= 256 && 9018 image->colormap != NULL) 9019 for (i=0; i<image_colors; i++) 9020 image->colormap[i].alpha = 9021 (image->colormap[i].alpha > TransparentAlpha/2 ? 9022 TransparentAlpha : OpaqueAlpha); 9023 } 9024 continue; 9025 } 9026 9027 /* PNG8 can't have more than 256 colors so we quantize the pixels and 9028 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the 9029 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256 9030 * colors or less. 9031 */ 9032 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9033 { 9034 if (logging != MagickFalse) 9035 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9036 " Quantizing the background color to 4-4-4"); 9037 9038 tried_444 = MagickTrue; 9039 9040 LBR04PacketRGB(image->background_color); 9041 9042 if (logging != MagickFalse) 9043 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9044 " Quantizing the pixel colors to 4-4-4"); 9045 9046 if (image->colormap == NULL) 9047 { 9048 for (y=0; y < (ssize_t) image->rows; y++) 9049 { 9050 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9051 9052 if (r == (Quantum *) NULL) 9053 break; 9054 9055 for (x=0; x < (ssize_t) image->columns; x++) 9056 { 9057 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9058 LBR04PixelRGB(r); 9059 r+=GetPixelChannels(image); 9060 } 9061 9062 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9063 break; 9064 } 9065 } 9066 9067 else /* Should not reach this; colormap already exists and 9068 must be <= 256 */ 9069 { 9070 if (logging != MagickFalse) 9071 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9072 " Quantizing the colormap to 4-4-4"); 9073 9074 for (i=0; i<image_colors; i++) 9075 { 9076 LBR04PacketRGB(image->colormap[i]); 9077 } 9078 } 9079 continue; 9080 } 9081 9082 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9083 { 9084 if (logging != MagickFalse) 9085 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9086 " Quantizing the background color to 3-3-3"); 9087 9088 tried_333 = MagickTrue; 9089 9090 LBR03PacketRGB(image->background_color); 9091 9092 if (logging != MagickFalse) 9093 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9094 " Quantizing the pixel colors to 3-3-3-1"); 9095 9096 if (image->colormap == NULL) 9097 { 9098 for (y=0; y < (ssize_t) image->rows; y++) 9099 { 9100 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9101 9102 if (r == (Quantum *) NULL) 9103 break; 9104 9105 for (x=0; x < (ssize_t) image->columns; x++) 9106 { 9107 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9108 LBR03RGB(r); 9109 r+=GetPixelChannels(image); 9110 } 9111 9112 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9113 break; 9114 } 9115 } 9116 9117 else /* Should not reach this; colormap already exists and 9118 must be <= 256 */ 9119 { 9120 if (logging != MagickFalse) 9121 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9122 " Quantizing the colormap to 3-3-3-1"); 9123 for (i=0; i<image_colors; i++) 9124 { 9125 LBR03PacketRGB(image->colormap[i]); 9126 } 9127 } 9128 continue; 9129 } 9130 9131 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256)) 9132 { 9133 if (logging != MagickFalse) 9134 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9135 " Quantizing the background color to 3-3-2"); 9136 9137 tried_332 = MagickTrue; 9138 9139 /* Red and green were already done so we only quantize the blue 9140 * channel 9141 */ 9142 9143 LBR02PacketBlue(image->background_color); 9144 9145 if (logging != MagickFalse) 9146 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9147 " Quantizing the pixel colors to 3-3-2-1"); 9148 9149 if (image->colormap == NULL) 9150 { 9151 for (y=0; y < (ssize_t) image->rows; y++) 9152 { 9153 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9154 9155 if (r == (Quantum *) NULL) 9156 break; 9157 9158 for (x=0; x < (ssize_t) image->columns; x++) 9159 { 9160 if (GetPixelAlpha(image,r) == OpaqueAlpha) 9161 LBR02PixelBlue(r); 9162 r+=GetPixelChannels(image); 9163 } 9164 9165 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9166 break; 9167 } 9168 } 9169 9170 else /* Should not reach this; colormap already exists and 9171 must be <= 256 */ 9172 { 9173 if (logging != MagickFalse) 9174 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9175 " Quantizing the colormap to 3-3-2-1"); 9176 for (i=0; i<image_colors; i++) 9177 { 9178 LBR02PacketBlue(image->colormap[i]); 9179 } 9180 } 9181 continue; 9182 } 9183 9184 if (image_colors == 0 || image_colors > 256) 9185 { 9186 /* Take care of special case with 256 opaque colors + 1 transparent 9187 * color. We don't need to quantize to 2-3-2-1; we only need to 9188 * eliminate one color, so we'll merge the two darkest red 9189 * colors (0x49, 0, 0) -> (0x24, 0, 0). 9190 */ 9191 if (logging != MagickFalse) 9192 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9193 " Merging two dark red background colors to 3-3-2-1"); 9194 9195 if (ScaleQuantumToChar(image->background_color.red) == 0x49 && 9196 ScaleQuantumToChar(image->background_color.green) == 0x00 && 9197 ScaleQuantumToChar(image->background_color.blue) == 0x00) 9198 { 9199 image->background_color.red=ScaleCharToQuantum(0x24); 9200 } 9201 9202 if (logging != MagickFalse) 9203 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9204 " Merging two dark red pixel colors to 3-3-2-1"); 9205 9206 if (image->colormap == NULL) 9207 { 9208 for (y=0; y < (ssize_t) image->rows; y++) 9209 { 9210 r=GetAuthenticPixels(image,0,y,image->columns,1,exception); 9211 9212 if (r == (Quantum *) NULL) 9213 break; 9214 9215 for (x=0; x < (ssize_t) image->columns; x++) 9216 { 9217 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 && 9218 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 && 9219 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 && 9220 GetPixelAlpha(image,r) == OpaqueAlpha) 9221 { 9222 SetPixelRed(image,ScaleCharToQuantum(0x24),r); 9223 } 9224 r+=GetPixelChannels(image); 9225 } 9226 9227 if (SyncAuthenticPixels(image,exception) == MagickFalse) 9228 break; 9229 9230 } 9231 } 9232 9233 else 9234 { 9235 for (i=0; i<image_colors; i++) 9236 { 9237 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 && 9238 ScaleQuantumToChar(image->colormap[i].green) == 0x00 && 9239 ScaleQuantumToChar(image->colormap[i].blue) == 0x00) 9240 { 9241 image->colormap[i].red=ScaleCharToQuantum(0x24); 9242 } 9243 } 9244 } 9245 } 9246 } 9247 } 9248 /* END OF BUILD_PALETTE */ 9249 9250 /* If we are excluding the tRNS chunk and there is transparency, 9251 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6) 9252 * PNG. 9253 */ 9254 if (mng_info->ping_exclude_tRNS != MagickFalse && 9255 (number_transparent != 0 || number_semitransparent != 0)) 9256 { 9257 unsigned int colortype=mng_info->write_png_colortype; 9258 9259 if (ping_have_color == MagickFalse) 9260 mng_info->write_png_colortype = 5; 9261 9262 else 9263 mng_info->write_png_colortype = 7; 9264 9265 if (colortype != 0 && 9266 mng_info->write_png_colortype != colortype) 9267 ping_need_colortype_warning=MagickTrue; 9268 9269 } 9270 9271 /* See if cheap transparency is possible. It is only possible 9272 * when there is a single transparent color, no semitransparent 9273 * color, and no opaque color that has the same RGB components 9274 * as the transparent color. We only need this information if 9275 * we are writing a PNG with colortype 0 or 2, and we have not 9276 * excluded the tRNS chunk. 9277 */ 9278 if (number_transparent == 1 && 9279 mng_info->write_png_colortype < 4) 9280 { 9281 ping_have_cheap_transparency = MagickTrue; 9282 9283 if (number_semitransparent != 0) 9284 ping_have_cheap_transparency = MagickFalse; 9285 9286 else if (image_colors == 0 || image_colors > 256 || 9287 image->colormap == NULL) 9288 { 9289 register const Quantum 9290 *q; 9291 9292 for (y=0; y < (ssize_t) image->rows; y++) 9293 { 9294 q=GetVirtualPixels(image,0,y,image->columns,1, exception); 9295 9296 if (q == (Quantum *) NULL) 9297 break; 9298 9299 for (x=0; x < (ssize_t) image->columns; x++) 9300 { 9301 if (GetPixelAlpha(image,q) != TransparentAlpha && 9302 (unsigned short) GetPixelRed(image,q) == 9303 ping_trans_color.red && 9304 (unsigned short) GetPixelGreen(image,q) == 9305 ping_trans_color.green && 9306 (unsigned short) GetPixelBlue(image,q) == 9307 ping_trans_color.blue) 9308 { 9309 ping_have_cheap_transparency = MagickFalse; 9310 break; 9311 } 9312 9313 q+=GetPixelChannels(image); 9314 } 9315 9316 if (ping_have_cheap_transparency == MagickFalse) 9317 break; 9318 } 9319 } 9320 else 9321 { 9322 /* Assuming that image->colormap[0] is the one transparent color 9323 * and that all others are opaque. 9324 */ 9325 if (image_colors > 1) 9326 for (i=1; i<image_colors; i++) 9327 if (image->colormap[i].red == image->colormap[0].red && 9328 image->colormap[i].green == image->colormap[0].green && 9329 image->colormap[i].blue == image->colormap[0].blue) 9330 { 9331 ping_have_cheap_transparency = MagickFalse; 9332 break; 9333 } 9334 } 9335 9336 if (logging != MagickFalse) 9337 { 9338 if (ping_have_cheap_transparency == MagickFalse) 9339 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9340 " Cheap transparency is not possible."); 9341 9342 else 9343 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9344 " Cheap transparency is possible."); 9345 } 9346 } 9347 else 9348 ping_have_cheap_transparency = MagickFalse; 9349 9350 image_depth=image->depth; 9351 9352 quantum_info = (QuantumInfo *) NULL; 9353 number_colors=0; 9354 image_colors=(int) image->colors; 9355 image_matte=image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse; 9356 9357 if (mng_info->write_png_colortype < 5) 9358 mng_info->IsPalette=image->storage_class == PseudoClass && 9359 image_colors <= 256 && image->colormap != NULL; 9360 else 9361 mng_info->IsPalette = MagickFalse; 9362 9363 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) && 9364 (image->colors == 0 || image->colormap == NULL)) 9365 { 9366 image_info=DestroyImageInfo(image_info); 9367 image=DestroyImage(image); 9368 (void) ThrowMagickException(exception,GetMagickModule(),CoderError, 9369 "Cannot write PNG8 or color-type 3; colormap is NULL", 9370 "`%s'",IMimage->filename); 9371 return(MagickFalse); 9372 } 9373 9374 /* 9375 Allocate the PNG structures 9376 */ 9377 #ifdef PNG_USER_MEM_SUPPORTED 9378 error_info.image=image; 9379 error_info.exception=exception; 9380 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info, 9381 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL, 9382 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free); 9383 9384 #else 9385 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info, 9386 MagickPNGErrorHandler,MagickPNGWarningHandler); 9387 9388 #endif 9389 if (ping == (png_struct *) NULL) 9390 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 9391 9392 ping_info=png_create_info_struct(ping); 9393 9394 if (ping_info == (png_info *) NULL) 9395 { 9396 png_destroy_write_struct(&ping,(png_info **) NULL); 9397 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 9398 } 9399 9400 png_set_write_fn(ping,image,png_put_data,png_flush_data); 9401 pixel_info=(MemoryInfo *) NULL; 9402 9403 if (setjmp(png_jmpbuf(ping))) 9404 { 9405 /* 9406 PNG write failed. 9407 */ 9408 #ifdef PNG_DEBUG 9409 if (image_info->verbose) 9410 (void) printf("PNG write has failed.\n"); 9411 #endif 9412 png_destroy_write_struct(&ping,&ping_info); 9413 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 9414 UnlockSemaphoreInfo(ping_semaphore); 9415 #endif 9416 9417 if (pixel_info != (MemoryInfo *) NULL) 9418 pixel_info=RelinquishVirtualMemory(pixel_info); 9419 9420 if (quantum_info != (QuantumInfo *) NULL) 9421 quantum_info=DestroyQuantumInfo(quantum_info); 9422 9423 if (ping_have_blob != MagickFalse) 9424 (void) CloseBlob(image); 9425 image_info=DestroyImageInfo(image_info); 9426 image=DestroyImage(image); 9427 return(MagickFalse); 9428 } 9429 9430 /* { For navigation to end of SETJMP-protected block. Within this 9431 * block, use png_error() instead of Throwing an Exception, to ensure 9432 * that libpng is able to clean up, and that the semaphore is unlocked. 9433 */ 9434 9435 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 9436 LockSemaphoreInfo(ping_semaphore); 9437 #endif 9438 9439 #ifdef PNG_BENIGN_ERRORS_SUPPORTED 9440 /* Allow benign errors */ 9441 png_set_benign_errors(ping, 1); 9442 #endif 9443 9444 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 9445 /* Reject images with too many rows or columns */ 9446 png_set_user_limits(ping, 9447 (png_uint_32) MagickMin(0x7fffffffL, 9448 GetMagickResourceLimit(WidthResource)), 9449 (png_uint_32) MagickMin(0x7fffffffL, 9450 GetMagickResourceLimit(HeightResource))); 9451 #endif /* PNG_SET_USER_LIMITS_SUPPORTED */ 9452 9453 /* 9454 Prepare PNG for writing. 9455 */ 9456 9457 #if defined(PNG_MNG_FEATURES_SUPPORTED) 9458 if (mng_info->write_mng) 9459 { 9460 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES); 9461 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED 9462 /* Disable new libpng-1.5.10 feature when writing a MNG because 9463 * zero-length PLTE is OK 9464 */ 9465 png_set_check_for_invalid_index (ping, 0); 9466 # endif 9467 } 9468 9469 #else 9470 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 9471 if (mng_info->write_mng) 9472 png_permit_empty_plte(ping,MagickTrue); 9473 9474 # endif 9475 #endif 9476 9477 x=0; 9478 9479 ping_width=(png_uint_32) image->columns; 9480 ping_height=(png_uint_32) image->rows; 9481 9482 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32) 9483 image_depth=8; 9484 9485 if (mng_info->write_png48 || mng_info->write_png64) 9486 image_depth=16; 9487 9488 if (mng_info->write_png_depth != 0) 9489 image_depth=mng_info->write_png_depth; 9490 9491 /* Adjust requested depth to next higher valid depth if necessary */ 9492 if (image_depth > 8) 9493 image_depth=16; 9494 9495 if ((image_depth > 4) && (image_depth < 8)) 9496 image_depth=8; 9497 9498 if (image_depth == 3) 9499 image_depth=4; 9500 9501 if (logging != MagickFalse) 9502 { 9503 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9504 " width=%.20g",(double) ping_width); 9505 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9506 " height=%.20g",(double) ping_height); 9507 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9508 " image_matte=%.20g",(double) image->alpha_trait); 9509 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9510 " image->depth=%.20g",(double) image->depth); 9511 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9512 " Tentative ping_bit_depth=%.20g",(double) image_depth); 9513 } 9514 9515 save_image_depth=image_depth; 9516 ping_bit_depth=(png_byte) save_image_depth; 9517 9518 9519 #if defined(PNG_pHYs_SUPPORTED) 9520 if (ping_exclude_pHYs == MagickFalse) 9521 { 9522 if ((image->resolution.x != 0) && (image->resolution.y != 0) && 9523 (!mng_info->write_mng || !mng_info->equal_physs)) 9524 { 9525 if (logging != MagickFalse) 9526 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9527 " Setting up pHYs chunk"); 9528 9529 if (image->units == PixelsPerInchResolution) 9530 { 9531 ping_pHYs_unit_type=PNG_RESOLUTION_METER; 9532 ping_pHYs_x_resolution= 9533 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54); 9534 ping_pHYs_y_resolution= 9535 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54); 9536 } 9537 9538 else if (image->units == PixelsPerCentimeterResolution) 9539 { 9540 ping_pHYs_unit_type=PNG_RESOLUTION_METER; 9541 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5); 9542 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5); 9543 } 9544 9545 else 9546 { 9547 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN; 9548 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x; 9549 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y; 9550 } 9551 9552 if (logging != MagickFalse) 9553 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9554 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.", 9555 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution, 9556 (int) ping_pHYs_unit_type); 9557 ping_have_pHYs = MagickTrue; 9558 } 9559 } 9560 #endif 9561 9562 if (ping_exclude_bKGD == MagickFalse) 9563 { 9564 if ((!mng_info->adjoin || !mng_info->equal_backgrounds)) 9565 { 9566 unsigned int 9567 mask; 9568 9569 mask=0xffff; 9570 if (ping_bit_depth == 8) 9571 mask=0x00ff; 9572 9573 if (ping_bit_depth == 4) 9574 mask=0x000f; 9575 9576 if (ping_bit_depth == 2) 9577 mask=0x0003; 9578 9579 if (ping_bit_depth == 1) 9580 mask=0x0001; 9581 9582 ping_background.red=(png_uint_16) 9583 (ScaleQuantumToShort(image->background_color.red) & mask); 9584 9585 ping_background.green=(png_uint_16) 9586 (ScaleQuantumToShort(image->background_color.green) & mask); 9587 9588 ping_background.blue=(png_uint_16) 9589 (ScaleQuantumToShort(image->background_color.blue) & mask); 9590 9591 ping_background.gray=(png_uint_16) ping_background.green; 9592 } 9593 9594 if (logging != MagickFalse) 9595 { 9596 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9597 " Setting up bKGD chunk (1)"); 9598 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9599 " background_color index is %d", 9600 (int) ping_background.index); 9601 9602 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9603 " ping_bit_depth=%d",ping_bit_depth); 9604 } 9605 9606 ping_have_bKGD = MagickTrue; 9607 } 9608 9609 /* 9610 Select the color type. 9611 */ 9612 matte=image_matte; 9613 old_bit_depth=0; 9614 9615 if (mng_info->IsPalette && mng_info->write_png8) 9616 { 9617 /* To do: make this a function cause it's used twice, except 9618 for reducing the sample depth from 8. */ 9619 9620 number_colors=image_colors; 9621 9622 ping_have_tRNS=MagickFalse; 9623 9624 /* 9625 Set image palette. 9626 */ 9627 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 9628 9629 if (logging != MagickFalse) 9630 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9631 " Setting up PLTE chunk with %d colors (%d)", 9632 number_colors, image_colors); 9633 9634 for (i=0; i < (ssize_t) number_colors; i++) 9635 { 9636 palette[i].red=ScaleQuantumToChar(image->colormap[i].red); 9637 palette[i].green=ScaleQuantumToChar(image->colormap[i].green); 9638 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); 9639 if (logging != MagickFalse) 9640 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9641 #if MAGICKCORE_QUANTUM_DEPTH == 8 9642 " %3ld (%3d,%3d,%3d)", 9643 #else 9644 " %5ld (%5d,%5d,%5d)", 9645 #endif 9646 (long) i,palette[i].red,palette[i].green,palette[i].blue); 9647 9648 } 9649 9650 ping_have_PLTE=MagickTrue; 9651 image_depth=ping_bit_depth; 9652 ping_num_trans=0; 9653 9654 if (matte != MagickFalse) 9655 { 9656 /* 9657 Identify which colormap entry is transparent. 9658 */ 9659 assert(number_colors <= 256); 9660 assert(image->colormap != NULL); 9661 9662 for (i=0; i < (ssize_t) number_transparent; i++) 9663 ping_trans_alpha[i]=0; 9664 9665 9666 ping_num_trans=(unsigned short) (number_transparent + 9667 number_semitransparent); 9668 9669 if (ping_num_trans == 0) 9670 ping_have_tRNS=MagickFalse; 9671 9672 else 9673 ping_have_tRNS=MagickTrue; 9674 } 9675 9676 if (ping_exclude_bKGD == MagickFalse) 9677 { 9678 /* 9679 * Identify which colormap entry is the background color. 9680 */ 9681 9682 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++) 9683 if (IsPNGColorEqual(ping_background,image->colormap[i])) 9684 break; 9685 9686 ping_background.index=(png_byte) i; 9687 9688 if (logging != MagickFalse) 9689 { 9690 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9691 " background_color index is %d", 9692 (int) ping_background.index); 9693 } 9694 } 9695 } /* end of write_png8 */ 9696 9697 else if (mng_info->write_png_colortype == 1) 9698 { 9699 image_matte=MagickFalse; 9700 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY; 9701 } 9702 9703 else if (mng_info->write_png24 || mng_info->write_png48 || 9704 mng_info->write_png_colortype == 3) 9705 { 9706 image_matte=MagickFalse; 9707 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9708 } 9709 9710 else if (mng_info->write_png32 || mng_info->write_png64 || 9711 mng_info->write_png_colortype == 7) 9712 { 9713 image_matte=MagickTrue; 9714 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; 9715 } 9716 9717 else /* mng_info->write_pngNN not specified */ 9718 { 9719 image_depth=ping_bit_depth; 9720 9721 if (mng_info->write_png_colortype != 0) 9722 { 9723 ping_color_type=(png_byte) mng_info->write_png_colortype-1; 9724 9725 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 9726 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 9727 image_matte=MagickTrue; 9728 9729 else 9730 image_matte=MagickFalse; 9731 9732 if (logging != MagickFalse) 9733 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9734 " PNG colortype %d was specified:",(int) ping_color_type); 9735 } 9736 9737 else /* write_png_colortype not specified */ 9738 { 9739 if (logging != MagickFalse) 9740 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9741 " Selecting PNG colortype:"); 9742 9743 ping_color_type=(png_byte) ((matte != MagickFalse)? 9744 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB); 9745 9746 if (image_info->type == TrueColorType) 9747 { 9748 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9749 image_matte=MagickFalse; 9750 } 9751 9752 if (image_info->type == TrueColorAlphaType) 9753 { 9754 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; 9755 image_matte=MagickTrue; 9756 } 9757 9758 if (image_info->type == PaletteType || 9759 image_info->type == PaletteAlphaType) 9760 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 9761 9762 if (mng_info->write_png_colortype == 0 && 9763 image_info->type == UndefinedType) 9764 { 9765 if (ping_have_color == MagickFalse) 9766 { 9767 if (image_matte == MagickFalse) 9768 { 9769 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY; 9770 image_matte=MagickFalse; 9771 } 9772 9773 else 9774 { 9775 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA; 9776 image_matte=MagickTrue; 9777 } 9778 } 9779 else 9780 { 9781 if (image_matte == MagickFalse) 9782 { 9783 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; 9784 image_matte=MagickFalse; 9785 } 9786 9787 else 9788 { 9789 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA; 9790 image_matte=MagickTrue; 9791 } 9792 } 9793 } 9794 9795 } 9796 9797 if (logging != MagickFalse) 9798 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9799 " Selected PNG colortype=%d",ping_color_type); 9800 9801 if (ping_bit_depth < 8) 9802 { 9803 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 9804 ping_color_type == PNG_COLOR_TYPE_RGB || 9805 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) 9806 ping_bit_depth=8; 9807 } 9808 9809 old_bit_depth=ping_bit_depth; 9810 9811 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 9812 { 9813 if (image->alpha_trait == UndefinedPixelTrait && ping_have_non_bw == MagickFalse) 9814 ping_bit_depth=1; 9815 } 9816 9817 if (ping_color_type == PNG_COLOR_TYPE_PALETTE) 9818 { 9819 size_t one = 1; 9820 ping_bit_depth=1; 9821 9822 if (image->colors == 0) 9823 { 9824 /* DO SOMETHING */ 9825 png_error(ping,"image has 0 colors"); 9826 } 9827 9828 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors) 9829 ping_bit_depth <<= 1; 9830 } 9831 9832 if (logging != MagickFalse) 9833 { 9834 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9835 " Number of colors: %.20g",(double) image_colors); 9836 9837 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9838 " Tentative PNG bit depth: %d",ping_bit_depth); 9839 } 9840 9841 if (ping_bit_depth < (int) mng_info->write_png_depth) 9842 ping_bit_depth = mng_info->write_png_depth; 9843 } 9844 9845 image_depth=ping_bit_depth; 9846 9847 if (logging != MagickFalse) 9848 { 9849 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9850 " Tentative PNG color type: %s (%.20g)", 9851 PngColorTypeToString(ping_color_type), 9852 (double) ping_color_type); 9853 9854 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9855 " image_info->type: %.20g",(double) image_info->type); 9856 9857 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9858 " image_depth: %.20g",(double) image_depth); 9859 9860 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9861 9862 " image->depth: %.20g",(double) image->depth); 9863 9864 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9865 " ping_bit_depth: %.20g",(double) ping_bit_depth); 9866 } 9867 9868 if (matte != MagickFalse) 9869 { 9870 if (mng_info->IsPalette) 9871 { 9872 if (mng_info->write_png_colortype == 0) 9873 { 9874 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA; 9875 9876 if (ping_have_color != MagickFalse) 9877 ping_color_type=PNG_COLOR_TYPE_RGBA; 9878 } 9879 9880 /* 9881 * Determine if there is any transparent color. 9882 */ 9883 if (number_transparent + number_semitransparent == 0) 9884 { 9885 /* 9886 No transparent pixels are present. Change 4 or 6 to 0 or 2. 9887 */ 9888 9889 image_matte=MagickFalse; 9890 9891 if (mng_info->write_png_colortype == 0) 9892 ping_color_type&=0x03; 9893 } 9894 9895 else 9896 { 9897 unsigned int 9898 mask; 9899 9900 mask=0xffff; 9901 9902 if (ping_bit_depth == 8) 9903 mask=0x00ff; 9904 9905 if (ping_bit_depth == 4) 9906 mask=0x000f; 9907 9908 if (ping_bit_depth == 2) 9909 mask=0x0003; 9910 9911 if (ping_bit_depth == 1) 9912 mask=0x0001; 9913 9914 ping_trans_color.red=(png_uint_16) 9915 (ScaleQuantumToShort(image->colormap[0].red) & mask); 9916 9917 ping_trans_color.green=(png_uint_16) 9918 (ScaleQuantumToShort(image->colormap[0].green) & mask); 9919 9920 ping_trans_color.blue=(png_uint_16) 9921 (ScaleQuantumToShort(image->colormap[0].blue) & mask); 9922 9923 ping_trans_color.gray=(png_uint_16) 9924 (ScaleQuantumToShort(GetPixelInfoIntensity(image, 9925 image->colormap)) & mask); 9926 9927 ping_trans_color.index=(png_byte) 0; 9928 9929 ping_have_tRNS=MagickTrue; 9930 } 9931 9932 if (ping_have_tRNS != MagickFalse) 9933 { 9934 /* 9935 * Determine if there is one and only one transparent color 9936 * and if so if it is fully transparent. 9937 */ 9938 if (ping_have_cheap_transparency == MagickFalse) 9939 ping_have_tRNS=MagickFalse; 9940 } 9941 9942 if (ping_have_tRNS != MagickFalse) 9943 { 9944 if (mng_info->write_png_colortype == 0) 9945 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */ 9946 9947 if (image_depth == 8) 9948 { 9949 ping_trans_color.red&=0xff; 9950 ping_trans_color.green&=0xff; 9951 ping_trans_color.blue&=0xff; 9952 ping_trans_color.gray&=0xff; 9953 } 9954 } 9955 } 9956 else 9957 { 9958 if (image_depth == 8) 9959 { 9960 ping_trans_color.red&=0xff; 9961 ping_trans_color.green&=0xff; 9962 ping_trans_color.blue&=0xff; 9963 ping_trans_color.gray&=0xff; 9964 } 9965 } 9966 } 9967 9968 matte=image_matte; 9969 9970 if (ping_have_tRNS != MagickFalse) 9971 image_matte=MagickFalse; 9972 9973 if ((mng_info->IsPalette) && 9974 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE && 9975 ping_have_color == MagickFalse && 9976 (image_matte == MagickFalse || image_depth >= 8)) 9977 { 9978 size_t one=1; 9979 9980 if (image_matte != MagickFalse) 9981 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA; 9982 9983 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA) 9984 { 9985 ping_color_type=PNG_COLOR_TYPE_GRAY; 9986 9987 if (save_image_depth == 16 && image_depth == 8) 9988 { 9989 if (logging != MagickFalse) 9990 { 9991 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 9992 " Scaling ping_trans_color (0)"); 9993 } 9994 ping_trans_color.gray*=0x0101; 9995 } 9996 } 9997 9998 if (image_depth > MAGICKCORE_QUANTUM_DEPTH) 9999 image_depth=MAGICKCORE_QUANTUM_DEPTH; 10000 10001 if ((image_colors == 0) || 10002 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize)) 10003 image_colors=(int) (one << image_depth); 10004 10005 if (image_depth > 8) 10006 ping_bit_depth=16; 10007 10008 else 10009 { 10010 ping_bit_depth=8; 10011 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 10012 { 10013 if(!mng_info->write_png_depth) 10014 { 10015 ping_bit_depth=1; 10016 10017 while ((int) (one << ping_bit_depth) 10018 < (ssize_t) image_colors) 10019 ping_bit_depth <<= 1; 10020 } 10021 } 10022 10023 else if (ping_color_type == 10024 PNG_COLOR_TYPE_GRAY && image_colors < 17 && 10025 mng_info->IsPalette) 10026 { 10027 /* Check if grayscale is reducible */ 10028 10029 int 10030 depth_4_ok=MagickTrue, 10031 depth_2_ok=MagickTrue, 10032 depth_1_ok=MagickTrue; 10033 10034 for (i=0; i < (ssize_t) image_colors; i++) 10035 { 10036 unsigned char 10037 intensity; 10038 10039 intensity=ScaleQuantumToChar(image->colormap[i].red); 10040 10041 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4)) 10042 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse; 10043 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2)) 10044 depth_2_ok=depth_1_ok=MagickFalse; 10045 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1)) 10046 depth_1_ok=MagickFalse; 10047 } 10048 10049 if (depth_1_ok && mng_info->write_png_depth <= 1) 10050 ping_bit_depth=1; 10051 10052 else if (depth_2_ok && mng_info->write_png_depth <= 2) 10053 ping_bit_depth=2; 10054 10055 else if (depth_4_ok && mng_info->write_png_depth <= 4) 10056 ping_bit_depth=4; 10057 } 10058 } 10059 10060 image_depth=ping_bit_depth; 10061 } 10062 10063 else 10064 10065 if (mng_info->IsPalette) 10066 { 10067 number_colors=image_colors; 10068 10069 if (image_depth <= 8) 10070 { 10071 /* 10072 Set image palette. 10073 */ 10074 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; 10075 10076 if (!(mng_info->have_write_global_plte && matte == MagickFalse)) 10077 { 10078 for (i=0; i < (ssize_t) number_colors; i++) 10079 { 10080 palette[i].red=ScaleQuantumToChar(image->colormap[i].red); 10081 palette[i].green=ScaleQuantumToChar(image->colormap[i].green); 10082 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); 10083 } 10084 10085 if (logging != MagickFalse) 10086 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10087 " Setting up PLTE chunk with %d colors", 10088 number_colors); 10089 10090 ping_have_PLTE=MagickTrue; 10091 } 10092 10093 /* color_type is PNG_COLOR_TYPE_PALETTE */ 10094 if (mng_info->write_png_depth == 0) 10095 { 10096 size_t 10097 one; 10098 10099 ping_bit_depth=1; 10100 one=1; 10101 10102 while ((one << ping_bit_depth) < (size_t) number_colors) 10103 ping_bit_depth <<= 1; 10104 } 10105 10106 ping_num_trans=0; 10107 10108 if (matte != MagickFalse) 10109 { 10110 /* 10111 * Set up trans_colors array. 10112 */ 10113 assert(number_colors <= 256); 10114 10115 ping_num_trans=(unsigned short) (number_transparent + 10116 number_semitransparent); 10117 10118 if (ping_num_trans == 0) 10119 ping_have_tRNS=MagickFalse; 10120 10121 else 10122 { 10123 if (logging != MagickFalse) 10124 { 10125 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10126 " Scaling ping_trans_color (1)"); 10127 } 10128 ping_have_tRNS=MagickTrue; 10129 10130 for (i=0; i < ping_num_trans; i++) 10131 { 10132 ping_trans_alpha[i]= (png_byte) 10133 ScaleQuantumToChar(image->colormap[i].alpha); 10134 } 10135 } 10136 } 10137 } 10138 } 10139 10140 else 10141 { 10142 10143 if (image_depth < 8) 10144 image_depth=8; 10145 10146 if ((save_image_depth == 16) && (image_depth == 8)) 10147 { 10148 if (logging != MagickFalse) 10149 { 10150 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10151 " Scaling ping_trans_color from (%d,%d,%d)", 10152 (int) ping_trans_color.red, 10153 (int) ping_trans_color.green, 10154 (int) ping_trans_color.blue); 10155 } 10156 10157 ping_trans_color.red*=0x0101; 10158 ping_trans_color.green*=0x0101; 10159 ping_trans_color.blue*=0x0101; 10160 ping_trans_color.gray*=0x0101; 10161 10162 if (logging != MagickFalse) 10163 { 10164 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10165 " to (%d,%d,%d)", 10166 (int) ping_trans_color.red, 10167 (int) ping_trans_color.green, 10168 (int) ping_trans_color.blue); 10169 } 10170 } 10171 } 10172 10173 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth) 10174 ping_bit_depth = (ssize_t) mng_info->write_png_depth; 10175 10176 /* 10177 Adjust background and transparency samples in sub-8-bit grayscale files. 10178 */ 10179 if (ping_bit_depth < 8 && ping_color_type == 10180 PNG_COLOR_TYPE_GRAY) 10181 { 10182 png_uint_16 10183 maxval; 10184 10185 size_t 10186 one=1; 10187 10188 maxval=(png_uint_16) ((one << ping_bit_depth)-1); 10189 10190 if (ping_exclude_bKGD == MagickFalse) 10191 { 10192 10193 ping_background.gray=(png_uint_16) ((maxval/65535.)* 10194 (ScaleQuantumToShort(((GetPixelInfoIntensity(image, 10195 &image->background_color))) +.5))); 10196 10197 if (logging != MagickFalse) 10198 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10199 " Setting up bKGD chunk (2)"); 10200 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10201 " background_color index is %d", 10202 (int) ping_background.index); 10203 10204 ping_have_bKGD = MagickTrue; 10205 } 10206 10207 if (logging != MagickFalse) 10208 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10209 " Scaling ping_trans_color.gray from %d", 10210 (int)ping_trans_color.gray); 10211 10212 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*( 10213 ping_trans_color.gray)+.5); 10214 10215 if (logging != MagickFalse) 10216 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10217 " to %d", (int)ping_trans_color.gray); 10218 } 10219 10220 if (ping_exclude_bKGD == MagickFalse) 10221 { 10222 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE) 10223 { 10224 /* 10225 Identify which colormap entry is the background color. 10226 */ 10227 10228 number_colors=image_colors; 10229 10230 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++) 10231 if (IsPNGColorEqual(image->background_color,image->colormap[i])) 10232 break; 10233 10234 ping_background.index=(png_byte) i; 10235 10236 if (logging != MagickFalse) 10237 { 10238 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10239 " Setting up bKGD chunk with index=%d",(int) i); 10240 } 10241 10242 if (i < (ssize_t) number_colors) 10243 { 10244 ping_have_bKGD = MagickTrue; 10245 10246 if (logging != MagickFalse) 10247 { 10248 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10249 " background =(%d,%d,%d)", 10250 (int) ping_background.red, 10251 (int) ping_background.green, 10252 (int) ping_background.blue); 10253 } 10254 } 10255 10256 else /* Can't happen */ 10257 { 10258 if (logging != MagickFalse) 10259 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10260 " No room in PLTE to add bKGD color"); 10261 ping_have_bKGD = MagickFalse; 10262 } 10263 } 10264 } 10265 10266 if (logging != MagickFalse) 10267 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10268 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type), 10269 ping_color_type); 10270 /* 10271 Initialize compression level and filtering. 10272 */ 10273 if (logging != MagickFalse) 10274 { 10275 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10276 " Setting up deflate compression"); 10277 10278 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10279 " Compression buffer size: 32768"); 10280 } 10281 10282 png_set_compression_buffer_size(ping,32768L); 10283 10284 if (logging != MagickFalse) 10285 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10286 " Compression mem level: 9"); 10287 10288 png_set_compression_mem_level(ping, 9); 10289 10290 /* Untangle the "-quality" setting: 10291 10292 Undefined is 0; the default is used. 10293 Default is 75 10294 10295 10's digit: 10296 10297 0 or omitted: Use Z_HUFFMAN_ONLY strategy with the 10298 zlib default compression level 10299 10300 1-9: the zlib compression level 10301 10302 1's digit: 10303 10304 0-4: the PNG filter method 10305 10306 5: libpng adaptive filtering if compression level > 5 10307 libpng filter type "none" if compression level <= 5 10308 or if image is grayscale or palette 10309 10310 6: libpng adaptive filtering 10311 10312 7: "LOCO" filtering (intrapixel differing) if writing 10313 a MNG, otherwise "none". Did not work in IM-6.7.0-9 10314 and earlier because of a missing "else". 10315 10316 8: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive 10317 filtering. Unused prior to IM-6.7.0-10, was same as 6 10318 10319 9: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters 10320 Unused prior to IM-6.7.0-10, was same as 6 10321 10322 Note that using the -quality option, not all combinations of 10323 PNG filter type, zlib compression level, and zlib compression 10324 strategy are possible. This will be addressed soon in a 10325 release that accomodates "-define png:compression-strategy", etc. 10326 10327 */ 10328 10329 quality=image_info->quality == UndefinedCompressionQuality ? 75UL : 10330 image_info->quality; 10331 10332 if (quality <= 9) 10333 { 10334 if (mng_info->write_png_compression_strategy == 0) 10335 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1; 10336 } 10337 10338 else if (mng_info->write_png_compression_level == 0) 10339 { 10340 int 10341 level; 10342 10343 level=(int) MagickMin((ssize_t) quality/10,9); 10344 10345 mng_info->write_png_compression_level = level+1; 10346 } 10347 10348 if (mng_info->write_png_compression_strategy == 0) 10349 { 10350 if ((quality %10) == 8 || (quality %10) == 9) 10351 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */ 10352 mng_info->write_png_compression_strategy=Z_RLE+1; 10353 #else 10354 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 10355 #endif 10356 } 10357 10358 if (mng_info->write_png_compression_filter == 0) 10359 mng_info->write_png_compression_filter=((int) quality % 10) + 1; 10360 10361 if (logging != MagickFalse) 10362 { 10363 if (mng_info->write_png_compression_level) 10364 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10365 " Compression level: %d", 10366 (int) mng_info->write_png_compression_level-1); 10367 10368 if (mng_info->write_png_compression_strategy) 10369 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10370 " Compression strategy: %d", 10371 (int) mng_info->write_png_compression_strategy-1); 10372 10373 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10374 " Setting up filtering"); 10375 10376 if (mng_info->write_png_compression_filter == 6) 10377 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10378 " Base filter method: ADAPTIVE"); 10379 else if (mng_info->write_png_compression_filter == 0 || 10380 mng_info->write_png_compression_filter == 1) 10381 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10382 " Base filter method: NONE"); 10383 else 10384 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10385 " Base filter method: %d", 10386 (int) mng_info->write_png_compression_filter-1); 10387 } 10388 10389 if (mng_info->write_png_compression_level != 0) 10390 png_set_compression_level(ping,mng_info->write_png_compression_level-1); 10391 10392 if (mng_info->write_png_compression_filter == 6) 10393 { 10394 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || 10395 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) || 10396 (quality < 50)) 10397 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10398 else 10399 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS); 10400 } 10401 else if (mng_info->write_png_compression_filter == 7 || 10402 mng_info->write_png_compression_filter == 10) 10403 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS); 10404 10405 else if (mng_info->write_png_compression_filter == 8) 10406 { 10407 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING) 10408 if (mng_info->write_mng) 10409 { 10410 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) || 10411 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA)) 10412 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING; 10413 } 10414 #endif 10415 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10416 } 10417 10418 else if (mng_info->write_png_compression_filter == 9) 10419 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); 10420 10421 else if (mng_info->write_png_compression_filter != 0) 10422 png_set_filter(ping,PNG_FILTER_TYPE_BASE, 10423 mng_info->write_png_compression_filter-1); 10424 10425 if (mng_info->write_png_compression_strategy != 0) 10426 png_set_compression_strategy(ping, 10427 mng_info->write_png_compression_strategy-1); 10428 10429 ping_interlace_method=image_info->interlace != NoInterlace; 10430 10431 if (mng_info->write_mng) 10432 png_set_sig_bytes(ping,8); 10433 10434 /* Bail out if cannot meet defined png:bit-depth or png:color-type */ 10435 10436 if (mng_info->write_png_colortype != 0) 10437 { 10438 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY) 10439 if (ping_have_color != MagickFalse) 10440 { 10441 ping_color_type = PNG_COLOR_TYPE_RGB; 10442 10443 if (ping_bit_depth < 8) 10444 ping_bit_depth=8; 10445 } 10446 10447 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA) 10448 if (ping_have_color != MagickFalse) 10449 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA; 10450 } 10451 10452 if (ping_need_colortype_warning != MagickFalse || 10453 ((mng_info->write_png_depth && 10454 (int) mng_info->write_png_depth != ping_bit_depth) || 10455 (mng_info->write_png_colortype && 10456 ((int) mng_info->write_png_colortype-1 != ping_color_type && 10457 mng_info->write_png_colortype != 7 && 10458 !(mng_info->write_png_colortype == 5 && ping_color_type == 0))))) 10459 { 10460 if (logging != MagickFalse) 10461 { 10462 if (ping_need_colortype_warning != MagickFalse) 10463 { 10464 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10465 " Image has transparency but tRNS chunk was excluded"); 10466 } 10467 10468 if (mng_info->write_png_depth) 10469 { 10470 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10471 " Defined png:bit-depth=%u, Computed depth=%u", 10472 mng_info->write_png_depth, 10473 ping_bit_depth); 10474 } 10475 10476 if (mng_info->write_png_colortype) 10477 { 10478 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10479 " Defined png:color-type=%u, Computed color type=%u", 10480 mng_info->write_png_colortype-1, 10481 ping_color_type); 10482 } 10483 } 10484 10485 png_warning(ping, 10486 "Cannot write image with defined png:bit-depth or png:color-type."); 10487 } 10488 10489 if (image_matte != MagickFalse && image->alpha_trait == UndefinedPixelTrait) 10490 { 10491 /* Add an opaque matte channel */ 10492 image->alpha_trait = BlendPixelTrait; 10493 (void) SetImageAlpha(image,OpaqueAlpha,exception); 10494 10495 if (logging != MagickFalse) 10496 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10497 " Added an opaque matte channel"); 10498 } 10499 10500 if (number_transparent != 0 || number_semitransparent != 0) 10501 { 10502 if (ping_color_type < 4) 10503 { 10504 ping_have_tRNS=MagickTrue; 10505 if (logging != MagickFalse) 10506 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10507 " Setting ping_have_tRNS=MagickTrue."); 10508 } 10509 } 10510 10511 if (logging != MagickFalse) 10512 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10513 " Writing PNG header chunks"); 10514 10515 png_set_IHDR(ping,ping_info,ping_width,ping_height, 10516 ping_bit_depth,ping_color_type, 10517 ping_interlace_method,ping_compression_method, 10518 ping_filter_method); 10519 10520 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse) 10521 { 10522 png_set_PLTE(ping,ping_info,palette,number_colors); 10523 10524 if (logging != MagickFalse) 10525 { 10526 for (i=0; i< (ssize_t) number_colors; i++) 10527 { 10528 if (i < ping_num_trans) 10529 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10530 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)", 10531 (int) i, 10532 (int) palette[i].red, 10533 (int) palette[i].green, 10534 (int) palette[i].blue, 10535 (int) i, 10536 (int) ping_trans_alpha[i]); 10537 else 10538 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10539 " PLTE[%d] = (%d,%d,%d)", 10540 (int) i, 10541 (int) palette[i].red, 10542 (int) palette[i].green, 10543 (int) palette[i].blue); 10544 } 10545 } 10546 } 10547 10548 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */ 10549 if (ping_exclude_sRGB != MagickFalse || 10550 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10551 { 10552 if ((ping_exclude_tEXt == MagickFalse || 10553 ping_exclude_zTXt == MagickFalse) && 10554 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)) 10555 { 10556 ResetImageProfileIterator(image); 10557 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 10558 { 10559 profile=GetImageProfile(image,name); 10560 10561 if (profile != (StringInfo *) NULL) 10562 { 10563 #ifdef PNG_WRITE_iCCP_SUPPORTED 10564 if ((LocaleCompare(name,"ICC") == 0) || 10565 (LocaleCompare(name,"ICM") == 0)) 10566 { 10567 10568 if (ping_exclude_iCCP == MagickFalse) 10569 { 10570 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10571 " Setting up iCCP chunk"); 10572 10573 png_set_iCCP(ping,ping_info,(png_charp) name,0, 10574 #if (PNG_LIBPNG_VER < 10500) 10575 (png_charp) GetStringInfoDatum(profile), 10576 #else 10577 (const png_byte *) GetStringInfoDatum(profile), 10578 #endif 10579 (png_uint_32) GetStringInfoLength(profile)); 10580 ping_have_iCCP = MagickTrue; 10581 } 10582 } 10583 10584 else 10585 #endif 10586 if (ping_exclude_zCCP == MagickFalse) 10587 { 10588 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10589 " Setting up zTXT chunk with uuencoded ICC"); 10590 Magick_png_write_raw_profile(image_info,ping,ping_info, 10591 (unsigned char *) name,(unsigned char *) name, 10592 GetStringInfoDatum(profile), 10593 (png_uint_32) GetStringInfoLength(profile)); 10594 ping_have_iCCP = MagickTrue; 10595 } 10596 } 10597 10598 if (logging != MagickFalse) 10599 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10600 " Setting up text chunk with %s profile",name); 10601 10602 name=GetNextImageProfile(image); 10603 } 10604 } 10605 } 10606 10607 #if defined(PNG_WRITE_sRGB_SUPPORTED) 10608 if ((mng_info->have_write_global_srgb == 0) && 10609 ping_have_iCCP != MagickTrue && 10610 (ping_have_sRGB != MagickFalse || 10611 png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10612 { 10613 if (ping_exclude_sRGB == MagickFalse) 10614 { 10615 /* 10616 Note image rendering intent. 10617 */ 10618 if (logging != MagickFalse) 10619 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10620 " Setting up sRGB chunk"); 10621 10622 (void) png_set_sRGB(ping,ping_info,( 10623 Magick_RenderingIntent_to_PNG_RenderingIntent( 10624 image->rendering_intent))); 10625 10626 ping_have_sRGB = MagickTrue; 10627 } 10628 } 10629 10630 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB))) 10631 #endif 10632 { 10633 if (ping_exclude_gAMA == MagickFalse && 10634 ping_have_iCCP == MagickFalse && 10635 ping_have_sRGB == MagickFalse && 10636 (ping_exclude_sRGB == MagickFalse || 10637 (image->gamma < .45 || image->gamma > .46))) 10638 { 10639 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0)) 10640 { 10641 /* 10642 Note image gamma. 10643 To do: check for cHRM+gAMA == sRGB, and write sRGB instead. 10644 */ 10645 if (logging != MagickFalse) 10646 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10647 " Setting up gAMA chunk"); 10648 10649 png_set_gAMA(ping,ping_info,image->gamma); 10650 } 10651 } 10652 10653 if (ping_exclude_cHRM == MagickFalse && ping_have_sRGB == MagickFalse) 10654 { 10655 if ((mng_info->have_write_global_chrm == 0) && 10656 (image->chromaticity.red_primary.x != 0.0)) 10657 { 10658 /* 10659 Note image chromaticity. 10660 Note: if cHRM+gAMA == sRGB write sRGB instead. 10661 */ 10662 PrimaryInfo 10663 bp, 10664 gp, 10665 rp, 10666 wp; 10667 10668 wp=image->chromaticity.white_point; 10669 rp=image->chromaticity.red_primary; 10670 gp=image->chromaticity.green_primary; 10671 bp=image->chromaticity.blue_primary; 10672 10673 if (logging != MagickFalse) 10674 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10675 " Setting up cHRM chunk"); 10676 10677 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y, 10678 bp.x,bp.y); 10679 } 10680 } 10681 } 10682 10683 if (ping_exclude_bKGD == MagickFalse) 10684 { 10685 if (ping_have_bKGD != MagickFalse) 10686 { 10687 png_set_bKGD(ping,ping_info,&ping_background); 10688 if (logging != MagickFalse) 10689 { 10690 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10691 " Setting up bKGD chunk"); 10692 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10693 " background color = (%d,%d,%d)", 10694 (int) ping_background.red, 10695 (int) ping_background.green, 10696 (int) ping_background.blue); 10697 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10698 " index = %d, gray=%d", 10699 (int) ping_background.index, 10700 (int) ping_background.gray); 10701 } 10702 } 10703 } 10704 10705 if (ping_exclude_pHYs == MagickFalse) 10706 { 10707 if (ping_have_pHYs != MagickFalse) 10708 { 10709 png_set_pHYs(ping,ping_info, 10710 ping_pHYs_x_resolution, 10711 ping_pHYs_y_resolution, 10712 ping_pHYs_unit_type); 10713 10714 if (logging != MagickFalse) 10715 { 10716 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10717 " Setting up pHYs chunk"); 10718 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10719 " x_resolution=%lu", 10720 (unsigned long) ping_pHYs_x_resolution); 10721 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10722 " y_resolution=%lu", 10723 (unsigned long) ping_pHYs_y_resolution); 10724 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10725 " unit_type=%lu", 10726 (unsigned long) ping_pHYs_unit_type); 10727 } 10728 } 10729 } 10730 10731 #if defined(PNG_oFFs_SUPPORTED) 10732 if (ping_exclude_oFFs == MagickFalse) 10733 { 10734 if (image->page.x || image->page.y) 10735 { 10736 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x, 10737 (png_int_32) image->page.y, 0); 10738 10739 if (logging != MagickFalse) 10740 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10741 " Setting up oFFs chunk with x=%d, y=%d, units=0", 10742 (int) image->page.x, (int) image->page.y); 10743 } 10744 } 10745 #endif 10746 10747 #if defined(PNG_tIME_SUPPORTED) 10748 if (ping_exclude_tIME == MagickFalse) 10749 { 10750 const char 10751 *timestamp; 10752 10753 if (image->taint == MagickFalse) 10754 { 10755 timestamp=GetImageOption(image_info,"png:tIME"); 10756 10757 if (timestamp == (const char *) NULL) 10758 timestamp=GetImageProperty(image,"png:tIME",exception); 10759 } 10760 10761 else 10762 { 10763 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10764 " Reset tIME in tainted image"); 10765 10766 timestamp=GetImageProperty(image,"date:modify",exception); 10767 } 10768 10769 if (timestamp != (const char *) NULL) 10770 write_tIME_chunk(image,ping,ping_info,timestamp,exception); 10771 } 10772 #endif 10773 10774 if (mng_info->need_blob != MagickFalse) 10775 { 10776 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) == 10777 MagickFalse) 10778 png_error(ping,"WriteBlob Failed"); 10779 10780 ping_have_blob=MagickTrue; 10781 } 10782 10783 png_write_info_before_PLTE(ping, ping_info); 10784 10785 if (ping_have_tRNS != MagickFalse && ping_color_type < 4) 10786 { 10787 if (logging != MagickFalse) 10788 { 10789 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10790 " Calling png_set_tRNS with num_trans=%d",ping_num_trans); 10791 } 10792 10793 if (ping_color_type == 3) 10794 (void) png_set_tRNS(ping, ping_info, 10795 ping_trans_alpha, 10796 ping_num_trans, 10797 NULL); 10798 10799 else 10800 { 10801 (void) png_set_tRNS(ping, ping_info, 10802 NULL, 10803 0, 10804 &ping_trans_color); 10805 10806 if (logging != MagickFalse) 10807 { 10808 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10809 " tRNS color =(%d,%d,%d)", 10810 (int) ping_trans_color.red, 10811 (int) ping_trans_color.green, 10812 (int) ping_trans_color.blue); 10813 } 10814 } 10815 } 10816 10817 /* write any png-chunk-b profiles */ 10818 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging); 10819 10820 png_write_info(ping,ping_info); 10821 10822 /* write any PNG-chunk-m profiles */ 10823 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging); 10824 10825 if (ping_exclude_vpAg == MagickFalse) 10826 { 10827 if ((image->page.width != 0 && image->page.width != image->columns) || 10828 (image->page.height != 0 && image->page.height != image->rows)) 10829 { 10830 unsigned char 10831 chunk[14]; 10832 10833 (void) WriteBlobMSBULong(image,9L); /* data length=8 */ 10834 PNGType(chunk,mng_vpAg); 10835 LogPNGChunk(logging,mng_vpAg,9L); 10836 PNGLong(chunk+4,(png_uint_32) image->page.width); 10837 PNGLong(chunk+8,(png_uint_32) image->page.height); 10838 chunk[12]=0; /* unit = pixels */ 10839 (void) WriteBlob(image,13,chunk); 10840 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 10841 } 10842 } 10843 10844 #if (PNG_LIBPNG_VER == 10206) 10845 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */ 10846 #define PNG_HAVE_IDAT 0x04 10847 ping->mode |= PNG_HAVE_IDAT; 10848 #undef PNG_HAVE_IDAT 10849 #endif 10850 10851 png_set_packing(ping); 10852 /* 10853 Allocate memory. 10854 */ 10855 rowbytes=image->columns; 10856 if (image_depth > 8) 10857 rowbytes*=2; 10858 switch (ping_color_type) 10859 { 10860 case PNG_COLOR_TYPE_RGB: 10861 rowbytes*=3; 10862 break; 10863 10864 case PNG_COLOR_TYPE_GRAY_ALPHA: 10865 rowbytes*=2; 10866 break; 10867 10868 case PNG_COLOR_TYPE_RGBA: 10869 rowbytes*=4; 10870 break; 10871 10872 default: 10873 break; 10874 } 10875 10876 if (logging != MagickFalse) 10877 { 10878 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10879 " Writing PNG image data"); 10880 10881 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10882 " Allocating %.20g bytes of memory for pixels",(double) rowbytes); 10883 } 10884 pixel_info=AcquireVirtualMemory(rowbytes,sizeof(*ping_pixels)); 10885 if (pixel_info == (MemoryInfo *) NULL) 10886 png_error(ping,"Allocation of memory for pixels failed"); 10887 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 10888 10889 /* 10890 Initialize image scanlines. 10891 */ 10892 quantum_info=AcquireQuantumInfo(image_info,image); 10893 if (quantum_info == (QuantumInfo *) NULL) 10894 png_error(ping,"Memory allocation for quantum_info failed"); 10895 quantum_info->format=UndefinedQuantumFormat; 10896 SetQuantumDepth(image,quantum_info,image_depth); 10897 (void) SetQuantumEndian(image,quantum_info,MSBEndian); 10898 num_passes=png_set_interlace_handling(ping); 10899 10900 if ((!mng_info->write_png8 && !mng_info->write_png24 && 10901 !mng_info->write_png48 && !mng_info->write_png64 && 10902 !mng_info->write_png32) && 10903 (mng_info->IsPalette || 10904 (image_info->type == BilevelType)) && 10905 image_matte == MagickFalse && 10906 ping_have_non_bw == MagickFalse) 10907 { 10908 /* Palette, Bilevel, or Opaque Monochrome */ 10909 register const Quantum 10910 *p; 10911 10912 SetQuantumDepth(image,quantum_info,8); 10913 for (pass=0; pass < num_passes; pass++) 10914 { 10915 /* 10916 Convert PseudoClass image to a PNG monochrome image. 10917 */ 10918 for (y=0; y < (ssize_t) image->rows; y++) 10919 { 10920 if (logging != MagickFalse && y == 0) 10921 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10922 " Writing row of pixels (0)"); 10923 10924 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 10925 10926 if (p == (const Quantum *) NULL) 10927 break; 10928 10929 if (mng_info->IsPalette) 10930 { 10931 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10932 quantum_info,GrayQuantum,ping_pixels,exception); 10933 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE && 10934 mng_info->write_png_depth && 10935 mng_info->write_png_depth != old_bit_depth) 10936 { 10937 /* Undo pixel scaling */ 10938 for (i=0; i < (ssize_t) image->columns; i++) 10939 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i) 10940 >> (8-old_bit_depth)); 10941 } 10942 } 10943 10944 else 10945 { 10946 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10947 quantum_info,RedQuantum,ping_pixels,exception); 10948 } 10949 10950 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE) 10951 for (i=0; i < (ssize_t) image->columns; i++) 10952 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ? 10953 255 : 0); 10954 10955 if (logging != MagickFalse && y == 0) 10956 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 10957 " Writing row of pixels (1)"); 10958 10959 png_write_row(ping,ping_pixels); 10960 10961 status=SetImageProgress(image,SaveImageTag, 10962 (MagickOffsetType) (pass * image->rows + y), 10963 num_passes * image->rows); 10964 10965 if (status == MagickFalse) 10966 break; 10967 } 10968 } 10969 } 10970 10971 else /* Not Palette, Bilevel, or Opaque Monochrome */ 10972 { 10973 if ((!mng_info->write_png8 && !mng_info->write_png24 && 10974 !mng_info->write_png48 && !mng_info->write_png64 && 10975 !mng_info->write_png32) && (image_matte != MagickFalse || 10976 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) && 10977 (mng_info->IsPalette) && ping_have_color == MagickFalse) 10978 { 10979 register const Quantum 10980 *p; 10981 10982 for (pass=0; pass < num_passes; pass++) 10983 { 10984 10985 for (y=0; y < (ssize_t) image->rows; y++) 10986 { 10987 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 10988 10989 if (p == (const Quantum *) NULL) 10990 break; 10991 10992 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 10993 { 10994 if (mng_info->IsPalette) 10995 (void) ExportQuantumPixels(image,(CacheView *) NULL, 10996 quantum_info,GrayQuantum,ping_pixels,exception); 10997 10998 else 10999 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11000 quantum_info,RedQuantum,ping_pixels,exception); 11001 11002 if (logging != MagickFalse && y == 0) 11003 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11004 " Writing GRAY PNG pixels (2)"); 11005 } 11006 11007 else /* PNG_COLOR_TYPE_GRAY_ALPHA */ 11008 { 11009 if (logging != MagickFalse && y == 0) 11010 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11011 " Writing GRAY_ALPHA PNG pixels (2)"); 11012 11013 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11014 quantum_info,GrayAlphaQuantum,ping_pixels,exception); 11015 } 11016 11017 if (logging != MagickFalse && y == 0) 11018 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11019 " Writing row of pixels (2)"); 11020 11021 png_write_row(ping,ping_pixels); 11022 11023 status=SetImageProgress(image,SaveImageTag, 11024 (MagickOffsetType) (pass * image->rows + y), 11025 num_passes * image->rows); 11026 11027 if (status == MagickFalse) 11028 break; 11029 } 11030 } 11031 } 11032 11033 else 11034 { 11035 register const Quantum 11036 *p; 11037 11038 for (pass=0; pass < num_passes; pass++) 11039 { 11040 if ((image_depth > 8) || 11041 mng_info->write_png24 || 11042 mng_info->write_png32 || 11043 mng_info->write_png48 || 11044 mng_info->write_png64 || 11045 (!mng_info->write_png8 && !mng_info->IsPalette)) 11046 { 11047 for (y=0; y < (ssize_t) image->rows; y++) 11048 { 11049 p=GetVirtualPixels(image,0,y,image->columns,1, exception); 11050 11051 if (p == (const Quantum *) NULL) 11052 break; 11053 11054 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 11055 { 11056 if (image->storage_class == DirectClass) 11057 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11058 quantum_info,RedQuantum,ping_pixels,exception); 11059 11060 else 11061 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11062 quantum_info,GrayQuantum,ping_pixels,exception); 11063 } 11064 11065 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 11066 { 11067 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11068 quantum_info,GrayAlphaQuantum,ping_pixels, 11069 exception); 11070 11071 if (logging != MagickFalse && y == 0) 11072 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11073 " Writing GRAY_ALPHA PNG pixels (3)"); 11074 } 11075 11076 else if (image_matte != MagickFalse) 11077 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11078 quantum_info,RGBAQuantum,ping_pixels,exception); 11079 11080 else 11081 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11082 quantum_info,RGBQuantum,ping_pixels,exception); 11083 11084 if (logging != MagickFalse && y == 0) 11085 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11086 " Writing row of pixels (3)"); 11087 11088 png_write_row(ping,ping_pixels); 11089 11090 status=SetImageProgress(image,SaveImageTag, 11091 (MagickOffsetType) (pass * image->rows + y), 11092 num_passes * image->rows); 11093 11094 if (status == MagickFalse) 11095 break; 11096 } 11097 } 11098 11099 else 11100 /* not ((image_depth > 8) || 11101 mng_info->write_png24 || mng_info->write_png32 || 11102 mng_info->write_png48 || mng_info->write_png64 || 11103 (!mng_info->write_png8 && !mng_info->IsPalette)) 11104 */ 11105 { 11106 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) && 11107 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA)) 11108 { 11109 if (logging != MagickFalse) 11110 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11111 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass); 11112 11113 SetQuantumDepth(image,quantum_info,8); 11114 image_depth=8; 11115 } 11116 11117 for (y=0; y < (ssize_t) image->rows; y++) 11118 { 11119 if (logging != MagickFalse && y == 0) 11120 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11121 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass); 11122 11123 p=GetVirtualPixels(image,0,y,image->columns,1, exception); 11124 11125 if (p == (const Quantum *) NULL) 11126 break; 11127 11128 if (ping_color_type == PNG_COLOR_TYPE_GRAY) 11129 { 11130 SetQuantumDepth(image,quantum_info,image->depth); 11131 11132 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11133 quantum_info,GrayQuantum,ping_pixels,exception); 11134 } 11135 11136 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 11137 { 11138 if (logging != MagickFalse && y == 0) 11139 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11140 " Writing GRAY_ALPHA PNG pixels (4)"); 11141 11142 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11143 quantum_info,GrayAlphaQuantum,ping_pixels, 11144 exception); 11145 } 11146 11147 else 11148 { 11149 (void) ExportQuantumPixels(image,(CacheView *) NULL, 11150 quantum_info,IndexQuantum,ping_pixels,exception); 11151 11152 if (logging != MagickFalse && y <= 2) 11153 { 11154 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11155 " Writing row of non-gray pixels (4)"); 11156 11157 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11158 " ping_pixels[0]=%d,ping_pixels[1]=%d", 11159 (int)ping_pixels[0],(int)ping_pixels[1]); 11160 } 11161 } 11162 png_write_row(ping,ping_pixels); 11163 11164 status=SetImageProgress(image,SaveImageTag, 11165 (MagickOffsetType) (pass * image->rows + y), 11166 num_passes * image->rows); 11167 11168 if (status == MagickFalse) 11169 break; 11170 } 11171 } 11172 } 11173 } 11174 } 11175 11176 if (quantum_info != (QuantumInfo *) NULL) 11177 quantum_info=DestroyQuantumInfo(quantum_info); 11178 11179 if (logging != MagickFalse) 11180 { 11181 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11182 " Wrote PNG image data"); 11183 11184 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11185 " Width: %.20g",(double) ping_width); 11186 11187 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11188 " Height: %.20g",(double) ping_height); 11189 11190 if (mng_info->write_png_depth) 11191 { 11192 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11193 " Defined png:bit-depth: %d",mng_info->write_png_depth); 11194 } 11195 11196 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11197 " PNG bit-depth written: %d",ping_bit_depth); 11198 11199 if (mng_info->write_png_colortype) 11200 { 11201 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11202 " Defined png:color-type: %d",mng_info->write_png_colortype-1); 11203 } 11204 11205 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11206 " PNG color-type written: %d",ping_color_type); 11207 11208 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11209 " PNG Interlace method: %d",ping_interlace_method); 11210 } 11211 /* 11212 Generate text chunks after IDAT. 11213 */ 11214 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse) 11215 { 11216 ResetImagePropertyIterator(image); 11217 property=GetNextImageProperty(image); 11218 while (property != (const char *) NULL) 11219 { 11220 png_textp 11221 text; 11222 11223 value=GetImageProperty(image,property,exception); 11224 11225 /* Don't write any "png:" or "jpeg:" properties; those are just for 11226 * "identify" or for passing through to another JPEG 11227 */ 11228 if ((LocaleNCompare(property,"png:",4) != 0 && 11229 LocaleNCompare(property,"jpeg:",5) != 0) && 11230 11231 11232 /* Suppress density and units if we wrote a pHYs chunk */ 11233 (ping_exclude_pHYs != MagickFalse || 11234 LocaleCompare(property,"density") != 0 || 11235 LocaleCompare(property,"units") != 0) && 11236 11237 /* Suppress the IM-generated Date:create and Date:modify */ 11238 (ping_exclude_date == MagickFalse || 11239 LocaleNCompare(property, "Date:",5) != 0)) 11240 { 11241 if (value != (const char *) NULL) 11242 { 11243 11244 #if PNG_LIBPNG_VER >= 10400 11245 text=(png_textp) png_malloc(ping, 11246 (png_alloc_size_t) sizeof(png_text)); 11247 #else 11248 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text)); 11249 #endif 11250 text[0].key=(char *) property; 11251 text[0].text=(char *) value; 11252 text[0].text_length=strlen(value); 11253 11254 if (ping_exclude_tEXt != MagickFalse) 11255 text[0].compression=PNG_TEXT_COMPRESSION_zTXt; 11256 11257 else if (ping_exclude_zTXt != MagickFalse) 11258 text[0].compression=PNG_TEXT_COMPRESSION_NONE; 11259 11260 else 11261 { 11262 text[0].compression=image_info->compression == NoCompression || 11263 (image_info->compression == UndefinedCompression && 11264 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE : 11265 PNG_TEXT_COMPRESSION_zTXt ; 11266 } 11267 11268 if (logging != MagickFalse) 11269 { 11270 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11271 " Setting up text chunk"); 11272 11273 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11274 " keyword: '%s'",text[0].key); 11275 } 11276 11277 png_set_text(ping,ping_info,text,1); 11278 png_free(ping,text); 11279 } 11280 } 11281 property=GetNextImageProperty(image); 11282 } 11283 } 11284 11285 /* write any PNG-chunk-e profiles */ 11286 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging); 11287 11288 if (logging != MagickFalse) 11289 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11290 " Writing PNG end info"); 11291 11292 png_write_end(ping,ping_info); 11293 11294 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose) 11295 { 11296 if (mng_info->page.x || mng_info->page.y || 11297 (ping_width != mng_info->page.width) || 11298 (ping_height != mng_info->page.height)) 11299 { 11300 unsigned char 11301 chunk[32]; 11302 11303 /* 11304 Write FRAM 4 with clipping boundaries followed by FRAM 1. 11305 */ 11306 (void) WriteBlobMSBULong(image,27L); /* data length=27 */ 11307 PNGType(chunk,mng_FRAM); 11308 LogPNGChunk(logging,mng_FRAM,27L); 11309 chunk[4]=4; 11310 chunk[5]=0; /* frame name separator (no name) */ 11311 chunk[6]=1; /* flag for changing delay, for next frame only */ 11312 chunk[7]=0; /* flag for changing frame timeout */ 11313 chunk[8]=1; /* flag for changing frame clipping for next frame */ 11314 chunk[9]=0; /* flag for changing frame sync_id */ 11315 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */ 11316 chunk[14]=0; /* clipping boundaries delta type */ 11317 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */ 11318 PNGLong(chunk+19, 11319 (png_uint_32) (mng_info->page.x + ping_width)); 11320 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */ 11321 PNGLong(chunk+27, 11322 (png_uint_32) (mng_info->page.y + ping_height)); 11323 (void) WriteBlob(image,31,chunk); 11324 (void) WriteBlobMSBULong(image,crc32(0,chunk,31)); 11325 mng_info->old_framing_mode=4; 11326 mng_info->framing_mode=1; 11327 } 11328 11329 else 11330 mng_info->framing_mode=3; 11331 } 11332 if (mng_info->write_mng && !mng_info->need_fram && 11333 ((int) image->dispose == 3)) 11334 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC"); 11335 11336 /* 11337 Free PNG resources. 11338 */ 11339 11340 png_destroy_write_struct(&ping,&ping_info); 11341 11342 pixel_info=RelinquishVirtualMemory(pixel_info); 11343 11344 if (ping_have_blob != MagickFalse) 11345 (void) CloseBlob(image); 11346 11347 image_info=DestroyImageInfo(image_info); 11348 image=DestroyImage(image); 11349 11350 /* Store bit depth actually written */ 11351 s[0]=(char) ping_bit_depth; 11352 s[1]='\0'; 11353 11354 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception); 11355 11356 if (logging != MagickFalse) 11357 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11358 " exit WriteOnePNGImage()"); 11359 11360 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE 11361 UnlockSemaphoreInfo(ping_semaphore); 11362 #endif 11363 11364 /* } for navigation to beginning of SETJMP-protected block. Revert to 11365 * Throwing an Exception when an error occurs. 11366 */ 11367 11368 return(MagickTrue); 11369 /* End write one PNG image */ 11370 11371 } 11372 11373 /* 11374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11375 % % 11376 % % 11377 % % 11378 % W r i t e P N G I m a g e % 11379 % % 11380 % % 11381 % % 11382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11383 % 11384 % WritePNGImage() writes a Portable Network Graphics (PNG) or 11385 % Multiple-image Network Graphics (MNG) image file. 11386 % 11387 % MNG support written by Glenn Randers-Pehrson, glennrp (at) image... 11388 % 11389 % The format of the WritePNGImage method is: 11390 % 11391 % MagickBooleanType WritePNGImage(const ImageInfo *image_info, 11392 % Image *image,ExceptionInfo *exception) 11393 % 11394 % A description of each parameter follows: 11395 % 11396 % o image_info: the image info. 11397 % 11398 % o image: The image. 11399 % 11400 % o exception: return any errors or warnings in this structure. 11401 % 11402 % Returns MagickTrue on success, MagickFalse on failure. 11403 % 11404 % Communicating with the PNG encoder: 11405 % 11406 % While the datastream written is always in PNG format and normally would 11407 % be given the "png" file extension, this method also writes the following 11408 % pseudo-formats which are subsets of png: 11409 % 11410 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has 11411 % a depth greater than 8, the depth is reduced. If transparency 11412 % is present, the tRNS chunk must only have values 0 and 255 11413 % (i.e., transparency is binary: fully opaque or fully 11414 % transparent). If other values are present they will be 11415 % 50%-thresholded to binary transparency. If more than 256 11416 % colors are present, they will be quantized to the 4-4-4-1, 11417 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color 11418 % of any resulting fully-transparent pixels is changed to 11419 % the image's background color. 11420 % 11421 % If you want better quantization or dithering of the colors 11422 % or alpha than that, you need to do it before calling the 11423 % PNG encoder. The pixels contain 8-bit indices even if 11424 % they could be represented with 1, 2, or 4 bits. Grayscale 11425 % images will be written as indexed PNG files even though the 11426 % PNG grayscale type might be slightly more efficient. Please 11427 % note that writing to the PNG8 format may result in loss 11428 % of color and alpha data. 11429 % 11430 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS 11431 % chunk can be present to convey binary transparency by naming 11432 % one of the colors as transparent. The only loss incurred 11433 % is reduction of sample depth to 8. If the image has more 11434 % than one transparent color, has semitransparent pixels, or 11435 % has an opaque pixel with the same RGB components as the 11436 % transparent color, an image is not written. 11437 % 11438 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial 11439 % transparency is permitted, i.e., the alpha sample for 11440 % each pixel can have any value from 0 to 255. The alpha 11441 % channel is present even if the image is fully opaque. 11442 % The only loss in data is the reduction of the sample depth 11443 % to 8. 11444 % 11445 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS 11446 % chunk can be present to convey binary transparency by naming 11447 % one of the colors as transparent. If the image has more 11448 % than one transparent color, has semitransparent pixels, or 11449 % has an opaque pixel with the same RGB components as the 11450 % transparent color, an image is not written. 11451 % 11452 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial 11453 % transparency is permitted, i.e., the alpha sample for 11454 % each pixel can have any value from 0 to 65535. The alpha 11455 % channel is present even if the image is fully opaque. 11456 % 11457 % o PNG00: A PNG that inherits its colortype and bit-depth from the input 11458 % image, if the input was a PNG, is written. If these values 11459 % cannot be found, or if the pixels have been changed in a way 11460 % that makes this impossible, then "PNG00" falls back to the 11461 % regular "PNG" format. 11462 % 11463 % o -define: For more precise control of the PNG output, you can use the 11464 % Image options "png:bit-depth" and "png:color-type". These 11465 % can be set from the commandline with "-define" and also 11466 % from the application programming interfaces. The options 11467 % are case-independent and are converted to lowercase before 11468 % being passed to this encoder. 11469 % 11470 % png:color-type can be 0, 2, 3, 4, or 6. 11471 % 11472 % When png:color-type is 0 (Grayscale), png:bit-depth can 11473 % be 1, 2, 4, 8, or 16. 11474 % 11475 % When png:color-type is 2 (RGB), png:bit-depth can 11476 % be 8 or 16. 11477 % 11478 % When png:color-type is 3 (Indexed), png:bit-depth can 11479 % be 1, 2, 4, or 8. This refers to the number of bits 11480 % used to store the index. The color samples always have 11481 % bit-depth 8 in indexed PNG files. 11482 % 11483 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte), 11484 % png:bit-depth can be 8 or 16. 11485 % 11486 % If the image cannot be written without loss with the 11487 % requested bit-depth and color-type, a PNG file will not 11488 % be written, a warning will be issued, and the encoder will 11489 % return MagickFalse. 11490 % 11491 % Since image encoders should not be responsible for the "heavy lifting", 11492 % the user should make sure that ImageMagick has already reduced the 11493 % image depth and number of colors and limit transparency to binary 11494 % transparency prior to attempting to write the image with depth, color, 11495 % or transparency limitations. 11496 % 11497 % Note that another definition, "png:bit-depth-written" exists, but it 11498 % is not intended for external use. It is only used internally by the 11499 % PNG encoder to inform the JNG encoder of the depth of the alpha channel. 11500 % 11501 % It is possible to request that the PNG encoder write previously-formatted 11502 % ancillary chunks in the output PNG file, using the "-profile" commandline 11503 % option as shown below or by setting the profile via a programming 11504 % interface: 11505 % 11506 % -profile PNG-chunk-x:<file> 11507 % 11508 % where x is a location flag and <file> is a file containing the chunk 11509 % name in the first 4 bytes, then a colon (":"), followed by the chunk data. 11510 % This encoder will compute the chunk length and CRC, so those must not 11511 % be included in the file. 11512 % 11513 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT), 11514 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks 11515 % of the same type, then add a short unique string after the "x" to prevent 11516 % subsequent profiles from overwriting the preceding ones, e.g., 11517 % 11518 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02 11519 % 11520 % As of version 6.6.6 the following optimizations are always done: 11521 % 11522 % o 32-bit depth is reduced to 16. 11523 % o 16-bit depth is reduced to 8 if all pixels contain samples whose 11524 % high byte and low byte are identical. 11525 % o Palette is sorted to remove unused entries and to put a 11526 % transparent color first, if BUILD_PNG_PALETTE is defined. 11527 % o Opaque matte channel is removed when writing an indexed PNG. 11528 % o Grayscale images are reduced to 1, 2, or 4 bit depth if 11529 % this can be done without loss and a larger bit depth N was not 11530 % requested via the "-define png:bit-depth=N" option. 11531 % o If matte channel is present but only one transparent color is 11532 % present, RGB+tRNS is written instead of RGBA 11533 % o Opaque matte channel is removed (or added, if color-type 4 or 6 11534 % was requested when converting an opaque image). 11535 % 11536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11537 */ 11538 static MagickBooleanType WritePNGImage(const ImageInfo *image_info, 11539 Image *image,ExceptionInfo *exception) 11540 { 11541 MagickBooleanType 11542 excluding, 11543 logging, 11544 have_mng_structure, 11545 status; 11546 11547 MngInfo 11548 *mng_info; 11549 11550 const char 11551 *value; 11552 11553 int 11554 source; 11555 11556 /* 11557 Open image file. 11558 */ 11559 assert(image_info != (const ImageInfo *) NULL); 11560 assert(image_info->signature == MagickCoreSignature); 11561 assert(image != (Image *) NULL); 11562 assert(image->signature == MagickCoreSignature); 11563 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 11564 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()"); 11565 /* 11566 Allocate a MngInfo structure. 11567 */ 11568 have_mng_structure=MagickFalse; 11569 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 11570 11571 if (mng_info == (MngInfo *) NULL) 11572 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 11573 11574 /* 11575 Initialize members of the MngInfo structure. 11576 */ 11577 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 11578 mng_info->image=image; 11579 mng_info->equal_backgrounds=MagickTrue; 11580 have_mng_structure=MagickTrue; 11581 11582 /* See if user has requested a specific PNG subformat */ 11583 11584 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; 11585 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; 11586 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; 11587 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0; 11588 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0; 11589 11590 value=GetImageOption(image_info,"png:format"); 11591 11592 if (value != (char *) NULL || LocaleCompare(image_info->magick,"PNG00") == 0) 11593 { 11594 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11595 " Format=%s",value); 11596 11597 mng_info->write_png8 = MagickFalse; 11598 mng_info->write_png24 = MagickFalse; 11599 mng_info->write_png32 = MagickFalse; 11600 mng_info->write_png48 = MagickFalse; 11601 mng_info->write_png64 = MagickFalse; 11602 11603 if (LocaleCompare(value,"png8") == 0) 11604 mng_info->write_png8 = MagickTrue; 11605 11606 else if (LocaleCompare(value,"png24") == 0) 11607 mng_info->write_png24 = MagickTrue; 11608 11609 else if (LocaleCompare(value,"png32") == 0) 11610 mng_info->write_png32 = MagickTrue; 11611 11612 else if (LocaleCompare(value,"png48") == 0) 11613 mng_info->write_png48 = MagickTrue; 11614 11615 else if (LocaleCompare(value,"png64") == 0) 11616 mng_info->write_png64 = MagickTrue; 11617 11618 else if ((LocaleCompare(value,"png00") == 0) || 11619 LocaleCompare(image_info->magick,"PNG00") == 0) 11620 { 11621 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig. */ 11622 value=GetImageProperty(image,"png:IHDR.bit-depth-orig",exception); 11623 11624 if (value != (char *) NULL) 11625 { 11626 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11627 " png00 inherited bit depth=%s",value); 11628 11629 if (LocaleCompare(value,"1") == 0) 11630 mng_info->write_png_depth = 1; 11631 11632 else if (LocaleCompare(value,"2") == 0) 11633 mng_info->write_png_depth = 2; 11634 11635 else if (LocaleCompare(value,"4") == 0) 11636 mng_info->write_png_depth = 4; 11637 11638 else if (LocaleCompare(value,"8") == 0) 11639 mng_info->write_png_depth = 8; 11640 11641 else if (LocaleCompare(value,"16") == 0) 11642 mng_info->write_png_depth = 16; 11643 } 11644 11645 value=GetImageProperty(image,"png:IHDR.color-type-orig",exception); 11646 11647 if (value != (char *) NULL) 11648 { 11649 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11650 " png00 inherited color type=%s",value); 11651 11652 if (LocaleCompare(value,"0") == 0) 11653 mng_info->write_png_colortype = 1; 11654 11655 else if (LocaleCompare(value,"2") == 0) 11656 mng_info->write_png_colortype = 3; 11657 11658 else if (LocaleCompare(value,"3") == 0) 11659 mng_info->write_png_colortype = 4; 11660 11661 else if (LocaleCompare(value,"4") == 0) 11662 mng_info->write_png_colortype = 5; 11663 11664 else if (LocaleCompare(value,"6") == 0) 11665 mng_info->write_png_colortype = 7; 11666 } 11667 } 11668 } 11669 11670 if (mng_info->write_png8) 11671 { 11672 mng_info->write_png_colortype = /* 3 */ 4; 11673 mng_info->write_png_depth = 8; 11674 image->depth = 8; 11675 } 11676 11677 if (mng_info->write_png24) 11678 { 11679 mng_info->write_png_colortype = /* 2 */ 3; 11680 mng_info->write_png_depth = 8; 11681 image->depth = 8; 11682 11683 if (image->alpha_trait != UndefinedPixelTrait) 11684 (void) SetImageType(image,TrueColorAlphaType,exception); 11685 11686 else 11687 (void) SetImageType(image,TrueColorType,exception); 11688 11689 (void) SyncImage(image,exception); 11690 } 11691 11692 if (mng_info->write_png32) 11693 { 11694 mng_info->write_png_colortype = /* 6 */ 7; 11695 mng_info->write_png_depth = 8; 11696 image->depth = 8; 11697 image->alpha_trait = BlendPixelTrait; 11698 11699 (void) SetImageType(image,TrueColorAlphaType,exception); 11700 (void) SyncImage(image,exception); 11701 } 11702 11703 if (mng_info->write_png48) 11704 { 11705 mng_info->write_png_colortype = /* 2 */ 3; 11706 mng_info->write_png_depth = 16; 11707 image->depth = 16; 11708 11709 if (image->alpha_trait != UndefinedPixelTrait) 11710 (void) SetImageType(image,TrueColorAlphaType,exception); 11711 11712 else 11713 (void) SetImageType(image,TrueColorType,exception); 11714 11715 (void) SyncImage(image,exception); 11716 } 11717 11718 if (mng_info->write_png64) 11719 { 11720 mng_info->write_png_colortype = /* 6 */ 7; 11721 mng_info->write_png_depth = 16; 11722 image->depth = 16; 11723 image->alpha_trait = BlendPixelTrait; 11724 11725 (void) SetImageType(image,TrueColorAlphaType,exception); 11726 (void) SyncImage(image,exception); 11727 } 11728 11729 value=GetImageOption(image_info,"png:bit-depth"); 11730 11731 if (value != (char *) NULL) 11732 { 11733 if (LocaleCompare(value,"1") == 0) 11734 mng_info->write_png_depth = 1; 11735 11736 else if (LocaleCompare(value,"2") == 0) 11737 mng_info->write_png_depth = 2; 11738 11739 else if (LocaleCompare(value,"4") == 0) 11740 mng_info->write_png_depth = 4; 11741 11742 else if (LocaleCompare(value,"8") == 0) 11743 mng_info->write_png_depth = 8; 11744 11745 else if (LocaleCompare(value,"16") == 0) 11746 mng_info->write_png_depth = 16; 11747 11748 else 11749 (void) ThrowMagickException(exception, 11750 GetMagickModule(),CoderWarning, 11751 "ignoring invalid defined png:bit-depth", 11752 "=%s",value); 11753 11754 if (logging != MagickFalse) 11755 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11756 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth); 11757 } 11758 11759 value=GetImageOption(image_info,"png:color-type"); 11760 11761 if (value != (char *) NULL) 11762 { 11763 /* We must store colortype+1 because 0 is a valid colortype */ 11764 if (LocaleCompare(value,"0") == 0) 11765 mng_info->write_png_colortype = 1; 11766 11767 else if (LocaleCompare(value,"1") == 0) 11768 mng_info->write_png_colortype = 2; 11769 11770 else if (LocaleCompare(value,"2") == 0) 11771 mng_info->write_png_colortype = 3; 11772 11773 else if (LocaleCompare(value,"3") == 0) 11774 mng_info->write_png_colortype = 4; 11775 11776 else if (LocaleCompare(value,"4") == 0) 11777 mng_info->write_png_colortype = 5; 11778 11779 else if (LocaleCompare(value,"6") == 0) 11780 mng_info->write_png_colortype = 7; 11781 11782 else 11783 (void) ThrowMagickException(exception, 11784 GetMagickModule(),CoderWarning, 11785 "ignoring invalid defined png:color-type", 11786 "=%s",value); 11787 11788 if (logging != MagickFalse) 11789 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 11790 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1); 11791 } 11792 11793 /* Check for chunks to be excluded: 11794 * 11795 * The default is to not exclude any known chunks except for any 11796 * listed in the "unused_chunks" array, above. 11797 * 11798 * Chunks can be listed for exclusion via a "png:exclude-chunk" 11799 * define (in the image properties or in the image artifacts) 11800 * or via a mng_info member. For convenience, in addition 11801 * to or instead of a comma-separated list of chunks, the 11802 * "exclude-chunk" string can be simply "all" or "none". 11803 * 11804 * The exclude-chunk define takes priority over the mng_info. 11805 * 11806 * A "png:include-chunk" define takes priority over both the 11807 * mng_info and the "png:exclude-chunk" define. Like the 11808 * "exclude-chunk" string, it can define "all" or "none" as 11809 * well as a comma-separated list. Chunks that are unknown to 11810 * ImageMagick are always excluded, regardless of their "copy-safe" 11811 * status according to the PNG specification, and even if they 11812 * appear in the "include-chunk" list. Such defines appearing among 11813 * the image options take priority over those found among the image 11814 * artifacts. 11815 * 11816 * Finally, all chunks listed in the "unused_chunks" array are 11817 * automatically excluded, regardless of the other instructions 11818 * or lack thereof. 11819 * 11820 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk 11821 * will not be written and the gAMA chunk will only be written if it 11822 * is not between .45 and .46, or approximately (1.0/2.2). 11823 * 11824 * If you exclude tRNS and the image has transparency, the colortype 11825 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA). 11826 * 11827 * The -strip option causes StripImage() to set the png:include-chunk 11828 * artifact to "none,trns,gama". 11829 */ 11830 11831 mng_info->ping_exclude_bKGD=MagickFalse; 11832 mng_info->ping_exclude_cHRM=MagickFalse; 11833 mng_info->ping_exclude_date=MagickFalse; 11834 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */ 11835 mng_info->ping_exclude_gAMA=MagickFalse; 11836 mng_info->ping_exclude_iCCP=MagickFalse; 11837 /* mng_info->ping_exclude_iTXt=MagickFalse; */ 11838 mng_info->ping_exclude_oFFs=MagickFalse; 11839 mng_info->ping_exclude_pHYs=MagickFalse; 11840 mng_info->ping_exclude_sRGB=MagickFalse; 11841 mng_info->ping_exclude_tEXt=MagickFalse; 11842 mng_info->ping_exclude_tIME=MagickFalse; 11843 mng_info->ping_exclude_tRNS=MagickFalse; 11844 mng_info->ping_exclude_vpAg=MagickFalse; 11845 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */ 11846 mng_info->ping_exclude_zTXt=MagickFalse; 11847 11848 mng_info->ping_preserve_colormap=MagickFalse; 11849 11850 value=GetImageOption(image_info,"png:preserve-colormap"); 11851 if (value == NULL) 11852 value=GetImageArtifact(image,"png:preserve-colormap"); 11853 if (value != NULL) 11854 mng_info->ping_preserve_colormap=MagickTrue; 11855 11856 mng_info->ping_preserve_iCCP=MagickFalse; 11857 11858 value=GetImageOption(image_info,"png:preserve-iCCP"); 11859 if (value == NULL) 11860 value=GetImageArtifact(image,"png:preserve-iCCP"); 11861 if (value != NULL) 11862 mng_info->ping_preserve_iCCP=MagickTrue; 11863 11864 /* These compression-level, compression-strategy, and compression-filter 11865 * defines take precedence over values from the -quality option. 11866 */ 11867 value=GetImageOption(image_info,"png:compression-level"); 11868 if (value == NULL) 11869 value=GetImageArtifact(image,"png:compression-level"); 11870 if (value != NULL) 11871 { 11872 /* We have to add 1 to everything because 0 is a valid input, 11873 * and we want to use 0 (the default) to mean undefined. 11874 */ 11875 if (LocaleCompare(value,"0") == 0) 11876 mng_info->write_png_compression_level = 1; 11877 11878 else if (LocaleCompare(value,"1") == 0) 11879 mng_info->write_png_compression_level = 2; 11880 11881 else if (LocaleCompare(value,"2") == 0) 11882 mng_info->write_png_compression_level = 3; 11883 11884 else if (LocaleCompare(value,"3") == 0) 11885 mng_info->write_png_compression_level = 4; 11886 11887 else if (LocaleCompare(value,"4") == 0) 11888 mng_info->write_png_compression_level = 5; 11889 11890 else if (LocaleCompare(value,"5") == 0) 11891 mng_info->write_png_compression_level = 6; 11892 11893 else if (LocaleCompare(value,"6") == 0) 11894 mng_info->write_png_compression_level = 7; 11895 11896 else if (LocaleCompare(value,"7") == 0) 11897 mng_info->write_png_compression_level = 8; 11898 11899 else if (LocaleCompare(value,"8") == 0) 11900 mng_info->write_png_compression_level = 9; 11901 11902 else if (LocaleCompare(value,"9") == 0) 11903 mng_info->write_png_compression_level = 10; 11904 11905 else 11906 (void) ThrowMagickException(exception, 11907 GetMagickModule(),CoderWarning, 11908 "ignoring invalid defined png:compression-level", 11909 "=%s",value); 11910 } 11911 11912 value=GetImageOption(image_info,"png:compression-strategy"); 11913 if (value == NULL) 11914 value=GetImageArtifact(image,"png:compression-strategy"); 11915 if (value != NULL) 11916 { 11917 if (LocaleCompare(value,"0") == 0) 11918 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11919 11920 else if (LocaleCompare(value,"1") == 0) 11921 mng_info->write_png_compression_strategy = Z_FILTERED+1; 11922 11923 else if (LocaleCompare(value,"2") == 0) 11924 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1; 11925 11926 else if (LocaleCompare(value,"3") == 0) 11927 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */ 11928 mng_info->write_png_compression_strategy = Z_RLE+1; 11929 #else 11930 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11931 #endif 11932 11933 else if (LocaleCompare(value,"4") == 0) 11934 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */ 11935 mng_info->write_png_compression_strategy = Z_FIXED+1; 11936 #else 11937 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1; 11938 #endif 11939 11940 else 11941 (void) ThrowMagickException(exception, 11942 GetMagickModule(),CoderWarning, 11943 "ignoring invalid defined png:compression-strategy", 11944 "=%s",value); 11945 } 11946 11947 value=GetImageOption(image_info,"png:compression-filter"); 11948 if (value == NULL) 11949 value=GetImageArtifact(image,"png:compression-filter"); 11950 if (value != NULL) 11951 { 11952 /* To do: combinations of filters allowed by libpng 11953 * masks 0x08 through 0xf8 11954 * 11955 * Implement this as a comma-separated list of 0,1,2,3,4,5 11956 * where 5 is a special case meaning PNG_ALL_FILTERS. 11957 */ 11958 11959 if (LocaleCompare(value,"0") == 0) 11960 mng_info->write_png_compression_filter = 1; 11961 11962 else if (LocaleCompare(value,"1") == 0) 11963 mng_info->write_png_compression_filter = 2; 11964 11965 else if (LocaleCompare(value,"2") == 0) 11966 mng_info->write_png_compression_filter = 3; 11967 11968 else if (LocaleCompare(value,"3") == 0) 11969 mng_info->write_png_compression_filter = 4; 11970 11971 else if (LocaleCompare(value,"4") == 0) 11972 mng_info->write_png_compression_filter = 5; 11973 11974 else if (LocaleCompare(value,"5") == 0) 11975 mng_info->write_png_compression_filter = 6; 11976 11977 else 11978 (void) ThrowMagickException(exception, 11979 GetMagickModule(),CoderWarning, 11980 "ignoring invalid defined png:compression-filter", 11981 "=%s",value); 11982 } 11983 11984 for (source=0; source<8; source++) 11985 { 11986 value = NULL; 11987 11988 if (source == 0) 11989 value=GetImageOption(image_info,"png:exclude-chunks"); 11990 11991 if (source == 1) 11992 value=GetImageArtifact(image,"png:exclude-chunks"); 11993 11994 if (source == 2) 11995 value=GetImageOption(image_info,"png:exclude-chunk"); 11996 11997 if (source == 3) 11998 value=GetImageArtifact(image,"png:exclude-chunk"); 11999 12000 if (source == 4) 12001 value=GetImageOption(image_info,"png:include-chunks"); 12002 12003 if (source == 5) 12004 value=GetImageArtifact(image,"png:include-chunks"); 12005 12006 if (source == 6) 12007 value=GetImageOption(image_info,"png:include-chunk"); 12008 12009 if (source == 7) 12010 value=GetImageArtifact(image,"png:include-chunk"); 12011 12012 if (value == NULL) 12013 continue; 12014 12015 if (source < 4) 12016 excluding = MagickTrue; 12017 else 12018 excluding = MagickFalse; 12019 12020 if (logging != MagickFalse) 12021 { 12022 if (source == 0 || source == 2) 12023 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12024 " png:exclude-chunk=%s found in image options.\n", value); 12025 else if (source == 1 || source == 3) 12026 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12027 " png:exclude-chunk=%s found in image artifacts.\n", value); 12028 else if (source == 4 || source == 6) 12029 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12030 " png:include-chunk=%s found in image options.\n", value); 12031 else /* if (source == 5 || source == 7) */ 12032 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12033 " png:include-chunk=%s found in image artifacts.\n", value); 12034 } 12035 12036 if (IsOptionMember("all",value) != MagickFalse) 12037 { 12038 mng_info->ping_exclude_bKGD=excluding; 12039 mng_info->ping_exclude_cHRM=excluding; 12040 mng_info->ping_exclude_date=excluding; 12041 mng_info->ping_exclude_EXIF=excluding; 12042 mng_info->ping_exclude_gAMA=excluding; 12043 mng_info->ping_exclude_iCCP=excluding; 12044 /* mng_info->ping_exclude_iTXt=excluding; */ 12045 mng_info->ping_exclude_oFFs=excluding; 12046 mng_info->ping_exclude_pHYs=excluding; 12047 mng_info->ping_exclude_sRGB=excluding; 12048 mng_info->ping_exclude_tEXt=excluding; 12049 mng_info->ping_exclude_tIME=excluding; 12050 mng_info->ping_exclude_tRNS=excluding; 12051 mng_info->ping_exclude_vpAg=excluding; 12052 mng_info->ping_exclude_zCCP=excluding; 12053 mng_info->ping_exclude_zTXt=excluding; 12054 } 12055 12056 if (IsOptionMember("none",value) != MagickFalse) 12057 { 12058 mng_info->ping_exclude_bKGD=excluding != MagickFalse ? MagickFalse : 12059 MagickTrue; 12060 mng_info->ping_exclude_cHRM=excluding != MagickFalse ? MagickFalse : 12061 MagickTrue; 12062 mng_info->ping_exclude_date=excluding != MagickFalse ? MagickFalse : 12063 MagickTrue; 12064 mng_info->ping_exclude_EXIF=excluding != MagickFalse ? MagickFalse : 12065 MagickTrue; 12066 mng_info->ping_exclude_gAMA=excluding != MagickFalse ? MagickFalse : 12067 MagickTrue; 12068 mng_info->ping_exclude_iCCP=excluding != MagickFalse ? MagickFalse : 12069 MagickTrue; 12070 /* mng_info->ping_exclude_iTXt=!excluding; */ 12071 mng_info->ping_exclude_oFFs=excluding != MagickFalse ? MagickFalse : 12072 MagickTrue; 12073 mng_info->ping_exclude_pHYs=excluding != MagickFalse ? MagickFalse : 12074 MagickTrue; 12075 mng_info->ping_exclude_sRGB=excluding != MagickFalse ? MagickFalse : 12076 MagickTrue; 12077 mng_info->ping_exclude_tEXt=excluding != MagickFalse ? MagickFalse : 12078 MagickTrue; 12079 mng_info->ping_exclude_tIME=excluding != MagickFalse ? MagickFalse : 12080 MagickTrue; 12081 mng_info->ping_exclude_tRNS=excluding != MagickFalse ? MagickFalse : 12082 MagickTrue; 12083 mng_info->ping_exclude_vpAg=excluding != MagickFalse ? MagickFalse : 12084 MagickTrue; 12085 mng_info->ping_exclude_zCCP=excluding != MagickFalse ? MagickFalse : 12086 MagickTrue; 12087 mng_info->ping_exclude_zTXt=excluding != MagickFalse ? MagickFalse : 12088 MagickTrue; 12089 } 12090 12091 if (IsOptionMember("bkgd",value) != MagickFalse) 12092 mng_info->ping_exclude_bKGD=excluding; 12093 12094 if (IsOptionMember("chrm",value) != MagickFalse) 12095 mng_info->ping_exclude_cHRM=excluding; 12096 12097 if (IsOptionMember("date",value) != MagickFalse) 12098 mng_info->ping_exclude_date=excluding; 12099 12100 if (IsOptionMember("exif",value) != MagickFalse) 12101 mng_info->ping_exclude_EXIF=excluding; 12102 12103 if (IsOptionMember("gama",value) != MagickFalse) 12104 mng_info->ping_exclude_gAMA=excluding; 12105 12106 if (IsOptionMember("iccp",value) != MagickFalse) 12107 mng_info->ping_exclude_iCCP=excluding; 12108 12109 #if 0 12110 if (IsOptionMember("itxt",value) != MagickFalse) 12111 mng_info->ping_exclude_iTXt=excluding; 12112 #endif 12113 12114 if (IsOptionMember("offs",value) != MagickFalse) 12115 mng_info->ping_exclude_oFFs=excluding; 12116 12117 if (IsOptionMember("phys",value) != MagickFalse) 12118 mng_info->ping_exclude_pHYs=excluding; 12119 12120 if (IsOptionMember("srgb",value) != MagickFalse) 12121 mng_info->ping_exclude_sRGB=excluding; 12122 12123 if (IsOptionMember("text",value) != MagickFalse) 12124 mng_info->ping_exclude_tEXt=excluding; 12125 12126 if (IsOptionMember("time",value) != MagickFalse) 12127 mng_info->ping_exclude_tIME=excluding; 12128 12129 if (IsOptionMember("trns",value) != MagickFalse) 12130 mng_info->ping_exclude_tRNS=excluding; 12131 12132 if (IsOptionMember("vpag",value) != MagickFalse) 12133 mng_info->ping_exclude_vpAg=excluding; 12134 12135 if (IsOptionMember("zccp",value) != MagickFalse) 12136 mng_info->ping_exclude_zCCP=excluding; 12137 12138 if (IsOptionMember("ztxt",value) != MagickFalse) 12139 mng_info->ping_exclude_zTXt=excluding; 12140 } 12141 12142 if (logging != MagickFalse) 12143 { 12144 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12145 " Chunks to be excluded from the output png:"); 12146 if (mng_info->ping_exclude_bKGD != MagickFalse) 12147 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12148 " bKGD"); 12149 if (mng_info->ping_exclude_cHRM != MagickFalse) 12150 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12151 " cHRM"); 12152 if (mng_info->ping_exclude_date != MagickFalse) 12153 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12154 " date"); 12155 if (mng_info->ping_exclude_EXIF != MagickFalse) 12156 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12157 " EXIF"); 12158 if (mng_info->ping_exclude_gAMA != MagickFalse) 12159 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12160 " gAMA"); 12161 if (mng_info->ping_exclude_iCCP != MagickFalse) 12162 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12163 " iCCP"); 12164 #if 0 12165 if (mng_info->ping_exclude_iTXt != MagickFalse) 12166 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12167 " iTXt"); 12168 #endif 12169 12170 if (mng_info->ping_exclude_oFFs != MagickFalse) 12171 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12172 " oFFs"); 12173 if (mng_info->ping_exclude_pHYs != MagickFalse) 12174 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12175 " pHYs"); 12176 if (mng_info->ping_exclude_sRGB != MagickFalse) 12177 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12178 " sRGB"); 12179 if (mng_info->ping_exclude_tEXt != MagickFalse) 12180 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12181 " tEXt"); 12182 if (mng_info->ping_exclude_tIME != MagickFalse) 12183 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12184 " tIME"); 12185 if (mng_info->ping_exclude_tRNS != MagickFalse) 12186 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12187 " tRNS"); 12188 if (mng_info->ping_exclude_vpAg != MagickFalse) 12189 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12190 " vpAg"); 12191 if (mng_info->ping_exclude_zCCP != MagickFalse) 12192 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12193 " zCCP"); 12194 if (mng_info->ping_exclude_zTXt != MagickFalse) 12195 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12196 " zTXt"); 12197 } 12198 12199 mng_info->need_blob = MagickTrue; 12200 12201 status=WriteOnePNGImage(mng_info,image_info,image,exception); 12202 12203 MngInfoFreeStruct(mng_info,&have_mng_structure); 12204 12205 if (logging != MagickFalse) 12206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()"); 12207 12208 return(status); 12209 } 12210 12211 #if defined(JNG_SUPPORTED) 12212 12213 /* Write one JNG image */ 12214 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, 12215 const ImageInfo *image_info,Image *image,ExceptionInfo *exception) 12216 { 12217 Image 12218 *jpeg_image; 12219 12220 ImageInfo 12221 *jpeg_image_info; 12222 12223 MagickBooleanType 12224 logging, 12225 status; 12226 12227 size_t 12228 length; 12229 12230 unsigned char 12231 *blob, 12232 chunk[80], 12233 *p; 12234 12235 unsigned int 12236 jng_alpha_compression_method, 12237 jng_alpha_sample_depth, 12238 jng_color_type, 12239 transparent; 12240 12241 size_t 12242 jng_alpha_quality, 12243 jng_quality; 12244 12245 logging=LogMagickEvent(CoderEvent,GetMagickModule(), 12246 " Enter WriteOneJNGImage()"); 12247 12248 blob=(unsigned char *) NULL; 12249 jpeg_image=(Image *) NULL; 12250 jpeg_image_info=(ImageInfo *) NULL; 12251 length=0; 12252 12253 status=MagickTrue; 12254 transparent=image_info->type==GrayscaleAlphaType || 12255 image_info->type==TrueColorAlphaType || 12256 image->alpha_trait != UndefinedPixelTrait; 12257 12258 jng_alpha_sample_depth = 0; 12259 12260 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000; 12261 12262 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0; 12263 12264 jng_alpha_quality=image_info->quality == 0UL ? 75UL : 12265 image_info->quality; 12266 12267 if (jng_alpha_quality >= 1000) 12268 jng_alpha_quality /= 1000; 12269 12270 length=0; 12271 12272 if (transparent != 0) 12273 { 12274 jng_color_type=14; 12275 12276 /* Create JPEG blob, image, and image_info */ 12277 if (logging != MagickFalse) 12278 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12279 " Creating jpeg_image_info for alpha."); 12280 12281 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); 12282 12283 if (jpeg_image_info == (ImageInfo *) NULL) 12284 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12285 12286 if (logging != MagickFalse) 12287 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12288 " Creating jpeg_image."); 12289 12290 jpeg_image=SeparateImage(image,AlphaChannel,exception); 12291 if (jpeg_image == (Image *) NULL) 12292 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12293 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12294 jpeg_image->alpha_trait=UndefinedPixelTrait; 12295 jpeg_image->quality=jng_alpha_quality; 12296 jpeg_image_info->type=GrayscaleType; 12297 (void) SetImageType(jpeg_image,GrayscaleType,exception); 12298 (void) AcquireUniqueFilename(jpeg_image->filename); 12299 (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent, 12300 "%s",jpeg_image->filename); 12301 } 12302 else 12303 { 12304 jng_alpha_compression_method=0; 12305 jng_color_type=10; 12306 jng_alpha_sample_depth=0; 12307 } 12308 12309 /* To do: check bit depth of PNG alpha channel */ 12310 12311 /* Check if image is grayscale. */ 12312 if (image_info->type != TrueColorAlphaType && image_info->type != 12313 TrueColorType && SetImageGray(image,exception)) 12314 jng_color_type-=2; 12315 12316 if (logging != MagickFalse) 12317 { 12318 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12319 " JNG Quality = %d",(int) jng_quality); 12320 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12321 " JNG Color Type = %d",jng_color_type); 12322 if (transparent != 0) 12323 { 12324 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12325 " JNG Alpha Compression = %d",jng_alpha_compression_method); 12326 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12327 " JNG Alpha Depth = %d",jng_alpha_sample_depth); 12328 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12329 " JNG Alpha Quality = %d",(int) jng_alpha_quality); 12330 } 12331 } 12332 12333 if (transparent != 0) 12334 { 12335 if (jng_alpha_compression_method==0) 12336 { 12337 const char 12338 *value; 12339 12340 /* Encode alpha as a grayscale PNG blob */ 12341 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12342 exception); 12343 if (status == MagickFalse) 12344 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12345 12346 if (logging != MagickFalse) 12347 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12348 " Creating PNG blob."); 12349 12350 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MagickPathExtent); 12351 (void) CopyMagickString(jpeg_image->magick,"PNG",MagickPathExtent); 12352 jpeg_image_info->interlace=NoInterlace; 12353 12354 /* Exclude all ancillary chunks */ 12355 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all"); 12356 12357 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image, 12358 &length,exception); 12359 12360 /* Retrieve sample depth used */ 12361 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception); 12362 if (value != (char *) NULL) 12363 jng_alpha_sample_depth= (unsigned int) value[0]; 12364 } 12365 else 12366 { 12367 /* Encode alpha as a grayscale JPEG blob */ 12368 12369 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12370 exception); 12371 if (status == MagickFalse) 12372 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12373 12374 12375 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent); 12376 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12377 jpeg_image_info->interlace=NoInterlace; 12378 if (logging != MagickFalse) 12379 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12380 " Creating blob."); 12381 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, 12382 exception); 12383 jng_alpha_sample_depth=8; 12384 12385 if (logging != MagickFalse) 12386 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12387 " Successfully read jpeg_image into a blob, length=%.20g.", 12388 (double) length); 12389 12390 } 12391 /* Destroy JPEG image and image_info */ 12392 jpeg_image=DestroyImage(jpeg_image); 12393 (void) RelinquishUniqueFileResource(jpeg_image_info->filename); 12394 jpeg_image_info=DestroyImageInfo(jpeg_image_info); 12395 } 12396 12397 /* Write JHDR chunk */ 12398 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */ 12399 PNGType(chunk,mng_JHDR); 12400 LogPNGChunk(logging,mng_JHDR,16L); 12401 PNGLong(chunk+4,(png_uint_32) image->columns); 12402 PNGLong(chunk+8,(png_uint_32) image->rows); 12403 chunk[12]=jng_color_type; 12404 chunk[13]=8; /* sample depth */ 12405 chunk[14]=8; /*jng_image_compression_method */ 12406 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8); 12407 chunk[16]=jng_alpha_sample_depth; 12408 chunk[17]=jng_alpha_compression_method; 12409 chunk[18]=0; /*jng_alpha_filter_method */ 12410 chunk[19]=0; /*jng_alpha_interlace_method */ 12411 (void) WriteBlob(image,20,chunk); 12412 (void) WriteBlobMSBULong(image,crc32(0,chunk,20)); 12413 if (logging != MagickFalse) 12414 { 12415 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12416 " JNG width:%15lu",(unsigned long) image->columns); 12417 12418 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12419 " JNG height:%14lu",(unsigned long) image->rows); 12420 12421 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12422 " JNG color type:%10d",jng_color_type); 12423 12424 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12425 " JNG sample depth:%8d",8); 12426 12427 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12428 " JNG compression:%9d",8); 12429 12430 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12431 " JNG interlace:%11d",0); 12432 12433 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12434 " JNG alpha depth:%9d",jng_alpha_sample_depth); 12435 12436 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12437 " JNG alpha compression:%3d",jng_alpha_compression_method); 12438 12439 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12440 " JNG alpha filter:%8d",0); 12441 12442 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12443 " JNG alpha interlace:%5d",0); 12444 } 12445 12446 /* Write any JNG-chunk-b profiles */ 12447 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging); 12448 12449 /* 12450 Write leading ancillary chunks 12451 */ 12452 12453 if (transparent != 0) 12454 { 12455 /* 12456 Write JNG bKGD chunk 12457 */ 12458 12459 unsigned char 12460 blue, 12461 green, 12462 red; 12463 12464 ssize_t 12465 num_bytes; 12466 12467 if (jng_color_type == 8 || jng_color_type == 12) 12468 num_bytes=6L; 12469 else 12470 num_bytes=10L; 12471 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L)); 12472 PNGType(chunk,mng_bKGD); 12473 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L)); 12474 red=ScaleQuantumToChar(image->background_color.red); 12475 green=ScaleQuantumToChar(image->background_color.green); 12476 blue=ScaleQuantumToChar(image->background_color.blue); 12477 *(chunk+4)=0; 12478 *(chunk+5)=red; 12479 *(chunk+6)=0; 12480 *(chunk+7)=green; 12481 *(chunk+8)=0; 12482 *(chunk+9)=blue; 12483 (void) WriteBlob(image,(size_t) num_bytes,chunk); 12484 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes)); 12485 } 12486 12487 if ((image->colorspace == sRGBColorspace || image->rendering_intent)) 12488 { 12489 /* 12490 Write JNG sRGB chunk 12491 */ 12492 (void) WriteBlobMSBULong(image,1L); 12493 PNGType(chunk,mng_sRGB); 12494 LogPNGChunk(logging,mng_sRGB,1L); 12495 12496 if (image->rendering_intent != UndefinedIntent) 12497 chunk[4]=(unsigned char) 12498 Magick_RenderingIntent_to_PNG_RenderingIntent( 12499 (image->rendering_intent)); 12500 12501 else 12502 chunk[4]=(unsigned char) 12503 Magick_RenderingIntent_to_PNG_RenderingIntent( 12504 (PerceptualIntent)); 12505 12506 (void) WriteBlob(image,5,chunk); 12507 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 12508 } 12509 else 12510 { 12511 if (image->gamma != 0.0) 12512 { 12513 /* 12514 Write JNG gAMA chunk 12515 */ 12516 (void) WriteBlobMSBULong(image,4L); 12517 PNGType(chunk,mng_gAMA); 12518 LogPNGChunk(logging,mng_gAMA,4L); 12519 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5)); 12520 (void) WriteBlob(image,8,chunk); 12521 (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); 12522 } 12523 12524 if ((mng_info->equal_chrms == MagickFalse) && 12525 (image->chromaticity.red_primary.x != 0.0)) 12526 { 12527 PrimaryInfo 12528 primary; 12529 12530 /* 12531 Write JNG cHRM chunk 12532 */ 12533 (void) WriteBlobMSBULong(image,32L); 12534 PNGType(chunk,mng_cHRM); 12535 LogPNGChunk(logging,mng_cHRM,32L); 12536 primary=image->chromaticity.white_point; 12537 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5)); 12538 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5)); 12539 primary=image->chromaticity.red_primary; 12540 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5)); 12541 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5)); 12542 primary=image->chromaticity.green_primary; 12543 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5)); 12544 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5)); 12545 primary=image->chromaticity.blue_primary; 12546 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5)); 12547 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5)); 12548 (void) WriteBlob(image,36,chunk); 12549 (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); 12550 } 12551 } 12552 12553 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs) 12554 { 12555 /* 12556 Write JNG pHYs chunk 12557 */ 12558 (void) WriteBlobMSBULong(image,9L); 12559 PNGType(chunk,mng_pHYs); 12560 LogPNGChunk(logging,mng_pHYs,9L); 12561 if (image->units == PixelsPerInchResolution) 12562 { 12563 PNGLong(chunk+4,(png_uint_32) 12564 (image->resolution.x*100.0/2.54+0.5)); 12565 12566 PNGLong(chunk+8,(png_uint_32) 12567 (image->resolution.y*100.0/2.54+0.5)); 12568 12569 chunk[12]=1; 12570 } 12571 12572 else 12573 { 12574 if (image->units == PixelsPerCentimeterResolution) 12575 { 12576 PNGLong(chunk+4,(png_uint_32) 12577 (image->resolution.x*100.0+0.5)); 12578 12579 PNGLong(chunk+8,(png_uint_32) 12580 (image->resolution.y*100.0+0.5)); 12581 12582 chunk[12]=1; 12583 } 12584 12585 else 12586 { 12587 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5)); 12588 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5)); 12589 chunk[12]=0; 12590 } 12591 } 12592 (void) WriteBlob(image,13,chunk); 12593 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12594 } 12595 12596 if (mng_info->write_mng == 0 && (image->page.x || image->page.y)) 12597 { 12598 /* 12599 Write JNG oFFs chunk 12600 */ 12601 (void) WriteBlobMSBULong(image,9L); 12602 PNGType(chunk,mng_oFFs); 12603 LogPNGChunk(logging,mng_oFFs,9L); 12604 PNGsLong(chunk+4,(ssize_t) (image->page.x)); 12605 PNGsLong(chunk+8,(ssize_t) (image->page.y)); 12606 chunk[12]=0; 12607 (void) WriteBlob(image,13,chunk); 12608 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12609 } 12610 if (mng_info->write_mng == 0 && (image->page.width || image->page.height)) 12611 { 12612 (void) WriteBlobMSBULong(image,9L); /* data length=8 */ 12613 PNGType(chunk,mng_vpAg); 12614 LogPNGChunk(logging,mng_vpAg,9L); 12615 PNGLong(chunk+4,(png_uint_32) image->page.width); 12616 PNGLong(chunk+8,(png_uint_32) image->page.height); 12617 chunk[12]=0; /* unit = pixels */ 12618 (void) WriteBlob(image,13,chunk); 12619 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 12620 } 12621 12622 if (transparent != 0) 12623 { 12624 if (jng_alpha_compression_method==0) 12625 { 12626 register ssize_t 12627 i; 12628 12629 size_t 12630 len; 12631 12632 /* Write IDAT chunk header */ 12633 if (logging != MagickFalse) 12634 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12635 " Write IDAT chunks from blob, length=%.20g.",(double) 12636 length); 12637 12638 /* Copy IDAT chunks */ 12639 len=0; 12640 p=blob+8; 12641 for (i=8; i<(ssize_t) length; i+=len+12) 12642 { 12643 len=(size_t) (*p) << 24; 12644 len|=(size_t) (*(p+1)) << 16; 12645 len|=(size_t) (*(p+2)) << 8; 12646 len|=(size_t) (*(p+3)); 12647 p+=4; 12648 12649 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */ 12650 { 12651 /* Found an IDAT chunk. */ 12652 (void) WriteBlobMSBULong(image,len); 12653 LogPNGChunk(logging,mng_IDAT,len); 12654 (void) WriteBlob(image,len+4,p); 12655 (void) WriteBlobMSBULong(image, crc32(0,p,(uInt) len+4)); 12656 } 12657 12658 else 12659 { 12660 if (logging != MagickFalse) 12661 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12662 " Skipping %c%c%c%c chunk, length=%.20g.", 12663 *(p),*(p+1),*(p+2),*(p+3),(double) len); 12664 } 12665 p+=(8+len); 12666 } 12667 } 12668 else if (length != 0) 12669 { 12670 /* Write JDAA chunk header */ 12671 if (logging != MagickFalse) 12672 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12673 " Write JDAA chunk, length=%.20g.",(double) length); 12674 (void) WriteBlobMSBULong(image,(size_t) length); 12675 PNGType(chunk,mng_JDAA); 12676 LogPNGChunk(logging,mng_JDAA,length); 12677 /* Write JDAT chunk(s) data */ 12678 (void) WriteBlob(image,4,chunk); 12679 (void) WriteBlob(image,length,blob); 12680 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob, 12681 (uInt) length)); 12682 } 12683 blob=(unsigned char *) RelinquishMagickMemory(blob); 12684 } 12685 12686 /* Encode image as a JPEG blob */ 12687 if (logging != MagickFalse) 12688 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12689 " Creating jpeg_image_info."); 12690 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); 12691 if (jpeg_image_info == (ImageInfo *) NULL) 12692 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12693 12694 if (logging != MagickFalse) 12695 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12696 " Creating jpeg_image."); 12697 12698 jpeg_image=CloneImage(image,0,0,MagickTrue,exception); 12699 if (jpeg_image == (Image *) NULL) 12700 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12701 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12702 12703 (void) AcquireUniqueFilename(jpeg_image->filename); 12704 (void) FormatLocaleString(jpeg_image_info->filename,MagickPathExtent,"%s", 12705 jpeg_image->filename); 12706 12707 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode, 12708 exception); 12709 12710 if (logging != MagickFalse) 12711 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12712 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns, 12713 (double) jpeg_image->rows); 12714 12715 if (status == MagickFalse) 12716 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12717 12718 if (jng_color_type == 8 || jng_color_type == 12) 12719 jpeg_image_info->type=GrayscaleType; 12720 12721 jpeg_image_info->quality=jng_quality; 12722 jpeg_image->quality=jng_quality; 12723 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MagickPathExtent); 12724 (void) CopyMagickString(jpeg_image->magick,"JPEG",MagickPathExtent); 12725 12726 if (logging != MagickFalse) 12727 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12728 " Creating blob."); 12729 12730 blob=(unsigned char *) ImageToBlob(jpeg_image_info,jpeg_image,&length, 12731 exception); 12732 12733 if (logging != MagickFalse) 12734 { 12735 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12736 " Successfully read jpeg_image into a blob, length=%.20g.", 12737 (double) length); 12738 12739 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12740 " Write JDAT chunk, length=%.20g.",(double) length); 12741 } 12742 12743 /* Write JDAT chunk(s) */ 12744 (void) WriteBlobMSBULong(image,(size_t) length); 12745 PNGType(chunk,mng_JDAT); 12746 LogPNGChunk(logging,mng_JDAT,length); 12747 (void) WriteBlob(image,4,chunk); 12748 (void) WriteBlob(image,length,blob); 12749 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length)); 12750 12751 jpeg_image=DestroyImage(jpeg_image); 12752 (void) RelinquishUniqueFileResource(jpeg_image_info->filename); 12753 jpeg_image_info=DestroyImageInfo(jpeg_image_info); 12754 blob=(unsigned char *) RelinquishMagickMemory(blob); 12755 12756 /* Write any JNG-chunk-e profiles */ 12757 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging); 12758 12759 /* Write IEND chunk */ 12760 (void) WriteBlobMSBULong(image,0L); 12761 PNGType(chunk,mng_IEND); 12762 LogPNGChunk(logging,mng_IEND,0); 12763 (void) WriteBlob(image,4,chunk); 12764 (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); 12765 12766 if (logging != MagickFalse) 12767 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12768 " exit WriteOneJNGImage()"); 12769 12770 return(status); 12771 } 12772 12773 12774 /* 12775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12776 % % 12777 % % 12778 % % 12779 % W r i t e J N G I m a g e % 12780 % % 12781 % % 12782 % % 12783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12784 % 12785 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file. 12786 % 12787 % JNG support written by Glenn Randers-Pehrson, glennrp (at) image... 12788 % 12789 % The format of the WriteJNGImage method is: 12790 % 12791 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info, 12792 % Image *image,ExceptionInfo *exception) 12793 % 12794 % A description of each parameter follows: 12795 % 12796 % o image_info: the image info. 12797 % 12798 % o image: The image. 12799 % 12800 % o exception: return any errors or warnings in this structure. 12801 % 12802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12803 */ 12804 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image, 12805 ExceptionInfo *exception) 12806 { 12807 MagickBooleanType 12808 have_mng_structure, 12809 logging, 12810 status; 12811 12812 MngInfo 12813 *mng_info; 12814 12815 /* 12816 Open image file. 12817 */ 12818 assert(image_info != (const ImageInfo *) NULL); 12819 assert(image_info->signature == MagickCoreSignature); 12820 assert(image != (Image *) NULL); 12821 assert(image->signature == MagickCoreSignature); 12822 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 12823 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()"); 12824 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 12825 if (status == MagickFalse) 12826 return(status); 12827 if ((image->columns > 65535UL) || (image->rows > 65535UL)) 12828 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 12829 12830 /* 12831 Allocate a MngInfo structure. 12832 */ 12833 have_mng_structure=MagickFalse; 12834 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 12835 if (mng_info == (MngInfo *) NULL) 12836 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12837 /* 12838 Initialize members of the MngInfo structure. 12839 */ 12840 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 12841 mng_info->image=image; 12842 have_mng_structure=MagickTrue; 12843 12844 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n"); 12845 12846 status=WriteOneJNGImage(mng_info,image_info,image,exception); 12847 (void) CloseBlob(image); 12848 12849 (void) CatchImageException(image); 12850 MngInfoFreeStruct(mng_info,&have_mng_structure); 12851 if (logging != MagickFalse) 12852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()"); 12853 return(status); 12854 } 12855 #endif 12856 12857 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image, 12858 ExceptionInfo *exception) 12859 { 12860 const char 12861 *option; 12862 12863 Image 12864 *next_image; 12865 12866 MagickBooleanType 12867 have_mng_structure, 12868 status; 12869 12870 volatile MagickBooleanType 12871 logging; 12872 12873 MngInfo 12874 *mng_info; 12875 12876 int 12877 image_count, 12878 need_iterations, 12879 need_matte; 12880 12881 volatile int 12882 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 12883 defined(PNG_MNG_FEATURES_SUPPORTED) 12884 need_local_plte, 12885 #endif 12886 all_images_are_gray, 12887 need_defi, 12888 use_global_plte; 12889 12890 register ssize_t 12891 i; 12892 12893 unsigned char 12894 chunk[800]; 12895 12896 volatile unsigned int 12897 write_jng, 12898 write_mng; 12899 12900 volatile size_t 12901 scene; 12902 12903 size_t 12904 final_delay=0, 12905 initial_delay; 12906 12907 #if (PNG_LIBPNG_VER < 10200) 12908 if (image_info->verbose) 12909 printf("Your PNG library (libpng-%s) is rather old.\n", 12910 PNG_LIBPNG_VER_STRING); 12911 #endif 12912 12913 /* 12914 Open image file. 12915 */ 12916 assert(image_info != (const ImageInfo *) NULL); 12917 assert(image_info->signature == MagickCoreSignature); 12918 assert(image != (Image *) NULL); 12919 assert(image->signature == MagickCoreSignature); 12920 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 12921 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()"); 12922 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 12923 if (status == MagickFalse) 12924 return(status); 12925 12926 /* 12927 Allocate a MngInfo structure. 12928 */ 12929 have_mng_structure=MagickFalse; 12930 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); 12931 if (mng_info == (MngInfo *) NULL) 12932 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 12933 /* 12934 Initialize members of the MngInfo structure. 12935 */ 12936 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo)); 12937 mng_info->image=image; 12938 have_mng_structure=MagickTrue; 12939 write_mng=LocaleCompare(image_info->magick,"MNG") == 0; 12940 12941 /* 12942 * See if user has requested a specific PNG subformat to be used 12943 * for all of the PNGs in the MNG being written, e.g., 12944 * 12945 * convert *.png png8:animation.mng 12946 * 12947 * To do: check -define png:bit_depth and png:color_type as well, 12948 * or perhaps use mng:bit_depth and mng:color_type instead for 12949 * global settings. 12950 */ 12951 12952 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0; 12953 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0; 12954 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0; 12955 12956 write_jng=MagickFalse; 12957 if (image_info->compression == JPEGCompression) 12958 write_jng=MagickTrue; 12959 12960 mng_info->adjoin=image_info->adjoin && 12961 (GetNextImageInList(image) != (Image *) NULL) && write_mng; 12962 12963 if (logging != MagickFalse) 12964 { 12965 /* Log some info about the input */ 12966 Image 12967 *p; 12968 12969 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12970 " Checking input image(s)\n" 12971 " Image_info depth: %.20g, Type: %d", 12972 (double) image_info->depth, image_info->type); 12973 12974 scene=0; 12975 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p)) 12976 { 12977 12978 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12979 " Scene: %.20g\n, Image depth: %.20g", 12980 (double) scene++, (double) p->depth); 12981 12982 if (p->alpha_trait != UndefinedPixelTrait) 12983 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12984 " Matte: True"); 12985 12986 else 12987 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12988 " Matte: False"); 12989 12990 if (p->storage_class == PseudoClass) 12991 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12992 " Storage class: PseudoClass"); 12993 12994 else 12995 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 12996 " Storage class: DirectClass"); 12997 12998 if (p->colors) 12999 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13000 " Number of colors: %.20g",(double) p->colors); 13001 13002 else 13003 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13004 " Number of colors: unspecified"); 13005 13006 if (mng_info->adjoin == MagickFalse) 13007 break; 13008 } 13009 } 13010 13011 use_global_plte=MagickFalse; 13012 all_images_are_gray=MagickFalse; 13013 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13014 need_local_plte=MagickTrue; 13015 #endif 13016 need_defi=MagickFalse; 13017 need_matte=MagickFalse; 13018 mng_info->framing_mode=1; 13019 mng_info->old_framing_mode=1; 13020 13021 if (write_mng) 13022 if (image_info->page != (char *) NULL) 13023 { 13024 /* 13025 Determine image bounding box. 13026 */ 13027 SetGeometry(image,&mng_info->page); 13028 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x, 13029 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height); 13030 } 13031 if (write_mng) 13032 { 13033 unsigned int 13034 need_geom; 13035 13036 unsigned short 13037 red, 13038 green, 13039 blue; 13040 13041 mng_info->page=image->page; 13042 need_geom=MagickTrue; 13043 if (mng_info->page.width || mng_info->page.height) 13044 need_geom=MagickFalse; 13045 /* 13046 Check all the scenes. 13047 */ 13048 initial_delay=image->delay; 13049 need_iterations=MagickFalse; 13050 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0; 13051 mng_info->equal_physs=MagickTrue, 13052 mng_info->equal_gammas=MagickTrue; 13053 mng_info->equal_srgbs=MagickTrue; 13054 mng_info->equal_backgrounds=MagickTrue; 13055 image_count=0; 13056 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13057 defined(PNG_MNG_FEATURES_SUPPORTED) 13058 all_images_are_gray=MagickTrue; 13059 mng_info->equal_palettes=MagickFalse; 13060 need_local_plte=MagickFalse; 13061 #endif 13062 for (next_image=image; next_image != (Image *) NULL; ) 13063 { 13064 if (need_geom) 13065 { 13066 if ((next_image->columns+next_image->page.x) > mng_info->page.width) 13067 mng_info->page.width=next_image->columns+next_image->page.x; 13068 13069 if ((next_image->rows+next_image->page.y) > mng_info->page.height) 13070 mng_info->page.height=next_image->rows+next_image->page.y; 13071 } 13072 13073 if (next_image->page.x || next_image->page.y) 13074 need_defi=MagickTrue; 13075 13076 if (next_image->alpha_trait != UndefinedPixelTrait) 13077 need_matte=MagickTrue; 13078 13079 if ((int) next_image->dispose >= BackgroundDispose) 13080 if ((next_image->alpha_trait != UndefinedPixelTrait) || 13081 next_image->page.x || next_image->page.y || 13082 ((next_image->columns < mng_info->page.width) && 13083 (next_image->rows < mng_info->page.height))) 13084 mng_info->need_fram=MagickTrue; 13085 13086 if (next_image->iterations) 13087 need_iterations=MagickTrue; 13088 13089 final_delay=next_image->delay; 13090 13091 if (final_delay != initial_delay || final_delay > 1UL* 13092 next_image->ticks_per_second) 13093 mng_info->need_fram=1; 13094 13095 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13096 defined(PNG_MNG_FEATURES_SUPPORTED) 13097 /* 13098 check for global palette possibility. 13099 */ 13100 if (image->alpha_trait != UndefinedPixelTrait) 13101 need_local_plte=MagickTrue; 13102 13103 if (need_local_plte == 0) 13104 { 13105 if (SetImageGray(image,exception) == MagickFalse) 13106 all_images_are_gray=MagickFalse; 13107 mng_info->equal_palettes=PalettesAreEqual(image,next_image); 13108 if (use_global_plte == 0) 13109 use_global_plte=mng_info->equal_palettes; 13110 need_local_plte=!mng_info->equal_palettes; 13111 } 13112 #endif 13113 if (GetNextImageInList(next_image) != (Image *) NULL) 13114 { 13115 if (next_image->background_color.red != 13116 next_image->next->background_color.red || 13117 next_image->background_color.green != 13118 next_image->next->background_color.green || 13119 next_image->background_color.blue != 13120 next_image->next->background_color.blue) 13121 mng_info->equal_backgrounds=MagickFalse; 13122 13123 if (next_image->gamma != next_image->next->gamma) 13124 mng_info->equal_gammas=MagickFalse; 13125 13126 if (next_image->rendering_intent != 13127 next_image->next->rendering_intent) 13128 mng_info->equal_srgbs=MagickFalse; 13129 13130 if ((next_image->units != next_image->next->units) || 13131 (next_image->resolution.x != next_image->next->resolution.x) || 13132 (next_image->resolution.y != next_image->next->resolution.y)) 13133 mng_info->equal_physs=MagickFalse; 13134 13135 if (mng_info->equal_chrms) 13136 { 13137 if (next_image->chromaticity.red_primary.x != 13138 next_image->next->chromaticity.red_primary.x || 13139 next_image->chromaticity.red_primary.y != 13140 next_image->next->chromaticity.red_primary.y || 13141 next_image->chromaticity.green_primary.x != 13142 next_image->next->chromaticity.green_primary.x || 13143 next_image->chromaticity.green_primary.y != 13144 next_image->next->chromaticity.green_primary.y || 13145 next_image->chromaticity.blue_primary.x != 13146 next_image->next->chromaticity.blue_primary.x || 13147 next_image->chromaticity.blue_primary.y != 13148 next_image->next->chromaticity.blue_primary.y || 13149 next_image->chromaticity.white_point.x != 13150 next_image->next->chromaticity.white_point.x || 13151 next_image->chromaticity.white_point.y != 13152 next_image->next->chromaticity.white_point.y) 13153 mng_info->equal_chrms=MagickFalse; 13154 } 13155 } 13156 image_count++; 13157 next_image=GetNextImageInList(next_image); 13158 } 13159 if (image_count < 2) 13160 { 13161 mng_info->equal_backgrounds=MagickFalse; 13162 mng_info->equal_chrms=MagickFalse; 13163 mng_info->equal_gammas=MagickFalse; 13164 mng_info->equal_srgbs=MagickFalse; 13165 mng_info->equal_physs=MagickFalse; 13166 use_global_plte=MagickFalse; 13167 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13168 need_local_plte=MagickTrue; 13169 #endif 13170 need_iterations=MagickFalse; 13171 } 13172 13173 if (mng_info->need_fram == MagickFalse) 13174 { 13175 /* 13176 Only certain framing rates 100/n are exactly representable without 13177 the FRAM chunk but we'll allow some slop in VLC files 13178 */ 13179 if (final_delay == 0) 13180 { 13181 if (need_iterations != MagickFalse) 13182 { 13183 /* 13184 It's probably a GIF with loop; don't run it *too* fast. 13185 */ 13186 if (mng_info->adjoin) 13187 { 13188 final_delay=10; 13189 (void) ThrowMagickException(exception,GetMagickModule(), 13190 CoderWarning, 13191 "input has zero delay between all frames; assuming", 13192 " 10 cs `%s'",""); 13193 } 13194 } 13195 else 13196 mng_info->ticks_per_second=0; 13197 } 13198 if (final_delay != 0) 13199 mng_info->ticks_per_second=(png_uint_32) 13200 (image->ticks_per_second/final_delay); 13201 if (final_delay > 50) 13202 mng_info->ticks_per_second=2; 13203 13204 if (final_delay > 75) 13205 mng_info->ticks_per_second=1; 13206 13207 if (final_delay > 125) 13208 mng_info->need_fram=MagickTrue; 13209 13210 if (need_defi && final_delay > 2 && (final_delay != 4) && 13211 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) && 13212 (final_delay != 25) && (final_delay != 50) && 13213 (final_delay != (size_t) image->ticks_per_second)) 13214 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */ 13215 } 13216 13217 if (mng_info->need_fram != MagickFalse) 13218 mng_info->ticks_per_second=image->ticks_per_second; 13219 /* 13220 If pseudocolor, we should also check to see if all the 13221 palettes are identical and write a global PLTE if they are. 13222 ../glennrp Feb 99. 13223 */ 13224 /* 13225 Write the MNG version 1.0 signature and MHDR chunk. 13226 */ 13227 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n"); 13228 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */ 13229 PNGType(chunk,mng_MHDR); 13230 LogPNGChunk(logging,mng_MHDR,28L); 13231 PNGLong(chunk+4,(png_uint_32) mng_info->page.width); 13232 PNGLong(chunk+8,(png_uint_32) mng_info->page.height); 13233 PNGLong(chunk+12,mng_info->ticks_per_second); 13234 PNGLong(chunk+16,0L); /* layer count=unknown */ 13235 PNGLong(chunk+20,0L); /* frame count=unknown */ 13236 PNGLong(chunk+24,0L); /* play time=unknown */ 13237 if (write_jng) 13238 { 13239 if (need_matte) 13240 { 13241 if (need_defi || mng_info->need_fram || use_global_plte) 13242 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */ 13243 13244 else 13245 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */ 13246 } 13247 13248 else 13249 { 13250 if (need_defi || mng_info->need_fram || use_global_plte) 13251 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */ 13252 13253 else 13254 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */ 13255 } 13256 } 13257 13258 else 13259 { 13260 if (need_matte) 13261 { 13262 if (need_defi || mng_info->need_fram || use_global_plte) 13263 PNGLong(chunk+28,11L); /* simplicity=LC */ 13264 13265 else 13266 PNGLong(chunk+28,9L); /* simplicity=VLC */ 13267 } 13268 13269 else 13270 { 13271 if (need_defi || mng_info->need_fram || use_global_plte) 13272 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */ 13273 13274 else 13275 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */ 13276 } 13277 } 13278 (void) WriteBlob(image,32,chunk); 13279 (void) WriteBlobMSBULong(image,crc32(0,chunk,32)); 13280 option=GetImageOption(image_info,"mng:need-cacheoff"); 13281 if (option != (const char *) NULL) 13282 { 13283 size_t 13284 length; 13285 13286 /* 13287 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG. 13288 */ 13289 PNGType(chunk,mng_nEED); 13290 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20); 13291 (void) WriteBlobMSBULong(image,(size_t) length); 13292 LogPNGChunk(logging,mng_nEED,(size_t) length); 13293 length+=4; 13294 (void) WriteBlob(image,length,chunk); 13295 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length)); 13296 } 13297 if ((GetPreviousImageInList(image) == (Image *) NULL) && 13298 (GetNextImageInList(image) != (Image *) NULL) && 13299 (image->iterations != 1)) 13300 { 13301 /* 13302 Write MNG TERM chunk 13303 */ 13304 (void) WriteBlobMSBULong(image,10L); /* data length=10 */ 13305 PNGType(chunk,mng_TERM); 13306 LogPNGChunk(logging,mng_TERM,10L); 13307 chunk[4]=3; /* repeat animation */ 13308 chunk[5]=0; /* show last frame when done */ 13309 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second* 13310 final_delay/MagickMax(image->ticks_per_second,1))); 13311 13312 if (image->iterations == 0) 13313 PNGLong(chunk+10,PNG_UINT_31_MAX); 13314 13315 else 13316 PNGLong(chunk+10,(png_uint_32) image->iterations); 13317 13318 if (logging != MagickFalse) 13319 { 13320 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13321 " TERM delay: %.20g",(double) (mng_info->ticks_per_second* 13322 final_delay/MagickMax(image->ticks_per_second,1))); 13323 13324 if (image->iterations == 0) 13325 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13326 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX); 13327 13328 else 13329 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13330 " Image iterations: %.20g",(double) image->iterations); 13331 } 13332 (void) WriteBlob(image,14,chunk); 13333 (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); 13334 } 13335 /* 13336 To do: check for cHRM+gAMA == sRGB, and write sRGB instead. 13337 */ 13338 if ((image->colorspace == sRGBColorspace || image->rendering_intent) && 13339 mng_info->equal_srgbs) 13340 { 13341 /* 13342 Write MNG sRGB chunk 13343 */ 13344 (void) WriteBlobMSBULong(image,1L); 13345 PNGType(chunk,mng_sRGB); 13346 LogPNGChunk(logging,mng_sRGB,1L); 13347 13348 if (image->rendering_intent != UndefinedIntent) 13349 chunk[4]=(unsigned char) 13350 Magick_RenderingIntent_to_PNG_RenderingIntent( 13351 (image->rendering_intent)); 13352 13353 else 13354 chunk[4]=(unsigned char) 13355 Magick_RenderingIntent_to_PNG_RenderingIntent( 13356 (PerceptualIntent)); 13357 13358 (void) WriteBlob(image,5,chunk); 13359 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 13360 mng_info->have_write_global_srgb=MagickTrue; 13361 } 13362 13363 else 13364 { 13365 if (image->gamma && mng_info->equal_gammas) 13366 { 13367 /* 13368 Write MNG gAMA chunk 13369 */ 13370 (void) WriteBlobMSBULong(image,4L); 13371 PNGType(chunk,mng_gAMA); 13372 LogPNGChunk(logging,mng_gAMA,4L); 13373 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5)); 13374 (void) WriteBlob(image,8,chunk); 13375 (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); 13376 mng_info->have_write_global_gama=MagickTrue; 13377 } 13378 if (mng_info->equal_chrms) 13379 { 13380 PrimaryInfo 13381 primary; 13382 13383 /* 13384 Write MNG cHRM chunk 13385 */ 13386 (void) WriteBlobMSBULong(image,32L); 13387 PNGType(chunk,mng_cHRM); 13388 LogPNGChunk(logging,mng_cHRM,32L); 13389 primary=image->chromaticity.white_point; 13390 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5)); 13391 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5)); 13392 primary=image->chromaticity.red_primary; 13393 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5)); 13394 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5)); 13395 primary=image->chromaticity.green_primary; 13396 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5)); 13397 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5)); 13398 primary=image->chromaticity.blue_primary; 13399 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5)); 13400 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5)); 13401 (void) WriteBlob(image,36,chunk); 13402 (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); 13403 mng_info->have_write_global_chrm=MagickTrue; 13404 } 13405 } 13406 if (image->resolution.x && image->resolution.y && mng_info->equal_physs) 13407 { 13408 /* 13409 Write MNG pHYs chunk 13410 */ 13411 (void) WriteBlobMSBULong(image,9L); 13412 PNGType(chunk,mng_pHYs); 13413 LogPNGChunk(logging,mng_pHYs,9L); 13414 13415 if (image->units == PixelsPerInchResolution) 13416 { 13417 PNGLong(chunk+4,(png_uint_32) 13418 (image->resolution.x*100.0/2.54+0.5)); 13419 13420 PNGLong(chunk+8,(png_uint_32) 13421 (image->resolution.y*100.0/2.54+0.5)); 13422 13423 chunk[12]=1; 13424 } 13425 13426 else 13427 { 13428 if (image->units == PixelsPerCentimeterResolution) 13429 { 13430 PNGLong(chunk+4,(png_uint_32) 13431 (image->resolution.x*100.0+0.5)); 13432 13433 PNGLong(chunk+8,(png_uint_32) 13434 (image->resolution.y*100.0+0.5)); 13435 13436 chunk[12]=1; 13437 } 13438 13439 else 13440 { 13441 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5)); 13442 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5)); 13443 chunk[12]=0; 13444 } 13445 } 13446 (void) WriteBlob(image,13,chunk); 13447 (void) WriteBlobMSBULong(image,crc32(0,chunk,13)); 13448 } 13449 /* 13450 Write MNG BACK chunk and global bKGD chunk, if the image is transparent 13451 or does not cover the entire frame. 13452 */ 13453 if (write_mng && ((image->alpha_trait != UndefinedPixelTrait) || 13454 image->page.x > 0 || image->page.y > 0 || (image->page.width && 13455 (image->page.width+image->page.x < mng_info->page.width)) 13456 || (image->page.height && (image->page.height+image->page.y 13457 < mng_info->page.height)))) 13458 { 13459 (void) WriteBlobMSBULong(image,6L); 13460 PNGType(chunk,mng_BACK); 13461 LogPNGChunk(logging,mng_BACK,6L); 13462 red=ScaleQuantumToShort(image->background_color.red); 13463 green=ScaleQuantumToShort(image->background_color.green); 13464 blue=ScaleQuantumToShort(image->background_color.blue); 13465 PNGShort(chunk+4,red); 13466 PNGShort(chunk+6,green); 13467 PNGShort(chunk+8,blue); 13468 (void) WriteBlob(image,10,chunk); 13469 (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); 13470 if (mng_info->equal_backgrounds) 13471 { 13472 (void) WriteBlobMSBULong(image,6L); 13473 PNGType(chunk,mng_bKGD); 13474 LogPNGChunk(logging,mng_bKGD,6L); 13475 (void) WriteBlob(image,10,chunk); 13476 (void) WriteBlobMSBULong(image,crc32(0,chunk,10)); 13477 } 13478 } 13479 13480 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED 13481 if ((need_local_plte == MagickFalse) && 13482 (image->storage_class == PseudoClass) && 13483 (all_images_are_gray == MagickFalse)) 13484 { 13485 size_t 13486 data_length; 13487 13488 /* 13489 Write MNG PLTE chunk 13490 */ 13491 data_length=3*image->colors; 13492 (void) WriteBlobMSBULong(image,data_length); 13493 PNGType(chunk,mng_PLTE); 13494 LogPNGChunk(logging,mng_PLTE,data_length); 13495 13496 for (i=0; i < (ssize_t) image->colors; i++) 13497 { 13498 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar( 13499 image->colormap[i].red) & 0xff); 13500 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar( 13501 image->colormap[i].green) & 0xff); 13502 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar( 13503 image->colormap[i].blue) & 0xff); 13504 } 13505 13506 (void) WriteBlob(image,data_length+4,chunk); 13507 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4))); 13508 mng_info->have_write_global_plte=MagickTrue; 13509 } 13510 #endif 13511 } 13512 scene=0; 13513 mng_info->delay=0; 13514 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13515 defined(PNG_MNG_FEATURES_SUPPORTED) 13516 mng_info->equal_palettes=MagickFalse; 13517 #endif 13518 do 13519 { 13520 if (mng_info->adjoin) 13521 { 13522 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ 13523 defined(PNG_MNG_FEATURES_SUPPORTED) 13524 /* 13525 If we aren't using a global palette for the entire MNG, check to 13526 see if we can use one for two or more consecutive images. 13527 */ 13528 if (need_local_plte && use_global_plte && !all_images_are_gray) 13529 { 13530 if (mng_info->IsPalette) 13531 { 13532 /* 13533 When equal_palettes is true, this image has the same palette 13534 as the previous PseudoClass image 13535 */ 13536 mng_info->have_write_global_plte=mng_info->equal_palettes; 13537 mng_info->equal_palettes=PalettesAreEqual(image,image->next); 13538 if (mng_info->equal_palettes && !mng_info->have_write_global_plte) 13539 { 13540 /* 13541 Write MNG PLTE chunk 13542 */ 13543 size_t 13544 data_length; 13545 13546 data_length=3*image->colors; 13547 (void) WriteBlobMSBULong(image,data_length); 13548 PNGType(chunk,mng_PLTE); 13549 LogPNGChunk(logging,mng_PLTE,data_length); 13550 13551 for (i=0; i < (ssize_t) image->colors; i++) 13552 { 13553 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red); 13554 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green); 13555 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue); 13556 } 13557 13558 (void) WriteBlob(image,data_length+4,chunk); 13559 (void) WriteBlobMSBULong(image,crc32(0,chunk, 13560 (uInt) (data_length+4))); 13561 mng_info->have_write_global_plte=MagickTrue; 13562 } 13563 } 13564 else 13565 mng_info->have_write_global_plte=MagickFalse; 13566 } 13567 #endif 13568 if (need_defi) 13569 { 13570 ssize_t 13571 previous_x, 13572 previous_y; 13573 13574 if (scene) 13575 { 13576 previous_x=mng_info->page.x; 13577 previous_y=mng_info->page.y; 13578 } 13579 else 13580 { 13581 previous_x=0; 13582 previous_y=0; 13583 } 13584 mng_info->page=image->page; 13585 if ((mng_info->page.x != previous_x) || 13586 (mng_info->page.y != previous_y)) 13587 { 13588 (void) WriteBlobMSBULong(image,12L); /* data length=12 */ 13589 PNGType(chunk,mng_DEFI); 13590 LogPNGChunk(logging,mng_DEFI,12L); 13591 chunk[4]=0; /* object 0 MSB */ 13592 chunk[5]=0; /* object 0 LSB */ 13593 chunk[6]=0; /* visible */ 13594 chunk[7]=0; /* abstract */ 13595 PNGLong(chunk+8,(png_uint_32) mng_info->page.x); 13596 PNGLong(chunk+12,(png_uint_32) mng_info->page.y); 13597 (void) WriteBlob(image,16,chunk); 13598 (void) WriteBlobMSBULong(image,crc32(0,chunk,16)); 13599 } 13600 } 13601 } 13602 13603 mng_info->write_mng=write_mng; 13604 13605 if ((int) image->dispose >= 3) 13606 mng_info->framing_mode=3; 13607 13608 if (mng_info->need_fram && mng_info->adjoin && 13609 ((image->delay != mng_info->delay) || 13610 (mng_info->framing_mode != mng_info->old_framing_mode))) 13611 { 13612 if (image->delay == mng_info->delay) 13613 { 13614 /* 13615 Write a MNG FRAM chunk with the new framing mode. 13616 */ 13617 (void) WriteBlobMSBULong(image,1L); /* data length=1 */ 13618 PNGType(chunk,mng_FRAM); 13619 LogPNGChunk(logging,mng_FRAM,1L); 13620 chunk[4]=(unsigned char) mng_info->framing_mode; 13621 (void) WriteBlob(image,5,chunk); 13622 (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); 13623 } 13624 else 13625 { 13626 /* 13627 Write a MNG FRAM chunk with the delay. 13628 */ 13629 (void) WriteBlobMSBULong(image,10L); /* data length=10 */ 13630 PNGType(chunk,mng_FRAM); 13631 LogPNGChunk(logging,mng_FRAM,10L); 13632 chunk[4]=(unsigned char) mng_info->framing_mode; 13633 chunk[5]=0; /* frame name separator (no name) */ 13634 chunk[6]=2; /* flag for changing default delay */ 13635 chunk[7]=0; /* flag for changing frame timeout */ 13636 chunk[8]=0; /* flag for changing frame clipping */ 13637 chunk[9]=0; /* flag for changing frame sync_id */ 13638 PNGLong(chunk+10,(png_uint_32) 13639 ((mng_info->ticks_per_second* 13640 image->delay)/MagickMax(image->ticks_per_second,1))); 13641 (void) WriteBlob(image,14,chunk); 13642 (void) WriteBlobMSBULong(image,crc32(0,chunk,14)); 13643 mng_info->delay=(png_uint_32) image->delay; 13644 } 13645 mng_info->old_framing_mode=mng_info->framing_mode; 13646 } 13647 13648 #if defined(JNG_SUPPORTED) 13649 if (image_info->compression == JPEGCompression) 13650 { 13651 ImageInfo 13652 *write_info; 13653 13654 if (logging != MagickFalse) 13655 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13656 " Writing JNG object."); 13657 /* To do: specify the desired alpha compression method. */ 13658 write_info=CloneImageInfo(image_info); 13659 write_info->compression=UndefinedCompression; 13660 status=WriteOneJNGImage(mng_info,write_info,image,exception); 13661 write_info=DestroyImageInfo(write_info); 13662 } 13663 else 13664 #endif 13665 { 13666 if (logging != MagickFalse) 13667 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 13668 " Writing PNG object."); 13669 13670 mng_info->need_blob = MagickFalse; 13671 mng_info->ping_preserve_colormap = MagickFalse; 13672 13673 /* We don't want any ancillary chunks written */ 13674 mng_info->ping_exclude_bKGD=MagickTrue; 13675 mng_info->ping_exclude_cHRM=MagickTrue; 13676 mng_info->ping_exclude_date=MagickTrue; 13677 mng_info->ping_exclude_EXIF=MagickTrue; 13678 mng_info->ping_exclude_gAMA=MagickTrue; 13679 mng_info->ping_exclude_iCCP=MagickTrue; 13680 /* mng_info->ping_exclude_iTXt=MagickTrue; */ 13681 mng_info->ping_exclude_oFFs=MagickTrue; 13682 mng_info->ping_exclude_pHYs=MagickTrue; 13683 mng_info->ping_exclude_sRGB=MagickTrue; 13684 mng_info->ping_exclude_tEXt=MagickTrue; 13685 mng_info->ping_exclude_tRNS=MagickTrue; 13686 mng_info->ping_exclude_vpAg=MagickTrue; 13687 mng_info->ping_exclude_zCCP=MagickTrue; 13688 mng_info->ping_exclude_zTXt=MagickTrue; 13689 13690 status=WriteOnePNGImage(mng_info,image_info,image,exception); 13691 } 13692 13693 if (status == MagickFalse) 13694 { 13695 MngInfoFreeStruct(mng_info,&have_mng_structure); 13696 (void) CloseBlob(image); 13697 return(MagickFalse); 13698 } 13699 (void) CatchImageException(image); 13700 if (GetNextImageInList(image) == (Image *) NULL) 13701 break; 13702 image=SyncNextImageInList(image); 13703 status=SetImageProgress(image,SaveImagesTag,scene++, 13704 GetImageListLength(image)); 13705 13706 if (status == MagickFalse) 13707 break; 13708 13709 } while (mng_info->adjoin); 13710 13711 if (write_mng) 13712 { 13713 while (GetPreviousImageInList(image) != (Image *) NULL) 13714 image=GetPreviousImageInList(image); 13715 /* 13716 Write the MEND chunk. 13717 */ 13718 (void) WriteBlobMSBULong(image,0x00000000L); 13719 PNGType(chunk,mng_MEND); 13720 LogPNGChunk(logging,mng_MEND,0L); 13721 (void) WriteBlob(image,4,chunk); 13722 (void) WriteBlobMSBULong(image,crc32(0,chunk,4)); 13723 } 13724 /* 13725 Relinquish resources. 13726 */ 13727 (void) CloseBlob(image); 13728 MngInfoFreeStruct(mng_info,&have_mng_structure); 13729 13730 if (logging != MagickFalse) 13731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()"); 13732 13733 return(MagickTrue); 13734 } 13735 #else /* PNG_LIBPNG_VER > 10011 */ 13736 13737 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image) 13738 { 13739 (void) image; 13740 printf("Your PNG library is too old: You have libpng-%s\n", 13741 PNG_LIBPNG_VER_STRING); 13742 13743 ThrowBinaryException(CoderError,"PNG library is too old", 13744 image_info->filename); 13745 } 13746 13747 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) 13748 { 13749 return(WritePNGImage(image_info,image)); 13750 } 13751 #endif /* PNG_LIBPNG_VER > 10011 */ 13752 #endif 13753