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