1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP SSSSS DDDD % 7 % P P SS D D % 8 % PPPP SSS D D % 9 % P SS D D % 10 % P SSSSS DDDD % 11 % % 12 % % 13 % Read/Write Adobe Photoshop Image Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % Leonard Rosenthol % 18 % July 1992 % 19 % Dirk Lemstra % 20 % December 2013 % 21 % % 22 % % 23 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization % 24 % dedicated to making software imaging solutions freely available. % 25 % % 26 % You may not use this file except in compliance with the License. You may % 27 % obtain a copy of the License at % 28 % % 29 % https://imagemagick.org/script/license.php % 30 % % 31 % Unless required by applicable law or agreed to in writing, software % 32 % distributed under the License is distributed on an "AS IS" BASIS, % 33 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 34 % See the License for the specific language governing permissions and % 35 % limitations under the License. % 36 % % 37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 % 39 % Photoshop spec @ https://www.adobe.com/devnet-apps/photoshop/fileformatashtml 40 % 41 */ 42 43 /* 45 Include declarations. 46 */ 47 #include "MagickCore/studio.h" 48 #include "MagickCore/artifact.h" 49 #include "MagickCore/attribute.h" 50 #include "MagickCore/blob.h" 51 #include "MagickCore/blob-private.h" 52 #include "MagickCore/cache.h" 53 #include "MagickCore/channel.h" 54 #include "MagickCore/colormap.h" 55 #include "MagickCore/colormap-private.h" 56 #include "MagickCore/colorspace.h" 57 #include "MagickCore/colorspace-private.h" 58 #include "MagickCore/constitute.h" 59 #include "MagickCore/enhance.h" 60 #include "MagickCore/exception.h" 61 #include "MagickCore/exception-private.h" 62 #include "MagickCore/image.h" 63 #include "MagickCore/image-private.h" 64 #include "MagickCore/list.h" 65 #include "MagickCore/log.h" 66 #include "MagickCore/magick.h" 67 #include "MagickCore/memory_.h" 68 #include "MagickCore/module.h" 69 #include "MagickCore/monitor-private.h" 70 #include "MagickCore/option.h" 71 #include "MagickCore/pixel.h" 72 #include "MagickCore/pixel-accessor.h" 73 #include "MagickCore/policy.h" 74 #include "MagickCore/profile.h" 75 #include "MagickCore/property.h" 76 #include "MagickCore/registry.h" 77 #include "MagickCore/quantum-private.h" 78 #include "MagickCore/static.h" 79 #include "MagickCore/string_.h" 80 #include "MagickCore/string-private.h" 81 #include "MagickCore/thread-private.h" 82 #ifdef MAGICKCORE_ZLIB_DELEGATE 83 #include <zlib.h> 84 #endif 85 #include "psd-private.h" 86 87 /* 88 Define declaractions. 89 */ 90 #define MaxPSDChannels 56 91 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2) 92 93 /* 95 Enumerated declaractions. 96 */ 97 typedef enum 98 { 99 Raw = 0, 100 RLE = 1, 101 ZipWithoutPrediction = 2, 102 ZipWithPrediction = 3 103 } PSDCompressionType; 104 105 typedef enum 106 { 107 BitmapMode = 0, 108 GrayscaleMode = 1, 109 IndexedMode = 2, 110 RGBMode = 3, 111 CMYKMode = 4, 112 MultichannelMode = 7, 113 DuotoneMode = 8, 114 LabMode = 9 115 } PSDImageType; 116 117 /* 119 Typedef declaractions. 120 */ 121 typedef struct _ChannelInfo 122 { 123 short 124 type; 125 126 size_t 127 size; 128 } ChannelInfo; 129 130 typedef struct _MaskInfo 131 { 132 Image 133 *image; 134 135 RectangleInfo 136 page; 137 138 unsigned char 139 background, 140 flags; 141 } MaskInfo; 142 143 typedef struct _LayerInfo 144 { 145 ChannelInfo 146 channel_info[MaxPSDChannels]; 147 148 char 149 blendkey[4]; 150 151 Image 152 *image; 153 154 MaskInfo 155 mask; 156 157 Quantum 158 opacity; 159 160 RectangleInfo 161 page; 162 163 size_t 164 offset_x, 165 offset_y; 166 167 unsigned char 168 clipping, 169 flags, 170 name[257], 171 visible; 172 173 unsigned short 174 channels; 175 176 StringInfo 177 *info; 178 } LayerInfo; 179 180 /* 181 Forward declarations. 182 */ 183 static MagickBooleanType 184 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *); 185 186 /* 188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 189 % % 190 % % 191 % % 192 % I s P S D % 193 % % 194 % % 195 % % 196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 197 % 198 % IsPSD()() returns MagickTrue if the image format type, identified by the 199 % magick string, is PSD. 200 % 201 % The format of the IsPSD method is: 202 % 203 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length) 204 % 205 % A description of each parameter follows: 206 % 207 % o magick: compare image format pattern against these bytes. 208 % 209 % o length: Specifies the length of the magick string. 210 % 211 */ 212 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length) 213 { 214 if (length < 4) 215 return(MagickFalse); 216 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0) 217 return(MagickTrue); 218 return(MagickFalse); 219 } 220 221 /* 223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 224 % % 225 % % 226 % % 227 % R e a d P S D I m a g e % 228 % % 229 % % 230 % % 231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232 % 233 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It 234 % allocates the memory necessary for the new Image structure and returns a 235 % pointer to the new image. 236 % 237 % The format of the ReadPSDImage method is: 238 % 239 % Image *ReadPSDImage(image_info,ExceptionInfo *exception) 240 % 241 % A description of each parameter follows: 242 % 243 % o image_info: the image info. 244 % 245 % o exception: return any errors or warnings in this structure. 246 % 247 */ 248 249 static const char *CompositeOperatorToPSDBlendMode(Image *image) 250 { 251 switch (image->compose) 252 { 253 case ColorBurnCompositeOp: 254 return(image->endian == LSBEndian ? "vidi" : "idiv"); 255 case ColorDodgeCompositeOp: 256 return(image->endian == LSBEndian ? " vid" : "div "); 257 case ColorizeCompositeOp: 258 return(image->endian == LSBEndian ? "rloc" : "colr"); 259 case DarkenCompositeOp: 260 return(image->endian == LSBEndian ? "krad" : "dark"); 261 case DifferenceCompositeOp: 262 return(image->endian == LSBEndian ? "ffid" : "diff"); 263 case DissolveCompositeOp: 264 return(image->endian == LSBEndian ? "ssid" : "diss"); 265 case ExclusionCompositeOp: 266 return(image->endian == LSBEndian ? "dums" : "smud"); 267 case HardLightCompositeOp: 268 return(image->endian == LSBEndian ? "tiLh" : "hLit"); 269 case HardMixCompositeOp: 270 return(image->endian == LSBEndian ? "xiMh" : "hMix"); 271 case HueCompositeOp: 272 return(image->endian == LSBEndian ? " euh" : "hue "); 273 case LightenCompositeOp: 274 return(image->endian == LSBEndian ? "etil" : "lite"); 275 case LinearBurnCompositeOp: 276 return(image->endian == LSBEndian ? "nrbl" : "lbrn"); 277 case LinearDodgeCompositeOp: 278 return(image->endian == LSBEndian ? "gddl" : "lddg"); 279 case LinearLightCompositeOp: 280 return(image->endian == LSBEndian ? "tiLl" : "lLit"); 281 case LuminizeCompositeOp: 282 return(image->endian == LSBEndian ? " mul" : "lum "); 283 case MultiplyCompositeOp: 284 return(image->endian == LSBEndian ? " lum" : "mul "); 285 case OverlayCompositeOp: 286 return(image->endian == LSBEndian ? "revo" : "over"); 287 case PinLightCompositeOp: 288 return(image->endian == LSBEndian ? "tiLp" : "pLit"); 289 case SaturateCompositeOp: 290 return(image->endian == LSBEndian ? " tas" : "sat "); 291 case ScreenCompositeOp: 292 return(image->endian == LSBEndian ? "nrcs" : "scrn"); 293 case SoftLightCompositeOp: 294 return(image->endian == LSBEndian ? "tiLs" : "sLit"); 295 case VividLightCompositeOp: 296 return(image->endian == LSBEndian ? "tiLv" : "vLit"); 297 case OverCompositeOp: 298 default: 299 return(image->endian == LSBEndian ? "mron" : "norm"); 300 } 301 } 302 303 /* 304 For some reason Photoshop seems to blend semi-transparent pixels with white. 305 This method reverts the blending. This can be disabled by setting the 306 option 'psd:alpha-unblend' to off. 307 */ 308 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info, 309 Image *image,ExceptionInfo* exception) 310 { 311 const char 312 *option; 313 314 MagickBooleanType 315 status; 316 317 ssize_t 318 y; 319 320 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace) 321 return(MagickTrue); 322 option=GetImageOption(image_info,"psd:alpha-unblend"); 323 if (IsStringFalse(option) != MagickFalse) 324 return(MagickTrue); 325 status=MagickTrue; 326 #if defined(MAGICKCORE_OPENMP_SUPPORT) 327 #pragma omp parallel for schedule(static) shared(status) \ 328 magick_number_threads(image,image,image->rows,1) 329 #endif 330 for (y=0; y < (ssize_t) image->rows; y++) 331 { 332 register Quantum 333 *magick_restrict q; 334 335 register ssize_t 336 x; 337 338 if (status == MagickFalse) 339 continue; 340 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 341 if (q == (Quantum *) NULL) 342 { 343 status=MagickFalse; 344 continue; 345 } 346 for (x=0; x < (ssize_t) image->columns; x++) 347 { 348 double 349 gamma; 350 351 register ssize_t 352 i; 353 354 gamma=QuantumScale*GetPixelAlpha(image, q); 355 if (gamma != 0.0 && gamma != 1.0) 356 { 357 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 358 { 359 PixelChannel channel = GetPixelChannelChannel(image,i); 360 if (channel != AlphaPixelChannel) 361 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma); 362 } 363 } 364 q+=GetPixelChannels(image); 365 } 366 if (SyncAuthenticPixels(image,exception) == MagickFalse) 367 status=MagickFalse; 368 } 369 370 return(status); 371 } 372 373 static inline CompressionType ConvertPSDCompression( 374 PSDCompressionType compression) 375 { 376 switch (compression) 377 { 378 case RLE: 379 return RLECompression; 380 case ZipWithPrediction: 381 case ZipWithoutPrediction: 382 return ZipCompression; 383 default: 384 return NoCompression; 385 } 386 } 387 388 static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity, 389 MagickBooleanType revert,ExceptionInfo *exception) 390 { 391 MagickBooleanType 392 status; 393 394 ssize_t 395 y; 396 397 if (image->debug != MagickFalse) 398 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 399 " applying layer opacity %.20g", (double) opacity); 400 if (opacity == OpaqueAlpha) 401 return(MagickTrue); 402 if (image->alpha_trait != BlendPixelTrait) 403 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception); 404 status=MagickTrue; 405 #if defined(MAGICKCORE_OPENMP_SUPPORT) 406 #pragma omp parallel for schedule(static) shared(status) \ 407 magick_number_threads(image,image,image->rows,1) 408 #endif 409 for (y=0; y < (ssize_t) image->rows; y++) 410 { 411 register Quantum 412 *magick_restrict q; 413 414 register ssize_t 415 x; 416 417 if (status == MagickFalse) 418 continue; 419 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 420 if (q == (Quantum *) NULL) 421 { 422 status=MagickFalse; 423 continue; 424 } 425 for (x=0; x < (ssize_t) image->columns; x++) 426 { 427 if (revert == MagickFalse) 428 SetPixelAlpha(image,(Quantum) (QuantumScale*(GetPixelAlpha(image,q))* 429 opacity),q); 430 else if (opacity > 0) 431 SetPixelAlpha(image,(Quantum) (QuantumRange*(GetPixelAlpha(image,q)/ 432 (MagickRealType) opacity)),q); 433 q+=GetPixelChannels(image); 434 } 435 if (SyncAuthenticPixels(image,exception) == MagickFalse) 436 status=MagickFalse; 437 } 438 439 return(status); 440 } 441 442 static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask, 443 Quantum background,MagickBooleanType revert,ExceptionInfo *exception) 444 { 445 Image 446 *complete_mask; 447 448 MagickBooleanType 449 status; 450 451 PixelInfo 452 color; 453 454 ssize_t 455 y; 456 457 if (image->alpha_trait == UndefinedPixelTrait) 458 return(MagickTrue); 459 if (image->debug != MagickFalse) 460 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 461 " applying opacity mask"); 462 complete_mask=CloneImage(image,0,0,MagickTrue,exception); 463 if (complete_mask == (Image *) NULL) 464 return(MagickFalse); 465 complete_mask->alpha_trait=BlendPixelTrait; 466 GetPixelInfo(complete_mask,&color); 467 color.red=(MagickRealType) background; 468 (void) SetImageColor(complete_mask,&color,exception); 469 status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue, 470 mask->page.x-image->page.x,mask->page.y-image->page.y,exception); 471 if (status == MagickFalse) 472 { 473 complete_mask=DestroyImage(complete_mask); 474 return(status); 475 } 476 477 #if defined(MAGICKCORE_OPENMP_SUPPORT) 478 #pragma omp parallel for schedule(static) shared(status) \ 479 magick_number_threads(image,image,image->rows,1) 480 #endif 481 for (y=0; y < (ssize_t) image->rows; y++) 482 { 483 register Quantum 484 *magick_restrict q; 485 486 register Quantum 487 *p; 488 489 register ssize_t 490 x; 491 492 if (status == MagickFalse) 493 continue; 494 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 495 p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception); 496 if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL)) 497 { 498 status=MagickFalse; 499 continue; 500 } 501 for (x=0; x < (ssize_t) image->columns; x++) 502 { 503 MagickRealType 504 alpha, 505 intensity; 506 507 alpha=(MagickRealType) GetPixelAlpha(image,q); 508 intensity=GetPixelIntensity(complete_mask,p); 509 if (revert == MagickFalse) 510 SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q); 511 else if (intensity > 0) 512 SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*QuantumRange),q); 513 q+=GetPixelChannels(image); 514 p+=GetPixelChannels(complete_mask); 515 } 516 if (SyncAuthenticPixels(image,exception) == MagickFalse) 517 status=MagickFalse; 518 } 519 complete_mask=DestroyImage(complete_mask); 520 return(status); 521 } 522 523 static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info, 524 ExceptionInfo *exception) 525 { 526 char 527 *key; 528 529 RandomInfo 530 *random_info; 531 532 StringInfo 533 *key_info; 534 535 if (image->debug != MagickFalse) 536 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 537 " preserving opacity mask"); 538 random_info=AcquireRandomInfo(); 539 key_info=GetRandomKey(random_info,2+1); 540 key=(char *) GetStringInfoDatum(key_info); 541 key[8]=(char ) layer_info->mask.background; 542 key[9]='\0'; 543 layer_info->mask.image->page.x+=layer_info->page.x; 544 layer_info->mask.image->page.y+=layer_info->page.y; 545 (void) SetImageRegistry(ImageRegistryType,(const char *) key, 546 layer_info->mask.image,exception); 547 (void) SetImageArtifact(layer_info->image,"psd:opacity-mask", 548 (const char *) key); 549 key_info=DestroyStringInfo(key_info); 550 random_info=DestroyRandomInfo(random_info); 551 } 552 553 static ssize_t DecodePSDPixels(const size_t number_compact_pixels, 554 const unsigned char *compact_pixels,const ssize_t depth, 555 const size_t number_pixels,unsigned char *pixels) 556 { 557 #define CheckNumberCompactPixels \ 558 if (packets == 0) \ 559 return(i); \ 560 packets-- 561 562 #define CheckNumberPixels(count) \ 563 if (((ssize_t) i + count) > (ssize_t) number_pixels) \ 564 return(i); \ 565 i+=count 566 567 int 568 pixel; 569 570 register ssize_t 571 i, 572 j; 573 574 size_t 575 length; 576 577 ssize_t 578 packets; 579 580 packets=(ssize_t) number_compact_pixels; 581 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); ) 582 { 583 packets--; 584 length=(size_t) (*compact_pixels++); 585 if (length == 128) 586 continue; 587 if (length > 128) 588 { 589 length=256-length+1; 590 CheckNumberCompactPixels; 591 pixel=(*compact_pixels++); 592 for (j=0; j < (ssize_t) length; j++) 593 { 594 switch (depth) 595 { 596 case 1: 597 { 598 CheckNumberPixels(8); 599 *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U; 600 *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U; 601 *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U; 602 *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U; 603 *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U; 604 *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U; 605 *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U; 606 *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U; 607 break; 608 } 609 case 2: 610 { 611 CheckNumberPixels(4); 612 *pixels++=(unsigned char) ((pixel >> 6) & 0x03); 613 *pixels++=(unsigned char) ((pixel >> 4) & 0x03); 614 *pixels++=(unsigned char) ((pixel >> 2) & 0x03); 615 *pixels++=(unsigned char) ((pixel & 0x03) & 0x03); 616 break; 617 } 618 case 4: 619 { 620 CheckNumberPixels(2); 621 *pixels++=(unsigned char) ((pixel >> 4) & 0xff); 622 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff); 623 break; 624 } 625 default: 626 { 627 CheckNumberPixels(1); 628 *pixels++=(unsigned char) pixel; 629 break; 630 } 631 } 632 } 633 continue; 634 } 635 length++; 636 for (j=0; j < (ssize_t) length; j++) 637 { 638 CheckNumberCompactPixels; 639 switch (depth) 640 { 641 case 1: 642 { 643 CheckNumberPixels(8); 644 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U; 645 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U; 646 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U; 647 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U; 648 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U; 649 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U; 650 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U; 651 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U; 652 break; 653 } 654 case 2: 655 { 656 CheckNumberPixels(4); 657 *pixels++=(*compact_pixels >> 6) & 0x03; 658 *pixels++=(*compact_pixels >> 4) & 0x03; 659 *pixels++=(*compact_pixels >> 2) & 0x03; 660 *pixels++=(*compact_pixels & 0x03) & 0x03; 661 break; 662 } 663 case 4: 664 { 665 CheckNumberPixels(2); 666 *pixels++=(*compact_pixels >> 4) & 0xff; 667 *pixels++=(*compact_pixels & 0x0f) & 0xff; 668 break; 669 } 670 default: 671 { 672 CheckNumberPixels(1); 673 *pixels++=(*compact_pixels); 674 break; 675 } 676 } 677 compact_pixels++; 678 } 679 } 680 return(i); 681 } 682 683 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info, 684 const ssize_t number_layers) 685 { 686 ssize_t 687 i; 688 689 for (i=0; i<number_layers; i++) 690 { 691 if (layer_info[i].image != (Image *) NULL) 692 layer_info[i].image=DestroyImage(layer_info[i].image); 693 if (layer_info[i].mask.image != (Image *) NULL) 694 layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image); 695 if (layer_info[i].info != (StringInfo *) NULL) 696 layer_info[i].info=DestroyStringInfo(layer_info[i].info); 697 } 698 699 return (LayerInfo *) RelinquishMagickMemory(layer_info); 700 } 701 702 static inline size_t GetPSDPacketSize(const Image *image) 703 { 704 if (image->storage_class == PseudoClass) 705 { 706 if (image->colors > 256) 707 return(2); 708 } 709 if (image->depth > 16) 710 return(4); 711 if (image->depth > 8) 712 return(2); 713 714 return(1); 715 } 716 717 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image) 718 { 719 if (psd_info->version == 1) 720 return((MagickSizeType) ReadBlobLong(image)); 721 return((MagickSizeType) ReadBlobLongLong(image)); 722 } 723 724 static inline size_t GetPSDRowSize(Image *image) 725 { 726 if (image->depth == 1) 727 return(((image->columns+7)/8)*GetPSDPacketSize(image)); 728 else 729 return(image->columns*GetPSDPacketSize(image)); 730 } 731 732 static const char *ModeToString(PSDImageType type) 733 { 734 switch (type) 735 { 736 case BitmapMode: return "Bitmap"; 737 case GrayscaleMode: return "Grayscale"; 738 case IndexedMode: return "Indexed"; 739 case RGBMode: return "RGB"; 740 case CMYKMode: return "CMYK"; 741 case MultichannelMode: return "Multichannel"; 742 case DuotoneMode: return "Duotone"; 743 case LabMode: return "L*A*B"; 744 default: return "unknown"; 745 } 746 } 747 748 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception) 749 { 750 ChannelType 751 channel_mask; 752 753 MagickBooleanType 754 status; 755 756 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~ 757 AlphaChannel)); 758 status=NegateImage(image,MagickFalse,exception); 759 (void) SetImageChannelMask(image,channel_mask); 760 return(status); 761 } 762 763 static StringInfo *ParseImageResourceBlocks(Image *image, 764 const unsigned char *blocks,size_t length, 765 MagickBooleanType *has_merged_image,ExceptionInfo *exception) 766 { 767 const unsigned char 768 *p; 769 770 ssize_t 771 offset; 772 773 StringInfo 774 *profile; 775 776 unsigned char 777 name_length; 778 779 unsigned int 780 count; 781 782 unsigned short 783 id, 784 short_sans; 785 786 if (length < 16) 787 return((StringInfo *) NULL); 788 profile=BlobToStringInfo((const unsigned char *) NULL,length); 789 SetStringInfoDatum(profile,blocks); 790 SetStringInfoName(profile,"8bim"); 791 for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); ) 792 { 793 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 794 break; 795 p+=4; 796 p=PushShortPixel(MSBEndian,p,&id); 797 p=PushCharPixel(p,&name_length); 798 if ((name_length % 2) == 0) 799 name_length++; 800 p+=name_length; 801 if (p > (blocks+length-4)) 802 break; 803 p=PushLongPixel(MSBEndian,p,&count); 804 offset=(ssize_t) count; 805 if (((p+offset) < blocks) || ((p+offset) > (blocks+length))) 806 break; 807 switch (id) 808 { 809 case 0x03ed: 810 { 811 char 812 value[MagickPathExtent]; 813 814 unsigned short 815 resolution; 816 817 /* 818 Resolution info. 819 */ 820 if (offset < 16) 821 break; 822 p=PushShortPixel(MSBEndian,p,&resolution); 823 image->resolution.x=(double) resolution; 824 (void) FormatLocaleString(value,MagickPathExtent,"%g", 825 image->resolution.x); 826 (void) SetImageProperty(image,"tiff:XResolution",value,exception); 827 p=PushShortPixel(MSBEndian,p,&short_sans); 828 p=PushShortPixel(MSBEndian,p,&short_sans); 829 p=PushShortPixel(MSBEndian,p,&short_sans); 830 p=PushShortPixel(MSBEndian,p,&resolution); 831 image->resolution.y=(double) resolution; 832 (void) FormatLocaleString(value,MagickPathExtent,"%g", 833 image->resolution.y); 834 (void) SetImageProperty(image,"tiff:YResolution",value,exception); 835 p=PushShortPixel(MSBEndian,p,&short_sans); 836 p=PushShortPixel(MSBEndian,p,&short_sans); 837 p=PushShortPixel(MSBEndian,p,&short_sans); 838 image->units=PixelsPerInchResolution; 839 break; 840 } 841 case 0x0421: 842 { 843 if ((offset > 4) && (*(p+4) == 0)) 844 *has_merged_image=MagickFalse; 845 p+=offset; 846 break; 847 } 848 default: 849 { 850 p+=offset; 851 break; 852 } 853 } 854 if ((offset & 0x01) != 0) 855 p++; 856 } 857 return(profile); 858 } 859 860 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode) 861 { 862 if (mode == (const char *) NULL) 863 return(OverCompositeOp); 864 if (LocaleNCompare(mode,"norm",4) == 0) 865 return(OverCompositeOp); 866 if (LocaleNCompare(mode,"mul ",4) == 0) 867 return(MultiplyCompositeOp); 868 if (LocaleNCompare(mode,"diss",4) == 0) 869 return(DissolveCompositeOp); 870 if (LocaleNCompare(mode,"diff",4) == 0) 871 return(DifferenceCompositeOp); 872 if (LocaleNCompare(mode,"dark",4) == 0) 873 return(DarkenCompositeOp); 874 if (LocaleNCompare(mode,"lite",4) == 0) 875 return(LightenCompositeOp); 876 if (LocaleNCompare(mode,"hue ",4) == 0) 877 return(HueCompositeOp); 878 if (LocaleNCompare(mode,"sat ",4) == 0) 879 return(SaturateCompositeOp); 880 if (LocaleNCompare(mode,"colr",4) == 0) 881 return(ColorizeCompositeOp); 882 if (LocaleNCompare(mode,"lum ",4) == 0) 883 return(LuminizeCompositeOp); 884 if (LocaleNCompare(mode,"scrn",4) == 0) 885 return(ScreenCompositeOp); 886 if (LocaleNCompare(mode,"over",4) == 0) 887 return(OverlayCompositeOp); 888 if (LocaleNCompare(mode,"hLit",4) == 0) 889 return(HardLightCompositeOp); 890 if (LocaleNCompare(mode,"sLit",4) == 0) 891 return(SoftLightCompositeOp); 892 if (LocaleNCompare(mode,"smud",4) == 0) 893 return(ExclusionCompositeOp); 894 if (LocaleNCompare(mode,"div ",4) == 0) 895 return(ColorDodgeCompositeOp); 896 if (LocaleNCompare(mode,"idiv",4) == 0) 897 return(ColorBurnCompositeOp); 898 if (LocaleNCompare(mode,"lbrn",4) == 0) 899 return(LinearBurnCompositeOp); 900 if (LocaleNCompare(mode,"lddg",4) == 0) 901 return(LinearDodgeCompositeOp); 902 if (LocaleNCompare(mode,"lLit",4) == 0) 903 return(LinearLightCompositeOp); 904 if (LocaleNCompare(mode,"vLit",4) == 0) 905 return(VividLightCompositeOp); 906 if (LocaleNCompare(mode,"pLit",4) == 0) 907 return(PinLightCompositeOp); 908 if (LocaleNCompare(mode,"hMix",4) == 0) 909 return(HardMixCompositeOp); 910 return(OverCompositeOp); 911 } 912 913 static inline void ReversePSDString(Image *image,char *p,size_t length) 914 { 915 char 916 *q; 917 918 if (image->endian == MSBEndian) 919 return; 920 921 q=p+length; 922 for(--q; p < q; ++p, --q) 923 { 924 *p = *p ^ *q, 925 *q = *p ^ *q, 926 *p = *p ^ *q; 927 } 928 } 929 930 static inline void SetPSDPixel(Image *image,const size_t channels, 931 const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q, 932 ExceptionInfo *exception) 933 { 934 if (image->storage_class == PseudoClass) 935 { 936 PixelInfo 937 *color; 938 939 if (type == 0) 940 { 941 if (packet_size == 1) 942 SetPixelIndex(image,ScaleQuantumToChar(pixel),q); 943 else 944 SetPixelIndex(image,ScaleQuantumToShort(pixel),q); 945 } 946 color=image->colormap+(ssize_t) ConstrainColormapIndex(image, 947 (ssize_t) GetPixelIndex(image,q),exception); 948 if ((type == 0) && (channels > 1)) 949 return; 950 else 951 color->alpha=(MagickRealType) pixel; 952 SetPixelViaPixelInfo(image,color,q); 953 return; 954 } 955 switch (type) 956 { 957 case -1: 958 { 959 SetPixelAlpha(image,pixel,q); 960 break; 961 } 962 case -2: 963 case 0: 964 { 965 SetPixelRed(image,pixel,q); 966 break; 967 } 968 case -3: 969 case 1: 970 { 971 SetPixelGreen(image,pixel,q); 972 break; 973 } 974 case -4: 975 case 2: 976 { 977 SetPixelBlue(image,pixel,q); 978 break; 979 } 980 case 3: 981 { 982 if (image->colorspace == CMYKColorspace) 983 SetPixelBlack(image,pixel,q); 984 else 985 if (image->alpha_trait != UndefinedPixelTrait) 986 SetPixelAlpha(image,pixel,q); 987 break; 988 } 989 case 4: 990 { 991 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) && 992 (channels > 3)) 993 break; 994 if (image->alpha_trait != UndefinedPixelTrait) 995 SetPixelAlpha(image,pixel,q); 996 break; 997 } 998 } 999 } 1000 1001 static MagickBooleanType ReadPSDChannelPixels(Image *image, 1002 const size_t channels,const ssize_t row,const ssize_t type, 1003 const unsigned char *pixels,ExceptionInfo *exception) 1004 { 1005 Quantum 1006 pixel; 1007 1008 register const unsigned char 1009 *p; 1010 1011 register Quantum 1012 *q; 1013 1014 register ssize_t 1015 x; 1016 1017 size_t 1018 packet_size; 1019 1020 p=pixels; 1021 q=GetAuthenticPixels(image,0,row,image->columns,1,exception); 1022 if (q == (Quantum *) NULL) 1023 return MagickFalse; 1024 packet_size=GetPSDPacketSize(image); 1025 for (x=0; x < (ssize_t) image->columns; x++) 1026 { 1027 if (packet_size == 1) 1028 pixel=ScaleCharToQuantum(*p++); 1029 else if (packet_size == 2) 1030 { 1031 unsigned short 1032 nibble; 1033 1034 p=PushShortPixel(MSBEndian,p,&nibble); 1035 pixel=ScaleShortToQuantum(nibble); 1036 } 1037 else 1038 { 1039 MagickFloatType 1040 nibble; 1041 1042 p=PushFloatPixel(MSBEndian,p,&nibble); 1043 pixel=ClampToQuantum((MagickRealType)QuantumRange*nibble); 1044 } 1045 if (image->depth > 1) 1046 { 1047 SetPSDPixel(image,channels,type,packet_size,pixel,q,exception); 1048 q+=GetPixelChannels(image); 1049 } 1050 else 1051 { 1052 ssize_t 1053 bit, 1054 number_bits; 1055 1056 number_bits=(ssize_t) image->columns-x; 1057 if (number_bits > 8) 1058 number_bits=8; 1059 for (bit = 0; bit < (ssize_t) number_bits; bit++) 1060 { 1061 SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel) 1062 & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception); 1063 q+=GetPixelChannels(image); 1064 x++; 1065 } 1066 if (x != (ssize_t) image->columns) 1067 x--; 1068 continue; 1069 } 1070 } 1071 return(SyncAuthenticPixels(image,exception)); 1072 } 1073 1074 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels, 1075 const ssize_t type,ExceptionInfo *exception) 1076 { 1077 MagickBooleanType 1078 status; 1079 1080 size_t 1081 row_size; 1082 1083 ssize_t 1084 count, 1085 y; 1086 1087 unsigned char 1088 *pixels; 1089 1090 if (image->debug != MagickFalse) 1091 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1092 " layer data is RAW"); 1093 1094 row_size=GetPSDRowSize(image); 1095 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels)); 1096 if (pixels == (unsigned char *) NULL) 1097 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1098 image->filename); 1099 1100 status=MagickTrue; 1101 for (y=0; y < (ssize_t) image->rows; y++) 1102 { 1103 status=MagickFalse; 1104 1105 count=ReadBlob(image,row_size,pixels); 1106 if (count != (ssize_t) row_size) 1107 { 1108 status=MagickFalse; 1109 break; 1110 } 1111 1112 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception); 1113 if (status == MagickFalse) 1114 break; 1115 } 1116 1117 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1118 return(status); 1119 } 1120 1121 static inline MagickOffsetType *ReadPSDRLESizes(Image *image, 1122 const PSDInfo *psd_info,const size_t size) 1123 { 1124 MagickOffsetType 1125 *sizes; 1126 1127 ssize_t 1128 y; 1129 1130 sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes)); 1131 if(sizes != (MagickOffsetType *) NULL) 1132 { 1133 for (y=0; y < (ssize_t) size; y++) 1134 { 1135 if (psd_info->version == 1) 1136 sizes[y]=(MagickOffsetType) ReadBlobShort(image); 1137 else 1138 sizes[y]=(MagickOffsetType) ReadBlobLong(image); 1139 } 1140 } 1141 return sizes; 1142 } 1143 1144 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info, 1145 const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception) 1146 { 1147 MagickBooleanType 1148 status; 1149 1150 size_t 1151 length, 1152 row_size; 1153 1154 ssize_t 1155 count, 1156 y; 1157 1158 unsigned char 1159 *compact_pixels, 1160 *pixels; 1161 1162 if (image->debug != MagickFalse) 1163 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1164 " layer data is RLE compressed"); 1165 1166 row_size=GetPSDRowSize(image); 1167 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels)); 1168 if (pixels == (unsigned char *) NULL) 1169 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1170 image->filename); 1171 1172 length=0; 1173 for (y=0; y < (ssize_t) image->rows; y++) 1174 if ((MagickOffsetType) length < sizes[y]) 1175 length=(size_t) sizes[y]; 1176 1177 if (length > (row_size+2048)) /* arbitrary number */ 1178 { 1179 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1180 ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename); 1181 } 1182 1183 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels)); 1184 if (compact_pixels == (unsigned char *) NULL) 1185 { 1186 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1187 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1188 image->filename); 1189 } 1190 1191 (void) memset(compact_pixels,0,length*sizeof(*compact_pixels)); 1192 1193 status=MagickTrue; 1194 for (y=0; y < (ssize_t) image->rows; y++) 1195 { 1196 status=MagickFalse; 1197 1198 count=ReadBlob(image,(size_t) sizes[y],compact_pixels); 1199 if (count != (ssize_t) sizes[y]) 1200 break; 1201 1202 count=DecodePSDPixels((size_t) sizes[y],compact_pixels, 1203 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels); 1204 if (count != (ssize_t) row_size) 1205 break; 1206 1207 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels, 1208 exception); 1209 if (status == MagickFalse) 1210 break; 1211 } 1212 1213 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1214 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1215 return(status); 1216 } 1217 1218 #ifdef MAGICKCORE_ZLIB_DELEGATE 1219 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels, 1220 const ssize_t type,const PSDCompressionType compression, 1221 const size_t compact_size,ExceptionInfo *exception) 1222 { 1223 MagickBooleanType 1224 status; 1225 1226 register unsigned char 1227 *p; 1228 1229 size_t 1230 count, 1231 length, 1232 packet_size, 1233 row_size; 1234 1235 ssize_t 1236 y; 1237 1238 unsigned char 1239 *compact_pixels, 1240 *pixels; 1241 1242 z_stream 1243 stream; 1244 1245 if (image->debug != MagickFalse) 1246 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1247 " layer data is ZIP compressed"); 1248 1249 if ((MagickSizeType) compact_size > GetBlobSize(image)) 1250 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile", 1251 image->filename); 1252 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size, 1253 sizeof(*compact_pixels)); 1254 if (compact_pixels == (unsigned char *) NULL) 1255 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1256 image->filename); 1257 1258 packet_size=GetPSDPacketSize(image); 1259 row_size=image->columns*packet_size; 1260 count=image->rows*row_size; 1261 1262 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels)); 1263 if (pixels == (unsigned char *) NULL) 1264 { 1265 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1266 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1267 image->filename); 1268 } 1269 if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size) 1270 { 1271 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1272 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1273 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile", 1274 image->filename); 1275 } 1276 1277 memset(&stream,0,sizeof(stream)); 1278 stream.data_type=Z_BINARY; 1279 stream.next_in=(Bytef *)compact_pixels; 1280 stream.avail_in=(uInt) compact_size; 1281 stream.next_out=(Bytef *)pixels; 1282 stream.avail_out=(uInt) count; 1283 1284 if (inflateInit(&stream) == Z_OK) 1285 { 1286 int 1287 ret; 1288 1289 while (stream.avail_out > 0) 1290 { 1291 ret=inflate(&stream,Z_SYNC_FLUSH); 1292 if ((ret != Z_OK) && (ret != Z_STREAM_END)) 1293 { 1294 (void) inflateEnd(&stream); 1295 compact_pixels=(unsigned char *) RelinquishMagickMemory( 1296 compact_pixels); 1297 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1298 return(MagickFalse); 1299 } 1300 if (ret == Z_STREAM_END) 1301 break; 1302 } 1303 (void) inflateEnd(&stream); 1304 } 1305 1306 if (compression == ZipWithPrediction) 1307 { 1308 p=pixels; 1309 while (count > 0) 1310 { 1311 length=image->columns; 1312 while (--length) 1313 { 1314 if (packet_size == 2) 1315 { 1316 p[2]+=p[0]+((p[1]+p[3]) >> 8); 1317 p[3]+=p[1]; 1318 } 1319 /* 1320 else if (packet_size == 4) 1321 { 1322 TODO: Figure out what to do there. 1323 } 1324 */ 1325 else 1326 *(p+1)+=*p; 1327 p+=packet_size; 1328 } 1329 p+=packet_size; 1330 count-=row_size; 1331 } 1332 } 1333 1334 status=MagickTrue; 1335 p=pixels; 1336 for (y=0; y < (ssize_t) image->rows; y++) 1337 { 1338 status=ReadPSDChannelPixels(image,channels,y,type,p,exception); 1339 if (status == MagickFalse) 1340 break; 1341 1342 p+=row_size; 1343 } 1344 1345 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1346 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1347 return(status); 1348 } 1349 #endif 1350 1351 static MagickBooleanType ReadPSDChannel(Image *image, 1352 const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info, 1353 const size_t channel,const PSDCompressionType compression, 1354 ExceptionInfo *exception) 1355 { 1356 Image 1357 *channel_image, 1358 *mask; 1359 1360 MagickOffsetType 1361 offset; 1362 1363 MagickBooleanType 1364 status; 1365 1366 channel_image=image; 1367 mask=(Image *) NULL; 1368 if ((layer_info->channel_info[channel].type < -1) && 1369 (layer_info->mask.page.width > 0) && (layer_info->mask.page.height > 0)) 1370 { 1371 const char 1372 *option; 1373 1374 /* 1375 Ignore mask that is not a user supplied layer mask, if the mask is 1376 disabled or if the flags have unsupported values. 1377 */ 1378 option=GetImageOption(image_info,"psd:preserve-opacity-mask"); 1379 if ((layer_info->channel_info[channel].type != -2) || 1380 (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) && 1381 (IsStringTrue(option) == MagickFalse))) 1382 { 1383 (void) SeekBlob(image,(MagickOffsetType) 1384 layer_info->channel_info[channel].size-2,SEEK_CUR); 1385 return(MagickTrue); 1386 } 1387 mask=CloneImage(image,layer_info->mask.page.width, 1388 layer_info->mask.page.height,MagickFalse,exception); 1389 if (mask != (Image *) NULL) 1390 { 1391 (void) SetImageType(mask,GrayscaleType,exception); 1392 channel_image=mask; 1393 } 1394 } 1395 1396 offset=TellBlob(image); 1397 status=MagickFalse; 1398 switch(compression) 1399 { 1400 case Raw: 1401 status=ReadPSDChannelRaw(channel_image,psd_info->channels, 1402 (ssize_t) layer_info->channel_info[channel].type,exception); 1403 break; 1404 case RLE: 1405 { 1406 MagickOffsetType 1407 *sizes; 1408 1409 sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows); 1410 if (sizes == (MagickOffsetType *) NULL) 1411 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1412 image->filename); 1413 status=ReadPSDChannelRLE(channel_image,psd_info, 1414 (ssize_t) layer_info->channel_info[channel].type,sizes,exception); 1415 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes); 1416 } 1417 break; 1418 case ZipWithPrediction: 1419 case ZipWithoutPrediction: 1420 #ifdef MAGICKCORE_ZLIB_DELEGATE 1421 status=ReadPSDChannelZip(channel_image,layer_info->channels, 1422 (ssize_t) layer_info->channel_info[channel].type,compression, 1423 layer_info->channel_info[channel].size-2,exception); 1424 #else 1425 (void) ThrowMagickException(exception,GetMagickModule(), 1426 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn", 1427 "'%s' (ZLIB)",image->filename); 1428 #endif 1429 break; 1430 default: 1431 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning, 1432 "CompressionNotSupported","'%.20g'",(double) compression); 1433 break; 1434 } 1435 1436 (void) SeekBlob(image,offset+layer_info->channel_info[channel].size-2, 1437 SEEK_SET); 1438 if (status == MagickFalse) 1439 { 1440 if (mask != (Image *) NULL) 1441 (void) DestroyImage(mask); 1442 ThrowBinaryException(CoderError,"UnableToDecompressImage", 1443 image->filename); 1444 } 1445 if (mask != (Image *) NULL) 1446 { 1447 if (layer_info->mask.image != (Image *) NULL) 1448 layer_info->mask.image=DestroyImage(layer_info->mask.image); 1449 layer_info->mask.image=mask; 1450 } 1451 return(status); 1452 } 1453 1454 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info, 1455 const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception) 1456 { 1457 char 1458 message[MagickPathExtent]; 1459 1460 MagickBooleanType 1461 status; 1462 1463 PSDCompressionType 1464 compression; 1465 1466 ssize_t 1467 j; 1468 1469 if (image->debug != MagickFalse) 1470 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1471 " setting up new layer image"); 1472 if (psd_info->mode != IndexedMode) 1473 (void) SetImageBackgroundColor(layer_info->image,exception); 1474 layer_info->image->compose=PSDBlendModeToCompositeOperator( 1475 layer_info->blendkey); 1476 if (layer_info->visible == MagickFalse) 1477 layer_info->image->compose=NoCompositeOp; 1478 /* 1479 Set up some hidden attributes for folks that need them. 1480 */ 1481 (void) FormatLocaleString(message,MagickPathExtent,"%.20g", 1482 (double) layer_info->page.x); 1483 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message); 1484 (void) FormatLocaleString(message,MagickPathExtent,"%.20g", 1485 (double) layer_info->page.y); 1486 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message); 1487 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double) 1488 layer_info->opacity); 1489 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message); 1490 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name, 1491 exception); 1492 1493 status=MagickTrue; 1494 for (j=0; j < (ssize_t) layer_info->channels; j++) 1495 { 1496 if (image->debug != MagickFalse) 1497 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1498 " reading data for channel %.20g",(double) j); 1499 1500 compression=(PSDCompressionType) ReadBlobShort(layer_info->image); 1501 1502 /* TODO: Remove this when we figure out how to support this */ 1503 if ((compression == ZipWithPrediction) && (image->depth == 32)) 1504 { 1505 (void) ThrowMagickException(exception,GetMagickModule(), 1506 TypeError,"CompressionNotSupported","ZipWithPrediction(32 bit)"); 1507 return(MagickFalse); 1508 } 1509 1510 layer_info->image->compression=ConvertPSDCompression(compression); 1511 if (layer_info->channel_info[j].type == -1) 1512 layer_info->image->alpha_trait=BlendPixelTrait; 1513 1514 status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info, 1515 (size_t) j,compression,exception); 1516 1517 if (status == MagickFalse) 1518 break; 1519 } 1520 1521 if (status != MagickFalse) 1522 status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity, 1523 MagickFalse,exception); 1524 1525 if ((status != MagickFalse) && 1526 (layer_info->image->colorspace == CMYKColorspace)) 1527 status=NegateCMYK(layer_info->image,exception); 1528 1529 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL)) 1530 { 1531 const char 1532 *option; 1533 1534 layer_info->mask.image->page.x=layer_info->mask.page.x; 1535 layer_info->mask.image->page.y=layer_info->mask.page.y; 1536 /* Do not composite the mask when it is disabled */ 1537 if ((layer_info->mask.flags & 0x02) == 0x02) 1538 layer_info->mask.image->compose=NoCompositeOp; 1539 else 1540 status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image, 1541 layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse, 1542 exception); 1543 option=GetImageOption(image_info,"psd:preserve-opacity-mask"); 1544 if (IsStringTrue(option) != MagickFalse) 1545 PreservePSDOpacityMask(image,layer_info,exception); 1546 layer_info->mask.image=DestroyImage(layer_info->mask.image); 1547 } 1548 1549 return(status); 1550 } 1551 1552 static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info, 1553 LayerInfo *layer_info) 1554 { 1555 int 1556 channel_type; 1557 1558 register ssize_t 1559 i; 1560 1561 if (layer_info->channels < psd_info->min_channels) 1562 return(MagickFalse); 1563 channel_type=RedChannel; 1564 if (psd_info->min_channels >= 3) 1565 channel_type|=(GreenChannel | BlueChannel); 1566 if (psd_info->min_channels >= 4) 1567 channel_type|=BlackChannel; 1568 for (i=0; i < (ssize_t) layer_info->channels; i++) 1569 { 1570 short 1571 type; 1572 1573 type=layer_info->channel_info[i].type; 1574 if (type == -1) 1575 { 1576 channel_type|=AlphaChannel; 1577 continue; 1578 } 1579 if (type < -1) 1580 continue; 1581 if (type == 0) 1582 channel_type&=~RedChannel; 1583 else if (type == 1) 1584 channel_type&=~GreenChannel; 1585 else if (type == 2) 1586 channel_type&=~BlueChannel; 1587 else if (type == 3) 1588 channel_type&=~BlackChannel; 1589 } 1590 if (channel_type == 0) 1591 return(MagickTrue); 1592 if ((channel_type == AlphaChannel) && 1593 (layer_info->channels >= psd_info->min_channels + 1)) 1594 return(MagickTrue); 1595 return(MagickFalse); 1596 } 1597 1598 static void AttachPSDLayers(Image *image,LayerInfo *layer_info, 1599 ssize_t number_layers) 1600 { 1601 register ssize_t 1602 i; 1603 1604 ssize_t 1605 j; 1606 1607 for (i=0; i < number_layers; i++) 1608 { 1609 if (layer_info[i].image == (Image *) NULL) 1610 { 1611 for (j=i; j < number_layers - 1; j++) 1612 layer_info[j] = layer_info[j+1]; 1613 number_layers--; 1614 i--; 1615 } 1616 } 1617 if (number_layers == 0) 1618 { 1619 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info); 1620 return; 1621 } 1622 for (i=0; i < number_layers; i++) 1623 { 1624 if (i > 0) 1625 layer_info[i].image->previous=layer_info[i-1].image; 1626 if (i < (number_layers-1)) 1627 layer_info[i].image->next=layer_info[i+1].image; 1628 layer_info[i].image->page=layer_info[i].page; 1629 } 1630 image->next=layer_info[0].image; 1631 layer_info[0].image->previous=image; 1632 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info); 1633 } 1634 1635 static inline MagickBooleanType PSDSkipImage(const ImageInfo *image_info, 1636 const size_t index) 1637 { 1638 if (image_info->number_scenes == 0) 1639 return(MagickFalse); 1640 if (index < image_info->scene) 1641 return(MagickTrue); 1642 if (index > image_info->scene+image_info->number_scenes-1) 1643 return(MagickTrue); 1644 return(MagickFalse); 1645 } 1646 1647 static MagickBooleanType ReadPSDLayersInternal(Image *image, 1648 const ImageInfo *image_info,const PSDInfo *psd_info, 1649 const MagickBooleanType skip_layers,ExceptionInfo *exception) 1650 { 1651 char 1652 type[4]; 1653 1654 LayerInfo 1655 *layer_info; 1656 1657 MagickSizeType 1658 size; 1659 1660 MagickBooleanType 1661 status; 1662 1663 register ssize_t 1664 i; 1665 1666 ssize_t 1667 count, 1668 j, 1669 number_layers; 1670 1671 size=GetPSDSize(psd_info,image); 1672 if (size == 0) 1673 { 1674 /* 1675 Skip layers & masks. 1676 */ 1677 (void) ReadBlobLong(image); 1678 count=ReadBlob(image,4,(unsigned char *) type); 1679 if (count == 4) 1680 ReversePSDString(image,type,(size_t) count); 1681 if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0)) 1682 return(MagickTrue); 1683 else 1684 { 1685 count=ReadBlob(image,4,(unsigned char *) type); 1686 if (count == 4) 1687 ReversePSDString(image,type,4); 1688 if ((count == 4) && ((LocaleNCompare(type,"Lr16",4) == 0) || 1689 (LocaleNCompare(type,"Lr32",4) == 0))) 1690 size=GetPSDSize(psd_info,image); 1691 else 1692 return(MagickTrue); 1693 } 1694 } 1695 if (size == 0) 1696 return(MagickTrue); 1697 1698 layer_info=(LayerInfo *) NULL; 1699 number_layers=(ssize_t) ReadBlobSignedShort(image); 1700 1701 if (number_layers < 0) 1702 { 1703 /* 1704 The first alpha channel in the merged result contains the 1705 transparency data for the merged result. 1706 */ 1707 number_layers=MagickAbsoluteValue(number_layers); 1708 if (image->debug != MagickFalse) 1709 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1710 " negative layer count corrected for"); 1711 image->alpha_trait=BlendPixelTrait; 1712 } 1713 1714 /* 1715 We only need to know if the image has an alpha channel 1716 */ 1717 if (skip_layers != MagickFalse) 1718 return(MagickTrue); 1719 1720 if (image->debug != MagickFalse) 1721 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1722 " image contains %.20g layers",(double) number_layers); 1723 1724 if (number_layers == 0) 1725 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers", 1726 image->filename); 1727 1728 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers, 1729 sizeof(*layer_info)); 1730 if (layer_info == (LayerInfo *) NULL) 1731 { 1732 if (image->debug != MagickFalse) 1733 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1734 " allocation of LayerInfo failed"); 1735 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1736 image->filename); 1737 } 1738 (void) memset(layer_info,0,(size_t) number_layers*sizeof(*layer_info)); 1739 1740 for (i=0; i < number_layers; i++) 1741 { 1742 ssize_t 1743 top, 1744 left, 1745 bottom, 1746 right; 1747 1748 if (image->debug != MagickFalse) 1749 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1750 " reading layer #%.20g",(double) i+1); 1751 top=(ssize_t) ReadBlobSignedLong(image); 1752 left=(ssize_t) ReadBlobSignedLong(image); 1753 bottom=(ssize_t) ReadBlobSignedLong(image); 1754 right=(ssize_t) ReadBlobSignedLong(image); 1755 if ((right < left) || (bottom < top)) 1756 { 1757 layer_info=DestroyLayerInfo(layer_info,number_layers); 1758 ThrowBinaryException(CorruptImageError,"ImproperImageHeader", 1759 image->filename); 1760 } 1761 layer_info[i].page.y=top; 1762 layer_info[i].page.x=left; 1763 layer_info[i].page.width=(size_t) (right-left); 1764 layer_info[i].page.height=(size_t) (bottom-top); 1765 layer_info[i].channels=ReadBlobShort(image); 1766 if (layer_info[i].channels > MaxPSDChannels) 1767 { 1768 layer_info=DestroyLayerInfo(layer_info,number_layers); 1769 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded", 1770 image->filename); 1771 } 1772 if (image->debug != MagickFalse) 1773 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1774 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g", 1775 (double) layer_info[i].page.x,(double) layer_info[i].page.y, 1776 (double) layer_info[i].page.height,(double) 1777 layer_info[i].page.width,(double) layer_info[i].channels); 1778 for (j=0; j < (ssize_t) layer_info[i].channels; j++) 1779 { 1780 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image); 1781 if ((layer_info[i].channel_info[j].type < -4) || 1782 (layer_info[i].channel_info[j].type > 4)) 1783 { 1784 layer_info=DestroyLayerInfo(layer_info,number_layers); 1785 ThrowBinaryException(CorruptImageError,"NoSuchImageChannel", 1786 image->filename); 1787 } 1788 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info, 1789 image); 1790 if (image->debug != MagickFalse) 1791 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1792 " channel[%.20g]: type=%.20g, size=%.20g",(double) j, 1793 (double) layer_info[i].channel_info[j].type, 1794 (double) layer_info[i].channel_info[j].size); 1795 } 1796 if (CheckPSDChannels(psd_info,&layer_info[i]) == MagickFalse) 1797 { 1798 layer_info=DestroyLayerInfo(layer_info,number_layers); 1799 ThrowBinaryException(CorruptImageError,"ImproperImageHeader", 1800 image->filename); 1801 } 1802 count=ReadBlob(image,4,(unsigned char *) type); 1803 if (count == 4) 1804 ReversePSDString(image,type,4); 1805 if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0)) 1806 { 1807 if (image->debug != MagickFalse) 1808 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1809 " layer type was %.4s instead of 8BIM", type); 1810 layer_info=DestroyLayerInfo(layer_info,number_layers); 1811 ThrowBinaryException(CorruptImageError,"ImproperImageHeader", 1812 image->filename); 1813 } 1814 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey); 1815 if (count != 4) 1816 { 1817 layer_info=DestroyLayerInfo(layer_info,number_layers); 1818 ThrowBinaryException(CorruptImageError,"ImproperImageHeader", 1819 image->filename); 1820 } 1821 ReversePSDString(image,layer_info[i].blendkey,4); 1822 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char) 1823 ReadBlobByte(image)); 1824 layer_info[i].clipping=(unsigned char) ReadBlobByte(image); 1825 layer_info[i].flags=(unsigned char) ReadBlobByte(image); 1826 layer_info[i].visible=!(layer_info[i].flags & 0x02); 1827 if (image->debug != MagickFalse) 1828 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1829 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s", 1830 layer_info[i].blendkey,(double) layer_info[i].opacity, 1831 layer_info[i].clipping ? "true" : "false",layer_info[i].flags, 1832 layer_info[i].visible ? "true" : "false"); 1833 (void) ReadBlobByte(image); /* filler */ 1834 1835 size=ReadBlobLong(image); 1836 if (size != 0) 1837 { 1838 MagickSizeType 1839 combined_length, 1840 length; 1841 1842 if (image->debug != MagickFalse) 1843 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1844 " layer contains additional info"); 1845 length=ReadBlobLong(image); 1846 combined_length=length+4; 1847 if (length != 0) 1848 { 1849 /* 1850 Layer mask info. 1851 */ 1852 layer_info[i].mask.page.y=(ssize_t) ReadBlobSignedLong(image); 1853 layer_info[i].mask.page.x=(ssize_t) ReadBlobSignedLong(image); 1854 layer_info[i].mask.page.height=(size_t) 1855 (ReadBlobSignedLong(image)-layer_info[i].mask.page.y); 1856 layer_info[i].mask.page.width=(size_t) ( 1857 ReadBlobSignedLong(image)-layer_info[i].mask.page.x); 1858 layer_info[i].mask.background=(unsigned char) ReadBlobByte( 1859 image); 1860 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image); 1861 if (!(layer_info[i].mask.flags & 0x01)) 1862 { 1863 layer_info[i].mask.page.y=layer_info[i].mask.page.y- 1864 layer_info[i].page.y; 1865 layer_info[i].mask.page.x=layer_info[i].mask.page.x- 1866 layer_info[i].page.x; 1867 } 1868 if (image->debug != MagickFalse) 1869 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1870 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g", 1871 (double) layer_info[i].mask.page.x,(double) 1872 layer_info[i].mask.page.y,(double) 1873 layer_info[i].mask.page.width,(double) 1874 layer_info[i].mask.page.height,(double) ((MagickOffsetType) 1875 length)-18); 1876 /* 1877 Skip over the rest of the layer mask information. 1878 */ 1879 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse) 1880 { 1881 layer_info=DestroyLayerInfo(layer_info,number_layers); 1882 ThrowBinaryException(CorruptImageError, 1883 "UnexpectedEndOfFile",image->filename); 1884 } 1885 } 1886 length=ReadBlobLong(image); 1887 combined_length+=length+4; 1888 if (length != 0) 1889 { 1890 /* 1891 Layer blending ranges info. 1892 */ 1893 if (image->debug != MagickFalse) 1894 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1895 " layer blending ranges: length=%.20g",(double) 1896 ((MagickOffsetType) length)); 1897 if (DiscardBlobBytes(image,length) == MagickFalse) 1898 { 1899 layer_info=DestroyLayerInfo(layer_info,number_layers); 1900 ThrowBinaryException(CorruptImageError, 1901 "UnexpectedEndOfFile",image->filename); 1902 } 1903 } 1904 /* 1905 Layer name. 1906 */ 1907 length=(MagickSizeType) (unsigned char) ReadBlobByte(image); 1908 combined_length+=length+1; 1909 if (length > 0) 1910 (void) ReadBlob(image,(size_t) length++,layer_info[i].name); 1911 layer_info[i].name[length]='\0'; 1912 if (image->debug != MagickFalse) 1913 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1914 " layer name: %s",layer_info[i].name); 1915 if ((length % 4) != 0) 1916 { 1917 length=4-(length % 4); 1918 combined_length+=length; 1919 /* Skip over the padding of the layer name */ 1920 if (DiscardBlobBytes(image,length) == MagickFalse) 1921 { 1922 layer_info=DestroyLayerInfo(layer_info,number_layers); 1923 ThrowBinaryException(CorruptImageError, 1924 "UnexpectedEndOfFile",image->filename); 1925 } 1926 } 1927 length=(MagickSizeType) size-combined_length; 1928 if (length > 0) 1929 { 1930 unsigned char 1931 *info; 1932 1933 if (length > GetBlobSize(image)) 1934 { 1935 layer_info=DestroyLayerInfo(layer_info,number_layers); 1936 ThrowBinaryException(CorruptImageError, 1937 "InsufficientImageDataInFile",image->filename); 1938 } 1939 layer_info[i].info=AcquireStringInfo((const size_t) length); 1940 info=GetStringInfoDatum(layer_info[i].info); 1941 (void) ReadBlob(image,(const size_t) length,info); 1942 } 1943 } 1944 } 1945 1946 for (i=0; i < number_layers; i++) 1947 { 1948 if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0)) 1949 { 1950 if (image->debug != MagickFalse) 1951 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1952 " layer data is empty"); 1953 if (layer_info[i].info != (StringInfo *) NULL) 1954 layer_info[i].info=DestroyStringInfo(layer_info[i].info); 1955 continue; 1956 } 1957 1958 /* 1959 Allocate layered image. 1960 */ 1961 layer_info[i].image=CloneImage(image,layer_info[i].page.width, 1962 layer_info[i].page.height,MagickFalse,exception); 1963 if (layer_info[i].image == (Image *) NULL) 1964 { 1965 layer_info=DestroyLayerInfo(layer_info,number_layers); 1966 if (image->debug != MagickFalse) 1967 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1968 " allocation of image for layer %.20g failed",(double) i); 1969 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1970 image->filename); 1971 } 1972 if (layer_info[i].info != (StringInfo *) NULL) 1973 { 1974 (void) SetImageProfile(layer_info[i].image,"psd:additional-info", 1975 layer_info[i].info,exception); 1976 layer_info[i].info=DestroyStringInfo(layer_info[i].info); 1977 } 1978 } 1979 if (image_info->ping != MagickFalse) 1980 { 1981 AttachPSDLayers(image,layer_info,number_layers); 1982 return(MagickTrue); 1983 } 1984 status=MagickTrue; 1985 for (i=0; i < number_layers; i++) 1986 { 1987 if ((layer_info[i].image == (Image *) NULL) || 1988 (PSDSkipImage(image_info,i) != MagickFalse)) 1989 { 1990 for (j=0; j < (ssize_t) layer_info[i].channels; j++) 1991 { 1992 if (DiscardBlobBytes(image,(MagickSizeType) 1993 layer_info[i].channel_info[j].size) == MagickFalse) 1994 { 1995 layer_info=DestroyLayerInfo(layer_info,number_layers); 1996 ThrowBinaryException(CorruptImageError, 1997 "UnexpectedEndOfFile",image->filename); 1998 } 1999 } 2000 continue; 2001 } 2002 2003 if (image->debug != MagickFalse) 2004 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2005 " reading data for layer %.20g",(double) i); 2006 2007 status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i], 2008 exception); 2009 if (status == MagickFalse) 2010 break; 2011 2012 status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i, 2013 (MagickSizeType) number_layers); 2014 if (status == MagickFalse) 2015 break; 2016 } 2017 2018 if (status != MagickFalse) 2019 AttachPSDLayers(image,layer_info,number_layers); 2020 else 2021 layer_info=DestroyLayerInfo(layer_info,number_layers); 2022 2023 return(status); 2024 } 2025 2026 ModuleExport MagickBooleanType ReadPSDLayers(Image *image, 2027 const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception) 2028 { 2029 PolicyDomain 2030 domain; 2031 2032 PolicyRights 2033 rights; 2034 2035 domain=CoderPolicyDomain; 2036 rights=ReadPolicyRights; 2037 if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse) 2038 return(MagickTrue); 2039 return(ReadPSDLayersInternal(image,image_info,psd_info,MagickFalse, 2040 exception)); 2041 } 2042 2043 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info, 2044 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception) 2045 { 2046 MagickOffsetType 2047 *sizes; 2048 2049 MagickBooleanType 2050 status; 2051 2052 PSDCompressionType 2053 compression; 2054 2055 register ssize_t 2056 i; 2057 2058 if ((image_info->number_scenes != 0) && (image_info->scene != 0)) 2059 return(MagickTrue); 2060 compression=(PSDCompressionType) ReadBlobMSBShort(image); 2061 image->compression=ConvertPSDCompression(compression); 2062 2063 if (compression != Raw && compression != RLE) 2064 { 2065 (void) ThrowMagickException(exception,GetMagickModule(), 2066 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression); 2067 return(MagickFalse); 2068 } 2069 2070 sizes=(MagickOffsetType *) NULL; 2071 if (compression == RLE) 2072 { 2073 sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels); 2074 if (sizes == (MagickOffsetType *) NULL) 2075 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 2076 image->filename); 2077 } 2078 2079 status=MagickTrue; 2080 for (i=0; i < (ssize_t) psd_info->channels; i++) 2081 { 2082 ssize_t 2083 type; 2084 2085 type=i; 2086 if ((type == 1) && (psd_info->channels == 2)) 2087 type=-1; 2088 2089 if (compression == RLE) 2090 status=ReadPSDChannelRLE(image,psd_info,type,sizes+(i*image->rows), 2091 exception); 2092 else 2093 status=ReadPSDChannelRaw(image,psd_info->channels,type,exception); 2094 2095 if (status != MagickFalse) 2096 status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i, 2097 psd_info->channels); 2098 2099 if (status == MagickFalse) 2100 break; 2101 } 2102 2103 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace)) 2104 status=NegateCMYK(image,exception); 2105 2106 if (status != MagickFalse) 2107 status=CorrectPSDAlphaBlend(image_info,image,exception); 2108 2109 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes); 2110 2111 return(status); 2112 } 2113 2114 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception) 2115 { 2116 Image 2117 *image; 2118 2119 MagickBooleanType 2120 has_merged_image, 2121 skip_layers; 2122 2123 MagickOffsetType 2124 offset; 2125 2126 MagickSizeType 2127 length; 2128 2129 MagickBooleanType 2130 status; 2131 2132 PSDInfo 2133 psd_info; 2134 2135 register ssize_t 2136 i; 2137 2138 size_t 2139 imageListLength; 2140 2141 ssize_t 2142 count; 2143 2144 StringInfo 2145 *profile; 2146 2147 /* 2148 Open image file. 2149 */ 2150 assert(image_info != (const ImageInfo *) NULL); 2151 assert(image_info->signature == MagickCoreSignature); 2152 if (image_info->debug != MagickFalse) 2153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 2154 image_info->filename); 2155 assert(exception != (ExceptionInfo *) NULL); 2156 assert(exception->signature == MagickCoreSignature); 2157 2158 image=AcquireImage(image_info,exception); 2159 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 2160 if (status == MagickFalse) 2161 { 2162 image=DestroyImageList(image); 2163 return((Image *) NULL); 2164 } 2165 /* 2166 Read image header. 2167 */ 2168 image->endian=MSBEndian; 2169 count=ReadBlob(image,4,(unsigned char *) psd_info.signature); 2170 psd_info.version=ReadBlobMSBShort(image); 2171 if ((count != 4) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) || 2172 ((psd_info.version != 1) && (psd_info.version != 2))) 2173 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2174 (void) ReadBlob(image,6,psd_info.reserved); 2175 psd_info.channels=ReadBlobMSBShort(image); 2176 if (psd_info.channels < 1) 2177 ThrowReaderException(CorruptImageError,"MissingImageChannel"); 2178 if (psd_info.channels > MaxPSDChannels) 2179 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded"); 2180 psd_info.rows=ReadBlobMSBLong(image); 2181 psd_info.columns=ReadBlobMSBLong(image); 2182 if ((psd_info.version == 1) && ((psd_info.rows > 30000) || 2183 (psd_info.columns > 30000))) 2184 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2185 psd_info.depth=ReadBlobMSBShort(image); 2186 if ((psd_info.depth != 1) && (psd_info.depth != 8) && 2187 (psd_info.depth != 16) && (psd_info.depth != 32)) 2188 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2189 psd_info.mode=ReadBlobMSBShort(image); 2190 if ((psd_info.mode == IndexedMode) && (psd_info.channels > 3)) 2191 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2192 if (image->debug != MagickFalse) 2193 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2194 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s", 2195 (double) psd_info.columns,(double) psd_info.rows,(double) 2196 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType) 2197 psd_info.mode)); 2198 if (EOFBlob(image) != MagickFalse) 2199 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2200 /* 2201 Initialize image. 2202 */ 2203 image->depth=psd_info.depth; 2204 image->columns=psd_info.columns; 2205 image->rows=psd_info.rows; 2206 status=SetImageExtent(image,image->columns,image->rows,exception); 2207 if (status == MagickFalse) 2208 return(DestroyImageList(image)); 2209 status=ResetImagePixels(image,exception); 2210 if (status == MagickFalse) 2211 return(DestroyImageList(image)); 2212 psd_info.min_channels=3; 2213 if (psd_info.mode == LabMode) 2214 (void) SetImageColorspace(image,LabColorspace,exception); 2215 if (psd_info.mode == CMYKMode) 2216 { 2217 psd_info.min_channels=4; 2218 (void) SetImageColorspace(image,CMYKColorspace,exception); 2219 } 2220 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) || 2221 (psd_info.mode == DuotoneMode)) 2222 { 2223 if (psd_info.depth != 32) 2224 { 2225 status=AcquireImageColormap(image,(size_t) (psd_info.depth < 16 ? 2226 256 : 65536),exception); 2227 if (status == MagickFalse) 2228 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2229 if (image->debug != MagickFalse) 2230 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2231 " Image colormap allocated"); 2232 } 2233 psd_info.min_channels=1; 2234 (void) SetImageColorspace(image,GRAYColorspace,exception); 2235 } 2236 if (psd_info.channels < psd_info.min_channels) 2237 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2238 /* 2239 Read PSD raster colormap only present for indexed and duotone images. 2240 */ 2241 length=ReadBlobMSBLong(image); 2242 if ((psd_info.mode == IndexedMode) && (length < 3)) 2243 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2244 if (length != 0) 2245 { 2246 if (image->debug != MagickFalse) 2247 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2248 " reading colormap"); 2249 if ((psd_info.mode == DuotoneMode) || (psd_info.depth == 32)) 2250 { 2251 /* 2252 Duotone image data; the format of this data is undocumented. 2253 32 bits per pixel; the colormap is ignored. 2254 */ 2255 (void) SeekBlob(image,(const MagickOffsetType) length,SEEK_CUR); 2256 } 2257 else 2258 { 2259 size_t 2260 number_colors; 2261 2262 /* 2263 Read PSD raster colormap. 2264 */ 2265 number_colors=(size_t) length/3; 2266 if (number_colors > 65536) 2267 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2268 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse) 2269 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2270 for (i=0; i < (ssize_t) image->colors; i++) 2271 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum( 2272 (unsigned char) ReadBlobByte(image)); 2273 for (i=0; i < (ssize_t) image->colors; i++) 2274 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum( 2275 (unsigned char) ReadBlobByte(image)); 2276 for (i=0; i < (ssize_t) image->colors; i++) 2277 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum( 2278 (unsigned char) ReadBlobByte(image)); 2279 image->alpha_trait=UndefinedPixelTrait; 2280 } 2281 } 2282 if ((image->depth == 1) && (image->storage_class != PseudoClass)) 2283 ThrowReaderException(CorruptImageError, "ImproperImageHeader"); 2284 has_merged_image=MagickTrue; 2285 profile=(StringInfo *) NULL; 2286 length=ReadBlobMSBLong(image); 2287 if (length != 0) 2288 { 2289 unsigned char 2290 *blocks; 2291 2292 /* 2293 Image resources block. 2294 */ 2295 if (image->debug != MagickFalse) 2296 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2297 " reading image resource blocks - %.20g bytes",(double) 2298 ((MagickOffsetType) length)); 2299 if (length > GetBlobSize(image)) 2300 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 2301 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length, 2302 sizeof(*blocks)); 2303 if (blocks == (unsigned char *) NULL) 2304 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 2305 count=ReadBlob(image,(size_t) length,blocks); 2306 if ((count != (ssize_t) length) || (length < 4) || 2307 (LocaleNCompare((char *) blocks,"8BIM",4) != 0)) 2308 { 2309 blocks=(unsigned char *) RelinquishMagickMemory(blocks); 2310 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 2311 } 2312 profile=ParseImageResourceBlocks(image,blocks,(size_t) length, 2313 &has_merged_image,exception); 2314 blocks=(unsigned char *) RelinquishMagickMemory(blocks); 2315 } 2316 /* 2317 Layer and mask block. 2318 */ 2319 length=GetPSDSize(&psd_info,image); 2320 if (length == 8) 2321 { 2322 length=ReadBlobMSBLong(image); 2323 length=ReadBlobMSBLong(image); 2324 } 2325 offset=TellBlob(image); 2326 skip_layers=MagickFalse; 2327 if ((image_info->number_scenes == 1) && (image_info->scene == 0) && 2328 (has_merged_image != MagickFalse)) 2329 { 2330 if (image->debug != MagickFalse) 2331 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2332 " read composite only"); 2333 skip_layers=MagickTrue; 2334 } 2335 if (length == 0) 2336 { 2337 if (image->debug != MagickFalse) 2338 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2339 " image has no layers"); 2340 } 2341 else 2342 { 2343 if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers, 2344 exception) != MagickTrue) 2345 { 2346 if (profile != (StringInfo *) NULL) 2347 profile=DestroyStringInfo(profile); 2348 (void) CloseBlob(image); 2349 image=DestroyImageList(image); 2350 return((Image *) NULL); 2351 } 2352 2353 /* 2354 Skip the rest of the layer and mask information. 2355 */ 2356 (void) SeekBlob(image,offset+length,SEEK_SET); 2357 } 2358 /* 2359 If we are only "pinging" the image, then we're done - so return. 2360 */ 2361 if (EOFBlob(image) != MagickFalse) 2362 { 2363 if (profile != (StringInfo *) NULL) 2364 profile=DestroyStringInfo(profile); 2365 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 2366 } 2367 if (image_info->ping != MagickFalse) 2368 { 2369 if (profile != (StringInfo *) NULL) 2370 profile=DestroyStringInfo(profile); 2371 (void) CloseBlob(image); 2372 return(GetFirstImageInList(image)); 2373 } 2374 /* 2375 Read the precombined layer, present for PSD < 4 compatibility. 2376 */ 2377 if (image->debug != MagickFalse) 2378 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2379 " reading the precombined layer"); 2380 imageListLength=GetImageListLength(image); 2381 if ((has_merged_image != MagickFalse) || (imageListLength == 1)) 2382 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image, 2383 &psd_info,exception); 2384 if ((has_merged_image == MagickFalse) && (imageListLength == 1) && 2385 (length != 0)) 2386 { 2387 (void) SeekBlob(image,offset,SEEK_SET); 2388 status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse, 2389 exception); 2390 if (status != MagickTrue) 2391 { 2392 if (profile != (StringInfo *) NULL) 2393 profile=DestroyStringInfo(profile); 2394 (void) CloseBlob(image); 2395 image=DestroyImageList(image); 2396 return((Image *) NULL); 2397 } 2398 } 2399 if (has_merged_image == MagickFalse) 2400 { 2401 Image 2402 *merged; 2403 2404 if (imageListLength == 1) 2405 { 2406 if (profile != (StringInfo *) NULL) 2407 profile=DestroyStringInfo(profile); 2408 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 2409 } 2410 image->background_color.alpha=(MagickRealType) TransparentAlpha; 2411 image->background_color.alpha_trait=BlendPixelTrait; 2412 (void) SetImageBackgroundColor(image,exception); 2413 merged=MergeImageLayers(image,FlattenLayer,exception); 2414 ReplaceImageInList(&image,merged); 2415 } 2416 if (profile != (StringInfo *) NULL) 2417 { 2418 Image 2419 *next; 2420 2421 i=0; 2422 next=image; 2423 while (next != (Image *) NULL) 2424 { 2425 if (PSDSkipImage(image_info,i++) == MagickFalse) 2426 (void) SetImageProfile(next,GetStringInfoName(profile),profile, 2427 exception); 2428 next=next->next; 2429 } 2430 profile=DestroyStringInfo(profile); 2431 } 2432 (void) CloseBlob(image); 2433 return(GetFirstImageInList(image)); 2434 } 2435 2436 /* 2438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2439 % % 2440 % % 2441 % % 2442 % R e g i s t e r P S D I m a g e % 2443 % % 2444 % % 2445 % % 2446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2447 % 2448 % RegisterPSDImage() adds properties for the PSD image format to 2449 % the list of supported formats. The properties include the image format 2450 % tag, a method to read and/or write the format, whether the format 2451 % supports the saving of more than one frame to the same file or blob, 2452 % whether the format supports native in-memory I/O, and a brief 2453 % description of the format. 2454 % 2455 % The format of the RegisterPSDImage method is: 2456 % 2457 % size_t RegisterPSDImage(void) 2458 % 2459 */ 2460 ModuleExport size_t RegisterPSDImage(void) 2461 { 2462 MagickInfo 2463 *entry; 2464 2465 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format"); 2466 entry->decoder=(DecodeImageHandler *) ReadPSDImage; 2467 entry->encoder=(EncodeImageHandler *) WritePSDImage; 2468 entry->magick=(IsImageFormatHandler *) IsPSD; 2469 entry->flags|=CoderDecoderSeekableStreamFlag; 2470 entry->flags|=CoderEncoderSeekableStreamFlag; 2471 (void) RegisterMagickInfo(entry); 2472 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap"); 2473 entry->decoder=(DecodeImageHandler *) ReadPSDImage; 2474 entry->encoder=(EncodeImageHandler *) WritePSDImage; 2475 entry->magick=(IsImageFormatHandler *) IsPSD; 2476 entry->flags|=CoderDecoderSeekableStreamFlag; 2477 entry->flags|=CoderEncoderSeekableStreamFlag; 2478 (void) RegisterMagickInfo(entry); 2479 return(MagickImageCoderSignature); 2480 } 2481 2482 /* 2484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2485 % % 2486 % % 2487 % % 2488 % U n r e g i s t e r P S D I m a g e % 2489 % % 2490 % % 2491 % % 2492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2493 % 2494 % UnregisterPSDImage() removes format registrations made by the 2495 % PSD module from the list of supported formats. 2496 % 2497 % The format of the UnregisterPSDImage method is: 2498 % 2499 % UnregisterPSDImage(void) 2500 % 2501 */ 2502 ModuleExport void UnregisterPSDImage(void) 2503 { 2504 (void) UnregisterMagickInfo("PSB"); 2505 (void) UnregisterMagickInfo("PSD"); 2506 } 2507 2508 /* 2510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2511 % % 2512 % % 2513 % % 2514 % W r i t e P S D I m a g e % 2515 % % 2516 % % 2517 % % 2518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2519 % 2520 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format. 2521 % 2522 % The format of the WritePSDImage method is: 2523 % 2524 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image, 2525 % ExceptionInfo *exception) 2526 % 2527 % A description of each parameter follows. 2528 % 2529 % o image_info: the image info. 2530 % 2531 % o image: The image. 2532 % 2533 % o exception: return any errors or warnings in this structure. 2534 % 2535 */ 2536 2537 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image, 2538 const size_t offset) 2539 { 2540 if (psd_info->version == 1) 2541 return(WriteBlobMSBShort(image,(unsigned short) offset)); 2542 return(WriteBlobMSBLong(image,(unsigned int) offset)); 2543 } 2544 2545 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image, 2546 const MagickSizeType size,const MagickOffsetType offset) 2547 { 2548 MagickOffsetType 2549 current_offset; 2550 2551 ssize_t 2552 result; 2553 2554 current_offset=TellBlob(image); 2555 (void) SeekBlob(image,offset,SEEK_SET); 2556 if (psd_info->version == 1) 2557 result=WriteBlobMSBShort(image,(unsigned short) size); 2558 else 2559 result=WriteBlobMSBLong(image,(unsigned int) size); 2560 (void) SeekBlob(image,current_offset,SEEK_SET); 2561 return(result); 2562 } 2563 2564 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image, 2565 const MagickSizeType size) 2566 { 2567 if (psd_info->version == 1) 2568 return(WriteBlobLong(image,(unsigned int) size)); 2569 return(WriteBlobLongLong(image,size)); 2570 } 2571 2572 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image, 2573 const MagickSizeType size,const MagickOffsetType offset) 2574 { 2575 MagickOffsetType 2576 current_offset; 2577 2578 ssize_t 2579 result; 2580 2581 current_offset=TellBlob(image); 2582 (void) SeekBlob(image,offset,SEEK_SET); 2583 result=SetPSDSize(psd_info,image,size); 2584 (void) SeekBlob(image,current_offset,SEEK_SET); 2585 return(result); 2586 } 2587 2588 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length, 2589 const unsigned char *pixels,unsigned char *compact_pixels, 2590 ExceptionInfo *exception) 2591 { 2592 int 2593 count; 2594 2595 register ssize_t 2596 i, 2597 j; 2598 2599 register unsigned char 2600 *q; 2601 2602 unsigned char 2603 *packbits; 2604 2605 /* 2606 Compress pixels with Packbits encoding. 2607 */ 2608 assert(image != (Image *) NULL); 2609 assert(image->signature == MagickCoreSignature); 2610 if (image->debug != MagickFalse) 2611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2612 assert(pixels != (unsigned char *) NULL); 2613 assert(compact_pixels != (unsigned char *) NULL); 2614 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits)); 2615 if (packbits == (unsigned char *) NULL) 2616 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 2617 image->filename); 2618 q=compact_pixels; 2619 for (i=(ssize_t) length; i != 0; ) 2620 { 2621 switch (i) 2622 { 2623 case 1: 2624 { 2625 i--; 2626 *q++=(unsigned char) 0; 2627 *q++=(*pixels); 2628 break; 2629 } 2630 case 2: 2631 { 2632 i-=2; 2633 *q++=(unsigned char) 1; 2634 *q++=(*pixels); 2635 *q++=pixels[1]; 2636 break; 2637 } 2638 case 3: 2639 { 2640 i-=3; 2641 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 2642 { 2643 *q++=(unsigned char) ((256-3)+1); 2644 *q++=(*pixels); 2645 break; 2646 } 2647 *q++=(unsigned char) 2; 2648 *q++=(*pixels); 2649 *q++=pixels[1]; 2650 *q++=pixels[2]; 2651 break; 2652 } 2653 default: 2654 { 2655 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 2656 { 2657 /* 2658 Packed run. 2659 */ 2660 count=3; 2661 while (((ssize_t) count < i) && (*pixels == *(pixels+count))) 2662 { 2663 count++; 2664 if (count >= 127) 2665 break; 2666 } 2667 i-=count; 2668 *q++=(unsigned char) ((256-count)+1); 2669 *q++=(*pixels); 2670 pixels+=count; 2671 break; 2672 } 2673 /* 2674 Literal run. 2675 */ 2676 count=0; 2677 while ((*(pixels+count) != *(pixels+count+1)) || 2678 (*(pixels+count+1) != *(pixels+count+2))) 2679 { 2680 packbits[count+1]=pixels[count]; 2681 count++; 2682 if (((ssize_t) count >= (i-3)) || (count >= 127)) 2683 break; 2684 } 2685 i-=count; 2686 *packbits=(unsigned char) (count-1); 2687 for (j=0; j <= (ssize_t) count; j++) 2688 *q++=packbits[j]; 2689 pixels+=count; 2690 break; 2691 } 2692 } 2693 } 2694 *q++=(unsigned char) 128; /* EOD marker */ 2695 packbits=(unsigned char *) RelinquishMagickMemory(packbits); 2696 return((size_t) (q-compact_pixels)); 2697 } 2698 2699 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image, 2700 const Image *next_image,const CompressionType compression, 2701 const ssize_t channels) 2702 { 2703 size_t 2704 length; 2705 2706 ssize_t 2707 i, 2708 y; 2709 2710 if (compression == RLECompression) 2711 { 2712 length=(size_t) WriteBlobShort(image,RLE); 2713 for (i=0; i < channels; i++) 2714 for (y=0; y < (ssize_t) next_image->rows; y++) 2715 length+=SetPSDOffset(psd_info,image,0); 2716 } 2717 #ifdef MAGICKCORE_ZLIB_DELEGATE 2718 else if (compression == ZipCompression) 2719 length=(size_t) WriteBlobShort(image,ZipWithoutPrediction); 2720 #endif 2721 else 2722 length=(size_t) WriteBlobShort(image,Raw); 2723 return(length); 2724 } 2725 2726 static size_t WritePSDChannel(const PSDInfo *psd_info, 2727 const ImageInfo *image_info,Image *image,Image *next_image, 2728 const QuantumType quantum_type, unsigned char *compact_pixels, 2729 MagickOffsetType size_offset,const MagickBooleanType separate, 2730 const CompressionType compression,ExceptionInfo *exception) 2731 { 2732 MagickBooleanType 2733 monochrome; 2734 2735 QuantumInfo 2736 *quantum_info; 2737 2738 register const Quantum 2739 *p; 2740 2741 register ssize_t 2742 i; 2743 2744 size_t 2745 count, 2746 length; 2747 2748 ssize_t 2749 y; 2750 2751 unsigned char 2752 *pixels; 2753 2754 #ifdef MAGICKCORE_ZLIB_DELEGATE 2755 2756 #define CHUNK 16384 2757 2758 int 2759 flush, 2760 level; 2761 2762 unsigned char 2763 *compressed_pixels; 2764 2765 z_stream 2766 stream; 2767 2768 compressed_pixels=(unsigned char *) NULL; 2769 flush=Z_NO_FLUSH; 2770 #endif 2771 count=0; 2772 if (separate != MagickFalse) 2773 { 2774 size_offset=TellBlob(image)+2; 2775 count+=WriteCompressionStart(psd_info,image,next_image,compression,1); 2776 } 2777 if (next_image->depth > 8) 2778 next_image->depth=16; 2779 monochrome=IsImageMonochrome(image) && (image->depth == 1) ? 2780 MagickTrue : MagickFalse; 2781 quantum_info=AcquireQuantumInfo(image_info,next_image); 2782 if (quantum_info == (QuantumInfo *) NULL) 2783 return(0); 2784 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 2785 #ifdef MAGICKCORE_ZLIB_DELEGATE 2786 if (compression == ZipCompression) 2787 { 2788 compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK, 2789 sizeof(*compressed_pixels)); 2790 if (compressed_pixels == (unsigned char *) NULL) 2791 { 2792 quantum_info=DestroyQuantumInfo(quantum_info); 2793 return(0); 2794 } 2795 memset(&stream,0,sizeof(stream)); 2796 stream.data_type=Z_BINARY; 2797 level=Z_DEFAULT_COMPRESSION; 2798 if ((image_info->quality > 0 && image_info->quality < 10)) 2799 level=(int) image_info->quality; 2800 if (deflateInit(&stream,level) != Z_OK) 2801 { 2802 quantum_info=DestroyQuantumInfo(quantum_info); 2803 compressed_pixels=(unsigned char *) RelinquishMagickMemory( 2804 compressed_pixels); 2805 return(0); 2806 } 2807 } 2808 #endif 2809 for (y=0; y < (ssize_t) next_image->rows; y++) 2810 { 2811 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception); 2812 if (p == (const Quantum *) NULL) 2813 break; 2814 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info, 2815 quantum_type,pixels,exception); 2816 if (monochrome != MagickFalse) 2817 for (i=0; i < (ssize_t) length; i++) 2818 pixels[i]=(~pixels[i]); 2819 if (compression == RLECompression) 2820 { 2821 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels, 2822 exception); 2823 count+=WriteBlob(image,length,compact_pixels); 2824 size_offset+=WritePSDOffset(psd_info,image,length,size_offset); 2825 } 2826 #ifdef MAGICKCORE_ZLIB_DELEGATE 2827 else if (compression == ZipCompression) 2828 { 2829 stream.avail_in=(uInt) length; 2830 stream.next_in=(Bytef *) pixels; 2831 if (y == (ssize_t) next_image->rows-1) 2832 flush=Z_FINISH; 2833 do { 2834 stream.avail_out=(uInt) CHUNK; 2835 stream.next_out=(Bytef *) compressed_pixels; 2836 if (deflate(&stream,flush) == Z_STREAM_ERROR) 2837 break; 2838 length=(size_t) CHUNK-stream.avail_out; 2839 if (length > 0) 2840 count+=WriteBlob(image,length,compressed_pixels); 2841 } while (stream.avail_out == 0); 2842 } 2843 #endif 2844 else 2845 count+=WriteBlob(image,length,pixels); 2846 } 2847 #ifdef MAGICKCORE_ZLIB_DELEGATE 2848 if (compression == ZipCompression) 2849 { 2850 (void) deflateEnd(&stream); 2851 compressed_pixels=(unsigned char *) RelinquishMagickMemory( 2852 compressed_pixels); 2853 } 2854 #endif 2855 quantum_info=DestroyQuantumInfo(quantum_info); 2856 return(count); 2857 } 2858 2859 static unsigned char *AcquireCompactPixels(const Image *image, 2860 ExceptionInfo *exception) 2861 { 2862 size_t 2863 packet_size; 2864 2865 unsigned char 2866 *compact_pixels; 2867 2868 packet_size=image->depth > 8UL ? 2UL : 1UL; 2869 compact_pixels=(unsigned char *) AcquireQuantumMemory((9* 2870 image->columns)+1,packet_size*sizeof(*compact_pixels)); 2871 if (compact_pixels == (unsigned char *) NULL) 2872 { 2873 (void) ThrowMagickException(exception,GetMagickModule(), 2874 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 2875 } 2876 return(compact_pixels); 2877 } 2878 2879 static size_t WritePSDChannels(const PSDInfo *psd_info, 2880 const ImageInfo *image_info,Image *image,Image *next_image, 2881 MagickOffsetType size_offset,const MagickBooleanType separate, 2882 ExceptionInfo *exception) 2883 { 2884 CompressionType 2885 compression; 2886 2887 Image 2888 *mask; 2889 2890 MagickOffsetType 2891 rows_offset; 2892 2893 size_t 2894 channels, 2895 count, 2896 length, 2897 offset_length; 2898 2899 unsigned char 2900 *compact_pixels; 2901 2902 count=0; 2903 offset_length=0; 2904 rows_offset=0; 2905 compact_pixels=(unsigned char *) NULL; 2906 compression=next_image->compression; 2907 if (image_info->compression != UndefinedCompression) 2908 compression=image_info->compression; 2909 if (compression == RLECompression) 2910 { 2911 compact_pixels=AcquireCompactPixels(next_image,exception); 2912 if (compact_pixels == (unsigned char *) NULL) 2913 return(0); 2914 } 2915 channels=1; 2916 if (separate == MagickFalse) 2917 { 2918 if (next_image->storage_class != PseudoClass) 2919 { 2920 if (IsImageGray(next_image) == MagickFalse) 2921 channels=(size_t) (next_image->colorspace == CMYKColorspace ? 4 : 2922 3); 2923 if (next_image->alpha_trait != UndefinedPixelTrait) 2924 channels++; 2925 } 2926 rows_offset=TellBlob(image)+2; 2927 count+=WriteCompressionStart(psd_info,image,next_image,compression, 2928 (ssize_t) channels); 2929 offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4)); 2930 } 2931 size_offset+=2; 2932 if (next_image->storage_class == PseudoClass) 2933 { 2934 length=WritePSDChannel(psd_info,image_info,image,next_image, 2935 IndexQuantum,compact_pixels,rows_offset,separate,compression, 2936 exception); 2937 if (separate != MagickFalse) 2938 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2939 else 2940 rows_offset+=offset_length; 2941 count+=length; 2942 } 2943 else 2944 { 2945 if (IsImageGray(next_image) != MagickFalse) 2946 { 2947 length=WritePSDChannel(psd_info,image_info,image,next_image, 2948 GrayQuantum,compact_pixels,rows_offset,separate,compression, 2949 exception); 2950 if (separate != MagickFalse) 2951 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2952 else 2953 rows_offset+=offset_length; 2954 count+=length; 2955 } 2956 else 2957 { 2958 if (next_image->colorspace == CMYKColorspace) 2959 (void) NegateCMYK(next_image,exception); 2960 2961 length=WritePSDChannel(psd_info,image_info,image,next_image, 2962 RedQuantum,compact_pixels,rows_offset,separate,compression, 2963 exception); 2964 if (separate != MagickFalse) 2965 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2966 else 2967 rows_offset+=offset_length; 2968 count+=length; 2969 2970 length=WritePSDChannel(psd_info,image_info,image,next_image, 2971 GreenQuantum,compact_pixels,rows_offset,separate,compression, 2972 exception); 2973 if (separate != MagickFalse) 2974 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2975 else 2976 rows_offset+=offset_length; 2977 count+=length; 2978 2979 length=WritePSDChannel(psd_info,image_info,image,next_image, 2980 BlueQuantum,compact_pixels,rows_offset,separate,compression, 2981 exception); 2982 if (separate != MagickFalse) 2983 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2984 else 2985 rows_offset+=offset_length; 2986 count+=length; 2987 2988 if (next_image->colorspace == CMYKColorspace) 2989 { 2990 length=WritePSDChannel(psd_info,image_info,image,next_image, 2991 BlackQuantum,compact_pixels,rows_offset,separate,compression, 2992 exception); 2993 if (separate != MagickFalse) 2994 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 2995 else 2996 rows_offset+=offset_length; 2997 count+=length; 2998 } 2999 } 3000 if (next_image->alpha_trait != UndefinedPixelTrait) 3001 { 3002 length=WritePSDChannel(psd_info,image_info,image,next_image, 3003 AlphaQuantum,compact_pixels,rows_offset,separate,compression, 3004 exception); 3005 if (separate != MagickFalse) 3006 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2; 3007 else 3008 rows_offset+=offset_length; 3009 count+=length; 3010 } 3011 } 3012 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 3013 if (next_image->colorspace == CMYKColorspace) 3014 (void) NegateCMYK(next_image,exception); 3015 if (separate != MagickFalse) 3016 { 3017 const char 3018 *property; 3019 3020 property=GetImageArtifact(next_image,"psd:opacity-mask"); 3021 if (property != (const char *) NULL) 3022 { 3023 mask=(Image *) GetImageRegistry(ImageRegistryType,property, 3024 exception); 3025 if (mask != (Image *) NULL) 3026 { 3027 if (compression == RLECompression) 3028 { 3029 compact_pixels=AcquireCompactPixels(mask,exception); 3030 if (compact_pixels == (unsigned char *) NULL) 3031 return(0); 3032 } 3033 length=WritePSDChannel(psd_info,image_info,image,mask, 3034 RedQuantum,compact_pixels,rows_offset,MagickTrue,compression, 3035 exception); 3036 (void) WritePSDSize(psd_info,image,length,size_offset); 3037 count+=length; 3038 compact_pixels=(unsigned char *) RelinquishMagickMemory( 3039 compact_pixels); 3040 } 3041 } 3042 } 3043 return(count); 3044 } 3045 3046 static size_t WritePascalString(Image *image,const char *value,size_t padding) 3047 { 3048 size_t 3049 count, 3050 length; 3051 3052 register ssize_t 3053 i; 3054 3055 /* 3056 Max length is 255. 3057 */ 3058 count=0; 3059 length=(strlen(value) > 255UL ) ? 255UL : strlen(value); 3060 if (length == 0) 3061 count+=WriteBlobByte(image,0); 3062 else 3063 { 3064 count+=WriteBlobByte(image,(unsigned char) length); 3065 count+=WriteBlob(image,length,(const unsigned char *) value); 3066 } 3067 length++; 3068 if ((length % padding) == 0) 3069 return(count); 3070 for (i=0; i < (ssize_t) (padding-(length % padding)); i++) 3071 count+=WriteBlobByte(image,0); 3072 return(count); 3073 } 3074 3075 static void WriteResolutionResourceBlock(Image *image) 3076 { 3077 double 3078 x_resolution, 3079 y_resolution; 3080 3081 unsigned short 3082 units; 3083 3084 if (image->units == PixelsPerCentimeterResolution) 3085 { 3086 x_resolution=2.54*65536.0*image->resolution.x+0.5; 3087 y_resolution=2.54*65536.0*image->resolution.y+0.5; 3088 units=2; 3089 } 3090 else 3091 { 3092 x_resolution=65536.0*image->resolution.x+0.5; 3093 y_resolution=65536.0*image->resolution.y+0.5; 3094 units=1; 3095 } 3096 (void) WriteBlob(image,4,(const unsigned char *) "8BIM"); 3097 (void) WriteBlobMSBShort(image,0x03ED); 3098 (void) WriteBlobMSBShort(image,0); 3099 (void) WriteBlobMSBLong(image,16); /* resource size */ 3100 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5)); 3101 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */ 3102 (void) WriteBlobMSBShort(image,units); /* width unit */ 3103 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5)); 3104 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */ 3105 (void) WriteBlobMSBShort(image,units); /* height unit */ 3106 } 3107 3108 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image, 3109 const signed short channel) 3110 { 3111 size_t 3112 count; 3113 3114 count=(size_t) WriteBlobShort(image,(const unsigned short) channel); 3115 count+=SetPSDSize(psd_info,image,0); 3116 return(count); 3117 } 3118 3119 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile) 3120 { 3121 register const unsigned char 3122 *p; 3123 3124 size_t 3125 length; 3126 3127 unsigned char 3128 *datum; 3129 3130 unsigned int 3131 count, 3132 long_sans; 3133 3134 unsigned short 3135 id, 3136 short_sans; 3137 3138 length=GetStringInfoLength(bim_profile); 3139 if (length < 16) 3140 return; 3141 datum=GetStringInfoDatum(bim_profile); 3142 for (p=datum; (p >= datum) && (p < (datum+length-16)); ) 3143 { 3144 register unsigned char 3145 *q; 3146 3147 q=(unsigned char *) p; 3148 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 3149 break; 3150 p=PushLongPixel(MSBEndian,p,&long_sans); 3151 p=PushShortPixel(MSBEndian,p,&id); 3152 p=PushShortPixel(MSBEndian,p,&short_sans); 3153 p=PushLongPixel(MSBEndian,p,&count); 3154 if (id == 0x0000040f) 3155 { 3156 ssize_t 3157 quantum; 3158 3159 quantum=PSDQuantum(count)+12; 3160 if ((quantum >= 12) && (quantum < (ssize_t) length)) 3161 { 3162 if ((q+quantum < (datum+length-16))) 3163 (void) memmove(q,q+quantum,length-quantum-(q-datum)); 3164 SetStringInfoLength(bim_profile,length-quantum); 3165 } 3166 break; 3167 } 3168 p+=count; 3169 if ((count & 0x01) != 0) 3170 p++; 3171 } 3172 } 3173 3174 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile) 3175 { 3176 register const unsigned char 3177 *p; 3178 3179 size_t 3180 length; 3181 3182 unsigned char 3183 *datum; 3184 3185 unsigned int 3186 count, 3187 long_sans; 3188 3189 unsigned short 3190 id, 3191 short_sans; 3192 3193 length=GetStringInfoLength(bim_profile); 3194 if (length < 16) 3195 return; 3196 datum=GetStringInfoDatum(bim_profile); 3197 for (p=datum; (p >= datum) && (p < (datum+length-16)); ) 3198 { 3199 register unsigned char 3200 *q; 3201 3202 ssize_t 3203 cnt; 3204 3205 q=(unsigned char *) p; 3206 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 3207 return; 3208 p=PushLongPixel(MSBEndian,p,&long_sans); 3209 p=PushShortPixel(MSBEndian,p,&id); 3210 p=PushShortPixel(MSBEndian,p,&short_sans); 3211 p=PushLongPixel(MSBEndian,p,&count); 3212 cnt=PSDQuantum(count); 3213 if (cnt < 0) 3214 return; 3215 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)) && 3216 ((ssize_t) length-(cnt+12)-(q-datum)) > 0) 3217 { 3218 (void) memmove(q,q+cnt+12,length-(cnt+12)-(q-datum)); 3219 SetStringInfoLength(bim_profile,length-(cnt+12)); 3220 break; 3221 } 3222 p+=count; 3223 if ((count & 0x01) != 0) 3224 p++; 3225 } 3226 } 3227 3228 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info, 3229 Image *image,ExceptionInfo *exception) 3230 { 3231 #define PSDKeySize 5 3232 #define PSDAllowedLength 36 3233 3234 char 3235 key[PSDKeySize]; 3236 3237 /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */ 3238 const char 3239 allowed[PSDAllowedLength][PSDKeySize] = { 3240 "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk", 3241 "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr", 3242 "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl", 3243 "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA" 3244 }, 3245 *option; 3246 3247 const StringInfo 3248 *info; 3249 3250 MagickBooleanType 3251 found; 3252 3253 register size_t 3254 i; 3255 3256 size_t 3257 remaining_length, 3258 length; 3259 3260 StringInfo 3261 *profile; 3262 3263 unsigned char 3264 *p; 3265 3266 unsigned int 3267 size; 3268 3269 info=GetImageProfile(image,"psd:additional-info"); 3270 if (info == (const StringInfo *) NULL) 3271 return((const StringInfo *) NULL); 3272 option=GetImageOption(image_info,"psd:additional-info"); 3273 if (LocaleCompare(option,"all") == 0) 3274 return(info); 3275 if (LocaleCompare(option,"selective") != 0) 3276 { 3277 profile=RemoveImageProfile(image,"psd:additional-info"); 3278 return(DestroyStringInfo(profile)); 3279 } 3280 length=GetStringInfoLength(info); 3281 p=GetStringInfoDatum(info); 3282 remaining_length=length; 3283 length=0; 3284 while (remaining_length >= 12) 3285 { 3286 /* skip over signature */ 3287 p+=4; 3288 key[0]=(char) (*p++); 3289 key[1]=(char) (*p++); 3290 key[2]=(char) (*p++); 3291 key[3]=(char) (*p++); 3292 key[4]='\0'; 3293 size=(unsigned int) (*p++) << 24; 3294 size|=(unsigned int) (*p++) << 16; 3295 size|=(unsigned int) (*p++) << 8; 3296 size|=(unsigned int) (*p++); 3297 size=size & 0xffffffff; 3298 remaining_length-=12; 3299 if ((size_t) size > remaining_length) 3300 return((const StringInfo *) NULL); 3301 found=MagickFalse; 3302 for (i=0; i < PSDAllowedLength; i++) 3303 { 3304 if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0) 3305 continue; 3306 3307 found=MagickTrue; 3308 break; 3309 } 3310 remaining_length-=(size_t) size; 3311 if (found == MagickFalse) 3312 { 3313 if (remaining_length > 0) 3314 p=(unsigned char *) memmove(p-12,p+size,remaining_length); 3315 continue; 3316 } 3317 length+=(size_t) size+12; 3318 p+=size; 3319 } 3320 profile=RemoveImageProfile(image,"psd:additional-info"); 3321 if (length == 0) 3322 return(DestroyStringInfo(profile)); 3323 SetStringInfoLength(profile,(const size_t) length); 3324 (void) SetImageProfile(image,"psd:additional-info",info,exception); 3325 return(profile); 3326 } 3327 3328 static MagickBooleanType WritePSDLayersInternal(Image *image, 3329 const ImageInfo *image_info,const PSDInfo *psd_info,size_t *layers_size, 3330 ExceptionInfo *exception) 3331 { 3332 char 3333 layer_name[MagickPathExtent]; 3334 3335 const char 3336 *property; 3337 3338 const StringInfo 3339 *info; 3340 3341 Image 3342 *base_image, 3343 *next_image; 3344 3345 MagickBooleanType 3346 status; 3347 3348 MagickOffsetType 3349 *layer_size_offsets, 3350 size_offset; 3351 3352 register ssize_t 3353 i; 3354 3355 size_t 3356 layer_count, 3357 layer_index, 3358 length, 3359 name_length, 3360 rounded_size, 3361 size; 3362 3363 status=MagickTrue; 3364 base_image=GetNextImageInList(image); 3365 if (base_image == (Image *) NULL) 3366 base_image=image; 3367 size=0; 3368 size_offset=TellBlob(image); 3369 (void) SetPSDSize(psd_info,image,0); 3370 layer_count=0; 3371 for (next_image=base_image; next_image != NULL; ) 3372 { 3373 layer_count++; 3374 next_image=GetNextImageInList(next_image); 3375 } 3376 if (image->alpha_trait != UndefinedPixelTrait) 3377 size+=WriteBlobShort(image,-(unsigned short) layer_count); 3378 else 3379 size+=WriteBlobShort(image,(unsigned short) layer_count); 3380 layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory( 3381 (size_t) layer_count,sizeof(MagickOffsetType)); 3382 if (layer_size_offsets == (MagickOffsetType *) NULL) 3383 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 3384 layer_index=0; 3385 for (next_image=base_image; next_image != NULL; ) 3386 { 3387 Image 3388 *mask; 3389 3390 unsigned char 3391 default_color; 3392 3393 unsigned short 3394 channels, 3395 total_channels; 3396 3397 mask=(Image *) NULL; 3398 property=GetImageArtifact(next_image,"psd:opacity-mask"); 3399 default_color=0; 3400 if (property != (const char *) NULL) 3401 { 3402 mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception); 3403 default_color=(unsigned char) (strlen(property) == 9 ? 255 : 0); 3404 } 3405 size+=WriteBlobSignedLong(image,(signed int) next_image->page.y); 3406 size+=WriteBlobSignedLong(image,(signed int) next_image->page.x); 3407 size+=WriteBlobSignedLong(image,(signed int) (next_image->page.y+ 3408 next_image->rows)); 3409 size+=WriteBlobSignedLong(image,(signed int) (next_image->page.x+ 3410 next_image->columns)); 3411 channels=1; 3412 if ((next_image->storage_class != PseudoClass) && 3413 (IsImageGray(next_image) == MagickFalse)) 3414 channels=(unsigned short) (next_image->colorspace == CMYKColorspace ? 4 : 3415 3); 3416 total_channels=channels; 3417 if (next_image->alpha_trait != UndefinedPixelTrait) 3418 total_channels++; 3419 if (mask != (Image *) NULL) 3420 total_channels++; 3421 size+=WriteBlobShort(image,total_channels); 3422 layer_size_offsets[layer_index++]=TellBlob(image); 3423 for (i=0; i < (ssize_t) channels; i++) 3424 size+=WriteChannelSize(psd_info,image,(signed short) i); 3425 if (next_image->alpha_trait != UndefinedPixelTrait) 3426 size+=WriteChannelSize(psd_info,image,-1); 3427 if (mask != (Image *) NULL) 3428 size+=WriteChannelSize(psd_info,image,-2); 3429 size+=WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :"8BIM"); 3430 size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(next_image)); 3431 property=GetImageArtifact(next_image,"psd:layer.opacity"); 3432 if (property != (const char *) NULL) 3433 { 3434 Quantum 3435 opacity; 3436 3437 opacity=(Quantum) StringToInteger(property); 3438 size+=WriteBlobByte(image,ScaleQuantumToChar(opacity)); 3439 (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception); 3440 } 3441 else 3442 size+=WriteBlobByte(image,255); 3443 size+=WriteBlobByte(image,0); 3444 size+=WriteBlobByte(image,(const unsigned char) 3445 (next_image->compose == NoCompositeOp ? 1 << 0x02 : 1)); /* layer properties - visible, etc. */ 3446 size+=WriteBlobByte(image,0); 3447 info=GetAdditionalInformation(image_info,next_image,exception); 3448 property=(const char *) GetImageProperty(next_image,"label",exception); 3449 if (property == (const char *) NULL) 3450 { 3451 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g", 3452 (double) layer_index); 3453 property=layer_name; 3454 } 3455 name_length=strlen(property)+1; 3456 if ((name_length % 4) != 0) 3457 name_length+=(4-(name_length % 4)); 3458 if (info != (const StringInfo *) NULL) 3459 name_length+=GetStringInfoLength(info); 3460 name_length+=8; 3461 if (mask != (Image *) NULL) 3462 name_length+=20; 3463 size+=WriteBlobLong(image,(unsigned int) name_length); 3464 if (mask == (Image *) NULL) 3465 size+=WriteBlobLong(image,0); 3466 else 3467 { 3468 if (mask->compose != NoCompositeOp) 3469 (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum( 3470 default_color),MagickTrue,exception); 3471 mask->page.y+=image->page.y; 3472 mask->page.x+=image->page.x; 3473 size+=WriteBlobLong(image,20); 3474 size+=WriteBlobSignedLong(image,(const signed int) mask->page.y); 3475 size+=WriteBlobSignedLong(image,(const signed int) mask->page.x); 3476 size+=WriteBlobSignedLong(image,(const signed int) (mask->rows+ 3477 mask->page.y)); 3478 size+=WriteBlobSignedLong(image,(const signed int) (mask->columns+ 3479 mask->page.x)); 3480 size+=WriteBlobByte(image,default_color); 3481 size+=WriteBlobByte(image,(const unsigned char) 3482 (mask->compose == NoCompositeOp ? 2 : 0)); 3483 size+=WriteBlobMSBShort(image,0); 3484 } 3485 size+=WriteBlobLong(image,0); 3486 size+=WritePascalString(image,property,4); 3487 if (info != (const StringInfo *) NULL) 3488 size+=WriteBlob(image,GetStringInfoLength(info), 3489 GetStringInfoDatum(info)); 3490 next_image=GetNextImageInList(next_image); 3491 } 3492 /* 3493 Now the image data! 3494 */ 3495 next_image=base_image; 3496 layer_index=0; 3497 while (next_image != NULL) 3498 { 3499 length=WritePSDChannels(psd_info,image_info,image,next_image, 3500 layer_size_offsets[layer_index++],MagickTrue,exception); 3501 if (length == 0) 3502 { 3503 status=MagickFalse; 3504 break; 3505 } 3506 size+=length; 3507 next_image=GetNextImageInList(next_image); 3508 } 3509 /* 3510 Write the total size 3511 */ 3512 if (layers_size != (size_t*) NULL) 3513 *layers_size=size; 3514 if ((size/2) != ((size+1)/2)) 3515 rounded_size=size+1; 3516 else 3517 rounded_size=size; 3518 (void) WritePSDSize(psd_info,image,rounded_size,size_offset); 3519 layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory( 3520 layer_size_offsets); 3521 /* 3522 Remove the opacity mask from the registry 3523 */ 3524 next_image=base_image; 3525 while (next_image != (Image *) NULL) 3526 { 3527 property=GetImageArtifact(next_image,"psd:opacity-mask"); 3528 if (property != (const char *) NULL) 3529 (void) DeleteImageRegistry(property); 3530 next_image=GetNextImageInList(next_image); 3531 } 3532 3533 return(status); 3534 } 3535 3536 ModuleExport MagickBooleanType WritePSDLayers(Image * image, 3537 const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception) 3538 { 3539 PolicyDomain 3540 domain; 3541 3542 PolicyRights 3543 rights; 3544 3545 domain=CoderPolicyDomain; 3546 rights=WritePolicyRights; 3547 if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse) 3548 return(MagickTrue); 3549 return WritePSDLayersInternal(image,image_info,psd_info,(size_t*) NULL, 3550 exception); 3551 } 3552 3553 static MagickBooleanType WritePSDImage(const ImageInfo *image_info, 3554 Image *image,ExceptionInfo *exception) 3555 { 3556 const StringInfo 3557 *icc_profile; 3558 3559 MagickBooleanType 3560 status; 3561 3562 PSDInfo 3563 psd_info; 3564 3565 register ssize_t 3566 i; 3567 3568 size_t 3569 length, 3570 num_channels, 3571 packet_size; 3572 3573 StringInfo 3574 *bim_profile; 3575 3576 /* 3577 Open image file. 3578 */ 3579 assert(image_info != (const ImageInfo *) NULL); 3580 assert(image_info->signature == MagickCoreSignature); 3581 assert(image != (Image *) NULL); 3582 assert(image->signature == MagickCoreSignature); 3583 if (image->debug != MagickFalse) 3584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 3585 assert(exception != (ExceptionInfo *) NULL); 3586 assert(exception->signature == MagickCoreSignature); 3587 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 3588 if (status == MagickFalse) 3589 return(status); 3590 packet_size=(size_t) (image->depth > 8 ? 6 : 3); 3591 if (image->alpha_trait != UndefinedPixelTrait) 3592 packet_size+=image->depth > 8 ? 2 : 1; 3593 psd_info.version=1; 3594 if ((LocaleCompare(image_info->magick,"PSB") == 0) || 3595 (image->columns > 30000) || (image->rows > 30000)) 3596 psd_info.version=2; 3597 (void) WriteBlob(image,4,(const unsigned char *) "8BPS"); 3598 (void) WriteBlobMSBShort(image,psd_info.version); /* version */ 3599 for (i=1; i <= 6; i++) 3600 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */ 3601 /* When the image has a color profile it won't be converted to gray scale */ 3602 if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) && 3603 (SetImageGray(image,exception) != MagickFalse)) 3604 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL); 3605 else 3606 if ((image_info->type != TrueColorType) && (image_info->type != 3607 TrueColorAlphaType) && (image->storage_class == PseudoClass)) 3608 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL); 3609 else 3610 { 3611 if (image->storage_class == PseudoClass) 3612 (void) SetImageStorageClass(image,DirectClass,exception); 3613 if (image->colorspace != CMYKColorspace) 3614 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL); 3615 else 3616 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL); 3617 } 3618 (void) WriteBlobMSBShort(image,(unsigned short) num_channels); 3619 (void) WriteBlobMSBLong(image,(unsigned int) image->rows); 3620 (void) WriteBlobMSBLong(image,(unsigned int) image->columns); 3621 if (IsImageGray(image) != MagickFalse) 3622 { 3623 MagickBooleanType 3624 monochrome; 3625 3626 /* 3627 Write depth & mode. 3628 */ 3629 monochrome=IsImageMonochrome(image) && (image->depth == 1) ? 3630 MagickTrue : MagickFalse; 3631 (void) WriteBlobMSBShort(image,(unsigned short) 3632 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8)); 3633 (void) WriteBlobMSBShort(image,(unsigned short) 3634 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode)); 3635 } 3636 else 3637 { 3638 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class == 3639 PseudoClass ? 8 : image->depth > 8 ? 16 : 8)); 3640 3641 if (((image_info->colorspace != UndefinedColorspace) || 3642 (image->colorspace != CMYKColorspace)) && 3643 (image_info->colorspace != CMYKColorspace)) 3644 { 3645 (void) TransformImageColorspace(image,sRGBColorspace,exception); 3646 (void) WriteBlobMSBShort(image,(unsigned short) 3647 (image->storage_class == PseudoClass ? IndexedMode : RGBMode)); 3648 } 3649 else 3650 { 3651 if (image->colorspace != CMYKColorspace) 3652 (void) TransformImageColorspace(image,CMYKColorspace,exception); 3653 (void) WriteBlobMSBShort(image,CMYKMode); 3654 } 3655 } 3656 if ((IsImageGray(image) != MagickFalse) || 3657 (image->storage_class == DirectClass) || (image->colors > 256)) 3658 (void) WriteBlobMSBLong(image,0); 3659 else 3660 { 3661 /* 3662 Write PSD raster colormap. 3663 */ 3664 (void) WriteBlobMSBLong(image,768); 3665 for (i=0; i < (ssize_t) image->colors; i++) 3666 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 3667 image->colormap[i].red))); 3668 for ( ; i < 256; i++) 3669 (void) WriteBlobByte(image,0); 3670 for (i=0; i < (ssize_t) image->colors; i++) 3671 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 3672 image->colormap[i].green))); 3673 for ( ; i < 256; i++) 3674 (void) WriteBlobByte(image,0); 3675 for (i=0; i < (ssize_t) image->colors; i++) 3676 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 3677 image->colormap[i].blue))); 3678 for ( ; i < 256; i++) 3679 (void) WriteBlobByte(image,0); 3680 } 3681 /* 3682 Image resource block. 3683 */ 3684 length=28; /* 0x03EB */ 3685 bim_profile=(StringInfo *) GetImageProfile(image,"8bim"); 3686 icc_profile=GetImageProfile(image,"icc"); 3687 if (bim_profile != (StringInfo *) NULL) 3688 { 3689 bim_profile=CloneStringInfo(bim_profile); 3690 if (icc_profile != (StringInfo *) NULL) 3691 RemoveICCProfileFromResourceBlock(bim_profile); 3692 RemoveResolutionFromResourceBlock(bim_profile); 3693 length+=PSDQuantum(GetStringInfoLength(bim_profile)); 3694 } 3695 if (icc_profile != (const StringInfo *) NULL) 3696 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12; 3697 (void) WriteBlobMSBLong(image,(unsigned int) length); 3698 WriteResolutionResourceBlock(image); 3699 if (bim_profile != (StringInfo *) NULL) 3700 { 3701 (void) WriteBlob(image,GetStringInfoLength(bim_profile), 3702 GetStringInfoDatum(bim_profile)); 3703 bim_profile=DestroyStringInfo(bim_profile); 3704 } 3705 if (icc_profile != (StringInfo *) NULL) 3706 { 3707 (void) WriteBlob(image,4,(const unsigned char *) "8BIM"); 3708 (void) WriteBlobMSBShort(image,0x0000040F); 3709 (void) WriteBlobMSBShort(image,0); 3710 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength( 3711 icc_profile)); 3712 (void) WriteBlob(image,GetStringInfoLength(icc_profile), 3713 GetStringInfoDatum(icc_profile)); 3714 if ((ssize_t) GetStringInfoLength(icc_profile) != PSDQuantum(GetStringInfoLength(icc_profile))) 3715 (void) WriteBlobByte(image,0); 3716 } 3717 if (status != MagickFalse) 3718 { 3719 MagickOffsetType 3720 size_offset; 3721 3722 size_t 3723 size; 3724 3725 size_offset=TellBlob(image); 3726 (void) SetPSDSize(&psd_info,image,0); 3727 status=WritePSDLayersInternal(image,image_info,&psd_info,&size, 3728 exception); 3729 size_offset+=WritePSDSize(&psd_info,image,size+ 3730 (psd_info.version == 1 ? 8 : 12),size_offset); 3731 } 3732 (void) WriteBlobMSBLong(image,0); /* user mask data */ 3733 /* 3734 Write composite image. 3735 */ 3736 if (status != MagickFalse) 3737 { 3738 CompressionType 3739 compression; 3740 3741 compression=image->compression; 3742 if (image->compression == ZipCompression) 3743 image->compression=RLECompression; 3744 if (image_info->compression != UndefinedCompression) 3745 image->compression=image_info->compression; 3746 if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse, 3747 exception) == 0) 3748 status=MagickFalse; 3749 image->compression=compression; 3750 } 3751 (void) CloseBlob(image); 3752 return(status); 3753 } 3754