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-2016 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 % http://www.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 % 40 */ 41 42 /* 44 Include declarations. 45 */ 46 #include "MagickCore/studio.h" 47 #include "MagickCore/artifact.h" 48 #include "MagickCore/attribute.h" 49 #include "MagickCore/blob.h" 50 #include "MagickCore/blob-private.h" 51 #include "MagickCore/cache.h" 52 #include "MagickCore/channel.h" 53 #include "MagickCore/colormap.h" 54 #include "MagickCore/colormap-private.h" 55 #include "MagickCore/colorspace.h" 56 #include "MagickCore/colorspace-private.h" 57 #include "MagickCore/constitute.h" 58 #include "MagickCore/enhance.h" 59 #include "MagickCore/exception.h" 60 #include "MagickCore/exception-private.h" 61 #include "MagickCore/image.h" 62 #include "MagickCore/image-private.h" 63 #include "MagickCore/list.h" 64 #include "MagickCore/log.h" 65 #include "MagickCore/magick.h" 66 #include "MagickCore/memory_.h" 67 #include "MagickCore/module.h" 68 #include "MagickCore/monitor-private.h" 69 #include "MagickCore/option.h" 70 #include "MagickCore/pixel.h" 71 #include "MagickCore/pixel-accessor.h" 72 #include "MagickCore/profile.h" 73 #include "MagickCore/property.h" 74 #include "MagickCore/quantum-private.h" 75 #include "MagickCore/static.h" 76 #include "MagickCore/string_.h" 77 #include "MagickCore/thread-private.h" 78 #ifdef MAGICKCORE_ZLIB_DELEGATE 79 #include <zlib.h> 80 #endif 81 #include "psd-private.h" 82 83 /* 84 Define declaractions. 85 */ 86 #define MaxPSDChannels 56 87 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2) 88 89 /* 91 Enumerated declaractions. 92 */ 93 typedef enum 94 { 95 Raw = 0, 96 RLE = 1, 97 ZipWithoutPrediction = 2, 98 ZipWithPrediction = 3 99 } PSDCompressionType; 100 101 typedef enum 102 { 103 BitmapMode = 0, 104 GrayscaleMode = 1, 105 IndexedMode = 2, 106 RGBMode = 3, 107 CMYKMode = 4, 108 MultichannelMode = 7, 109 DuotoneMode = 8, 110 LabMode = 9 111 } PSDImageType; 112 113 /* 115 Typedef declaractions. 116 */ 117 typedef struct _ChannelInfo 118 { 119 short int 120 type; 121 122 size_t 123 size; 124 } ChannelInfo; 125 126 typedef struct _MaskInfo 127 { 128 Image 129 *image; 130 131 RectangleInfo 132 page; 133 134 unsigned char 135 background, 136 flags; 137 } MaskInfo; 138 139 typedef struct _LayerInfo 140 { 141 ChannelInfo 142 channel_info[MaxPSDChannels]; 143 144 char 145 blendkey[4]; 146 147 Image 148 *image; 149 150 MaskInfo 151 mask; 152 153 Quantum 154 opacity; 155 156 RectangleInfo 157 page; 158 159 size_t 160 offset_x, 161 offset_y; 162 163 unsigned char 164 clipping, 165 flags, 166 name[256], 167 visible; 168 169 unsigned short 170 channels; 171 } LayerInfo; 172 173 /* 174 Forward declarations. 175 */ 176 static MagickBooleanType 177 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *); 178 179 /* 181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 182 % % 183 % % 184 % % 185 % I s P S D % 186 % % 187 % % 188 % % 189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 190 % 191 % IsPSD()() returns MagickTrue if the image format type, identified by the 192 % magick string, is PSD. 193 % 194 % The format of the IsPSD method is: 195 % 196 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length) 197 % 198 % A description of each parameter follows: 199 % 200 % o magick: compare image format pattern against these bytes. 201 % 202 % o length: Specifies the length of the magick string. 203 % 204 */ 205 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length) 206 { 207 if (length < 4) 208 return(MagickFalse); 209 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0) 210 return(MagickTrue); 211 return(MagickFalse); 212 } 213 214 /* 216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 217 % % 218 % % 219 % % 220 % R e a d P S D I m a g e % 221 % % 222 % % 223 % % 224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 225 % 226 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It 227 % allocates the memory necessary for the new Image structure and returns a 228 % pointer to the new image. 229 % 230 % The format of the ReadPSDImage method is: 231 % 232 % Image *ReadPSDImage(image_info,ExceptionInfo *exception) 233 % 234 % A description of each parameter follows: 235 % 236 % o image_info: the image info. 237 % 238 % o exception: return any errors or warnings in this structure. 239 % 240 */ 241 242 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op) 243 { 244 const char 245 *blend_mode; 246 247 switch (op) 248 { 249 case ColorBurnCompositeOp: blend_mode = "idiv"; break; 250 case ColorDodgeCompositeOp: blend_mode = "div "; break; 251 case ColorizeCompositeOp: blend_mode = "colr"; break; 252 case DarkenCompositeOp: blend_mode = "dark"; break; 253 case DifferenceCompositeOp: blend_mode = "diff"; break; 254 case DissolveCompositeOp: blend_mode = "diss"; break; 255 case ExclusionCompositeOp: blend_mode = "smud"; break; 256 case HardLightCompositeOp: blend_mode = "hLit"; break; 257 case HardMixCompositeOp: blend_mode = "hMix"; break; 258 case HueCompositeOp: blend_mode = "hue "; break; 259 case LightenCompositeOp: blend_mode = "lite"; break; 260 case LinearBurnCompositeOp: blend_mode = "lbrn"; break; 261 case LinearDodgeCompositeOp:blend_mode = "lddg"; break; 262 case LinearLightCompositeOp:blend_mode = "lLit"; break; 263 case LuminizeCompositeOp: blend_mode = "lum "; break; 264 case MultiplyCompositeOp: blend_mode = "mul "; break; 265 case OverCompositeOp: blend_mode = "norm"; break; 266 case OverlayCompositeOp: blend_mode = "over"; break; 267 case PinLightCompositeOp: blend_mode = "pLit"; break; 268 case SaturateCompositeOp: blend_mode = "sat "; break; 269 case ScreenCompositeOp: blend_mode = "scrn"; break; 270 case SoftLightCompositeOp: blend_mode = "sLit"; break; 271 case VividLightCompositeOp: blend_mode = "vLit"; break; 272 default: blend_mode = "norm"; 273 } 274 return(blend_mode); 275 } 276 277 /* 278 For some reason Photoshop seems to blend semi-transparent pixels with white. 279 This method reverts the blending. This can be disabled by setting the 280 option 'psd:alpha-unblend' to off. 281 */ 282 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info, 283 Image *image,ExceptionInfo* exception) 284 { 285 const char 286 *option; 287 288 MagickBooleanType 289 status; 290 291 ssize_t 292 y; 293 294 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace) 295 return(MagickTrue); 296 option=GetImageOption(image_info,"psd:alpha-unblend"); 297 if (IsStringFalse(option) != MagickFalse) 298 return(MagickTrue); 299 status=MagickTrue; 300 #if defined(MAGICKCORE_OPENMP_SUPPORT) 301 #pragma omp parallel for schedule(static,4) shared(status) \ 302 magick_threads(image,image,image->rows,1) 303 #endif 304 for (y=0; y < (ssize_t) image->rows; y++) 305 { 306 register Quantum 307 *magick_restrict q; 308 309 register ssize_t 310 x; 311 312 if (status == MagickFalse) 313 continue; 314 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 315 if (q == (Quantum *) NULL) 316 { 317 status=MagickFalse; 318 continue; 319 } 320 for (x=0; x < (ssize_t) image->columns; x++) 321 { 322 double 323 gamma; 324 325 register ssize_t 326 i; 327 328 gamma=QuantumScale*GetPixelAlpha(image, q); 329 if (gamma != 0.0 && gamma != 1.0) 330 { 331 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 332 { 333 PixelChannel channel=GetPixelChannelChannel(image,i); 334 if (channel != AlphaPixelChannel) 335 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma); 336 } 337 } 338 q+=GetPixelChannels(image); 339 } 340 if (SyncAuthenticPixels(image,exception) == MagickFalse) 341 status=MagickFalse; 342 } 343 344 return(status); 345 } 346 347 static inline CompressionType ConvertPSDCompression( 348 PSDCompressionType compression) 349 { 350 switch (compression) 351 { 352 case RLE: 353 return RLECompression; 354 case ZipWithPrediction: 355 case ZipWithoutPrediction: 356 return ZipCompression; 357 default: 358 return NoCompression; 359 } 360 } 361 362 static MagickBooleanType CorrectPSDOpacity(LayerInfo *layer_info, 363 ExceptionInfo *exception) 364 { 365 MagickBooleanType 366 status; 367 368 ssize_t 369 y; 370 371 if (layer_info->opacity == OpaqueAlpha) 372 return(MagickTrue); 373 374 layer_info->image->alpha_trait=BlendPixelTrait; 375 status=MagickTrue; 376 #if defined(MAGICKCORE_OPENMP_SUPPORT) 377 #pragma omp parallel for schedule(static,4) shared(status) \ 378 magick_threads(layer_info->image,layer_info->image,layer_info->image->rows,1) 379 #endif 380 for (y=0; y < (ssize_t) layer_info->image->rows; y++) 381 { 382 register Quantum 383 *magick_restrict q; 384 385 register ssize_t 386 x; 387 388 if (status == MagickFalse) 389 continue; 390 q=GetAuthenticPixels(layer_info->image,0,y,layer_info->image->columns,1, 391 exception); 392 if (q == (Quantum *)NULL) 393 { 394 status=MagickFalse; 395 continue; 396 } 397 for (x=0; x < (ssize_t) layer_info->image->columns; x++) 398 { 399 SetPixelAlpha(layer_info->image,(Quantum) (QuantumScale*(GetPixelAlpha( 400 layer_info->image,q))*layer_info->opacity),q); 401 q+=GetPixelChannels(layer_info->image); 402 } 403 if (SyncAuthenticPixels(layer_info->image,exception) == MagickFalse) 404 status=MagickFalse; 405 } 406 407 return(status); 408 } 409 410 static ssize_t DecodePSDPixels(const size_t number_compact_pixels, 411 const unsigned char *compact_pixels,const ssize_t depth, 412 const size_t number_pixels,unsigned char *pixels) 413 { 414 #define CheckNumberCompactPixels \ 415 if (packets == 0) \ 416 return(i); \ 417 packets-- 418 419 #define CheckNumberPixels(count) \ 420 if (((ssize_t) i + count) > (ssize_t) number_pixels) \ 421 return(i); \ 422 i+=count 423 424 int 425 pixel; 426 427 register ssize_t 428 i, 429 j; 430 431 size_t 432 length; 433 434 ssize_t 435 packets; 436 437 packets=(ssize_t) number_compact_pixels; 438 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); ) 439 { 440 packets--; 441 length=(size_t) (*compact_pixels++); 442 if (length == 128) 443 continue; 444 if (length > 128) 445 { 446 length=256-length+1; 447 CheckNumberCompactPixels; 448 pixel=(*compact_pixels++); 449 for (j=0; j < (ssize_t) length; j++) 450 { 451 switch (depth) 452 { 453 case 1: 454 { 455 CheckNumberPixels(8); 456 *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U; 457 *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U; 458 *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U; 459 *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U; 460 *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U; 461 *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U; 462 *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U; 463 *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U; 464 break; 465 } 466 case 2: 467 { 468 CheckNumberPixels(4); 469 *pixels++=(unsigned char) ((pixel >> 6) & 0x03); 470 *pixels++=(unsigned char) ((pixel >> 4) & 0x03); 471 *pixels++=(unsigned char) ((pixel >> 2) & 0x03); 472 *pixels++=(unsigned char) ((pixel & 0x03) & 0x03); 473 break; 474 } 475 case 4: 476 { 477 CheckNumberPixels(2); 478 *pixels++=(unsigned char) ((pixel >> 4) & 0xff); 479 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff); 480 break; 481 } 482 default: 483 { 484 CheckNumberPixels(1); 485 *pixels++=(unsigned char) pixel; 486 break; 487 } 488 } 489 } 490 continue; 491 } 492 length++; 493 for (j=0; j < (ssize_t) length; j++) 494 { 495 CheckNumberCompactPixels; 496 switch (depth) 497 { 498 case 1: 499 { 500 CheckNumberPixels(8); 501 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U; 502 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U; 503 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U; 504 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U; 505 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U; 506 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U; 507 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U; 508 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U; 509 break; 510 } 511 case 2: 512 { 513 CheckNumberPixels(4); 514 *pixels++=(*compact_pixels >> 6) & 0x03; 515 *pixels++=(*compact_pixels >> 4) & 0x03; 516 *pixels++=(*compact_pixels >> 2) & 0x03; 517 *pixels++=(*compact_pixels & 0x03) & 0x03; 518 break; 519 } 520 case 4: 521 { 522 CheckNumberPixels(2); 523 *pixels++=(*compact_pixels >> 4) & 0xff; 524 *pixels++=(*compact_pixels & 0x0f) & 0xff; 525 break; 526 } 527 default: 528 { 529 CheckNumberPixels(1); 530 *pixels++=(*compact_pixels); 531 break; 532 } 533 } 534 compact_pixels++; 535 } 536 } 537 return(i); 538 } 539 540 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info, 541 const ssize_t number_layers) 542 { 543 ssize_t 544 i; 545 546 for (i=0; i<number_layers; i++) 547 { 548 if (layer_info[i].image != (Image *) NULL) 549 layer_info[i].image=DestroyImage(layer_info[i].image); 550 if (layer_info[i].mask.image != (Image *) NULL) 551 layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image); 552 } 553 554 return (LayerInfo *) RelinquishMagickMemory(layer_info); 555 } 556 557 static inline size_t GetPSDPacketSize(Image *image) 558 { 559 if (image->storage_class == PseudoClass) 560 { 561 if (image->colors > 256) 562 return(2); 563 else if (image->depth > 8) 564 return(2); 565 } 566 else 567 if (image->depth > 8) 568 return(2); 569 570 return(1); 571 } 572 573 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image) 574 { 575 if (psd_info->version == 1) 576 return((MagickSizeType) ReadBlobLong(image)); 577 return((MagickSizeType) ReadBlobLongLong(image)); 578 } 579 580 static inline size_t GetPSDRowSize(Image *image) 581 { 582 if (image->depth == 1) 583 return(((image->columns+7)/8)*GetPSDPacketSize(image)); 584 else 585 return(image->columns*GetPSDPacketSize(image)); 586 } 587 588 static const char *ModeToString(PSDImageType type) 589 { 590 switch (type) 591 { 592 case BitmapMode: return "Bitmap"; 593 case GrayscaleMode: return "Grayscale"; 594 case IndexedMode: return "Indexed"; 595 case RGBMode: return "RGB"; 596 case CMYKMode: return "CMYK"; 597 case MultichannelMode: return "Multichannel"; 598 case DuotoneMode: return "Duotone"; 599 case LabMode: return "L*A*B"; 600 default: return "unknown"; 601 } 602 } 603 604 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception) 605 { 606 ChannelType 607 channel_mask; 608 609 MagickBooleanType 610 status; 611 612 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~ 613 AlphaChannel)); 614 status=NegateImage(image,MagickFalse,exception); 615 (void) SetImageChannelMask(image,channel_mask); 616 return(status); 617 } 618 619 static void ParseImageResourceBlocks(Image *image, 620 const unsigned char *blocks,size_t length, 621 MagickBooleanType *has_merged_image,ExceptionInfo *exception) 622 { 623 const unsigned char 624 *p; 625 626 StringInfo 627 *profile; 628 629 unsigned int 630 count, 631 long_sans; 632 633 unsigned short 634 id, 635 short_sans; 636 637 if (length < 16) 638 return; 639 profile=BlobToStringInfo((const unsigned char *) NULL,length); 640 SetStringInfoDatum(profile,blocks); 641 (void) SetImageProfile(image,"8bim",profile,exception); 642 profile=DestroyStringInfo(profile); 643 for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); ) 644 { 645 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 646 break; 647 p=PushLongPixel(MSBEndian,p,&long_sans); 648 p=PushShortPixel(MSBEndian,p,&id); 649 p=PushShortPixel(MSBEndian,p,&short_sans); 650 p=PushLongPixel(MSBEndian,p,&count); 651 if ((p+count) > (blocks+length-16)) 652 return; 653 switch (id) 654 { 655 case 0x03ed: 656 { 657 char 658 value[MagickPathExtent]; 659 660 unsigned short 661 resolution; 662 663 /* 664 Resolution info. 665 */ 666 p=PushShortPixel(MSBEndian,p,&resolution); 667 image->resolution.x=(double) resolution; 668 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.x); 669 (void) SetImageProperty(image,"tiff:XResolution",value,exception); 670 p=PushShortPixel(MSBEndian,p,&short_sans); 671 p=PushShortPixel(MSBEndian,p,&short_sans); 672 p=PushShortPixel(MSBEndian,p,&short_sans); 673 p=PushShortPixel(MSBEndian,p,&resolution); 674 image->resolution.y=(double) resolution; 675 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.y); 676 (void) SetImageProperty(image,"tiff:YResolution",value,exception); 677 p=PushShortPixel(MSBEndian,p,&short_sans); 678 p=PushShortPixel(MSBEndian,p,&short_sans); 679 p=PushShortPixel(MSBEndian,p,&short_sans); 680 image->units=PixelsPerInchResolution; 681 break; 682 } 683 case 0x0421: 684 { 685 if (*(p+4) == 0) 686 *has_merged_image=MagickFalse; 687 p+=count; 688 break; 689 } 690 default: 691 { 692 p+=count; 693 break; 694 } 695 } 696 if ((count & 0x01) != 0) 697 p++; 698 } 699 return; 700 } 701 702 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode) 703 { 704 if (mode == (const char *) NULL) 705 return(OverCompositeOp); 706 if (LocaleNCompare(mode,"norm",4) == 0) 707 return(OverCompositeOp); 708 if (LocaleNCompare(mode,"mul ",4) == 0) 709 return(MultiplyCompositeOp); 710 if (LocaleNCompare(mode,"diss",4) == 0) 711 return(DissolveCompositeOp); 712 if (LocaleNCompare(mode,"diff",4) == 0) 713 return(DifferenceCompositeOp); 714 if (LocaleNCompare(mode,"dark",4) == 0) 715 return(DarkenCompositeOp); 716 if (LocaleNCompare(mode,"lite",4) == 0) 717 return(LightenCompositeOp); 718 if (LocaleNCompare(mode,"hue ",4) == 0) 719 return(HueCompositeOp); 720 if (LocaleNCompare(mode,"sat ",4) == 0) 721 return(SaturateCompositeOp); 722 if (LocaleNCompare(mode,"colr",4) == 0) 723 return(ColorizeCompositeOp); 724 if (LocaleNCompare(mode,"lum ",4) == 0) 725 return(LuminizeCompositeOp); 726 if (LocaleNCompare(mode,"scrn",4) == 0) 727 return(ScreenCompositeOp); 728 if (LocaleNCompare(mode,"over",4) == 0) 729 return(OverlayCompositeOp); 730 if (LocaleNCompare(mode,"hLit",4) == 0) 731 return(HardLightCompositeOp); 732 if (LocaleNCompare(mode,"sLit",4) == 0) 733 return(SoftLightCompositeOp); 734 if (LocaleNCompare(mode,"smud",4) == 0) 735 return(ExclusionCompositeOp); 736 if (LocaleNCompare(mode,"div ",4) == 0) 737 return(ColorDodgeCompositeOp); 738 if (LocaleNCompare(mode,"idiv",4) == 0) 739 return(ColorBurnCompositeOp); 740 if (LocaleNCompare(mode,"lbrn",4) == 0) 741 return(LinearBurnCompositeOp); 742 if (LocaleNCompare(mode,"lddg",4) == 0) 743 return(LinearDodgeCompositeOp); 744 if (LocaleNCompare(mode,"lLit",4) == 0) 745 return(LinearLightCompositeOp); 746 if (LocaleNCompare(mode,"vLit",4) == 0) 747 return(VividLightCompositeOp); 748 if (LocaleNCompare(mode,"pLit",4) == 0) 749 return(PinLightCompositeOp); 750 if (LocaleNCompare(mode,"hMix",4) == 0) 751 return(HardMixCompositeOp); 752 return(OverCompositeOp); 753 } 754 755 static inline void ReversePSDString(Image *image,char *p,size_t length) 756 { 757 char 758 *q; 759 760 if (image->endian == MSBEndian) 761 return; 762 763 q=p+length; 764 for(--q; p < q; ++p, --q) 765 { 766 *p = *p ^ *q, 767 *q = *p ^ *q, 768 *p = *p ^ *q; 769 } 770 } 771 772 static inline void SetPSDPixel(Image *image,const size_t channels, 773 const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q, 774 ExceptionInfo *exception) 775 { 776 if (image->storage_class == PseudoClass) 777 { 778 if (packet_size == 1) 779 SetPixelIndex(image,ScaleQuantumToChar(pixel),q); 780 else 781 SetPixelIndex(image,ScaleQuantumToShort(pixel),q); 782 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) 783 ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q); 784 return; 785 } 786 switch (type) 787 { 788 case -1: 789 { 790 SetPixelAlpha(image, pixel,q); 791 break; 792 } 793 case -2: 794 case 0: 795 { 796 SetPixelRed(image,pixel,q); 797 if (channels == 1 || type == -2) 798 SetPixelGray(image,pixel,q); 799 break; 800 } 801 case 1: 802 { 803 if (image->storage_class == PseudoClass) 804 SetPixelAlpha(image,pixel,q); 805 else 806 SetPixelGreen(image,pixel,q); 807 break; 808 } 809 case 2: 810 { 811 if (image->storage_class == PseudoClass) 812 SetPixelAlpha(image,pixel,q); 813 else 814 SetPixelBlue(image,pixel,q); 815 break; 816 } 817 case 3: 818 { 819 if (image->colorspace == CMYKColorspace) 820 SetPixelBlack(image,pixel,q); 821 else 822 if (image->alpha_trait != UndefinedPixelTrait) 823 SetPixelAlpha(image,pixel,q); 824 break; 825 } 826 case 4: 827 { 828 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) && 829 (channels > 3)) 830 break; 831 if (image->alpha_trait != UndefinedPixelTrait) 832 SetPixelAlpha(image,pixel,q); 833 break; 834 } 835 } 836 } 837 838 static MagickBooleanType ReadPSDChannelPixels(Image *image, 839 const size_t channels,const size_t row,const ssize_t type, 840 const unsigned char *pixels,ExceptionInfo *exception) 841 { 842 Quantum 843 pixel; 844 845 register const unsigned char 846 *p; 847 848 register Quantum 849 *q; 850 851 register ssize_t 852 x; 853 854 size_t 855 packet_size; 856 857 unsigned short 858 nibble; 859 860 p=pixels; 861 q=GetAuthenticPixels(image,0,row,image->columns,1,exception); 862 if (q == (Quantum *) NULL) 863 return MagickFalse; 864 packet_size=GetPSDPacketSize(image); 865 for (x=0; x < (ssize_t) image->columns; x++) 866 { 867 if (packet_size == 1) 868 pixel=ScaleCharToQuantum(*p++); 869 else 870 { 871 p=PushShortPixel(MSBEndian,p,&nibble); 872 pixel=ScaleShortToQuantum(nibble); 873 } 874 if (image->depth > 1) 875 { 876 SetPSDPixel(image,channels,type,packet_size,pixel,q,exception); 877 q+=GetPixelChannels(image); 878 } 879 else 880 { 881 ssize_t 882 bit, 883 number_bits; 884 885 number_bits=image->columns-x; 886 if (number_bits > 8) 887 number_bits=8; 888 for (bit = 0; bit < number_bits; bit++) 889 { 890 SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel) 891 & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception); 892 q+=GetPixelChannels(image); 893 x++; 894 } 895 if (x != (ssize_t) image->columns) 896 x--; 897 continue; 898 } 899 } 900 return(SyncAuthenticPixels(image,exception)); 901 } 902 903 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels, 904 const ssize_t type,ExceptionInfo *exception) 905 { 906 MagickBooleanType 907 status; 908 909 size_t 910 count, 911 row_size; 912 913 ssize_t 914 y; 915 916 unsigned char 917 *pixels; 918 919 if (image->debug != MagickFalse) 920 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 921 " layer data is RAW"); 922 923 row_size=GetPSDRowSize(image); 924 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels)); 925 if (pixels == (unsigned char *) NULL) 926 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 927 image->filename); 928 929 status=MagickTrue; 930 for (y=0; y < (ssize_t) image->rows; y++) 931 { 932 status=MagickFalse; 933 934 count=ReadBlob(image,row_size,pixels); 935 if (count != row_size) 936 break; 937 938 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception); 939 if (status == MagickFalse) 940 break; 941 } 942 943 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 944 return(status); 945 } 946 947 static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image, 948 const PSDInfo *psd_info,const size_t size) 949 { 950 MagickOffsetType 951 *offsets; 952 953 ssize_t 954 y; 955 956 offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets)); 957 if(offsets != (MagickOffsetType *) NULL) 958 { 959 for (y=0; y < (ssize_t) size; y++) 960 { 961 if (psd_info->version == 1) 962 offsets[y]=(MagickOffsetType) ReadBlobShort(image); 963 else 964 offsets[y]=(MagickOffsetType) ReadBlobLong(image); 965 } 966 } 967 return offsets; 968 } 969 970 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info, 971 const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception) 972 { 973 MagickBooleanType 974 status; 975 976 size_t 977 length, 978 row_size; 979 980 ssize_t 981 count, 982 y; 983 984 unsigned char 985 *compact_pixels, 986 *pixels; 987 988 if (image->debug != MagickFalse) 989 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 990 " layer data is RLE compressed"); 991 992 row_size=GetPSDRowSize(image); 993 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels)); 994 if (pixels == (unsigned char *) NULL) 995 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 996 image->filename); 997 998 length=0; 999 for (y=0; y < (ssize_t) image->rows; y++) 1000 if ((MagickOffsetType) length < offsets[y]) 1001 length=(size_t) offsets[y]; 1002 1003 if (length > row_size + 256) // arbitrary number 1004 { 1005 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1006 ThrowBinaryException(ResourceLimitError,"InvalidLength", 1007 image->filename); 1008 } 1009 1010 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels)); 1011 if (compact_pixels == (unsigned char *) NULL) 1012 { 1013 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1014 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1015 image->filename); 1016 } 1017 1018 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels)); 1019 1020 status=MagickTrue; 1021 for (y=0; y < (ssize_t) image->rows; y++) 1022 { 1023 status=MagickFalse; 1024 1025 count=ReadBlob(image,(size_t) offsets[y],compact_pixels); 1026 if (count != (ssize_t) offsets[y]) 1027 break; 1028 1029 count=DecodePSDPixels((size_t) offsets[y],compact_pixels, 1030 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels); 1031 if (count != (ssize_t) row_size) 1032 break; 1033 1034 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels, 1035 exception); 1036 if (status == MagickFalse) 1037 break; 1038 } 1039 1040 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1041 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1042 return(status); 1043 } 1044 1045 #ifdef MAGICKCORE_ZLIB_DELEGATE 1046 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels, 1047 const ssize_t type,const PSDCompressionType compression, 1048 const size_t compact_size,ExceptionInfo *exception) 1049 { 1050 MagickBooleanType 1051 status; 1052 1053 register unsigned char 1054 *p; 1055 1056 size_t 1057 count, 1058 length, 1059 packet_size, 1060 row_size; 1061 1062 ssize_t 1063 y; 1064 1065 unsigned char 1066 *compact_pixels, 1067 *pixels; 1068 1069 z_stream 1070 stream; 1071 1072 if (image->debug != MagickFalse) 1073 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1074 " layer data is ZIP compressed"); 1075 1076 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size, 1077 sizeof(*compact_pixels)); 1078 if (compact_pixels == (unsigned char *) NULL) 1079 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1080 image->filename); 1081 1082 packet_size=GetPSDPacketSize(image); 1083 row_size=image->columns*packet_size; 1084 count=image->rows*row_size; 1085 1086 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels)); 1087 if (pixels == (unsigned char *) NULL) 1088 { 1089 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1090 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1091 image->filename); 1092 } 1093 1094 ResetMagickMemory(&stream, 0, sizeof(z_stream)); 1095 stream.data_type=Z_BINARY; 1096 (void) ReadBlob(image,compact_size,compact_pixels); 1097 1098 stream.next_in=(Bytef *)compact_pixels; 1099 stream.avail_in=(unsigned int) compact_size; 1100 stream.next_out=(Bytef *)pixels; 1101 stream.avail_out=(unsigned int) count; 1102 1103 if(inflateInit(&stream) == Z_OK) 1104 { 1105 int 1106 ret; 1107 1108 while (stream.avail_out > 0) 1109 { 1110 ret=inflate(&stream, Z_SYNC_FLUSH); 1111 if (ret != Z_OK && ret != Z_STREAM_END) 1112 { 1113 compact_pixels=(unsigned char *) RelinquishMagickMemory( 1114 compact_pixels); 1115 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1116 return(MagickFalse); 1117 } 1118 } 1119 } 1120 1121 if (compression == ZipWithPrediction) 1122 { 1123 p=pixels; 1124 while(count > 0) 1125 { 1126 length=image->columns; 1127 while(--length) 1128 { 1129 if (packet_size == 2) 1130 { 1131 p[2]+=p[0]+((p[1]+p[3]) >> 8); 1132 p[3]+=p[1]; 1133 } 1134 else 1135 *(p+1)+=*p; 1136 p+=packet_size; 1137 } 1138 p+=packet_size; 1139 count-=row_size; 1140 } 1141 } 1142 1143 status=MagickTrue; 1144 p=pixels; 1145 for (y=0; y < (ssize_t) image->rows; y++) 1146 { 1147 status=ReadPSDChannelPixels(image,channels,y,type,p,exception); 1148 if (status == MagickFalse) 1149 break; 1150 1151 p+=row_size; 1152 } 1153 1154 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 1155 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1156 return(status); 1157 } 1158 #endif 1159 1160 static MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info, 1161 LayerInfo* layer_info,const size_t channel, 1162 const PSDCompressionType compression,ExceptionInfo *exception) 1163 { 1164 Image 1165 *channel_image, 1166 *mask; 1167 1168 MagickOffsetType 1169 offset; 1170 1171 MagickBooleanType 1172 status; 1173 1174 channel_image=image; 1175 mask=(Image *) NULL; 1176 if (layer_info->channel_info[channel].type < -1) 1177 { 1178 /* 1179 Ignore mask that is not a user supplied layer mask, if the mask is 1180 disabled or if the flags have unsupported values. 1181 */ 1182 if (layer_info->channel_info[channel].type != -2 || 1183 (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02)) 1184 { 1185 SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR); 1186 return(MagickTrue); 1187 } 1188 mask=CloneImage(image,layer_info->mask.page.width, 1189 layer_info->mask.page.height,MagickFalse,exception); 1190 SetImageType(mask,GrayscaleType,exception); 1191 channel_image=mask; 1192 } 1193 1194 offset=TellBlob(image); 1195 status=MagickTrue; 1196 switch(compression) 1197 { 1198 case Raw: 1199 status=ReadPSDChannelRaw(channel_image,psd_info->channels, 1200 layer_info->channel_info[channel].type,exception); 1201 break; 1202 case RLE: 1203 { 1204 MagickOffsetType 1205 *offsets; 1206 1207 offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows); 1208 if (offsets == (MagickOffsetType *) NULL) 1209 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1210 image->filename); 1211 status=ReadPSDChannelRLE(channel_image,psd_info, 1212 layer_info->channel_info[channel].type,offsets,exception); 1213 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets); 1214 } 1215 break; 1216 case ZipWithPrediction: 1217 case ZipWithoutPrediction: 1218 #ifdef MAGICKCORE_ZLIB_DELEGATE 1219 status=ReadPSDChannelZip(channel_image,layer_info->channels, 1220 layer_info->channel_info[channel].type,compression, 1221 layer_info->channel_info[channel].size-2,exception); 1222 #else 1223 (void) ThrowMagickException(exception,GetMagickModule(), 1224 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn", 1225 "'%s' (ZLIB)",image->filename); 1226 #endif 1227 break; 1228 default: 1229 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning, 1230 "CompressionNotSupported","'%.20g'",(double) compression); 1231 break; 1232 } 1233 1234 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET); 1235 if (status == MagickFalse) 1236 { 1237 if (mask != (Image *) NULL) 1238 DestroyImage(mask); 1239 ThrowBinaryException(CoderError,"UnableToDecompressImage", 1240 image->filename); 1241 } 1242 if (mask != (Image *) NULL) 1243 { 1244 if (status != MagickFalse) 1245 { 1246 PixelInfo 1247 color; 1248 1249 layer_info->mask.image=CloneImage(image,image->columns,image->rows, 1250 MagickTrue,exception); 1251 layer_info->mask.image->alpha_trait=UndefinedPixelTrait; 1252 GetPixelInfo(layer_info->mask.image,&color); 1253 color.red=layer_info->mask.background == 0 ? 0 : QuantumRange; 1254 SetImageColor(layer_info->mask.image,&color,exception); 1255 (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp, 1256 MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y, 1257 exception); 1258 } 1259 DestroyImage(mask); 1260 } 1261 1262 return(status); 1263 } 1264 1265 static MagickBooleanType ReadPSDLayer(Image *image,const PSDInfo *psd_info, 1266 LayerInfo* layer_info,ExceptionInfo *exception) 1267 { 1268 char 1269 message[MagickPathExtent]; 1270 1271 MagickBooleanType 1272 status; 1273 1274 PSDCompressionType 1275 compression; 1276 1277 ssize_t 1278 j; 1279 1280 if (image->debug != MagickFalse) 1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1282 " setting up new layer image"); 1283 (void) SetImageBackgroundColor(layer_info->image,exception); 1284 layer_info->image->compose=PSDBlendModeToCompositeOperator( 1285 layer_info->blendkey); 1286 if (layer_info->visible == MagickFalse) 1287 layer_info->image->compose=NoCompositeOp; 1288 if (psd_info->mode == CMYKMode) 1289 SetImageColorspace(layer_info->image,CMYKColorspace,exception); 1290 if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) || 1291 (psd_info->mode == DuotoneMode)) 1292 SetImageColorspace(layer_info->image,GRAYColorspace,exception); 1293 /* 1294 Set up some hidden attributes for folks that need them. 1295 */ 1296 (void) FormatLocaleString(message,MagickPathExtent,"%.20g", 1297 (double) layer_info->page.x); 1298 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message); 1299 (void) FormatLocaleString(message,MagickPathExtent,"%.20g", 1300 (double) layer_info->page.y); 1301 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message); 1302 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double) 1303 layer_info->opacity); 1304 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message); 1305 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name, 1306 exception); 1307 1308 status=MagickTrue; 1309 for (j=0; j < (ssize_t) layer_info->channels; j++) 1310 { 1311 if (image->debug != MagickFalse) 1312 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1313 " reading data for channel %.20g",(double) j); 1314 1315 compression=(PSDCompressionType) ReadBlobShort(layer_info->image); 1316 layer_info->image->compression=ConvertPSDCompression(compression); 1317 if (layer_info->channel_info[j].type == -1) 1318 layer_info->image->alpha_trait=BlendPixelTrait; 1319 1320 status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j, 1321 compression,exception); 1322 1323 if (status == MagickFalse) 1324 break; 1325 } 1326 1327 if (status != MagickFalse) 1328 status=CorrectPSDOpacity(layer_info,exception); 1329 1330 if ((status != MagickFalse) && 1331 (layer_info->image->colorspace == CMYKColorspace)) 1332 status=NegateCMYK(layer_info->image,exception); 1333 1334 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL)) 1335 { 1336 status=CompositeImage(layer_info->image,layer_info->mask.image, 1337 CopyAlphaCompositeOp,MagickTrue,0,0,exception); 1338 layer_info->mask.image=DestroyImage(layer_info->mask.image); 1339 } 1340 1341 return(status); 1342 } 1343 1344 ModuleExport MagickBooleanType ReadPSDLayers(Image *image, 1345 const ImageInfo *image_info,const PSDInfo *psd_info, 1346 const MagickBooleanType skip_layers,ExceptionInfo *exception) 1347 { 1348 char 1349 type[4]; 1350 1351 LayerInfo 1352 *layer_info; 1353 1354 MagickSizeType 1355 size; 1356 1357 MagickBooleanType 1358 status; 1359 1360 register ssize_t 1361 i; 1362 1363 ssize_t 1364 count, 1365 j, 1366 number_layers; 1367 1368 size=GetPSDSize(psd_info,image); 1369 if (size == 0) 1370 { 1371 /* 1372 Skip layers & masks. 1373 */ 1374 (void) ReadBlobLong(image); 1375 count=ReadBlob(image,4,(unsigned char *) type); 1376 ReversePSDString(image,type,4); 1377 status=MagickFalse; 1378 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0)) 1379 return(MagickTrue); 1380 else 1381 { 1382 count=ReadBlob(image,4,(unsigned char *) type); 1383 ReversePSDString(image,type,4); 1384 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0)) 1385 size=GetPSDSize(psd_info,image); 1386 else 1387 return(MagickTrue); 1388 } 1389 } 1390 status=MagickTrue; 1391 if (size != 0) 1392 { 1393 layer_info=(LayerInfo *) NULL; 1394 number_layers=(short) ReadBlobShort(image); 1395 1396 if (number_layers < 0) 1397 { 1398 /* 1399 The first alpha channel in the merged result contains the 1400 transparency data for the merged result. 1401 */ 1402 number_layers=MagickAbsoluteValue(number_layers); 1403 if (image->debug != MagickFalse) 1404 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1405 " negative layer count corrected for"); 1406 image->alpha_trait=BlendPixelTrait; 1407 } 1408 1409 /* 1410 We only need to know if the image has an alpha channel 1411 */ 1412 if (skip_layers != MagickFalse) 1413 return(MagickTrue); 1414 1415 if (image->debug != MagickFalse) 1416 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1417 " image contains %.20g layers",(double) number_layers); 1418 1419 if (number_layers == 0) 1420 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers", 1421 image->filename); 1422 1423 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers, 1424 sizeof(*layer_info)); 1425 if (layer_info == (LayerInfo *) NULL) 1426 { 1427 if (image->debug != MagickFalse) 1428 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1429 " allocation of LayerInfo failed"); 1430 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1431 image->filename); 1432 } 1433 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers* 1434 sizeof(*layer_info)); 1435 1436 for (i=0; i < number_layers; i++) 1437 { 1438 ssize_t 1439 x, 1440 y; 1441 1442 if (image->debug != MagickFalse) 1443 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1444 " reading layer #%.20g",(double) i+1); 1445 layer_info[i].page.y=ReadBlobSignedLong(image); 1446 layer_info[i].page.x=ReadBlobSignedLong(image); 1447 y=ReadBlobSignedLong(image); 1448 x=ReadBlobSignedLong(image); 1449 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x); 1450 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y); 1451 layer_info[i].channels=ReadBlobShort(image); 1452 if (layer_info[i].channels > MaxPSDChannels) 1453 { 1454 layer_info=DestroyLayerInfo(layer_info,number_layers); 1455 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded", 1456 image->filename); 1457 } 1458 if (image->debug != MagickFalse) 1459 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1460 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g", 1461 (double) layer_info[i].page.x,(double) layer_info[i].page.y, 1462 (double) layer_info[i].page.height,(double) 1463 layer_info[i].page.width,(double) layer_info[i].channels); 1464 for (j=0; j < (ssize_t) layer_info[i].channels; j++) 1465 { 1466 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image); 1467 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info, 1468 image); 1469 if (image->debug != MagickFalse) 1470 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1471 " channel[%.20g]: type=%.20g, size=%.20g",(double) j, 1472 (double) layer_info[i].channel_info[j].type, 1473 (double) layer_info[i].channel_info[j].size); 1474 } 1475 count=ReadBlob(image,4,(unsigned char *) type); 1476 ReversePSDString(image,type,4); 1477 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0)) 1478 { 1479 if (image->debug != MagickFalse) 1480 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1481 " layer type was %.4s instead of 8BIM", type); 1482 layer_info=DestroyLayerInfo(layer_info,number_layers); 1483 ThrowBinaryException(CorruptImageError,"ImproperImageHeader", 1484 image->filename); 1485 } 1486 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey); 1487 ReversePSDString(image,layer_info[i].blendkey,4); 1488 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char) 1489 ReadBlobByte(image)); 1490 layer_info[i].clipping=(unsigned char) ReadBlobByte(image); 1491 layer_info[i].flags=(unsigned char) ReadBlobByte(image); 1492 layer_info[i].visible=!(layer_info[i].flags & 0x02); 1493 if (image->debug != MagickFalse) 1494 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1495 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s", 1496 layer_info[i].blendkey,(double) layer_info[i].opacity, 1497 layer_info[i].clipping ? "true" : "false",layer_info[i].flags, 1498 layer_info[i].visible ? "true" : "false"); 1499 (void) ReadBlobByte(image); /* filler */ 1500 1501 size=ReadBlobLong(image); 1502 if (size != 0) 1503 { 1504 MagickSizeType 1505 combined_length, 1506 length; 1507 1508 if (image->debug != MagickFalse) 1509 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1510 " layer contains additional info"); 1511 length=ReadBlobLong(image); 1512 combined_length=length+4; 1513 if (length != 0) 1514 { 1515 /* 1516 Layer mask info. 1517 */ 1518 layer_info[i].mask.page.y=ReadBlobSignedLong(image); 1519 layer_info[i].mask.page.x=ReadBlobSignedLong(image); 1520 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)- 1521 layer_info[i].mask.page.y); 1522 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)- 1523 layer_info[i].mask.page.x); 1524 layer_info[i].mask.background=(unsigned char) ReadBlobByte( 1525 image); 1526 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image); 1527 if (!(layer_info[i].mask.flags & 0x01)) 1528 { 1529 layer_info[i].mask.page.y=layer_info[i].mask.page.y- 1530 layer_info[i].page.y; 1531 layer_info[i].mask.page.x=layer_info[i].mask.page.x- 1532 layer_info[i].page.x; 1533 } 1534 if (image->debug != MagickFalse) 1535 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1536 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g", 1537 (double) layer_info[i].mask.page.x,(double) 1538 layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width, 1539 (double) layer_info[i].mask.page.height,(double) 1540 ((MagickOffsetType) length)-18); 1541 /* 1542 Skip over the rest of the layer mask information. 1543 */ 1544 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse) 1545 { 1546 layer_info=DestroyLayerInfo(layer_info,number_layers); 1547 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile", 1548 image->filename); 1549 } 1550 } 1551 length=ReadBlobLong(image); 1552 combined_length+=length+4; 1553 if (length != 0) 1554 { 1555 /* 1556 Layer blending ranges info. 1557 */ 1558 if (image->debug != MagickFalse) 1559 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1560 " layer blending ranges: length=%.20g",(double) 1561 ((MagickOffsetType) length)); 1562 /* 1563 We read it, but don't use it... 1564 */ 1565 for (j=0; j < (ssize_t) (length); j+=8) 1566 { 1567 size_t blend_source=ReadBlobLong(image); 1568 size_t blend_dest=ReadBlobLong(image); 1569 if (image->debug != MagickFalse) 1570 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1571 " source(%x), dest(%x)",(unsigned int) 1572 blend_source,(unsigned int) blend_dest); 1573 } 1574 } 1575 /* 1576 Layer name. 1577 */ 1578 length=(size_t) ReadBlobByte(image); 1579 combined_length+=length+1; 1580 if (length > 0) 1581 (void) ReadBlob(image,(size_t) length++,layer_info[i].name); 1582 layer_info[i].name[length]='\0'; 1583 if (image->debug != MagickFalse) 1584 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1585 " layer name: %s",layer_info[i].name); 1586 /* 1587 Skip the rest of the variable data until we support it. 1588 */ 1589 if (image->debug != MagickFalse) 1590 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1591 " unsupported data: length=%.20g",(double) 1592 ((MagickOffsetType) (size-combined_length))); 1593 if (DiscardBlobBytes(image,(MagickSizeType) (size-combined_length)) == MagickFalse) 1594 { 1595 layer_info=DestroyLayerInfo(layer_info,number_layers); 1596 ThrowBinaryException(CorruptImageError, 1597 "UnexpectedEndOfFile",image->filename); 1598 } 1599 } 1600 } 1601 1602 for (i=0; i < number_layers; i++) 1603 { 1604 if ((layer_info[i].page.width == 0) || 1605 (layer_info[i].page.height == 0)) 1606 { 1607 if (image->debug != MagickFalse) 1608 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1609 " layer data is empty"); 1610 continue; 1611 } 1612 1613 /* 1614 Allocate layered image. 1615 */ 1616 layer_info[i].image=CloneImage(image,layer_info[i].page.width, 1617 layer_info[i].page.height,MagickFalse,exception); 1618 if (layer_info[i].image == (Image *) NULL) 1619 { 1620 layer_info=DestroyLayerInfo(layer_info,number_layers); 1621 if (image->debug != MagickFalse) 1622 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1623 " allocation of image for layer %.20g failed",(double) i); 1624 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1625 image->filename); 1626 } 1627 } 1628 1629 if (image_info->ping == MagickFalse) 1630 { 1631 for (i=0; i < number_layers; i++) 1632 { 1633 if (layer_info[i].image == (Image *) NULL) 1634 { 1635 for (j=0; j < layer_info[i].channels; j++) 1636 { 1637 if (DiscardBlobBytes(image,(MagickSizeType) 1638 layer_info[i].channel_info[j].size) == MagickFalse) 1639 { 1640 layer_info=DestroyLayerInfo(layer_info,number_layers); 1641 ThrowBinaryException(CorruptImageError, 1642 "UnexpectedEndOfFile",image->filename); 1643 } 1644 } 1645 continue; 1646 } 1647 1648 if (image->debug != MagickFalse) 1649 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1650 " reading data for layer %.20g",(double) i); 1651 1652 status=ReadPSDLayer(image,psd_info,&layer_info[i],exception); 1653 if (status == MagickFalse) 1654 break; 1655 1656 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType) 1657 number_layers); 1658 if (status == MagickFalse) 1659 break; 1660 } 1661 } 1662 1663 if (status != MagickFalse) 1664 { 1665 for (i=0; i < number_layers; i++) 1666 { 1667 if (layer_info[i].image == (Image *) NULL) 1668 { 1669 for (j=i; j < number_layers - 1; j++) 1670 layer_info[j] = layer_info[j+1]; 1671 number_layers--; 1672 i--; 1673 } 1674 } 1675 1676 if (number_layers > 0) 1677 { 1678 for (i=0; i < number_layers; i++) 1679 { 1680 if (i > 0) 1681 layer_info[i].image->previous=layer_info[i-1].image; 1682 if (i < (number_layers-1)) 1683 layer_info[i].image->next=layer_info[i+1].image; 1684 layer_info[i].image->page=layer_info[i].page; 1685 } 1686 image->next=layer_info[0].image; 1687 layer_info[0].image->previous=image; 1688 } 1689 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info); 1690 } 1691 else 1692 layer_info=DestroyLayerInfo(layer_info,number_layers); 1693 } 1694 1695 return(status); 1696 } 1697 1698 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info, 1699 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception) 1700 { 1701 MagickOffsetType 1702 *offsets; 1703 1704 MagickBooleanType 1705 status; 1706 1707 PSDCompressionType 1708 compression; 1709 1710 register ssize_t 1711 i; 1712 1713 compression=(PSDCompressionType) ReadBlobMSBShort(image); 1714 image->compression=ConvertPSDCompression(compression); 1715 1716 if (compression != Raw && compression != RLE) 1717 { 1718 (void) ThrowMagickException(exception,GetMagickModule(), 1719 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression); 1720 return(MagickFalse); 1721 } 1722 1723 offsets=(MagickOffsetType *) NULL; 1724 if (compression == RLE) 1725 { 1726 offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels); 1727 if (offsets == (MagickOffsetType *) NULL) 1728 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 1729 image->filename); 1730 } 1731 1732 status=MagickTrue; 1733 for (i=0; i < (ssize_t) psd_info->channels; i++) 1734 { 1735 if (compression == RLE) 1736 status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows), 1737 exception); 1738 else 1739 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception); 1740 1741 if (status != MagickFalse) 1742 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels); 1743 1744 if (status == MagickFalse) 1745 break; 1746 } 1747 1748 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace)) 1749 status=NegateCMYK(image,exception); 1750 1751 if (status != MagickFalse) 1752 status=CorrectPSDAlphaBlend(image_info,image,exception); 1753 1754 if (offsets != (MagickOffsetType *) NULL) 1755 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets); 1756 1757 return(status); 1758 } 1759 1760 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception) 1761 { 1762 Image 1763 *image; 1764 1765 MagickBooleanType 1766 has_merged_image, 1767 skip_layers; 1768 1769 MagickOffsetType 1770 offset; 1771 1772 MagickSizeType 1773 length; 1774 1775 MagickBooleanType 1776 status; 1777 1778 PSDInfo 1779 psd_info; 1780 1781 register ssize_t 1782 i; 1783 1784 ssize_t 1785 count; 1786 1787 unsigned char 1788 *data; 1789 1790 /* 1791 Open image file. 1792 */ 1793 assert(image_info != (const ImageInfo *) NULL); 1794 assert(image_info->signature == MagickCoreSignature); 1795 if (image_info->debug != MagickFalse) 1796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 1797 image_info->filename); 1798 assert(exception != (ExceptionInfo *) NULL); 1799 assert(exception->signature == MagickCoreSignature); 1800 1801 image=AcquireImage(image_info,exception); 1802 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 1803 if (status == MagickFalse) 1804 { 1805 image=DestroyImageList(image); 1806 return((Image *) NULL); 1807 } 1808 /* 1809 Read image header. 1810 */ 1811 image->endian=MSBEndian; 1812 count=ReadBlob(image,4,(unsigned char *) psd_info.signature); 1813 psd_info.version=ReadBlobMSBShort(image); 1814 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) || 1815 ((psd_info.version != 1) && (psd_info.version != 2))) 1816 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 1817 (void) ReadBlob(image,6,psd_info.reserved); 1818 psd_info.channels=ReadBlobMSBShort(image); 1819 if (psd_info.channels > MaxPSDChannels) 1820 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded"); 1821 psd_info.rows=ReadBlobMSBLong(image); 1822 psd_info.columns=ReadBlobMSBLong(image); 1823 if ((psd_info.version == 1) && ((psd_info.rows > 30000) || 1824 (psd_info.columns > 30000))) 1825 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 1826 psd_info.depth=ReadBlobMSBShort(image); 1827 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16)) 1828 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 1829 psd_info.mode=ReadBlobMSBShort(image); 1830 if (image->debug != MagickFalse) 1831 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1832 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s", 1833 (double) psd_info.columns,(double) psd_info.rows,(double) 1834 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType) 1835 psd_info.mode)); 1836 /* 1837 Initialize image. 1838 */ 1839 image->depth=psd_info.depth; 1840 image->columns=psd_info.columns; 1841 image->rows=psd_info.rows; 1842 status=SetImageExtent(image,image->columns,image->rows,exception); 1843 if (status == MagickFalse) 1844 return(DestroyImageList(image)); 1845 if (SetImageBackgroundColor(image,exception) == MagickFalse) 1846 { 1847 image=DestroyImageList(image); 1848 return((Image *) NULL); 1849 } 1850 if (psd_info.mode == LabMode) 1851 SetImageColorspace(image,LabColorspace,exception); 1852 if (psd_info.mode == CMYKMode) 1853 { 1854 SetImageColorspace(image,CMYKColorspace,exception); 1855 image->alpha_trait=psd_info.channels > 4 ? BlendPixelTrait : 1856 UndefinedPixelTrait; 1857 } 1858 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) || 1859 (psd_info.mode == DuotoneMode)) 1860 { 1861 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536, 1862 exception); 1863 if (status == MagickFalse) 1864 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1865 if (image->debug != MagickFalse) 1866 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1867 " Image colormap allocated"); 1868 SetImageColorspace(image,GRAYColorspace,exception); 1869 image->alpha_trait=psd_info.channels > 1 ? BlendPixelTrait : 1870 UndefinedPixelTrait; 1871 } 1872 else 1873 image->alpha_trait=psd_info.channels > 3 ? BlendPixelTrait : 1874 UndefinedPixelTrait; 1875 /* 1876 Read PSD raster colormap only present for indexed and duotone images. 1877 */ 1878 length=ReadBlobMSBLong(image); 1879 if (length != 0) 1880 { 1881 if (image->debug != MagickFalse) 1882 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1883 " reading colormap"); 1884 if (psd_info.mode == DuotoneMode) 1885 { 1886 /* 1887 Duotone image data; the format of this data is undocumented. 1888 */ 1889 data=(unsigned char *) AcquireQuantumMemory((size_t) length, 1890 sizeof(*data)); 1891 if (data == (unsigned char *) NULL) 1892 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1893 (void) ReadBlob(image,(size_t) length,data); 1894 data=(unsigned char *) RelinquishMagickMemory(data); 1895 } 1896 else 1897 { 1898 size_t 1899 number_colors; 1900 1901 /* 1902 Read PSD raster colormap. 1903 */ 1904 number_colors=length/3; 1905 if (number_colors > 65536) 1906 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 1907 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse) 1908 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1909 for (i=0; i < (ssize_t) image->colors; i++) 1910 image->colormap[i].red=ScaleCharToQuantum((unsigned char) 1911 ReadBlobByte(image)); 1912 for (i=0; i < (ssize_t) image->colors; i++) 1913 image->colormap[i].green=ScaleCharToQuantum((unsigned char) 1914 ReadBlobByte(image)); 1915 for (i=0; i < (ssize_t) image->colors; i++) 1916 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) 1917 ReadBlobByte(image)); 1918 image->alpha_trait=UndefinedPixelTrait; 1919 } 1920 } 1921 if ((image->depth == 1) && (image->storage_class != PseudoClass)) 1922 ThrowReaderException(CorruptImageError, "ImproperImageHeader"); 1923 has_merged_image=MagickTrue; 1924 length=ReadBlobMSBLong(image); 1925 if (length != 0) 1926 { 1927 unsigned char 1928 *blocks; 1929 1930 /* 1931 Image resources block. 1932 */ 1933 if (image->debug != MagickFalse) 1934 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1935 " reading image resource blocks - %.20g bytes",(double) 1936 ((MagickOffsetType) length)); 1937 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length, 1938 sizeof(*blocks)); 1939 if (blocks == (unsigned char *) NULL) 1940 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1941 count=ReadBlob(image,(size_t) length,blocks); 1942 if ((count != (ssize_t) length) || (length < 4) || 1943 (LocaleNCompare((char *) blocks,"8BIM",4) != 0)) 1944 { 1945 blocks=(unsigned char *) RelinquishMagickMemory(blocks); 1946 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 1947 } 1948 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image, 1949 exception); 1950 blocks=(unsigned char *) RelinquishMagickMemory(blocks); 1951 } 1952 /* 1953 Layer and mask block. 1954 */ 1955 length=GetPSDSize(&psd_info,image); 1956 if (length == 8) 1957 { 1958 length=ReadBlobMSBLong(image); 1959 length=ReadBlobMSBLong(image); 1960 } 1961 offset=TellBlob(image); 1962 skip_layers=MagickFalse; 1963 if ((image_info->number_scenes == 1) && (image_info->scene == 0) && 1964 (has_merged_image != MagickFalse)) 1965 { 1966 if (image->debug != MagickFalse) 1967 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1968 " read composite only"); 1969 skip_layers=MagickTrue; 1970 } 1971 if (length == 0) 1972 { 1973 if (image->debug != MagickFalse) 1974 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1975 " image has no layers"); 1976 } 1977 else 1978 { 1979 if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) != 1980 MagickTrue) 1981 { 1982 (void) CloseBlob(image); 1983 image=DestroyImageList(image); 1984 return((Image *) NULL); 1985 } 1986 1987 /* 1988 Skip the rest of the layer and mask information. 1989 */ 1990 SeekBlob(image,offset+length,SEEK_SET); 1991 } 1992 /* 1993 If we are only "pinging" the image, then we're done - so return. 1994 */ 1995 if (image_info->ping != MagickFalse) 1996 { 1997 (void) CloseBlob(image); 1998 return(GetFirstImageInList(image)); 1999 } 2000 /* 2001 Read the precombined layer, present for PSD < 4 compatibility. 2002 */ 2003 if (image->debug != MagickFalse) 2004 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2005 " reading the precombined layer"); 2006 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1)) 2007 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image, 2008 &psd_info,exception); 2009 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) && 2010 (length != 0)) 2011 { 2012 SeekBlob(image,offset,SEEK_SET); 2013 status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception); 2014 if (status != MagickTrue) 2015 { 2016 (void) CloseBlob(image); 2017 image=DestroyImageList(image); 2018 return((Image *) NULL); 2019 } 2020 } 2021 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) > 1)) 2022 { 2023 Image 2024 *merged; 2025 2026 SetImageAlphaChannel(image,TransparentAlphaChannel,exception); 2027 image->background_color.alpha=TransparentAlpha; 2028 image->background_color.alpha_trait=BlendPixelTrait; 2029 merged=MergeImageLayers(image,FlattenLayer,exception); 2030 ReplaceImageInList(&image,merged); 2031 } 2032 (void) CloseBlob(image); 2033 return(GetFirstImageInList(image)); 2034 } 2035 2036 /* 2038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2039 % % 2040 % % 2041 % % 2042 % R e g i s t e r P S D I m a g e % 2043 % % 2044 % % 2045 % % 2046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2047 % 2048 % RegisterPSDImage() adds properties for the PSD image format to 2049 % the list of supported formats. The properties include the image format 2050 % tag, a method to read and/or write the format, whether the format 2051 % supports the saving of more than one frame to the same file or blob, 2052 % whether the format supports native in-memory I/O, and a brief 2053 % description of the format. 2054 % 2055 % The format of the RegisterPSDImage method is: 2056 % 2057 % size_t RegisterPSDImage(void) 2058 % 2059 */ 2060 ModuleExport size_t RegisterPSDImage(void) 2061 { 2062 MagickInfo 2063 *entry; 2064 2065 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format"); 2066 entry->decoder=(DecodeImageHandler *) ReadPSDImage; 2067 entry->encoder=(EncodeImageHandler *) WritePSDImage; 2068 entry->magick=(IsImageFormatHandler *) IsPSD; 2069 entry->flags|=CoderSeekableStreamFlag; 2070 (void) RegisterMagickInfo(entry); 2071 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap"); 2072 entry->decoder=(DecodeImageHandler *) ReadPSDImage; 2073 entry->encoder=(EncodeImageHandler *) WritePSDImage; 2074 entry->magick=(IsImageFormatHandler *) IsPSD; 2075 entry->flags|=CoderSeekableStreamFlag; 2076 (void) RegisterMagickInfo(entry); 2077 return(MagickImageCoderSignature); 2078 } 2079 2080 /* 2082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2083 % % 2084 % % 2085 % % 2086 % U n r e g i s t e r P S D I m a g e % 2087 % % 2088 % % 2089 % % 2090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2091 % 2092 % UnregisterPSDImage() removes format registrations made by the 2093 % PSD module from the list of supported formats. 2094 % 2095 % The format of the UnregisterPSDImage method is: 2096 % 2097 % UnregisterPSDImage(void) 2098 % 2099 */ 2100 ModuleExport void UnregisterPSDImage(void) 2101 { 2102 (void) UnregisterMagickInfo("PSB"); 2103 (void) UnregisterMagickInfo("PSD"); 2104 } 2105 2106 /* 2108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2109 % % 2110 % % 2111 % % 2112 % W r i t e P S D I m a g e % 2113 % % 2114 % % 2115 % % 2116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2117 % 2118 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format. 2119 % 2120 % The format of the WritePSDImage method is: 2121 % 2122 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image, 2123 % ExceptionInfo *exception) 2124 % 2125 % A description of each parameter follows. 2126 % 2127 % o image_info: the image info. 2128 % 2129 % o image: The image. 2130 % 2131 % o exception: return any errors or warnings in this structure. 2132 % 2133 */ 2134 2135 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image, 2136 const size_t offset) 2137 { 2138 if (psd_info->version == 1) 2139 return(WriteBlobMSBShort(image,(unsigned short) offset)); 2140 return(WriteBlobMSBLong(image,(unsigned short) offset)); 2141 } 2142 2143 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image, 2144 const MagickSizeType size) 2145 { 2146 if (psd_info->version == 1) 2147 return(WriteBlobMSBLong(image,(unsigned int) size)); 2148 return(WriteBlobMSBLongLong(image,size)); 2149 } 2150 2151 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length, 2152 const unsigned char *pixels,unsigned char *compact_pixels, 2153 ExceptionInfo *exception) 2154 { 2155 int 2156 count; 2157 2158 register ssize_t 2159 i, 2160 j; 2161 2162 register unsigned char 2163 *q; 2164 2165 unsigned char 2166 *packbits; 2167 2168 /* 2169 Compress pixels with Packbits encoding. 2170 */ 2171 assert(image != (Image *) NULL); 2172 assert(image->signature == MagickCoreSignature); 2173 if (image->debug != MagickFalse) 2174 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2175 assert(pixels != (unsigned char *) NULL); 2176 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits)); 2177 if (packbits == (unsigned char *) NULL) 2178 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 2179 image->filename); 2180 q=compact_pixels; 2181 for (i=(ssize_t) length; i != 0; ) 2182 { 2183 switch (i) 2184 { 2185 case 1: 2186 { 2187 i--; 2188 *q++=(unsigned char) 0; 2189 *q++=(*pixels); 2190 break; 2191 } 2192 case 2: 2193 { 2194 i-=2; 2195 *q++=(unsigned char) 1; 2196 *q++=(*pixels); 2197 *q++=pixels[1]; 2198 break; 2199 } 2200 case 3: 2201 { 2202 i-=3; 2203 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 2204 { 2205 *q++=(unsigned char) ((256-3)+1); 2206 *q++=(*pixels); 2207 break; 2208 } 2209 *q++=(unsigned char) 2; 2210 *q++=(*pixels); 2211 *q++=pixels[1]; 2212 *q++=pixels[2]; 2213 break; 2214 } 2215 default: 2216 { 2217 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 2218 { 2219 /* 2220 Packed run. 2221 */ 2222 count=3; 2223 while (((ssize_t) count < i) && (*pixels == *(pixels+count))) 2224 { 2225 count++; 2226 if (count >= 127) 2227 break; 2228 } 2229 i-=count; 2230 *q++=(unsigned char) ((256-count)+1); 2231 *q++=(*pixels); 2232 pixels+=count; 2233 break; 2234 } 2235 /* 2236 Literal run. 2237 */ 2238 count=0; 2239 while ((*(pixels+count) != *(pixels+count+1)) || 2240 (*(pixels+count+1) != *(pixels+count+2))) 2241 { 2242 packbits[count+1]=pixels[count]; 2243 count++; 2244 if (((ssize_t) count >= (i-3)) || (count >= 127)) 2245 break; 2246 } 2247 i-=count; 2248 *packbits=(unsigned char) (count-1); 2249 for (j=0; j <= (ssize_t) count; j++) 2250 *q++=packbits[j]; 2251 pixels+=count; 2252 break; 2253 } 2254 } 2255 } 2256 *q++=(unsigned char) 128; /* EOD marker */ 2257 packbits=(unsigned char *) RelinquishMagickMemory(packbits); 2258 return((size_t) (q-compact_pixels)); 2259 } 2260 2261 static void WritePackbitsLength(const PSDInfo *psd_info, 2262 const ImageInfo *image_info,Image *image,Image *next_image, 2263 unsigned char *compact_pixels,const QuantumType quantum_type, 2264 ExceptionInfo *exception) 2265 { 2266 QuantumInfo 2267 *quantum_info; 2268 2269 register const Quantum 2270 *p; 2271 2272 size_t 2273 length, 2274 packet_size; 2275 2276 ssize_t 2277 y; 2278 2279 unsigned char 2280 *pixels; 2281 2282 if (next_image->depth > 8) 2283 next_image->depth=16; 2284 packet_size=next_image->depth > 8UL ? 2UL : 1UL; 2285 (void) packet_size; 2286 quantum_info=AcquireQuantumInfo(image_info,image); 2287 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 2288 for (y=0; y < (ssize_t) next_image->rows; y++) 2289 { 2290 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception); 2291 if (p == (const Quantum *) NULL) 2292 break; 2293 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info, 2294 quantum_type,pixels,exception); 2295 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels, 2296 exception); 2297 (void) SetPSDOffset(psd_info,image,length); 2298 } 2299 quantum_info=DestroyQuantumInfo(quantum_info); 2300 } 2301 2302 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info, 2303 Image *image,Image *next_image,unsigned char *compact_pixels, 2304 const QuantumType quantum_type,const MagickBooleanType compression_flag, 2305 ExceptionInfo *exception) 2306 { 2307 int 2308 y; 2309 2310 MagickBooleanType 2311 monochrome; 2312 2313 QuantumInfo 2314 *quantum_info; 2315 2316 register const Quantum 2317 *p; 2318 2319 register ssize_t 2320 i; 2321 2322 size_t 2323 length, 2324 packet_size; 2325 2326 unsigned char 2327 *pixels; 2328 2329 (void) psd_info; 2330 if ((compression_flag != MagickFalse) && 2331 (next_image->compression != RLECompression)) 2332 (void) WriteBlobMSBShort(image,0); 2333 if (next_image->depth > 8) 2334 next_image->depth=16; 2335 monochrome=IsImageMonochrome(image) && (image->depth == 1) ? 2336 MagickTrue : MagickFalse; 2337 packet_size=next_image->depth > 8UL ? 2UL : 1UL; 2338 (void) packet_size; 2339 quantum_info=AcquireQuantumInfo(image_info,image); 2340 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 2341 for (y=0; y < (ssize_t) next_image->rows; y++) 2342 { 2343 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception); 2344 if (p == (const Quantum *) NULL) 2345 break; 2346 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info, 2347 quantum_type,pixels,exception); 2348 if (monochrome != MagickFalse) 2349 for (i=0; i < (ssize_t) length; i++) 2350 pixels[i]=(~pixels[i]); 2351 if (next_image->compression != RLECompression) 2352 (void) WriteBlob(image,length,pixels); 2353 else 2354 { 2355 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels, 2356 exception); 2357 (void) WriteBlob(image,length,compact_pixels); 2358 } 2359 } 2360 quantum_info=DestroyQuantumInfo(quantum_info); 2361 } 2362 2363 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info, 2364 const ImageInfo *image_info,Image *image,Image *next_image, 2365 const MagickBooleanType separate,ExceptionInfo *exception) 2366 { 2367 size_t 2368 channels, 2369 packet_size; 2370 2371 unsigned char 2372 *compact_pixels; 2373 2374 /* 2375 Write uncompressed pixels as separate planes. 2376 */ 2377 channels=1; 2378 packet_size=next_image->depth > 8UL ? 2UL : 1UL; 2379 compact_pixels=(unsigned char *) NULL; 2380 if (next_image->compression == RLECompression) 2381 { 2382 compact_pixels=(unsigned char *) AcquireQuantumMemory((9*channels* 2383 next_image->columns)+1,packet_size*sizeof(*compact_pixels)); 2384 if (compact_pixels == (unsigned char *) NULL) 2385 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2386 } 2387 if (IsImageGray(next_image) != MagickFalse) 2388 { 2389 if (next_image->compression == RLECompression) 2390 { 2391 /* 2392 Packbits compression. 2393 */ 2394 (void) WriteBlobMSBShort(image,1); 2395 WritePackbitsLength(psd_info,image_info,image,next_image, 2396 compact_pixels,GrayQuantum,exception); 2397 if (next_image->alpha_trait != UndefinedPixelTrait) 2398 WritePackbitsLength(psd_info,image_info,image,next_image, 2399 compact_pixels,AlphaQuantum,exception); 2400 } 2401 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2402 GrayQuantum,MagickTrue,exception); 2403 if (next_image->alpha_trait != UndefinedPixelTrait) 2404 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2405 AlphaQuantum,separate,exception); 2406 (void) SetImageProgress(image,SaveImagesTag,0,1); 2407 } 2408 else 2409 if (next_image->storage_class == PseudoClass) 2410 { 2411 if (next_image->compression == RLECompression) 2412 { 2413 /* 2414 Packbits compression. 2415 */ 2416 (void) WriteBlobMSBShort(image,1); 2417 WritePackbitsLength(psd_info,image_info,image,next_image, 2418 compact_pixels,IndexQuantum,exception); 2419 if (next_image->alpha_trait != UndefinedPixelTrait) 2420 WritePackbitsLength(psd_info,image_info,image,next_image, 2421 compact_pixels,AlphaQuantum,exception); 2422 } 2423 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2424 IndexQuantum,MagickTrue,exception); 2425 if (next_image->alpha_trait != UndefinedPixelTrait) 2426 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2427 AlphaQuantum,separate,exception); 2428 (void) SetImageProgress(image,SaveImagesTag,0,1); 2429 } 2430 else 2431 { 2432 if (next_image->colorspace == CMYKColorspace) 2433 (void) NegateCMYK(next_image,exception); 2434 if (next_image->compression == RLECompression) 2435 { 2436 /* 2437 Packbits compression. 2438 */ 2439 (void) WriteBlobMSBShort(image,1); 2440 WritePackbitsLength(psd_info,image_info,image,next_image, 2441 compact_pixels,RedQuantum,exception); 2442 WritePackbitsLength(psd_info,image_info,image,next_image, 2443 compact_pixels,GreenQuantum,exception); 2444 WritePackbitsLength(psd_info,image_info,image,next_image, 2445 compact_pixels,BlueQuantum,exception); 2446 if (next_image->colorspace == CMYKColorspace) 2447 WritePackbitsLength(psd_info,image_info,image,next_image, 2448 compact_pixels,BlackQuantum,exception); 2449 if (next_image->alpha_trait != UndefinedPixelTrait) 2450 WritePackbitsLength(psd_info,image_info,image,next_image, 2451 compact_pixels,AlphaQuantum,exception); 2452 } 2453 (void) SetImageProgress(image,SaveImagesTag,0,6); 2454 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2455 RedQuantum,MagickTrue,exception); 2456 (void) SetImageProgress(image,SaveImagesTag,1,6); 2457 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2458 GreenQuantum,separate,exception); 2459 (void) SetImageProgress(image,SaveImagesTag,2,6); 2460 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2461 BlueQuantum,separate,exception); 2462 (void) SetImageProgress(image,SaveImagesTag,3,6); 2463 if (next_image->colorspace == CMYKColorspace) 2464 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2465 BlackQuantum,separate,exception); 2466 (void) SetImageProgress(image,SaveImagesTag,4,6); 2467 if (next_image->alpha_trait != UndefinedPixelTrait) 2468 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels, 2469 AlphaQuantum,separate,exception); 2470 (void) SetImageProgress(image,SaveImagesTag,5,6); 2471 if (next_image->colorspace == CMYKColorspace) 2472 (void) NegateCMYK(next_image,exception); 2473 } 2474 if (next_image->compression == RLECompression) 2475 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels); 2476 return(MagickTrue); 2477 } 2478 2479 static void WritePascalString(Image* inImage,const char *inString,int inPad) 2480 { 2481 size_t 2482 length; 2483 2484 register ssize_t 2485 i; 2486 2487 /* 2488 Max length is 255. 2489 */ 2490 length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString); 2491 if (length == 0) 2492 (void) WriteBlobByte(inImage,0); 2493 else 2494 { 2495 (void) WriteBlobByte(inImage,(unsigned char) length); 2496 (void) WriteBlob(inImage, length, (const unsigned char *) inString); 2497 } 2498 length++; 2499 if ((length % inPad) == 0) 2500 return; 2501 for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++) 2502 (void) WriteBlobByte(inImage,0); 2503 } 2504 2505 static void WriteResolutionResourceBlock(Image *image) 2506 { 2507 double 2508 x_resolution, 2509 y_resolution; 2510 2511 unsigned short 2512 units; 2513 2514 if (image->units == PixelsPerCentimeterResolution) 2515 { 2516 x_resolution=2.54*65536.0*image->resolution.x+0.5; 2517 y_resolution=2.54*65536.0*image->resolution.y+0.5; 2518 units=2; 2519 } 2520 else 2521 { 2522 x_resolution=65536.0*image->resolution.x+0.5; 2523 y_resolution=65536.0*image->resolution.y+0.5; 2524 units=1; 2525 } 2526 (void) WriteBlob(image,4,(const unsigned char *) "8BIM"); 2527 (void) WriteBlobMSBShort(image,0x03ED); 2528 (void) WriteBlobMSBShort(image,0); 2529 (void) WriteBlobMSBLong(image,16); /* resource size */ 2530 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5)); 2531 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */ 2532 (void) WriteBlobMSBShort(image,units); /* width unit */ 2533 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5)); 2534 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */ 2535 (void) WriteBlobMSBShort(image,units); /* height unit */ 2536 } 2537 2538 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile) 2539 { 2540 register const unsigned char 2541 *p; 2542 2543 size_t 2544 length; 2545 2546 unsigned char 2547 *datum; 2548 2549 unsigned int 2550 count, 2551 long_sans; 2552 2553 unsigned short 2554 id, 2555 short_sans; 2556 2557 length=GetStringInfoLength(bim_profile); 2558 if (length < 16) 2559 return; 2560 datum=GetStringInfoDatum(bim_profile); 2561 for (p=datum; (p >= datum) && (p < (datum+length-16)); ) 2562 { 2563 register unsigned char 2564 *q; 2565 2566 q=(unsigned char *) p; 2567 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 2568 break; 2569 p=PushLongPixel(MSBEndian,p,&long_sans); 2570 p=PushShortPixel(MSBEndian,p,&id); 2571 p=PushShortPixel(MSBEndian,p,&short_sans); 2572 p=PushLongPixel(MSBEndian,p,&count); 2573 if (id == 0x0000040f) 2574 { 2575 ssize_t 2576 quantum; 2577 2578 quantum=PSDQuantum(count)+12; 2579 if ((quantum >= 12) && (q+quantum < (datum+length-16))) 2580 { 2581 (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum)); 2582 SetStringInfoLength(bim_profile,length-quantum); 2583 } 2584 break; 2585 } 2586 p+=count; 2587 if ((count & 0x01) != 0) 2588 p++; 2589 } 2590 } 2591 2592 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile) 2593 { 2594 register const unsigned char 2595 *p; 2596 2597 size_t 2598 length; 2599 2600 unsigned char 2601 *datum; 2602 2603 unsigned int 2604 count, 2605 long_sans; 2606 2607 unsigned short 2608 id, 2609 short_sans; 2610 2611 length=GetStringInfoLength(bim_profile); 2612 if (length < 16) 2613 return; 2614 datum=GetStringInfoDatum(bim_profile); 2615 for (p=datum; (p >= datum) && (p < (datum+length-16)); ) 2616 { 2617 register unsigned char 2618 *q; 2619 2620 ssize_t 2621 cnt; 2622 2623 q=(unsigned char *) p; 2624 if (LocaleNCompare((const char *) p,"8BIM",4) != 0) 2625 return; 2626 p=PushLongPixel(MSBEndian,p,&long_sans); 2627 p=PushShortPixel(MSBEndian,p,&id); 2628 p=PushShortPixel(MSBEndian,p,&short_sans); 2629 p=PushLongPixel(MSBEndian,p,&count); 2630 cnt=PSDQuantum(count); 2631 if (cnt < 0) 2632 return; 2633 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12))) 2634 { 2635 (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum)); 2636 SetStringInfoLength(bim_profile,length-(cnt+12)); 2637 break; 2638 } 2639 p+=count; 2640 if ((count & 0x01) != 0) 2641 p++; 2642 } 2643 } 2644 2645 static MagickBooleanType WritePSDImage(const ImageInfo *image_info, 2646 Image *image,ExceptionInfo *exception) 2647 { 2648 const char 2649 *property; 2650 2651 const StringInfo 2652 *icc_profile; 2653 2654 Image 2655 *base_image, 2656 *next_image; 2657 2658 MagickBooleanType 2659 status; 2660 2661 PSDInfo 2662 psd_info; 2663 2664 register ssize_t 2665 i; 2666 2667 size_t 2668 channel_size, 2669 channelLength, 2670 layer_count, 2671 layer_info_size, 2672 length, 2673 num_channels, 2674 packet_size, 2675 rounded_layer_info_size; 2676 2677 StringInfo 2678 *bim_profile; 2679 2680 /* 2681 Open image file. 2682 */ 2683 assert(image_info != (const ImageInfo *) NULL); 2684 assert(image_info->signature == MagickCoreSignature); 2685 assert(image != (Image *) NULL); 2686 assert(image->signature == MagickCoreSignature); 2687 if (image->debug != MagickFalse) 2688 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2689 assert(exception != (ExceptionInfo *) NULL); 2690 assert(exception->signature == MagickCoreSignature); 2691 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2692 if (status == MagickFalse) 2693 return(status); 2694 packet_size=(size_t) (image->depth > 8 ? 6 : 3); 2695 if (image->alpha_trait != UndefinedPixelTrait) 2696 packet_size+=image->depth > 8 ? 2 : 1; 2697 psd_info.version=1; 2698 if ((LocaleCompare(image_info->magick,"PSB") == 0) || 2699 (image->columns > 30000) || (image->rows > 30000)) 2700 psd_info.version=2; 2701 (void) WriteBlob(image,4,(const unsigned char *) "8BPS"); 2702 (void) WriteBlobMSBShort(image,psd_info.version); /* version */ 2703 for (i=1; i <= 6; i++) 2704 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */ 2705 if (SetImageGray(image,exception) != MagickFalse) 2706 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL); 2707 else 2708 if ((image_info->type != TrueColorType) && (image_info->type != 2709 TrueColorAlphaType) && (image->storage_class == PseudoClass)) 2710 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL); 2711 else 2712 { 2713 if (image->storage_class == PseudoClass) 2714 (void) SetImageStorageClass(image,DirectClass,exception); 2715 if (image->colorspace != CMYKColorspace) 2716 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL); 2717 else 2718 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL); 2719 } 2720 (void) WriteBlobMSBShort(image,(unsigned short) num_channels); 2721 (void) WriteBlobMSBLong(image,(unsigned int) image->rows); 2722 (void) WriteBlobMSBLong(image,(unsigned int) image->columns); 2723 if (IsImageGray(image) != MagickFalse) 2724 { 2725 MagickBooleanType 2726 monochrome; 2727 2728 /* 2729 Write depth & mode. 2730 */ 2731 monochrome=IsImageMonochrome(image) && (image->depth == 1) ? 2732 MagickTrue : MagickFalse; 2733 (void) WriteBlobMSBShort(image,(unsigned short) 2734 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8)); 2735 (void) WriteBlobMSBShort(image,(unsigned short) 2736 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode)); 2737 } 2738 else 2739 { 2740 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class == 2741 PseudoClass ? 8 : image->depth > 8 ? 16 : 8)); 2742 2743 if (((image_info->colorspace != UndefinedColorspace) || 2744 (image->colorspace != CMYKColorspace)) && 2745 (image_info->colorspace != CMYKColorspace)) 2746 { 2747 (void) TransformImageColorspace(image,sRGBColorspace,exception); 2748 (void) WriteBlobMSBShort(image,(unsigned short) 2749 (image->storage_class == PseudoClass ? IndexedMode : RGBMode)); 2750 } 2751 else 2752 { 2753 if (image->colorspace != CMYKColorspace) 2754 (void) TransformImageColorspace(image,CMYKColorspace,exception); 2755 (void) WriteBlobMSBShort(image,CMYKMode); 2756 } 2757 } 2758 if ((IsImageGray(image) != MagickFalse) || 2759 (image->storage_class == DirectClass) || (image->colors > 256)) 2760 (void) WriteBlobMSBLong(image,0); 2761 else 2762 { 2763 /* 2764 Write PSD raster colormap. 2765 */ 2766 (void) WriteBlobMSBLong(image,768); 2767 for (i=0; i < (ssize_t) image->colors; i++) 2768 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red)); 2769 for ( ; i < 256; i++) 2770 (void) WriteBlobByte(image,0); 2771 for (i=0; i < (ssize_t) image->colors; i++) 2772 (void) WriteBlobByte(image,ScaleQuantumToChar( 2773 image->colormap[i].green)); 2774 for ( ; i < 256; i++) 2775 (void) WriteBlobByte(image,0); 2776 for (i=0; i < (ssize_t) image->colors; i++) 2777 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue)); 2778 for ( ; i < 256; i++) 2779 (void) WriteBlobByte(image,0); 2780 } 2781 /* 2782 Image resource block. 2783 */ 2784 length=28; /* 0x03EB */ 2785 bim_profile=(StringInfo *) GetImageProfile(image,"8bim"); 2786 icc_profile=GetImageProfile(image,"icc"); 2787 if (bim_profile != (StringInfo *) NULL) 2788 { 2789 bim_profile=CloneStringInfo(bim_profile); 2790 if (icc_profile != (StringInfo *) NULL) 2791 RemoveICCProfileFromResourceBlock(bim_profile); 2792 RemoveResolutionFromResourceBlock(bim_profile); 2793 length+=PSDQuantum(GetStringInfoLength(bim_profile)); 2794 } 2795 if (icc_profile != (const StringInfo *) NULL) 2796 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12; 2797 (void) WriteBlobMSBLong(image,(unsigned int) length); 2798 WriteResolutionResourceBlock(image); 2799 if (bim_profile != (StringInfo *) NULL) 2800 { 2801 (void) WriteBlob(image,GetStringInfoLength(bim_profile), 2802 GetStringInfoDatum(bim_profile)); 2803 bim_profile=DestroyStringInfo(bim_profile); 2804 } 2805 if (icc_profile != (StringInfo *) NULL) 2806 { 2807 (void) WriteBlob(image,4,(const unsigned char *) "8BIM"); 2808 (void) WriteBlobMSBShort(image,0x0000040F); 2809 (void) WriteBlobMSBShort(image,0); 2810 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength( 2811 icc_profile)); 2812 (void) WriteBlob(image,GetStringInfoLength(icc_profile), 2813 GetStringInfoDatum(icc_profile)); 2814 if ((MagickOffsetType) GetStringInfoLength(icc_profile) != 2815 PSDQuantum(GetStringInfoLength(icc_profile))) 2816 (void) WriteBlobByte(image,0); 2817 } 2818 layer_count=0; 2819 layer_info_size=2; 2820 base_image=GetNextImageInList(image); 2821 if (base_image == (Image *) NULL) 2822 base_image=image; 2823 next_image=base_image; 2824 while (next_image != (Image *) NULL) 2825 { 2826 packet_size=next_image->depth > 8 ? 2UL : 1UL; 2827 if (IsImageGray(next_image) != MagickFalse) 2828 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL; 2829 else 2830 if (next_image->storage_class == PseudoClass) 2831 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL; 2832 else 2833 if (next_image->colorspace != CMYKColorspace) 2834 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL; 2835 else 2836 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL; 2837 channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2); 2838 layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 : 2839 16)+4*1+4+num_channels*channelLength); 2840 property=(const char *) GetImageProperty(next_image,"label",exception); 2841 if (property == (const char *) NULL) 2842 layer_info_size+=16; 2843 else 2844 { 2845 size_t 2846 layer_length; 2847 2848 layer_length=strlen(property); 2849 layer_info_size+=8+layer_length+(4-(layer_length % 4)); 2850 } 2851 layer_count++; 2852 next_image=GetNextImageInList(next_image); 2853 } 2854 if (layer_count == 0) 2855 (void) SetPSDSize(&psd_info,image,0); 2856 else 2857 { 2858 CompressionType 2859 compression; 2860 2861 (void) SetPSDSize(&psd_info,image,layer_info_size+ 2862 (psd_info.version == 1 ? 8 : 16)); 2863 if ((layer_info_size/2) != ((layer_info_size+1)/2)) 2864 rounded_layer_info_size=layer_info_size+1; 2865 else 2866 rounded_layer_info_size=layer_info_size; 2867 (void) SetPSDSize(&psd_info,image,rounded_layer_info_size); 2868 if (image->alpha_trait != UndefinedPixelTrait) 2869 (void) WriteBlobMSBShort(image,-(unsigned short) layer_count); 2870 else 2871 (void) WriteBlobMSBShort(image,(unsigned short) layer_count); 2872 layer_count=1; 2873 compression=base_image->compression; 2874 for (next_image=base_image; next_image != NULL; ) 2875 { 2876 next_image->compression=NoCompression; 2877 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y); 2878 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x); 2879 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+ 2880 next_image->rows)); 2881 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+ 2882 next_image->columns)); 2883 packet_size=next_image->depth > 8 ? 2UL : 1UL; 2884 channel_size=(unsigned int) ((packet_size*next_image->rows* 2885 next_image->columns)+2); 2886 if ((IsImageGray(next_image) != MagickFalse) || 2887 (next_image->storage_class == PseudoClass)) 2888 { 2889 (void) WriteBlobMSBShort(image,(unsigned short) 2890 (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1)); 2891 (void) WriteBlobMSBShort(image,0); 2892 (void) SetPSDSize(&psd_info,image,channel_size); 2893 if (next_image->alpha_trait != UndefinedPixelTrait) 2894 { 2895 (void) WriteBlobMSBShort(image,(unsigned short) -1); 2896 (void) SetPSDSize(&psd_info,image,channel_size); 2897 } 2898 } 2899 else 2900 if (next_image->colorspace != CMYKColorspace) 2901 { 2902 (void) WriteBlobMSBShort(image,(unsigned short) 2903 (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3)); 2904 (void) WriteBlobMSBShort(image,0); 2905 (void) SetPSDSize(&psd_info,image,channel_size); 2906 (void) WriteBlobMSBShort(image,1); 2907 (void) SetPSDSize(&psd_info,image,channel_size); 2908 (void) WriteBlobMSBShort(image,2); 2909 (void) SetPSDSize(&psd_info,image,channel_size); 2910 if (next_image->alpha_trait != UndefinedPixelTrait) 2911 { 2912 (void) WriteBlobMSBShort(image,(unsigned short) -1); 2913 (void) SetPSDSize(&psd_info,image,channel_size); 2914 } 2915 } 2916 else 2917 { 2918 (void) WriteBlobMSBShort(image,(unsigned short) 2919 (next_image->alpha_trait ? 5 : 4)); 2920 (void) WriteBlobMSBShort(image,0); 2921 (void) SetPSDSize(&psd_info,image,channel_size); 2922 (void) WriteBlobMSBShort(image,1); 2923 (void) SetPSDSize(&psd_info,image,channel_size); 2924 (void) WriteBlobMSBShort(image,2); 2925 (void) SetPSDSize(&psd_info,image,channel_size); 2926 (void) WriteBlobMSBShort(image,3); 2927 (void) SetPSDSize(&psd_info,image,channel_size); 2928 if (next_image->alpha_trait) 2929 { 2930 (void) WriteBlobMSBShort(image,(unsigned short) -1); 2931 (void) SetPSDSize(&psd_info,image,channel_size); 2932 } 2933 } 2934 (void) WriteBlob(image,4,(const unsigned char *) "8BIM"); 2935 (void) WriteBlob(image,4,(const unsigned char *) 2936 CompositeOperatorToPSDBlendMode(next_image->compose)); 2937 (void) WriteBlobByte(image,255); /* layer opacity */ 2938 (void) WriteBlobByte(image,0); 2939 (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ? 2940 1 << 0x02 : 1); /* layer properties - visible, etc. */ 2941 (void) WriteBlobByte(image,0); 2942 property=(const char *) GetImageProperty(next_image,"label",exception); 2943 if (property == (const char *) NULL) 2944 { 2945 char 2946 layer_name[MagickPathExtent]; 2947 2948 (void) WriteBlobMSBLong(image,16); 2949 (void) WriteBlobMSBLong(image,0); 2950 (void) WriteBlobMSBLong(image,0); 2951 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%04ld",(long) 2952 layer_count++); 2953 WritePascalString(image,layer_name,4); 2954 } 2955 else 2956 { 2957 size_t 2958 label_length; 2959 2960 label_length=strlen(property); 2961 (void) WriteBlobMSBLong(image,(unsigned int) (label_length+(4- 2962 (label_length % 4))+8)); 2963 (void) WriteBlobMSBLong(image,0); 2964 (void) WriteBlobMSBLong(image,0); 2965 WritePascalString(image,property,4); 2966 } 2967 next_image=GetNextImageInList(next_image); 2968 } 2969 /* 2970 Now the image data! 2971 */ 2972 next_image=base_image; 2973 while (next_image != NULL) 2974 { 2975 status=WriteImageChannels(&psd_info,image_info,image,next_image, 2976 MagickTrue,exception); 2977 next_image=GetNextImageInList(next_image); 2978 } 2979 (void) WriteBlobMSBLong(image,0); /* user mask data */ 2980 base_image->compression=compression; 2981 } 2982 /* 2983 Write composite image. 2984 */ 2985 if (status != MagickFalse) 2986 status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse, 2987 exception); 2988 (void) CloseBlob(image); 2989 return(status); 2990 } 2991