2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Adobe Photoshop Image Format %
23 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
24 % dedicated to making software imaging solutions freely available. %
26 % You may not use this file except in compliance with the License. You may %
27 % obtain a copy of the License at %
29 % http://www.imagemagick.org/script/license.php %
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. %
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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
80 #include "psd-private.h"
85 #define MaxPSDChannels 56
86 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
89 Enumerated declaractions.
95 ZipWithoutPrediction = 2,
106 MultichannelMode = 7,
112 Typedef declaractions.
114 typedef struct _ChannelInfo
123 typedef struct _MaskInfo
136 typedef struct _LayerInfo
139 channel_info[MaxPSDChannels];
171 Forward declarations.
173 static MagickBooleanType
174 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 % IsPSD()() returns MagickTrue if the image format type, identified by the
188 % magick string, is PSD.
190 % The format of the IsPSD method is:
192 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
194 % A description of each parameter follows:
196 % o magick: compare image format pattern against these bytes.
198 % o length: Specifies the length of the magick string.
201 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
205 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 % R e a d P S D I m a g e %
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
225 % The format of the ReadPSDImage method is:
227 % Image *ReadPSDImage(image_info,ExceptionInfo *exception)
229 % A description of each parameter follows:
231 % o image_info: the image info.
233 % o exception: return any errors or warnings in this structure.
237 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
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";
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.
277 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
278 Image *image,ExceptionInfo* exception)
289 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace)
291 option=GetImageOption(image_info,"psd:alpha-unblend");
292 if (IsStringFalse(option) != MagickFalse)
295 #if defined(MAGICKCORE_OPENMP_SUPPORT)
296 #pragma omp parallel for schedule(static,4) shared(status) \
297 magick_threads(image,image,image->rows,1)
299 for (y=0; y < (ssize_t) image->rows; y++)
307 if (status == MagickFalse)
309 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
310 if (q == (Quantum *) NULL)
315 for (x=0; x < (ssize_t) image->columns; x++)
323 gamma=QuantumScale*GetPixelAlpha(image, q);
324 if (gamma != 0.0 && gamma != 1.0)
326 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
328 PixelChannel channel=GetPixelChannelChannel(image,i);
329 if (channel != AlphaPixelChannel)
330 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
333 q+=GetPixelChannels(image);
335 if (SyncAuthenticPixels(image,exception) == MagickFalse)
342 static inline CompressionType ConvertPSDCompression(
343 PSDCompressionType compression)
348 return RLECompression;
349 case ZipWithPrediction:
350 case ZipWithoutPrediction:
351 return ZipCompression;
353 return NoCompression;
357 static MagickBooleanType CorrectPSDOpacity(LayerInfo *layer_info,
358 ExceptionInfo *exception)
366 if (layer_info->opacity == OpaqueAlpha)
369 layer_info->image->alpha_trait=BlendPixelTrait;
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)
375 for (y=0; y < (ssize_t) layer_info->image->rows; y++)
383 if (status == MagickFalse)
385 q=GetAuthenticPixels(layer_info->image,0,y,layer_info->image->columns,1,
387 if (q == (Quantum *)NULL)
392 for (x=0; x < (ssize_t) layer_info->image->columns; x++)
394 SetPixelAlpha(layer_info->image,(Quantum) (QuantumScale*(GetPixelAlpha(
395 layer_info->image,q))*layer_info->opacity),q);
396 q+=GetPixelChannels(layer_info->image);
398 if (SyncAuthenticPixels(layer_info->image,exception) == MagickFalse)
405 static 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)
409 #define CheckNumberCompactPixels \
414 #define CheckNumberPixels(count) \
415 if (((ssize_t) i + count) > (ssize_t) number_pixels) \
432 packets=(ssize_t) number_compact_pixels;
433 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
436 length=(size_t) (*compact_pixels++);
442 CheckNumberCompactPixels;
443 pixel=(*compact_pixels++);
444 for (j=0; j < (ssize_t) length; j++)
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;
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);
472 CheckNumberPixels(2);
473 *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
474 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
479 CheckNumberPixels(1);
480 *pixels++=(unsigned char) pixel;
488 for (j=0; j < (ssize_t) length; j++)
494 CheckNumberPixels(8);
495 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
496 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
497 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
498 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
499 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
500 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
501 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
502 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
507 CheckNumberPixels(4);
508 *pixels++=(*compact_pixels >> 6) & 0x03;
509 *pixels++=(*compact_pixels >> 4) & 0x03;
510 *pixels++=(*compact_pixels >> 2) & 0x03;
511 *pixels++=(*compact_pixels & 0x03) & 0x03;
516 CheckNumberPixels(2);
517 *pixels++=(*compact_pixels >> 4) & 0xff;
518 *pixels++=(*compact_pixels & 0x0f) & 0xff;
523 CheckNumberPixels(1);
524 *pixels++=(*compact_pixels);
528 CheckNumberCompactPixels;
535 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
536 const ssize_t number_layers)
541 for (i=0; i<number_layers; i++)
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);
549 return (LayerInfo *) RelinquishMagickMemory(layer_info);
552 static inline size_t GetPSDPacketSize(Image *image)
554 if (image->storage_class == PseudoClass)
556 if (image->colors > 256)
558 else if (image->depth > 8)
562 if (image->depth > 8)
568 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
570 if (psd_info->version == 1)
571 return((MagickSizeType) ReadBlobLong(image));
572 return((MagickSizeType) ReadBlobLongLong(image));
575 static inline size_t GetPSDRowSize(Image *image)
577 if (image->depth == 1)
578 return((image->columns+7)/8);
580 return(image->columns*GetPSDPacketSize(image));
583 static const char *ModeToString(PSDImageType type)
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";
599 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
607 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
609 status=NegateImage(image,MagickFalse,exception);
610 (void) SetImageChannelMask(image,channel_mask);
614 static void ParseImageResourceBlocks(Image *image,
615 const unsigned char *blocks,size_t length,
616 MagickBooleanType *has_merged_image,ExceptionInfo *exception)
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)); )
640 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
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)
653 value[MagickPathExtent];
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;
681 *has_merged_image=MagickFalse;
691 if ((count & 0x01) != 0)
697 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
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);
750 static inline void ReversePSDString(Image *image,char *p,size_t length)
755 if (image->endian == MSBEndian)
759 for(--q; p < q; ++p, --q)
767 static MagickBooleanType ReadPSDChannelPixels(Image *image,
768 const size_t channels,const size_t row,const ssize_t type,
769 const unsigned char *pixels,ExceptionInfo *exception)
774 register const unsigned char
790 q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
791 if (q == (Quantum *) NULL)
793 packet_size=GetPSDPacketSize(image);
794 for (x=0; x < (ssize_t) image->columns; x++)
796 if (packet_size == 1)
797 pixel=ScaleCharToQuantum(*p++);
800 p=PushShortPixel(MSBEndian,p,&nibble);
801 pixel=ScaleShortToQuantum(nibble);
807 SetPixelAlpha(image,pixel,q);
813 SetPixelRed(image,pixel,q);
814 if (channels == 1 || type == -2)
815 SetPixelGray(image,pixel,q);
816 if (image->storage_class == PseudoClass)
818 if (packet_size == 1)
819 SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
821 SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
822 SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
823 ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
824 if (image->depth == 1)
830 number_bits=image->columns-x;
833 for (bit=0; bit < number_bits; bit++)
835 SetPixelIndex(image,(((unsigned char) pixel) &
836 (0x01 << (7-bit))) != 0 ? 0 : 255,q);
837 SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
838 GetPixelIndex(image,q),q);
839 q+=GetPixelChannels(image);
850 if (image->storage_class == PseudoClass)
851 SetPixelAlpha(image,pixel,q);
853 SetPixelGreen(image,pixel,q);
858 if (image->storage_class == PseudoClass)
859 SetPixelAlpha(image,pixel,q);
861 SetPixelBlue(image,pixel,q);
866 if (image->colorspace == CMYKColorspace)
867 SetPixelBlack(image,pixel,q);
869 if (image->alpha_trait != UndefinedPixelTrait)
870 SetPixelAlpha(image,pixel,q);
875 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
878 if (image->alpha_trait != UndefinedPixelTrait)
879 SetPixelAlpha(image,pixel,q);
885 q+=GetPixelChannels(image);
887 return(SyncAuthenticPixels(image,exception));
890 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
891 const ssize_t type,ExceptionInfo *exception)
906 if (image->debug != MagickFalse)
907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
908 " layer data is RAW");
910 row_size=GetPSDRowSize(image);
911 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
912 if (pixels == (unsigned char *) NULL)
913 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
917 for (y=0; y < (ssize_t) image->rows; y++)
921 count=ReadBlob(image,row_size,pixels);
922 if (count != row_size)
925 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
926 if (status == MagickFalse)
930 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
934 static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
935 const PSDInfo *psd_info,const size_t size)
943 offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets));
944 if(offsets != (MagickOffsetType *) NULL)
946 for (y=0; y < (ssize_t) size; y++)
948 if (psd_info->version == 1)
949 offsets[y]=(MagickOffsetType) ReadBlobShort(image);
951 offsets[y]=(MagickOffsetType) ReadBlobLong(image);
957 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
958 const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
975 if (image->debug != MagickFalse)
976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
977 " layer data is RLE compressed");
979 row_size=GetPSDRowSize(image);
980 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
981 if (pixels == (unsigned char *) NULL)
982 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
986 for (y=0; y < (ssize_t) image->rows; y++)
987 if ((MagickOffsetType) length < offsets[y])
988 length=(size_t) offsets[y];
990 if (length > row_size + 256) // arbitrary number
992 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
993 ThrowBinaryException(ResourceLimitError,"InvalidLength",
997 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
998 if (compact_pixels == (unsigned char *) NULL)
1000 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1001 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1005 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
1008 for (y=0; y < (ssize_t) image->rows; y++)
1012 count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
1013 if (count != (ssize_t) offsets[y])
1016 count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
1017 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1018 if (count != (ssize_t) row_size)
1021 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1023 if (status == MagickFalse)
1027 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1028 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1032 #ifdef MAGICKCORE_ZLIB_DELEGATE
1033 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1034 const ssize_t type,const PSDCompressionType compression,
1035 const size_t compact_size,ExceptionInfo *exception)
1040 register unsigned char
1059 if (image->debug != MagickFalse)
1060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1061 " layer data is ZIP compressed");
1063 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1064 sizeof(*compact_pixels));
1065 if (compact_pixels == (unsigned char *) NULL)
1066 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1069 packet_size=GetPSDPacketSize(image);
1070 row_size=image->columns*packet_size;
1071 count=image->rows*row_size;
1073 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1074 if (pixels == (unsigned char *) NULL)
1076 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1077 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1081 ResetMagickMemory(&stream, 0, sizeof(z_stream));
1082 stream.data_type=Z_BINARY;
1083 (void) ReadBlob(image,compact_size,compact_pixels);
1085 stream.next_in=(Bytef *)compact_pixels;
1086 stream.avail_in=(unsigned int) compact_size;
1087 stream.next_out=(Bytef *)pixels;
1088 stream.avail_out=(unsigned int) count;
1090 if(inflateInit(&stream) == Z_OK)
1095 while (stream.avail_out > 0)
1097 ret=inflate(&stream, Z_SYNC_FLUSH);
1098 if (ret != Z_OK && ret != Z_STREAM_END)
1100 compact_pixels=(unsigned char *) RelinquishMagickMemory(
1102 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1103 return(MagickFalse);
1108 if (compression == ZipWithPrediction)
1113 length=image->columns;
1116 if (packet_size == 2)
1118 p[2]+=p[0]+((p[1]+p[3]) >> 8);
1132 for (y=0; y < (ssize_t) image->rows; y++)
1134 status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1135 if (status == MagickFalse)
1141 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1142 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1147 static MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
1148 LayerInfo* layer_info,const size_t channel,
1149 const PSDCompressionType compression,ExceptionInfo *exception)
1161 channel_image=image;
1162 mask=(Image *) NULL;
1163 if (layer_info->channel_info[channel].type < -1)
1166 Ignore mask that is not a user supplied layer mask, if the mask is
1167 disabled or if the flags have unsupported values.
1169 if (layer_info->channel_info[channel].type != -2 ||
1170 (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02))
1172 SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1175 mask=CloneImage(image,layer_info->mask.page.width,
1176 layer_info->mask.page.height,MagickFalse,exception);
1177 SetImageType(mask,GrayscaleType,exception);
1181 offset=TellBlob(channel_image);
1186 status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1187 layer_info->channel_info[channel].type,exception);
1194 offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
1195 if (offsets == (MagickOffsetType *) NULL)
1196 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1198 status=ReadPSDChannelRLE(channel_image,psd_info,
1199 layer_info->channel_info[channel].type,offsets,exception);
1200 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1203 case ZipWithPrediction:
1204 case ZipWithoutPrediction:
1205 #ifdef MAGICKCORE_ZLIB_DELEGATE
1206 status=ReadPSDChannelZip(channel_image,layer_info->channels,
1207 layer_info->channel_info[channel].type,compression,
1208 layer_info->channel_info[channel].size-2,exception);
1210 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1211 (void) ThrowMagickException(exception,GetMagickModule(),
1212 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1213 "'%s' (ZLIB)",image->filename);
1217 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1218 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1219 "CompressionNotSupported","'%.20g'",(double) compression);
1223 if (status == MagickFalse)
1225 if (mask != (Image *) NULL)
1227 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1228 ThrowBinaryException(CoderError,"UnableToDecompressImage",
1231 if (mask != (Image *) NULL)
1233 if (status != MagickFalse)
1238 layer_info->mask.image=CloneImage(image,image->columns,image->rows,
1239 MagickTrue,exception);
1240 layer_info->mask.image->alpha_trait=UndefinedPixelTrait;
1241 GetPixelInfo(layer_info->mask.image,&color);
1242 color.red=layer_info->mask.background == 0 ? 0 : QuantumRange;
1243 SetImageColor(layer_info->mask.image,&color,exception);
1244 (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp,
1245 MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y,
1254 static MagickBooleanType ReadPSDLayer(Image *image,const PSDInfo *psd_info,
1255 LayerInfo* layer_info,ExceptionInfo *exception)
1258 message[MagickPathExtent];
1269 if (image->debug != MagickFalse)
1270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1271 " setting up new layer image");
1272 (void) SetImageBackgroundColor(layer_info->image,exception);
1273 layer_info->image->compose=PSDBlendModeToCompositeOperator(
1274 layer_info->blendkey);
1275 if (layer_info->visible == MagickFalse)
1276 layer_info->image->compose=NoCompositeOp;
1277 if (psd_info->mode == CMYKMode)
1278 SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1279 if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) ||
1280 (psd_info->mode == DuotoneMode))
1281 SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1283 Set up some hidden attributes for folks that need them.
1285 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1286 (double) layer_info->page.x);
1287 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1288 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1289 (double) layer_info->page.y);
1290 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1291 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1292 layer_info->opacity);
1293 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1294 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1298 for (j=0; j < (ssize_t) layer_info->channels; j++)
1300 if (image->debug != MagickFalse)
1301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1302 " reading data for channel %.20g",(double) j);
1304 compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1305 layer_info->image->compression=ConvertPSDCompression(compression);
1306 if (layer_info->channel_info[j].type == -1)
1307 layer_info->image->alpha_trait=BlendPixelTrait;
1309 status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j,
1310 compression,exception);
1312 if (status == MagickFalse)
1316 if (status != MagickFalse)
1317 status=CorrectPSDOpacity(layer_info,exception);
1319 if ((status != MagickFalse) &&
1320 (layer_info->image->colorspace == CMYKColorspace))
1321 status=NegateCMYK(layer_info->image,exception);
1323 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1325 status=CompositeImage(layer_info->image,layer_info->mask.image,
1326 CopyAlphaCompositeOp,MagickTrue,0,0,exception);
1327 layer_info->mask.image=DestroyImage(layer_info->mask.image);
1333 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1334 const ImageInfo *image_info,const PSDInfo *psd_info,
1335 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1357 size=GetPSDSize(psd_info,image);
1361 Skip layers & masks.
1363 (void) ReadBlobLong(image);
1364 count=ReadBlob(image,4,(unsigned char *) type);
1365 ReversePSDString(image,type,4);
1367 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1371 count=ReadBlob(image,4,(unsigned char *) type);
1372 ReversePSDString(image,type,4);
1373 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1374 size=GetPSDSize(psd_info,image);
1382 layer_info=(LayerInfo *) NULL;
1383 number_layers=(short) ReadBlobShort(image);
1385 if (number_layers < 0)
1388 The first alpha channel in the merged result contains the
1389 transparency data for the merged result.
1391 number_layers=MagickAbsoluteValue(number_layers);
1392 if (image->debug != MagickFalse)
1393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1394 " negative layer count corrected for");
1395 image->alpha_trait=BlendPixelTrait;
1399 We only need to know if the image has an alpha channel
1401 if (skip_layers != MagickFalse)
1404 if (image->debug != MagickFalse)
1405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1406 " image contains %.20g layers",(double) number_layers);
1408 if (number_layers == 0)
1409 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1412 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1413 sizeof(*layer_info));
1414 if (layer_info == (LayerInfo *) NULL)
1416 if (image->debug != MagickFalse)
1417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1418 " allocation of LayerInfo failed");
1419 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1422 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1423 sizeof(*layer_info));
1425 for (i=0; i < number_layers; i++)
1431 if (image->debug != MagickFalse)
1432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1433 " reading layer #%.20g",(double) i+1);
1434 layer_info[i].page.y=(int) ReadBlobLong(image);
1435 layer_info[i].page.x=(int) ReadBlobLong(image);
1436 y=(int) ReadBlobLong(image);
1437 x=(int) ReadBlobLong(image);
1438 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1439 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1440 layer_info[i].channels=ReadBlobShort(image);
1441 if (layer_info[i].channels > MaxPSDChannels)
1443 layer_info=DestroyLayerInfo(layer_info,number_layers);
1444 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1447 if (image->debug != MagickFalse)
1448 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1449 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1450 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1451 (double) layer_info[i].page.height,(double)
1452 layer_info[i].page.width,(double) layer_info[i].channels);
1453 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1455 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1456 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1458 if (image->debug != MagickFalse)
1459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1460 " channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1461 (double) layer_info[i].channel_info[j].type,
1462 (double) layer_info[i].channel_info[j].size);
1464 count=ReadBlob(image,4,(unsigned char *) type);
1465 ReversePSDString(image,type,4);
1466 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1468 if (image->debug != MagickFalse)
1469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1470 " layer type was %.4s instead of 8BIM", type);
1471 layer_info=DestroyLayerInfo(layer_info,number_layers);
1472 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1475 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1476 ReversePSDString(image,layer_info[i].blendkey,4);
1477 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1478 ReadBlobByte(image));
1479 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1480 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1481 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1482 if (image->debug != MagickFalse)
1483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1484 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1485 layer_info[i].blendkey,(double) layer_info[i].opacity,
1486 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1487 layer_info[i].visible ? "true" : "false");
1488 (void) ReadBlobByte(image); /* filler */
1490 size=ReadBlobLong(image);
1497 if (image->debug != MagickFalse)
1498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1499 " layer contains additional info");
1500 length=ReadBlobLong(image);
1501 combined_length=length+4;
1507 layer_info[i].mask.page.y=(int) ReadBlobLong(image);
1508 layer_info[i].mask.page.x=(int) ReadBlobLong(image);
1509 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
1510 layer_info[i].mask.page.y);
1511 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
1512 layer_info[i].mask.page.x);
1513 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1515 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1516 if (!(layer_info[i].mask.flags & 0x01))
1518 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1519 layer_info[i].page.y;
1520 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1521 layer_info[i].page.x;
1523 if (image->debug != MagickFalse)
1524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1525 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1526 (double) layer_info[i].mask.page.x,(double)
1527 layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1528 (double) layer_info[i].mask.page.height,(double)
1529 ((MagickOffsetType) length)-18);
1531 Skip over the rest of the layer mask information.
1533 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1535 layer_info=DestroyLayerInfo(layer_info,number_layers);
1536 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1540 length=ReadBlobLong(image);
1541 combined_length+=length+4;
1545 Layer blending ranges info.
1547 if (image->debug != MagickFalse)
1548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1549 " layer blending ranges: length=%.20g",(double)
1550 ((MagickOffsetType) length));
1552 We read it, but don't use it...
1554 for (j=0; j < (ssize_t) (length); j+=8)
1556 size_t blend_source=ReadBlobLong(image);
1557 size_t blend_dest=ReadBlobLong(image);
1558 if (image->debug != MagickFalse)
1559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1560 " source(%x), dest(%x)",(unsigned int)
1561 blend_source,(unsigned int) blend_dest);
1567 length=(size_t) ReadBlobByte(image);
1568 combined_length+=length+1;
1570 (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1571 layer_info[i].name[length]='\0';
1572 if (image->debug != MagickFalse)
1573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1574 " layer name: %s",layer_info[i].name);
1576 Skip the rest of the variable data until we support it.
1578 if (image->debug != MagickFalse)
1579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1580 " unsupported data: length=%.20g",(double)
1581 ((MagickOffsetType) (size-combined_length)));
1582 if (DiscardBlobBytes(image,(MagickSizeType) (size-combined_length)) == MagickFalse)
1584 layer_info=DestroyLayerInfo(layer_info,number_layers);
1585 ThrowBinaryException(CorruptImageError,
1586 "UnexpectedEndOfFile",image->filename);
1591 for (i=0; i < number_layers; i++)
1593 if ((layer_info[i].page.width == 0) ||
1594 (layer_info[i].page.height == 0))
1596 if (image->debug != MagickFalse)
1597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1598 " layer data is empty");
1603 Allocate layered image.
1605 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1606 layer_info[i].page.height,MagickFalse,exception);
1607 if (layer_info[i].image == (Image *) NULL)
1609 layer_info=DestroyLayerInfo(layer_info,number_layers);
1610 if (image->debug != MagickFalse)
1611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1612 " allocation of image for layer %.20g failed",(double) i);
1613 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1618 if (image_info->ping == MagickFalse)
1620 for (i=0; i < number_layers; i++)
1622 if (layer_info[i].image == (Image *) NULL)
1624 for (j=0; j < layer_info[i].channels; j++)
1626 if (DiscardBlobBytes(image,(MagickSizeType)
1627 layer_info[i].channel_info[j].size) == MagickFalse)
1629 layer_info=DestroyLayerInfo(layer_info,number_layers);
1630 ThrowBinaryException(CorruptImageError,
1631 "UnexpectedEndOfFile",image->filename);
1637 if (image->debug != MagickFalse)
1638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1639 " reading data for layer %.20g",(double) i);
1641 status=ReadPSDLayer(image,psd_info,&layer_info[i],exception);
1642 if (status == MagickFalse)
1645 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1647 if (status == MagickFalse)
1652 if (status != MagickFalse)
1654 for (i=0; i < number_layers; i++)
1656 if (layer_info[i].image == (Image *) NULL)
1658 for (j=i; j < number_layers - 1; j++)
1659 layer_info[j] = layer_info[j+1];
1665 if (number_layers > 0)
1667 for (i=0; i < number_layers; i++)
1670 layer_info[i].image->previous=layer_info[i-1].image;
1671 if (i < (number_layers-1))
1672 layer_info[i].image->next=layer_info[i+1].image;
1673 layer_info[i].image->page=layer_info[i].page;
1675 image->next=layer_info[0].image;
1676 layer_info[0].image->previous=image;
1678 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1681 layer_info=DestroyLayerInfo(layer_info,number_layers);
1687 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1688 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1702 compression=(PSDCompressionType) ReadBlobMSBShort(image);
1703 image->compression=ConvertPSDCompression(compression);
1705 if (compression != Raw && compression != RLE)
1707 (void) ThrowMagickException(exception,GetMagickModule(),
1708 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1709 return(MagickFalse);
1712 offsets=(MagickOffsetType *) NULL;
1713 if (compression == RLE)
1715 offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
1716 if (offsets == (MagickOffsetType *) NULL)
1717 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1722 for (i=0; i < (ssize_t) psd_info->channels; i++)
1724 if (compression == RLE)
1725 status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
1728 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1730 if (status != MagickFalse)
1731 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1733 if (status == MagickFalse)
1737 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1738 status=NegateCMYK(image,exception);
1740 if (status != MagickFalse)
1741 status=CorrectPSDAlphaBlend(image_info,image,exception);
1743 if (offsets != (MagickOffsetType *) NULL)
1744 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1749 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1782 assert(image_info != (const ImageInfo *) NULL);
1783 assert(image_info->signature == MagickCoreSignature);
1784 if (image_info->debug != MagickFalse)
1785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1786 image_info->filename);
1787 assert(exception != (ExceptionInfo *) NULL);
1788 assert(exception->signature == MagickCoreSignature);
1790 image=AcquireImage(image_info,exception);
1791 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1792 if (status == MagickFalse)
1794 image=DestroyImageList(image);
1795 return((Image *) NULL);
1800 image->endian=MSBEndian;
1801 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1802 psd_info.version=ReadBlobMSBShort(image);
1803 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1804 ((psd_info.version != 1) && (psd_info.version != 2)))
1805 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1806 (void) ReadBlob(image,6,psd_info.reserved);
1807 psd_info.channels=ReadBlobMSBShort(image);
1808 if (psd_info.channels > MaxPSDChannels)
1809 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1810 psd_info.rows=ReadBlobMSBLong(image);
1811 psd_info.columns=ReadBlobMSBLong(image);
1812 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1813 (psd_info.columns > 30000)))
1814 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1815 psd_info.depth=ReadBlobMSBShort(image);
1816 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1817 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1818 psd_info.mode=ReadBlobMSBShort(image);
1819 if (image->debug != MagickFalse)
1820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1821 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1822 (double) psd_info.columns,(double) psd_info.rows,(double)
1823 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1828 image->depth=psd_info.depth;
1829 image->columns=psd_info.columns;
1830 image->rows=psd_info.rows;
1831 status=SetImageExtent(image,image->columns,image->rows,exception);
1832 if (status == MagickFalse)
1833 return(DestroyImageList(image));
1834 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1836 image=DestroyImageList(image);
1837 return((Image *) NULL);
1839 if (psd_info.mode == LabMode)
1840 SetImageColorspace(image,LabColorspace,exception);
1841 if (psd_info.mode == CMYKMode)
1843 SetImageColorspace(image,CMYKColorspace,exception);
1844 image->alpha_trait=psd_info.channels > 4 ? BlendPixelTrait :
1845 UndefinedPixelTrait;
1847 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
1848 (psd_info.mode == DuotoneMode))
1850 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1852 if (status == MagickFalse)
1853 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1854 if (image->debug != MagickFalse)
1855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1856 " Image colormap allocated");
1857 SetImageColorspace(image,GRAYColorspace,exception);
1858 image->alpha_trait=psd_info.channels > 1 ? BlendPixelTrait :
1859 UndefinedPixelTrait;
1862 image->alpha_trait=psd_info.channels > 3 ? BlendPixelTrait :
1863 UndefinedPixelTrait;
1865 Read PSD raster colormap only present for indexed and duotone images.
1867 length=ReadBlobMSBLong(image);
1870 if (image->debug != MagickFalse)
1871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1872 " reading colormap");
1873 if (psd_info.mode == DuotoneMode)
1876 Duotone image data; the format of this data is undocumented.
1878 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
1880 if (data == (unsigned char *) NULL)
1881 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1882 (void) ReadBlob(image,(size_t) length,data);
1883 data=(unsigned char *) RelinquishMagickMemory(data);
1891 Read PSD raster colormap.
1893 number_colors=length/3;
1894 if (number_colors > 65536)
1895 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1896 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
1897 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1898 for (i=0; i < (ssize_t) image->colors; i++)
1899 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1900 ReadBlobByte(image));
1901 for (i=0; i < (ssize_t) image->colors; i++)
1902 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1903 ReadBlobByte(image));
1904 for (i=0; i < (ssize_t) image->colors; i++)
1905 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1906 ReadBlobByte(image));
1907 image->alpha_trait=UndefinedPixelTrait;
1910 has_merged_image=MagickTrue;
1911 length=ReadBlobMSBLong(image);
1918 Image resources block.
1920 if (image->debug != MagickFalse)
1921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1922 " reading image resource blocks - %.20g bytes",(double)
1923 ((MagickOffsetType) length));
1924 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
1926 if (blocks == (unsigned char *) NULL)
1927 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1928 count=ReadBlob(image,(size_t) length,blocks);
1929 if ((count != (ssize_t) length) ||
1930 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
1932 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1933 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1935 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
1937 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1940 Layer and mask block.
1942 length=GetPSDSize(&psd_info,image);
1945 length=ReadBlobMSBLong(image);
1946 length=ReadBlobMSBLong(image);
1948 offset=TellBlob(image);
1949 skip_layers=MagickFalse;
1950 if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
1951 (has_merged_image != MagickFalse))
1953 if (image->debug != MagickFalse)
1954 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1955 " read composite only");
1956 skip_layers=MagickTrue;
1960 if (image->debug != MagickFalse)
1961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962 " image has no layers");
1966 if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
1969 (void) CloseBlob(image);
1970 image=DestroyImageList(image);
1971 return((Image *) NULL);
1975 Skip the rest of the layer and mask information.
1977 SeekBlob(image,offset+length,SEEK_SET);
1980 If we are only "pinging" the image, then we're done - so return.
1982 if (image_info->ping != MagickFalse)
1984 (void) CloseBlob(image);
1985 return(GetFirstImageInList(image));
1988 Read the precombined layer, present for PSD < 4 compatibility.
1990 if (image->debug != MagickFalse)
1991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1992 " reading the precombined layer");
1993 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
1994 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
1995 &psd_info,exception);
1996 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
1999 SeekBlob(image,offset,SEEK_SET);
2000 status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
2001 if (status != MagickTrue)
2003 (void) CloseBlob(image);
2004 image=DestroyImageList(image);
2005 return((Image *) NULL);
2008 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) > 1))
2013 SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2014 image->background_color.alpha=TransparentAlpha;
2015 image->background_color.alpha_trait=BlendPixelTrait;
2016 merged=MergeImageLayers(image,FlattenLayer,exception);
2017 ReplaceImageInList(&image,merged);
2019 (void) CloseBlob(image);
2020 return(GetFirstImageInList(image));
2024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028 % R e g i s t e r P S D I m a g e %
2032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2034 % RegisterPSDImage() adds properties for the PSD image format to
2035 % the list of supported formats. The properties include the image format
2036 % tag, a method to read and/or write the format, whether the format
2037 % supports the saving of more than one frame to the same file or blob,
2038 % whether the format supports native in-memory I/O, and a brief
2039 % description of the format.
2041 % The format of the RegisterPSDImage method is:
2043 % size_t RegisterPSDImage(void)
2046 ModuleExport size_t RegisterPSDImage(void)
2051 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2052 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2053 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2054 entry->magick=(IsImageFormatHandler *) IsPSD;
2055 entry->flags|=CoderSeekableStreamFlag;
2056 (void) RegisterMagickInfo(entry);
2057 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2058 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2059 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2060 entry->magick=(IsImageFormatHandler *) IsPSD;
2061 entry->flags|=CoderSeekableStreamFlag;
2062 (void) RegisterMagickInfo(entry);
2063 return(MagickImageCoderSignature);
2067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071 % U n r e g i s t e r P S D I m a g e %
2075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2077 % UnregisterPSDImage() removes format registrations made by the
2078 % PSD module from the list of supported formats.
2080 % The format of the UnregisterPSDImage method is:
2082 % UnregisterPSDImage(void)
2085 ModuleExport void UnregisterPSDImage(void)
2087 (void) UnregisterMagickInfo("PSB");
2088 (void) UnregisterMagickInfo("PSD");
2092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2096 % W r i t e P S D I m a g e %
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2104 % The format of the WritePSDImage method is:
2106 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2107 % ExceptionInfo *exception)
2109 % A description of each parameter follows.
2111 % o image_info: the image info.
2113 % o image: The image.
2115 % o exception: return any errors or warnings in this structure.
2119 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2120 const size_t offset)
2122 if (psd_info->version == 1)
2123 return(WriteBlobMSBShort(image,(unsigned short) offset));
2124 return(WriteBlobMSBLong(image,(unsigned short) offset));
2127 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2128 const MagickSizeType size)
2130 if (psd_info->version == 1)
2131 return(WriteBlobMSBLong(image,(unsigned int) size));
2132 return(WriteBlobMSBLongLong(image,size));
2135 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2136 const unsigned char *pixels,unsigned char *compact_pixels,
2137 ExceptionInfo *exception)
2146 register unsigned char
2153 Compress pixels with Packbits encoding.
2155 assert(image != (Image *) NULL);
2156 assert(image->signature == MagickCoreSignature);
2157 if (image->debug != MagickFalse)
2158 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2159 assert(pixels != (unsigned char *) NULL);
2160 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2161 if (packbits == (unsigned char *) NULL)
2162 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2165 for (i=(ssize_t) length; i != 0; )
2172 *q++=(unsigned char) 0;
2179 *q++=(unsigned char) 1;
2187 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2189 *q++=(unsigned char) ((256-3)+1);
2193 *q++=(unsigned char) 2;
2201 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2207 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2214 *q++=(unsigned char) ((256-count)+1);
2223 while ((*(pixels+count) != *(pixels+count+1)) ||
2224 (*(pixels+count+1) != *(pixels+count+2)))
2226 packbits[count+1]=pixels[count];
2228 if (((ssize_t) count >= (i-3)) || (count >= 127))
2232 *packbits=(unsigned char) (count-1);
2233 for (j=0; j <= (ssize_t) count; j++)
2240 *q++=(unsigned char) 128; /* EOD marker */
2241 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2242 return((size_t) (q-compact_pixels));
2245 static void WritePackbitsLength(const PSDInfo *psd_info,
2246 const ImageInfo *image_info,Image *image,Image *next_image,
2247 unsigned char *compact_pixels,const QuantumType quantum_type,
2248 ExceptionInfo *exception)
2253 register const Quantum
2266 if (next_image->depth > 8)
2267 next_image->depth=16;
2268 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2270 quantum_info=AcquireQuantumInfo(image_info,image);
2271 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2272 for (y=0; y < (ssize_t) next_image->rows; y++)
2274 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2275 if (p == (const Quantum *) NULL)
2277 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2278 quantum_type,pixels,exception);
2279 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2281 (void) SetPSDOffset(psd_info,image,length);
2283 quantum_info=DestroyQuantumInfo(quantum_info);
2286 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
2287 Image *image,Image *next_image,unsigned char *compact_pixels,
2288 const QuantumType quantum_type,const MagickBooleanType compression_flag,
2289 ExceptionInfo *exception)
2300 register const Quantum
2314 if ((compression_flag != MagickFalse) &&
2315 (next_image->compression != RLECompression))
2316 (void) WriteBlobMSBShort(image,0);
2317 if (next_image->depth > 8)
2318 next_image->depth=16;
2319 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2320 MagickTrue : MagickFalse;
2321 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2323 quantum_info=AcquireQuantumInfo(image_info,image);
2324 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2325 for (y=0; y < (ssize_t) next_image->rows; y++)
2327 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2328 if (p == (const Quantum *) NULL)
2330 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2331 quantum_type,pixels,exception);
2332 if (monochrome != MagickFalse)
2333 for (i=0; i < (ssize_t) length; i++)
2334 pixels[i]=(~pixels[i]);
2335 if (next_image->compression != RLECompression)
2336 (void) WriteBlob(image,length,pixels);
2339 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2341 (void) WriteBlob(image,length,compact_pixels);
2344 quantum_info=DestroyQuantumInfo(quantum_info);
2347 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
2348 const ImageInfo *image_info,Image *image,Image *next_image,
2349 const MagickBooleanType separate,ExceptionInfo *exception)
2359 Write uncompressed pixels as separate planes.
2362 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2363 compact_pixels=(unsigned char *) NULL;
2364 if (next_image->compression == RLECompression)
2366 compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
2367 next_image->columns,packet_size*sizeof(*compact_pixels));
2368 if (compact_pixels == (unsigned char *) NULL)
2369 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2371 if (IsImageGray(next_image) != MagickFalse)
2373 if (next_image->compression == RLECompression)
2376 Packbits compression.
2378 (void) WriteBlobMSBShort(image,1);
2379 WritePackbitsLength(psd_info,image_info,image,next_image,
2380 compact_pixels,GrayQuantum,exception);
2381 if (next_image->alpha_trait != UndefinedPixelTrait)
2382 WritePackbitsLength(psd_info,image_info,image,next_image,
2383 compact_pixels,AlphaQuantum,exception);
2385 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2386 GrayQuantum,MagickTrue,exception);
2387 if (next_image->alpha_trait != UndefinedPixelTrait)
2388 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2389 AlphaQuantum,separate,exception);
2390 (void) SetImageProgress(image,SaveImagesTag,0,1);
2393 if (next_image->storage_class == PseudoClass)
2395 if (next_image->compression == RLECompression)
2398 Packbits compression.
2400 (void) WriteBlobMSBShort(image,1);
2401 WritePackbitsLength(psd_info,image_info,image,next_image,
2402 compact_pixels,IndexQuantum,exception);
2403 if (next_image->alpha_trait != UndefinedPixelTrait)
2404 WritePackbitsLength(psd_info,image_info,image,next_image,
2405 compact_pixels,AlphaQuantum,exception);
2407 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2408 IndexQuantum,MagickTrue,exception);
2409 if (next_image->alpha_trait != UndefinedPixelTrait)
2410 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2411 AlphaQuantum,separate,exception);
2412 (void) SetImageProgress(image,SaveImagesTag,0,1);
2416 if (next_image->colorspace == CMYKColorspace)
2417 (void) NegateCMYK(next_image,exception);
2418 if (next_image->compression == RLECompression)
2421 Packbits compression.
2423 (void) WriteBlobMSBShort(image,1);
2424 WritePackbitsLength(psd_info,image_info,image,next_image,
2425 compact_pixels,RedQuantum,exception);
2426 WritePackbitsLength(psd_info,image_info,image,next_image,
2427 compact_pixels,GreenQuantum,exception);
2428 WritePackbitsLength(psd_info,image_info,image,next_image,
2429 compact_pixels,BlueQuantum,exception);
2430 if (next_image->colorspace == CMYKColorspace)
2431 WritePackbitsLength(psd_info,image_info,image,next_image,
2432 compact_pixels,BlackQuantum,exception);
2433 if (next_image->alpha_trait != UndefinedPixelTrait)
2434 WritePackbitsLength(psd_info,image_info,image,next_image,
2435 compact_pixels,AlphaQuantum,exception);
2437 (void) SetImageProgress(image,SaveImagesTag,0,6);
2438 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2439 RedQuantum,MagickTrue,exception);
2440 (void) SetImageProgress(image,SaveImagesTag,1,6);
2441 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2442 GreenQuantum,separate,exception);
2443 (void) SetImageProgress(image,SaveImagesTag,2,6);
2444 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2445 BlueQuantum,separate,exception);
2446 (void) SetImageProgress(image,SaveImagesTag,3,6);
2447 if (next_image->colorspace == CMYKColorspace)
2448 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2449 BlackQuantum,separate,exception);
2450 (void) SetImageProgress(image,SaveImagesTag,4,6);
2451 if (next_image->alpha_trait != UndefinedPixelTrait)
2452 WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2453 AlphaQuantum,separate,exception);
2454 (void) SetImageProgress(image,SaveImagesTag,5,6);
2455 if (next_image->colorspace == CMYKColorspace)
2456 (void) NegateCMYK(next_image,exception);
2458 if (next_image->compression == RLECompression)
2459 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2463 static void WritePascalString(Image* inImage,const char *inString,int inPad)
2474 length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
2476 (void) WriteBlobByte(inImage,0);
2479 (void) WriteBlobByte(inImage,(unsigned char) length);
2480 (void) WriteBlob(inImage, length, (const unsigned char *) inString);
2483 if ((length % inPad) == 0)
2485 for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
2486 (void) WriteBlobByte(inImage,0);
2489 static void WriteResolutionResourceBlock(Image *image)
2498 if (image->units == PixelsPerCentimeterResolution)
2500 x_resolution=2.54*65536.0*image->resolution.x+0.5;
2501 y_resolution=2.54*65536.0*image->resolution.y+0.5;
2506 x_resolution=65536.0*image->resolution.x+0.5;
2507 y_resolution=65536.0*image->resolution.y+0.5;
2510 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2511 (void) WriteBlobMSBShort(image,0x03ED);
2512 (void) WriteBlobMSBShort(image,0);
2513 (void) WriteBlobMSBLong(image,16); /* resource size */
2514 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2515 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2516 (void) WriteBlobMSBShort(image,units); /* width unit */
2517 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2518 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2519 (void) WriteBlobMSBShort(image,units); /* height unit */
2522 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2524 register const unsigned char
2541 length=GetStringInfoLength(bim_profile);
2544 datum=GetStringInfoDatum(bim_profile);
2545 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2547 register unsigned char
2550 q=(unsigned char *) p;
2551 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2553 p=PushLongPixel(MSBEndian,p,&long_sans);
2554 p=PushShortPixel(MSBEndian,p,&id);
2555 p=PushShortPixel(MSBEndian,p,&short_sans);
2556 p=PushLongPixel(MSBEndian,p,&count);
2557 if (id == 0x0000040f)
2559 (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2560 (PSDQuantum(count)+12)-(q-datum));
2561 SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2565 if ((count & 0x01) != 0)
2570 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2572 register const unsigned char
2589 length=GetStringInfoLength(bim_profile);
2592 datum=GetStringInfoDatum(bim_profile);
2593 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2595 register unsigned char
2598 q=(unsigned char *) p;
2599 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2601 p=PushLongPixel(MSBEndian,p,&long_sans);
2602 p=PushShortPixel(MSBEndian,p,&id);
2603 p=PushShortPixel(MSBEndian,p,&short_sans);
2604 p=PushLongPixel(MSBEndian,p,&count);
2605 if ((id == 0x000003ed) && (PSDQuantum(count) < (ssize_t) (length-12)))
2607 (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2608 (PSDQuantum(count)+12)-(q-datum));
2609 SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2613 if ((count & 0x01) != 0)
2618 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2619 ExceptionInfo *exception)
2648 rounded_layer_info_size;
2656 assert(image_info != (const ImageInfo *) NULL);
2657 assert(image_info->signature == MagickCoreSignature);
2658 assert(image != (Image *) NULL);
2659 assert(image->signature == MagickCoreSignature);
2660 if (image->debug != MagickFalse)
2661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2662 assert(exception != (ExceptionInfo *) NULL);
2663 assert(exception->signature == MagickCoreSignature);
2664 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2665 if (status == MagickFalse)
2667 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2668 if (image->alpha_trait != UndefinedPixelTrait)
2669 packet_size+=image->depth > 8 ? 2 : 1;
2671 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2672 (image->columns > 30000) || (image->rows > 30000))
2674 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2675 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
2676 for (i=1; i <= 6; i++)
2677 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
2678 if (SetImageGray(image,exception) != MagickFalse)
2679 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2681 if ((image_info->type != TrueColorType) && (image_info->type !=
2682 TrueColorAlphaType) && (image->storage_class == PseudoClass))
2683 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2686 if (image->storage_class == PseudoClass)
2687 (void) SetImageStorageClass(image,DirectClass,exception);
2688 if (image->colorspace != CMYKColorspace)
2689 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
2691 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
2693 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2694 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2695 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2696 if (IsImageGray(image) != MagickFalse)
2704 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2705 MagickTrue : MagickFalse;
2706 (void) WriteBlobMSBShort(image,(unsigned short)
2707 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2708 (void) WriteBlobMSBShort(image,(unsigned short)
2709 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
2713 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2714 PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2716 if (((image_info->colorspace != UndefinedColorspace) ||
2717 (image->colorspace != CMYKColorspace)) &&
2718 (image_info->colorspace != CMYKColorspace))
2720 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2721 (void) WriteBlobMSBShort(image,(unsigned short)
2722 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2726 if (image->colorspace != CMYKColorspace)
2727 (void) TransformImageColorspace(image,CMYKColorspace,exception);
2728 (void) WriteBlobMSBShort(image,CMYKMode);
2731 if ((IsImageGray(image) != MagickFalse) ||
2732 (image->storage_class == DirectClass) || (image->colors > 256))
2733 (void) WriteBlobMSBLong(image,0);
2737 Write PSD raster colormap.
2739 (void) WriteBlobMSBLong(image,768);
2740 for (i=0; i < (ssize_t) image->colors; i++)
2741 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2742 for ( ; i < 256; i++)
2743 (void) WriteBlobByte(image,0);
2744 for (i=0; i < (ssize_t) image->colors; i++)
2745 (void) WriteBlobByte(image,ScaleQuantumToChar(
2746 image->colormap[i].green));
2747 for ( ; i < 256; i++)
2748 (void) WriteBlobByte(image,0);
2749 for (i=0; i < (ssize_t) image->colors; i++)
2750 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2751 for ( ; i < 256; i++)
2752 (void) WriteBlobByte(image,0);
2755 Image resource block.
2757 length=28; /* 0x03EB */
2758 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2759 icc_profile=GetImageProfile(image,"icc");
2760 if (bim_profile != (StringInfo *) NULL)
2762 bim_profile=CloneStringInfo(bim_profile);
2763 if (icc_profile != (StringInfo *) NULL)
2764 RemoveICCProfileFromResourceBlock(bim_profile);
2765 RemoveResolutionFromResourceBlock(bim_profile);
2766 length+=PSDQuantum(GetStringInfoLength(bim_profile));
2768 if (icc_profile != (const StringInfo *) NULL)
2769 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2770 (void) WriteBlobMSBLong(image,(unsigned int) length);
2771 WriteResolutionResourceBlock(image);
2772 if (bim_profile != (StringInfo *) NULL)
2774 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2775 GetStringInfoDatum(bim_profile));
2776 bim_profile=DestroyStringInfo(bim_profile);
2778 if (icc_profile != (StringInfo *) NULL)
2780 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2781 (void) WriteBlobMSBShort(image,0x0000040F);
2782 (void) WriteBlobMSBShort(image,0);
2783 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2785 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2786 GetStringInfoDatum(icc_profile));
2787 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2788 PSDQuantum(GetStringInfoLength(icc_profile)))
2789 (void) WriteBlobByte(image,0);
2793 base_image=GetNextImageInList(image);
2794 if ((image->alpha_trait != UndefinedPixelTrait) && (base_image == (Image *) NULL))
2796 next_image=base_image;
2797 while ( next_image != NULL )
2799 packet_size=next_image->depth > 8 ? 2UL : 1UL;
2800 if (IsImageGray(next_image) != MagickFalse)
2801 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2803 if (next_image->storage_class == PseudoClass)
2804 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2806 if (next_image->colorspace != CMYKColorspace)
2807 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
2809 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
2810 channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
2811 layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
2812 16)+4*1+4+num_channels*channelLength);
2813 property=(const char *) GetImageProperty(next_image,"label",exception);
2814 if (property == (const char *) NULL)
2815 layer_info_size+=16;
2821 layer_length=strlen(property);
2822 layer_info_size+=8+layer_length+(4-(layer_length % 4));
2825 next_image=GetNextImageInList(next_image);
2827 if (layer_count == 0)
2828 (void) SetPSDSize(&psd_info,image,0);
2834 (void) SetPSDSize(&psd_info,image,layer_info_size+
2835 (psd_info.version == 1 ? 8 : 16));
2836 if ((layer_info_size/2) != ((layer_info_size+1)/2))
2837 rounded_layer_info_size=layer_info_size+1;
2839 rounded_layer_info_size=layer_info_size;
2840 (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2841 if (image->alpha_trait != UndefinedPixelTrait)
2842 (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
2844 (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2846 compression=base_image->compression;
2847 for (next_image=base_image; next_image != NULL; )
2849 next_image->compression=NoCompression;
2850 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2851 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
2852 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
2854 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
2855 next_image->columns));
2856 packet_size=next_image->depth > 8 ? 2UL : 1UL;
2857 channel_size=(unsigned int) ((packet_size*next_image->rows*
2858 next_image->columns)+2);
2859 if ((IsImageGray(next_image) != MagickFalse) ||
2860 (next_image->storage_class == PseudoClass))
2862 (void) WriteBlobMSBShort(image,(unsigned short)
2863 (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
2864 (void) WriteBlobMSBShort(image,0);
2865 (void) SetPSDSize(&psd_info,image,channel_size);
2866 if (next_image->alpha_trait != UndefinedPixelTrait)
2868 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2869 (void) SetPSDSize(&psd_info,image,channel_size);
2873 if (next_image->colorspace != CMYKColorspace)
2875 (void) WriteBlobMSBShort(image,(unsigned short)
2876 (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
2877 (void) WriteBlobMSBShort(image,0);
2878 (void) SetPSDSize(&psd_info,image,channel_size);
2879 (void) WriteBlobMSBShort(image,1);
2880 (void) SetPSDSize(&psd_info,image,channel_size);
2881 (void) WriteBlobMSBShort(image,2);
2882 (void) SetPSDSize(&psd_info,image,channel_size);
2883 if (next_image->alpha_trait != UndefinedPixelTrait)
2885 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2886 (void) SetPSDSize(&psd_info,image,channel_size);
2891 (void) WriteBlobMSBShort(image,(unsigned short)
2892 (next_image->alpha_trait ? 5 : 4));
2893 (void) WriteBlobMSBShort(image,0);
2894 (void) SetPSDSize(&psd_info,image,channel_size);
2895 (void) WriteBlobMSBShort(image,1);
2896 (void) SetPSDSize(&psd_info,image,channel_size);
2897 (void) WriteBlobMSBShort(image,2);
2898 (void) SetPSDSize(&psd_info,image,channel_size);
2899 (void) WriteBlobMSBShort(image,3);
2900 (void) SetPSDSize(&psd_info,image,channel_size);
2901 if (next_image->alpha_trait)
2903 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2904 (void) SetPSDSize(&psd_info,image,channel_size);
2907 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2908 (void) WriteBlob(image,4,(const unsigned char *)
2909 CompositeOperatorToPSDBlendMode(next_image->compose));
2910 (void) WriteBlobByte(image,255); /* layer opacity */
2911 (void) WriteBlobByte(image,0);
2912 (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
2913 1 << 0x02 : 1); /* layer properties - visible, etc. */
2914 (void) WriteBlobByte(image,0);
2915 property=(const char *) GetImageProperty(next_image,"label",exception);
2916 if (property == (const char *) NULL)
2919 layer_name[MagickPathExtent];
2921 (void) WriteBlobMSBLong(image,16);
2922 (void) WriteBlobMSBLong(image,0);
2923 (void) WriteBlobMSBLong(image,0);
2924 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%04ld",(long)
2926 WritePascalString(image,layer_name,4);
2933 label_length=strlen(property);
2934 (void) WriteBlobMSBLong(image,(unsigned int) (label_length+(4-
2935 (label_length % 4))+8));
2936 (void) WriteBlobMSBLong(image,0);
2937 (void) WriteBlobMSBLong(image,0);
2938 WritePascalString(image,property,4);
2940 next_image=GetNextImageInList(next_image);
2945 next_image=base_image;
2946 while (next_image != NULL)
2948 status=WriteImageChannels(&psd_info,image_info,image,next_image,
2949 MagickTrue,exception);
2950 next_image=GetNextImageInList(next_image);
2952 (void) WriteBlobMSBLong(image,0); /* user mask data */
2953 base_image->compression=compression;
2956 Write composite image.
2958 if (status != MagickFalse)
2959 status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
2961 (void) CloseBlob(image);