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)
87 #define PSDAdditionalInfo "psd:additional-info"
90 Enumerated declaractions.
96 ZipWithoutPrediction = 2,
107 MultichannelMode = 7,
113 Typedef declaractions.
115 typedef struct _ChannelInfo
124 typedef struct _MaskInfo
137 typedef struct _LayerInfo
140 channel_info[MaxPSDChannels];
175 Forward declarations.
177 static MagickBooleanType
178 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 % IsPSD()() returns MagickTrue if the image format type, identified by the
192 % magick string, is PSD.
194 % The format of the IsPSD method is:
196 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
198 % A description of each parameter follows:
200 % o magick: compare image format pattern against these bytes.
202 % o length: Specifies the length of the magick string.
205 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
209 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 % R e a d P S D I m a g e %
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It
226 % allocates the memory necessary for the new Image structure and returns a
227 % pointer to the new image.
229 % The format of the ReadPSDImage method is:
231 % Image *ReadPSDImage(image_info,ExceptionInfo *exception)
233 % A description of each parameter follows:
235 % o image_info: the image info.
237 % o exception: return any errors or warnings in this structure.
241 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
248 case ColorBurnCompositeOp: blend_mode = "idiv"; break;
249 case ColorDodgeCompositeOp: blend_mode = "div "; break;
250 case ColorizeCompositeOp: blend_mode = "colr"; break;
251 case DarkenCompositeOp: blend_mode = "dark"; break;
252 case DifferenceCompositeOp: blend_mode = "diff"; break;
253 case DissolveCompositeOp: blend_mode = "diss"; break;
254 case ExclusionCompositeOp: blend_mode = "smud"; break;
255 case HardLightCompositeOp: blend_mode = "hLit"; break;
256 case HardMixCompositeOp: blend_mode = "hMix"; break;
257 case HueCompositeOp: blend_mode = "hue "; break;
258 case LightenCompositeOp: blend_mode = "lite"; break;
259 case LinearBurnCompositeOp: blend_mode = "lbrn"; break;
260 case LinearDodgeCompositeOp:blend_mode = "lddg"; break;
261 case LinearLightCompositeOp:blend_mode = "lLit"; break;
262 case LuminizeCompositeOp: blend_mode = "lum "; break;
263 case MultiplyCompositeOp: blend_mode = "mul "; break;
264 case OverCompositeOp: blend_mode = "norm"; break;
265 case OverlayCompositeOp: blend_mode = "over"; break;
266 case PinLightCompositeOp: blend_mode = "pLit"; break;
267 case SaturateCompositeOp: blend_mode = "sat "; break;
268 case ScreenCompositeOp: blend_mode = "scrn"; break;
269 case SoftLightCompositeOp: blend_mode = "sLit"; break;
270 case VividLightCompositeOp: blend_mode = "vLit"; break;
271 default: blend_mode = "norm";
277 For some reason Photoshop seems to blend semi-transparent pixels with white.
278 This method reverts the blending. This can be disabled by setting the
279 option 'psd:alpha-unblend' to off.
281 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
282 Image *image,ExceptionInfo* exception)
293 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace)
295 option=GetImageOption(image_info,"psd:alpha-unblend");
296 if (IsStringFalse(option) != MagickFalse)
299 #if defined(MAGICKCORE_OPENMP_SUPPORT)
300 #pragma omp parallel for schedule(static,4) shared(status) \
301 magick_threads(image,image,image->rows,1)
303 for (y=0; y < (ssize_t) image->rows; y++)
311 if (status == MagickFalse)
313 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
314 if (q == (Quantum *) NULL)
319 for (x=0; x < (ssize_t) image->columns; x++)
327 gamma=QuantumScale*GetPixelAlpha(image, q);
328 if (gamma != 0.0 && gamma != 1.0)
330 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
332 PixelChannel channel=GetPixelChannelChannel(image,i);
333 if (channel != AlphaPixelChannel)
334 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
337 q+=GetPixelChannels(image);
339 if (SyncAuthenticPixels(image,exception) == MagickFalse)
346 static inline CompressionType ConvertPSDCompression(
347 PSDCompressionType compression)
352 return RLECompression;
353 case ZipWithPrediction:
354 case ZipWithoutPrediction:
355 return ZipCompression;
357 return NoCompression;
361 static MagickBooleanType CorrectPSDOpacity(LayerInfo *layer_info,
362 ExceptionInfo *exception)
370 if (layer_info->opacity == OpaqueAlpha)
373 layer_info->image->alpha_trait=BlendPixelTrait;
375 #if defined(MAGICKCORE_OPENMP_SUPPORT)
376 #pragma omp parallel for schedule(static,4) shared(status) \
377 magick_threads(layer_info->image,layer_info->image,layer_info->image->rows,1)
379 for (y=0; y < (ssize_t) layer_info->image->rows; y++)
387 if (status == MagickFalse)
389 q=GetAuthenticPixels(layer_info->image,0,y,layer_info->image->columns,1,
391 if (q == (Quantum *)NULL)
396 for (x=0; x < (ssize_t) layer_info->image->columns; x++)
398 SetPixelAlpha(layer_info->image,(Quantum) (QuantumScale*(GetPixelAlpha(
399 layer_info->image,q))*layer_info->opacity),q);
400 q+=GetPixelChannels(layer_info->image);
402 if (SyncAuthenticPixels(layer_info->image,exception) == MagickFalse)
409 static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
410 const unsigned char *compact_pixels,const ssize_t depth,
411 const size_t number_pixels,unsigned char *pixels)
413 #define CheckNumberCompactPixels \
418 #define CheckNumberPixels(count) \
419 if (((ssize_t) i + count) > (ssize_t) number_pixels) \
436 packets=(ssize_t) number_compact_pixels;
437 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
440 length=(size_t) (*compact_pixels++);
446 CheckNumberCompactPixels;
447 pixel=(*compact_pixels++);
448 for (j=0; j < (ssize_t) length; j++)
454 CheckNumberPixels(8);
455 *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
456 *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
457 *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
458 *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
459 *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
460 *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
461 *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
462 *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
467 CheckNumberPixels(4);
468 *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
469 *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
470 *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
471 *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
476 CheckNumberPixels(2);
477 *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
478 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
483 CheckNumberPixels(1);
484 *pixels++=(unsigned char) pixel;
492 for (j=0; j < (ssize_t) length; j++)
494 CheckNumberCompactPixels;
499 CheckNumberPixels(8);
500 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
501 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
502 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
503 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
504 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
505 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
506 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
507 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
512 CheckNumberPixels(4);
513 *pixels++=(*compact_pixels >> 6) & 0x03;
514 *pixels++=(*compact_pixels >> 4) & 0x03;
515 *pixels++=(*compact_pixels >> 2) & 0x03;
516 *pixels++=(*compact_pixels & 0x03) & 0x03;
521 CheckNumberPixels(2);
522 *pixels++=(*compact_pixels >> 4) & 0xff;
523 *pixels++=(*compact_pixels & 0x0f) & 0xff;
528 CheckNumberPixels(1);
529 *pixels++=(*compact_pixels);
539 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
540 const ssize_t number_layers)
545 for (i=0; i<number_layers; i++)
547 if (layer_info[i].image != (Image *) NULL)
548 layer_info[i].image=DestroyImage(layer_info[i].image);
549 if (layer_info[i].mask.image != (Image *) NULL)
550 layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
551 if (layer_info[i].info != (StringInfo *) NULL)
552 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
555 return (LayerInfo *) RelinquishMagickMemory(layer_info);
558 static inline size_t GetPSDPacketSize(Image *image)
560 if (image->storage_class == PseudoClass)
562 if (image->colors > 256)
564 else if (image->depth > 8)
568 if (image->depth > 8)
574 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
576 if (psd_info->version == 1)
577 return((MagickSizeType) ReadBlobLong(image));
578 return((MagickSizeType) ReadBlobLongLong(image));
581 static inline size_t GetPSDRowSize(Image *image)
583 if (image->depth == 1)
584 return(((image->columns+7)/8)*GetPSDPacketSize(image));
586 return(image->columns*GetPSDPacketSize(image));
589 static const char *ModeToString(PSDImageType type)
593 case BitmapMode: return "Bitmap";
594 case GrayscaleMode: return "Grayscale";
595 case IndexedMode: return "Indexed";
596 case RGBMode: return "RGB";
597 case CMYKMode: return "CMYK";
598 case MultichannelMode: return "Multichannel";
599 case DuotoneMode: return "Duotone";
600 case LabMode: return "L*A*B";
601 default: return "unknown";
605 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
613 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
615 status=NegateImage(image,MagickFalse,exception);
616 (void) SetImageChannelMask(image,channel_mask);
620 static void ParseImageResourceBlocks(Image *image,
621 const unsigned char *blocks,size_t length,
622 MagickBooleanType *has_merged_image,ExceptionInfo *exception)
640 profile=BlobToStringInfo((const unsigned char *) NULL,length);
641 SetStringInfoDatum(profile,blocks);
642 (void) SetImageProfile(image,"8bim",profile,exception);
643 profile=DestroyStringInfo(profile);
644 for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); )
646 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
648 p=PushLongPixel(MSBEndian,p,&long_sans);
649 p=PushShortPixel(MSBEndian,p,&id);
650 p=PushShortPixel(MSBEndian,p,&short_sans);
651 p=PushLongPixel(MSBEndian,p,&count);
652 if ((p+count) > (blocks+length-16))
659 value[MagickPathExtent];
667 p=PushShortPixel(MSBEndian,p,&resolution);
668 image->resolution.x=(double) resolution;
669 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.x);
670 (void) SetImageProperty(image,"tiff:XResolution",value,exception);
671 p=PushShortPixel(MSBEndian,p,&short_sans);
672 p=PushShortPixel(MSBEndian,p,&short_sans);
673 p=PushShortPixel(MSBEndian,p,&short_sans);
674 p=PushShortPixel(MSBEndian,p,&resolution);
675 image->resolution.y=(double) resolution;
676 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.y);
677 (void) SetImageProperty(image,"tiff:YResolution",value,exception);
678 p=PushShortPixel(MSBEndian,p,&short_sans);
679 p=PushShortPixel(MSBEndian,p,&short_sans);
680 p=PushShortPixel(MSBEndian,p,&short_sans);
681 image->units=PixelsPerInchResolution;
687 *has_merged_image=MagickFalse;
697 if ((count & 0x01) != 0)
703 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
705 if (mode == (const char *) NULL)
706 return(OverCompositeOp);
707 if (LocaleNCompare(mode,"norm",4) == 0)
708 return(OverCompositeOp);
709 if (LocaleNCompare(mode,"mul ",4) == 0)
710 return(MultiplyCompositeOp);
711 if (LocaleNCompare(mode,"diss",4) == 0)
712 return(DissolveCompositeOp);
713 if (LocaleNCompare(mode,"diff",4) == 0)
714 return(DifferenceCompositeOp);
715 if (LocaleNCompare(mode,"dark",4) == 0)
716 return(DarkenCompositeOp);
717 if (LocaleNCompare(mode,"lite",4) == 0)
718 return(LightenCompositeOp);
719 if (LocaleNCompare(mode,"hue ",4) == 0)
720 return(HueCompositeOp);
721 if (LocaleNCompare(mode,"sat ",4) == 0)
722 return(SaturateCompositeOp);
723 if (LocaleNCompare(mode,"colr",4) == 0)
724 return(ColorizeCompositeOp);
725 if (LocaleNCompare(mode,"lum ",4) == 0)
726 return(LuminizeCompositeOp);
727 if (LocaleNCompare(mode,"scrn",4) == 0)
728 return(ScreenCompositeOp);
729 if (LocaleNCompare(mode,"over",4) == 0)
730 return(OverlayCompositeOp);
731 if (LocaleNCompare(mode,"hLit",4) == 0)
732 return(HardLightCompositeOp);
733 if (LocaleNCompare(mode,"sLit",4) == 0)
734 return(SoftLightCompositeOp);
735 if (LocaleNCompare(mode,"smud",4) == 0)
736 return(ExclusionCompositeOp);
737 if (LocaleNCompare(mode,"div ",4) == 0)
738 return(ColorDodgeCompositeOp);
739 if (LocaleNCompare(mode,"idiv",4) == 0)
740 return(ColorBurnCompositeOp);
741 if (LocaleNCompare(mode,"lbrn",4) == 0)
742 return(LinearBurnCompositeOp);
743 if (LocaleNCompare(mode,"lddg",4) == 0)
744 return(LinearDodgeCompositeOp);
745 if (LocaleNCompare(mode,"lLit",4) == 0)
746 return(LinearLightCompositeOp);
747 if (LocaleNCompare(mode,"vLit",4) == 0)
748 return(VividLightCompositeOp);
749 if (LocaleNCompare(mode,"pLit",4) == 0)
750 return(PinLightCompositeOp);
751 if (LocaleNCompare(mode,"hMix",4) == 0)
752 return(HardMixCompositeOp);
753 return(OverCompositeOp);
756 static inline void ReversePSDString(Image *image,char *p,size_t length)
761 if (image->endian == MSBEndian)
765 for(--q; p < q; ++p, --q)
773 static inline void SetPSDPixel(Image *image,const size_t channels,
774 const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
775 ExceptionInfo *exception)
777 if (image->storage_class == PseudoClass)
779 if (packet_size == 1)
780 SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
782 SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
783 SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
784 ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
791 SetPixelAlpha(image, pixel,q);
797 SetPixelRed(image,pixel,q);
798 if (channels == 1 || type == -2)
799 SetPixelGray(image,pixel,q);
804 if (image->storage_class == PseudoClass)
805 SetPixelAlpha(image,pixel,q);
807 SetPixelGreen(image,pixel,q);
812 if (image->storage_class == PseudoClass)
813 SetPixelAlpha(image,pixel,q);
815 SetPixelBlue(image,pixel,q);
820 if (image->colorspace == CMYKColorspace)
821 SetPixelBlack(image,pixel,q);
823 if (image->alpha_trait != UndefinedPixelTrait)
824 SetPixelAlpha(image,pixel,q);
829 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
832 if (image->alpha_trait != UndefinedPixelTrait)
833 SetPixelAlpha(image,pixel,q);
839 static MagickBooleanType ReadPSDChannelPixels(Image *image,
840 const size_t channels,const size_t row,const ssize_t type,
841 const unsigned char *pixels,ExceptionInfo *exception)
846 register const unsigned char
862 q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
863 if (q == (Quantum *) NULL)
865 packet_size=GetPSDPacketSize(image);
866 for (x=0; x < (ssize_t) image->columns; x++)
868 if (packet_size == 1)
869 pixel=ScaleCharToQuantum(*p++);
872 p=PushShortPixel(MSBEndian,p,&nibble);
873 pixel=ScaleShortToQuantum(nibble);
875 if (image->depth > 1)
877 SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
878 q+=GetPixelChannels(image);
886 number_bits=image->columns-x;
889 for (bit = 0; bit < number_bits; bit++)
891 SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
892 & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
893 q+=GetPixelChannels(image);
896 if (x != (ssize_t) image->columns)
901 return(SyncAuthenticPixels(image,exception));
904 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
905 const ssize_t type,ExceptionInfo *exception)
920 if (image->debug != MagickFalse)
921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
922 " layer data is RAW");
924 row_size=GetPSDRowSize(image);
925 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
926 if (pixels == (unsigned char *) NULL)
927 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
931 for (y=0; y < (ssize_t) image->rows; y++)
935 count=ReadBlob(image,row_size,pixels);
936 if (count != row_size)
939 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
940 if (status == MagickFalse)
944 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
948 static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
949 const PSDInfo *psd_info,const size_t size)
957 offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets));
958 if(offsets != (MagickOffsetType *) NULL)
960 for (y=0; y < (ssize_t) size; y++)
962 if (psd_info->version == 1)
963 offsets[y]=(MagickOffsetType) ReadBlobShort(image);
965 offsets[y]=(MagickOffsetType) ReadBlobLong(image);
971 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
972 const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
989 if (image->debug != MagickFalse)
990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991 " layer data is RLE compressed");
993 row_size=GetPSDRowSize(image);
994 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
995 if (pixels == (unsigned char *) NULL)
996 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1000 for (y=0; y < (ssize_t) image->rows; y++)
1001 if ((MagickOffsetType) length < offsets[y])
1002 length=(size_t) offsets[y];
1004 if (length > row_size + 256) // arbitrary number
1006 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1007 ThrowBinaryException(ResourceLimitError,"InvalidLength",
1011 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1012 if (compact_pixels == (unsigned char *) NULL)
1014 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1015 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1019 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
1022 for (y=0; y < (ssize_t) image->rows; y++)
1026 count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
1027 if (count != (ssize_t) offsets[y])
1030 count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
1031 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1032 if (count != (ssize_t) row_size)
1035 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1037 if (status == MagickFalse)
1041 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1042 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1046 #ifdef MAGICKCORE_ZLIB_DELEGATE
1047 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1048 const ssize_t type,const PSDCompressionType compression,
1049 const size_t compact_size,ExceptionInfo *exception)
1054 register unsigned char
1073 if (image->debug != MagickFalse)
1074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1075 " layer data is ZIP compressed");
1077 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1078 sizeof(*compact_pixels));
1079 if (compact_pixels == (unsigned char *) NULL)
1080 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1083 packet_size=GetPSDPacketSize(image);
1084 row_size=image->columns*packet_size;
1085 count=image->rows*row_size;
1087 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1088 if (pixels == (unsigned char *) NULL)
1090 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1091 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1095 ResetMagickMemory(&stream, 0, sizeof(z_stream));
1096 stream.data_type=Z_BINARY;
1097 (void) ReadBlob(image,compact_size,compact_pixels);
1099 stream.next_in=(Bytef *)compact_pixels;
1100 stream.avail_in=(unsigned int) compact_size;
1101 stream.next_out=(Bytef *)pixels;
1102 stream.avail_out=(unsigned int) count;
1104 if(inflateInit(&stream) == Z_OK)
1109 while (stream.avail_out > 0)
1111 ret=inflate(&stream, Z_SYNC_FLUSH);
1112 if (ret != Z_OK && ret != Z_STREAM_END)
1114 compact_pixels=(unsigned char *) RelinquishMagickMemory(
1116 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1117 return(MagickFalse);
1122 if (compression == ZipWithPrediction)
1127 length=image->columns;
1130 if (packet_size == 2)
1132 p[2]+=p[0]+((p[1]+p[3]) >> 8);
1146 for (y=0; y < (ssize_t) image->rows; y++)
1148 status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1149 if (status == MagickFalse)
1155 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1156 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1161 static MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
1162 LayerInfo* layer_info,const size_t channel,
1163 const PSDCompressionType compression,ExceptionInfo *exception)
1175 channel_image=image;
1176 mask=(Image *) NULL;
1177 if (layer_info->channel_info[channel].type < -1)
1180 Ignore mask that is not a user supplied layer mask, if the mask is
1181 disabled or if the flags have unsupported values.
1183 if (layer_info->channel_info[channel].type != -2 ||
1184 (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02))
1186 SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1189 mask=CloneImage(image,layer_info->mask.page.width,
1190 layer_info->mask.page.height,MagickFalse,exception);
1191 SetImageType(mask,GrayscaleType,exception);
1195 offset=TellBlob(image);
1200 status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1201 layer_info->channel_info[channel].type,exception);
1208 offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
1209 if (offsets == (MagickOffsetType *) NULL)
1210 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1212 status=ReadPSDChannelRLE(channel_image,psd_info,
1213 layer_info->channel_info[channel].type,offsets,exception);
1214 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1217 case ZipWithPrediction:
1218 case ZipWithoutPrediction:
1219 #ifdef MAGICKCORE_ZLIB_DELEGATE
1220 status=ReadPSDChannelZip(channel_image,layer_info->channels,
1221 layer_info->channel_info[channel].type,compression,
1222 layer_info->channel_info[channel].size-2,exception);
1224 (void) ThrowMagickException(exception,GetMagickModule(),
1225 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1226 "'%s' (ZLIB)",image->filename);
1230 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1231 "CompressionNotSupported","'%.20g'",(double) compression);
1235 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1236 if (status == MagickFalse)
1238 if (mask != (Image *) NULL)
1240 ThrowBinaryException(CoderError,"UnableToDecompressImage",
1243 if (mask != (Image *) NULL)
1245 if (status != MagickFalse)
1250 layer_info->mask.image=CloneImage(image,image->columns,image->rows,
1251 MagickTrue,exception);
1252 layer_info->mask.image->alpha_trait=UndefinedPixelTrait;
1253 GetPixelInfo(layer_info->mask.image,&color);
1254 color.red=layer_info->mask.background == 0 ? 0 : QuantumRange;
1255 SetImageColor(layer_info->mask.image,&color,exception);
1256 (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp,
1257 MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y,
1266 static MagickBooleanType ReadPSDLayer(Image *image,const PSDInfo *psd_info,
1267 LayerInfo* layer_info,ExceptionInfo *exception)
1270 message[MagickPathExtent];
1281 if (image->debug != MagickFalse)
1282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1283 " setting up new layer image");
1284 (void) SetImageBackgroundColor(layer_info->image,exception);
1285 layer_info->image->compose=PSDBlendModeToCompositeOperator(
1286 layer_info->blendkey);
1287 if (layer_info->visible == MagickFalse)
1288 layer_info->image->compose=NoCompositeOp;
1289 if (psd_info->mode == CMYKMode)
1290 SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1291 if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) ||
1292 (psd_info->mode == DuotoneMode))
1293 SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1295 Set up some hidden attributes for folks that need them.
1297 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1298 (double) layer_info->page.x);
1299 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1300 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1301 (double) layer_info->page.y);
1302 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1303 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1304 layer_info->opacity);
1305 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1306 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1310 for (j=0; j < (ssize_t) layer_info->channels; j++)
1312 if (image->debug != MagickFalse)
1313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1314 " reading data for channel %.20g",(double) j);
1316 compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1317 layer_info->image->compression=ConvertPSDCompression(compression);
1318 if (layer_info->channel_info[j].type == -1)
1319 layer_info->image->alpha_trait=BlendPixelTrait;
1321 status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j,
1322 compression,exception);
1324 if (status == MagickFalse)
1328 if (status != MagickFalse)
1329 status=CorrectPSDOpacity(layer_info,exception);
1331 if ((status != MagickFalse) &&
1332 (layer_info->image->colorspace == CMYKColorspace))
1333 status=NegateCMYK(layer_info->image,exception);
1335 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1337 status=CompositeImage(layer_info->image,layer_info->mask.image,
1338 CopyAlphaCompositeOp,MagickTrue,0,0,exception);
1339 layer_info->mask.image=DestroyImage(layer_info->mask.image);
1345 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1346 const ImageInfo *image_info,const PSDInfo *psd_info,
1347 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1369 size=GetPSDSize(psd_info,image);
1373 Skip layers & masks.
1375 (void) ReadBlobLong(image);
1376 count=ReadBlob(image,4,(unsigned char *) type);
1377 ReversePSDString(image,type,4);
1379 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1383 count=ReadBlob(image,4,(unsigned char *) type);
1384 ReversePSDString(image,type,4);
1385 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1386 size=GetPSDSize(psd_info,image);
1394 layer_info=(LayerInfo *) NULL;
1395 number_layers=(short) ReadBlobShort(image);
1397 if (number_layers < 0)
1400 The first alpha channel in the merged result contains the
1401 transparency data for the merged result.
1403 number_layers=MagickAbsoluteValue(number_layers);
1404 if (image->debug != MagickFalse)
1405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1406 " negative layer count corrected for");
1407 image->alpha_trait=BlendPixelTrait;
1411 We only need to know if the image has an alpha channel
1413 if (skip_layers != MagickFalse)
1416 if (image->debug != MagickFalse)
1417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1418 " image contains %.20g layers",(double) number_layers);
1420 if (number_layers == 0)
1421 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1424 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1425 sizeof(*layer_info));
1426 if (layer_info == (LayerInfo *) NULL)
1428 if (image->debug != MagickFalse)
1429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1430 " allocation of LayerInfo failed");
1431 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1434 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1435 sizeof(*layer_info));
1437 for (i=0; i < number_layers; i++)
1443 if (image->debug != MagickFalse)
1444 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1445 " reading layer #%.20g",(double) i+1);
1446 layer_info[i].page.y=ReadBlobSignedLong(image);
1447 layer_info[i].page.x=ReadBlobSignedLong(image);
1448 y=ReadBlobSignedLong(image);
1449 x=ReadBlobSignedLong(image);
1450 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1451 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1452 layer_info[i].channels=ReadBlobShort(image);
1453 if (layer_info[i].channels > MaxPSDChannels)
1455 layer_info=DestroyLayerInfo(layer_info,number_layers);
1456 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1459 if (image->debug != MagickFalse)
1460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1461 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1462 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1463 (double) layer_info[i].page.height,(double)
1464 layer_info[i].page.width,(double) layer_info[i].channels);
1465 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1467 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1468 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1470 if (image->debug != MagickFalse)
1471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1472 " channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1473 (double) layer_info[i].channel_info[j].type,
1474 (double) layer_info[i].channel_info[j].size);
1476 count=ReadBlob(image,4,(unsigned char *) type);
1477 ReversePSDString(image,type,4);
1478 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1480 if (image->debug != MagickFalse)
1481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1482 " layer type was %.4s instead of 8BIM", type);
1483 layer_info=DestroyLayerInfo(layer_info,number_layers);
1484 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1487 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1488 ReversePSDString(image,layer_info[i].blendkey,4);
1489 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1490 ReadBlobByte(image));
1491 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1492 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1493 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1494 if (image->debug != MagickFalse)
1495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1496 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1497 layer_info[i].blendkey,(double) layer_info[i].opacity,
1498 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1499 layer_info[i].visible ? "true" : "false");
1500 (void) ReadBlobByte(image); /* filler */
1502 size=ReadBlobLong(image);
1509 if (image->debug != MagickFalse)
1510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1511 " layer contains additional info");
1512 length=ReadBlobLong(image);
1513 combined_length=length+4;
1519 layer_info[i].mask.page.y=ReadBlobSignedLong(image);
1520 layer_info[i].mask.page.x=ReadBlobSignedLong(image);
1521 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
1522 layer_info[i].mask.page.y);
1523 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
1524 layer_info[i].mask.page.x);
1525 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1527 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1528 if (!(layer_info[i].mask.flags & 0x01))
1530 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1531 layer_info[i].page.y;
1532 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1533 layer_info[i].page.x;
1535 if (image->debug != MagickFalse)
1536 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1537 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1538 (double) layer_info[i].mask.page.x,(double)
1539 layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1540 (double) layer_info[i].mask.page.height,(double)
1541 ((MagickOffsetType) length)-18);
1543 Skip over the rest of the layer mask information.
1545 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1547 layer_info=DestroyLayerInfo(layer_info,number_layers);
1548 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1552 length=ReadBlobLong(image);
1553 combined_length+=length+4;
1557 Layer blending ranges info.
1559 if (image->debug != MagickFalse)
1560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1561 " layer blending ranges: length=%.20g",(double)
1562 ((MagickOffsetType) length));
1564 We read it, but don't use it...
1566 for (j=0; j < (ssize_t) length; j+=8)
1568 size_t blend_source=ReadBlobLong(image);
1569 size_t blend_dest=ReadBlobLong(image);
1570 if (image->debug != MagickFalse)
1571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1572 " source(%x), dest(%x)",(unsigned int)
1573 blend_source,(unsigned int) blend_dest);
1579 length=(MagickSizeType) ReadBlobByte(image);
1580 combined_length+=length+1;
1582 (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1583 layer_info[i].name[length]='\0';
1584 if (image->debug != MagickFalse)
1585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1586 " layer name: %s",layer_info[i].name);
1587 length=(length+(4-(length % 4)))-length;
1588 combined_length+=length;
1589 /* Skip over the padding of the layer name */
1590 if (DiscardBlobBytes(image,length) == MagickFalse)
1592 layer_info=DestroyLayerInfo(layer_info,number_layers);
1593 ThrowBinaryException(CorruptImageError,
1594 "UnexpectedEndOfFile",image->filename);
1596 length=(MagickSizeType) size-combined_length;
1602 layer_info[i].info=AcquireStringInfo((const size_t) length);
1603 info=GetStringInfoDatum(layer_info[i].info);
1604 (void) ReadBlob(image,(const size_t) length,info);
1609 for (i=0; i < number_layers; i++)
1611 if ((layer_info[i].page.width == 0) ||
1612 (layer_info[i].page.height == 0))
1614 if (image->debug != MagickFalse)
1615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1616 " layer data is empty");
1621 Allocate layered image.
1623 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1624 layer_info[i].page.height,MagickFalse,exception);
1625 if (layer_info[i].image == (Image *) NULL)
1627 layer_info=DestroyLayerInfo(layer_info,number_layers);
1628 if (image->debug != MagickFalse)
1629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1630 " allocation of image for layer %.20g failed",(double) i);
1631 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1635 if (layer_info[i].info != (StringInfo *) NULL)
1637 (void) SetImageProfile(layer_info[i].image,PSDAdditionalInfo,
1638 layer_info[i].info,exception);
1639 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1643 if (image_info->ping == MagickFalse)
1645 for (i=0; i < number_layers; i++)
1647 if (layer_info[i].image == (Image *) NULL)
1649 for (j=0; j < layer_info[i].channels; j++)
1651 if (DiscardBlobBytes(image,(MagickSizeType)
1652 layer_info[i].channel_info[j].size) == MagickFalse)
1654 layer_info=DestroyLayerInfo(layer_info,number_layers);
1655 ThrowBinaryException(CorruptImageError,
1656 "UnexpectedEndOfFile",image->filename);
1662 if (image->debug != MagickFalse)
1663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1664 " reading data for layer %.20g",(double) i);
1666 status=ReadPSDLayer(image,psd_info,&layer_info[i],exception);
1667 if (status == MagickFalse)
1670 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1672 if (status == MagickFalse)
1677 if (status != MagickFalse)
1679 for (i=0; i < number_layers; i++)
1681 if (layer_info[i].image == (Image *) NULL)
1683 for (j=i; j < number_layers - 1; j++)
1684 layer_info[j] = layer_info[j+1];
1690 if (number_layers > 0)
1692 for (i=0; i < number_layers; i++)
1695 layer_info[i].image->previous=layer_info[i-1].image;
1696 if (i < (number_layers-1))
1697 layer_info[i].image->next=layer_info[i+1].image;
1698 layer_info[i].image->page=layer_info[i].page;
1700 image->next=layer_info[0].image;
1701 layer_info[0].image->previous=image;
1703 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1706 layer_info=DestroyLayerInfo(layer_info,number_layers);
1712 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1713 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1727 compression=(PSDCompressionType) ReadBlobMSBShort(image);
1728 image->compression=ConvertPSDCompression(compression);
1730 if (compression != Raw && compression != RLE)
1732 (void) ThrowMagickException(exception,GetMagickModule(),
1733 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1734 return(MagickFalse);
1737 offsets=(MagickOffsetType *) NULL;
1738 if (compression == RLE)
1740 offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
1741 if (offsets == (MagickOffsetType *) NULL)
1742 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1747 for (i=0; i < (ssize_t) psd_info->channels; i++)
1749 if (compression == RLE)
1750 status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
1753 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1755 if (status != MagickFalse)
1756 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1758 if (status == MagickFalse)
1762 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1763 status=NegateCMYK(image,exception);
1765 if (status != MagickFalse)
1766 status=CorrectPSDAlphaBlend(image_info,image,exception);
1768 if (offsets != (MagickOffsetType *) NULL)
1769 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1774 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1807 assert(image_info != (const ImageInfo *) NULL);
1808 assert(image_info->signature == MagickCoreSignature);
1809 if (image_info->debug != MagickFalse)
1810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1811 image_info->filename);
1812 assert(exception != (ExceptionInfo *) NULL);
1813 assert(exception->signature == MagickCoreSignature);
1815 image=AcquireImage(image_info,exception);
1816 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1817 if (status == MagickFalse)
1819 image=DestroyImageList(image);
1820 return((Image *) NULL);
1825 image->endian=MSBEndian;
1826 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1827 psd_info.version=ReadBlobMSBShort(image);
1828 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1829 ((psd_info.version != 1) && (psd_info.version != 2)))
1830 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1831 (void) ReadBlob(image,6,psd_info.reserved);
1832 psd_info.channels=ReadBlobMSBShort(image);
1833 if (psd_info.channels > MaxPSDChannels)
1834 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1835 psd_info.rows=ReadBlobMSBLong(image);
1836 psd_info.columns=ReadBlobMSBLong(image);
1837 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1838 (psd_info.columns > 30000)))
1839 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1840 psd_info.depth=ReadBlobMSBShort(image);
1841 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1842 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1843 psd_info.mode=ReadBlobMSBShort(image);
1844 if (image->debug != MagickFalse)
1845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1846 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1847 (double) psd_info.columns,(double) psd_info.rows,(double)
1848 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1853 image->depth=psd_info.depth;
1854 image->columns=psd_info.columns;
1855 image->rows=psd_info.rows;
1856 status=SetImageExtent(image,image->columns,image->rows,exception);
1857 if (status == MagickFalse)
1858 return(DestroyImageList(image));
1859 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1861 image=DestroyImageList(image);
1862 return((Image *) NULL);
1864 if (psd_info.mode == LabMode)
1865 SetImageColorspace(image,LabColorspace,exception);
1866 if (psd_info.mode == CMYKMode)
1868 SetImageColorspace(image,CMYKColorspace,exception);
1869 if (psd_info.channels > 4)
1870 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1872 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
1873 (psd_info.mode == DuotoneMode))
1875 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1877 if (status == MagickFalse)
1878 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1879 if (image->debug != MagickFalse)
1880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1881 " Image colormap allocated");
1882 SetImageColorspace(image,GRAYColorspace,exception);
1883 if (psd_info.channels > 1)
1884 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1887 if (psd_info.channels > 3)
1888 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1890 Read PSD raster colormap only present for indexed and duotone images.
1892 length=ReadBlobMSBLong(image);
1895 if (image->debug != MagickFalse)
1896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1897 " reading colormap");
1898 if (psd_info.mode == DuotoneMode)
1901 Duotone image data; the format of this data is undocumented.
1903 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
1905 if (data == (unsigned char *) NULL)
1906 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1907 (void) ReadBlob(image,(size_t) length,data);
1908 data=(unsigned char *) RelinquishMagickMemory(data);
1916 Read PSD raster colormap.
1918 number_colors=length/3;
1919 if (number_colors > 65536)
1920 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1921 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
1922 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1923 for (i=0; i < (ssize_t) image->colors; i++)
1924 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1925 ReadBlobByte(image));
1926 for (i=0; i < (ssize_t) image->colors; i++)
1927 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1928 ReadBlobByte(image));
1929 for (i=0; i < (ssize_t) image->colors; i++)
1930 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1931 ReadBlobByte(image));
1932 image->alpha_trait=UndefinedPixelTrait;
1935 if ((image->depth == 1) && (image->storage_class != PseudoClass))
1936 ThrowReaderException(CorruptImageError, "ImproperImageHeader");
1937 has_merged_image=MagickTrue;
1938 length=ReadBlobMSBLong(image);
1945 Image resources block.
1947 if (image->debug != MagickFalse)
1948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1949 " reading image resource blocks - %.20g bytes",(double)
1950 ((MagickOffsetType) length));
1951 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
1953 if (blocks == (unsigned char *) NULL)
1954 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1955 count=ReadBlob(image,(size_t) length,blocks);
1956 if ((count != (ssize_t) length) || (length < 4) ||
1957 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
1959 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1960 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1962 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
1964 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1967 Layer and mask block.
1969 length=GetPSDSize(&psd_info,image);
1972 length=ReadBlobMSBLong(image);
1973 length=ReadBlobMSBLong(image);
1975 offset=TellBlob(image);
1976 skip_layers=MagickFalse;
1977 if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
1978 (has_merged_image != MagickFalse))
1980 if (image->debug != MagickFalse)
1981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1982 " read composite only");
1983 skip_layers=MagickTrue;
1987 if (image->debug != MagickFalse)
1988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1989 " image has no layers");
1993 if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
1996 (void) CloseBlob(image);
1997 image=DestroyImageList(image);
1998 return((Image *) NULL);
2002 Skip the rest of the layer and mask information.
2004 SeekBlob(image,offset+length,SEEK_SET);
2007 If we are only "pinging" the image, then we're done - so return.
2009 if (image_info->ping != MagickFalse)
2011 (void) CloseBlob(image);
2012 return(GetFirstImageInList(image));
2015 Read the precombined layer, present for PSD < 4 compatibility.
2017 if (image->debug != MagickFalse)
2018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2019 " reading the precombined layer");
2020 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2021 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2022 &psd_info,exception);
2023 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
2026 SeekBlob(image,offset,SEEK_SET);
2027 status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
2028 if (status != MagickTrue)
2030 (void) CloseBlob(image);
2031 image=DestroyImageList(image);
2032 return((Image *) NULL);
2035 if (has_merged_image == MagickFalse)
2040 if (GetImageListLength(image) == 1)
2041 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2042 SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2043 image->background_color.alpha=TransparentAlpha;
2044 image->background_color.alpha_trait=BlendPixelTrait;
2045 merged=MergeImageLayers(image,FlattenLayer,exception);
2046 ReplaceImageInList(&image,merged);
2048 (void) CloseBlob(image);
2049 return(GetFirstImageInList(image));
2053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2057 % R e g i s t e r P S D I m a g e %
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 % RegisterPSDImage() adds properties for the PSD image format to
2064 % the list of supported formats. The properties include the image format
2065 % tag, a method to read and/or write the format, whether the format
2066 % supports the saving of more than one frame to the same file or blob,
2067 % whether the format supports native in-memory I/O, and a brief
2068 % description of the format.
2070 % The format of the RegisterPSDImage method is:
2072 % size_t RegisterPSDImage(void)
2075 ModuleExport size_t RegisterPSDImage(void)
2080 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2081 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2082 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2083 entry->magick=(IsImageFormatHandler *) IsPSD;
2084 entry->flags|=CoderSeekableStreamFlag;
2085 (void) RegisterMagickInfo(entry);
2086 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2087 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2088 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2089 entry->magick=(IsImageFormatHandler *) IsPSD;
2090 entry->flags|=CoderSeekableStreamFlag;
2091 (void) RegisterMagickInfo(entry);
2092 return(MagickImageCoderSignature);
2096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100 % U n r e g i s t e r P S D I m a g e %
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2106 % UnregisterPSDImage() removes format registrations made by the
2107 % PSD module from the list of supported formats.
2109 % The format of the UnregisterPSDImage method is:
2111 % UnregisterPSDImage(void)
2114 ModuleExport void UnregisterPSDImage(void)
2116 (void) UnregisterMagickInfo("PSB");
2117 (void) UnregisterMagickInfo("PSD");
2121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125 % W r i t e P S D I m a g e %
2129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2133 % The format of the WritePSDImage method is:
2135 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2136 % ExceptionInfo *exception)
2138 % A description of each parameter follows.
2140 % o image_info: the image info.
2142 % o image: The image.
2144 % o exception: return any errors or warnings in this structure.
2148 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2149 const size_t offset)
2151 if (psd_info->version == 1)
2152 return(WriteBlobMSBShort(image,(unsigned short) offset));
2153 return(WriteBlobMSBLong(image,(unsigned short) offset));
2156 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2157 const MagickSizeType size)
2159 if (psd_info->version == 1)
2160 return(WriteBlobMSBLong(image,(unsigned int) size));
2161 return(WriteBlobMSBLongLong(image,size));
2164 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2165 const unsigned char *pixels,unsigned char *compact_pixels,
2166 ExceptionInfo *exception)
2175 register unsigned char
2182 Compress pixels with Packbits encoding.
2184 assert(image != (Image *) NULL);
2185 assert(image->signature == MagickCoreSignature);
2186 if (image->debug != MagickFalse)
2187 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2188 assert(pixels != (unsigned char *) NULL);
2189 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2190 if (packbits == (unsigned char *) NULL)
2191 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2194 for (i=(ssize_t) length; i != 0; )
2201 *q++=(unsigned char) 0;
2208 *q++=(unsigned char) 1;
2216 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2218 *q++=(unsigned char) ((256-3)+1);
2222 *q++=(unsigned char) 2;
2230 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2236 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2243 *q++=(unsigned char) ((256-count)+1);
2252 while ((*(pixels+count) != *(pixels+count+1)) ||
2253 (*(pixels+count+1) != *(pixels+count+2)))
2255 packbits[count+1]=pixels[count];
2257 if (((ssize_t) count >= (i-3)) || (count >= 127))
2261 *packbits=(unsigned char) (count-1);
2262 for (j=0; j <= (ssize_t) count; j++)
2269 *q++=(unsigned char) 128; /* EOD marker */
2270 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2271 return((size_t) (q-compact_pixels));
2274 static void WritePackbitsLength(const PSDInfo *psd_info,
2275 const ImageInfo *image_info,Image *image,Image *next_image,
2276 unsigned char *compact_pixels,const QuantumType quantum_type,
2277 ExceptionInfo *exception)
2282 register const Quantum
2295 if (next_image->depth > 8)
2296 next_image->depth=16;
2297 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2299 quantum_info=AcquireQuantumInfo(image_info,image);
2300 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2301 for (y=0; y < (ssize_t) next_image->rows; y++)
2303 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2304 if (p == (const Quantum *) NULL)
2306 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2307 quantum_type,pixels,exception);
2308 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2310 (void) SetPSDOffset(psd_info,image,length);
2312 quantum_info=DestroyQuantumInfo(quantum_info);
2315 static void WriteOneChannel(const ImageInfo *image_info,Image *image,
2316 Image *next_image,unsigned char *compact_pixels,
2317 const QuantumType quantum_type,const MagickBooleanType compression_flag,
2318 ExceptionInfo *exception)
2329 register const Quantum
2342 if ((compression_flag != MagickFalse) &&
2343 (next_image->compression != RLECompression))
2344 (void) WriteBlobMSBShort(image,0);
2345 if (next_image->depth > 8)
2346 next_image->depth=16;
2347 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2348 MagickTrue : MagickFalse;
2349 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2351 quantum_info=AcquireQuantumInfo(image_info,image);
2352 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2353 for (y=0; y < (ssize_t) next_image->rows; y++)
2355 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2356 if (p == (const Quantum *) NULL)
2358 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2359 quantum_type,pixels,exception);
2360 if (monochrome != MagickFalse)
2361 for (i=0; i < (ssize_t) length; i++)
2362 pixels[i]=(~pixels[i]);
2363 if (next_image->compression != RLECompression)
2364 (void) WriteBlob(image,length,pixels);
2367 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2369 (void) WriteBlob(image,length,compact_pixels);
2372 quantum_info=DestroyQuantumInfo(quantum_info);
2375 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
2376 const ImageInfo *image_info,Image *image,Image *next_image,
2377 const MagickBooleanType separate,ExceptionInfo *exception)
2387 Write uncompressed pixels as separate planes.
2390 packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2391 compact_pixels=(unsigned char *) NULL;
2392 if (next_image->compression == RLECompression)
2394 compact_pixels=(unsigned char *) AcquireQuantumMemory((9*channels*
2395 next_image->columns)+1,packet_size*sizeof(*compact_pixels));
2396 if (compact_pixels == (unsigned char *) NULL)
2397 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2399 if (IsImageGray(next_image) != MagickFalse)
2401 if (next_image->compression == RLECompression)
2404 Packbits compression.
2406 (void) WriteBlobMSBShort(image,1);
2407 WritePackbitsLength(psd_info,image_info,image,next_image,
2408 compact_pixels,GrayQuantum,exception);
2409 if (next_image->alpha_trait != UndefinedPixelTrait)
2410 WritePackbitsLength(psd_info,image_info,image,next_image,
2411 compact_pixels,AlphaQuantum,exception);
2413 WriteOneChannel(image_info,image,next_image,compact_pixels,GrayQuantum,
2414 MagickTrue,exception);
2415 if (next_image->alpha_trait != UndefinedPixelTrait)
2416 WriteOneChannel(image_info,image,next_image,compact_pixels,
2417 AlphaQuantum,separate,exception);
2418 (void) SetImageProgress(image,SaveImagesTag,0,1);
2421 if (next_image->storage_class == PseudoClass)
2423 if (next_image->compression == RLECompression)
2426 Packbits compression.
2428 (void) WriteBlobMSBShort(image,1);
2429 WritePackbitsLength(psd_info,image_info,image,next_image,
2430 compact_pixels,IndexQuantum,exception);
2431 if (next_image->alpha_trait != UndefinedPixelTrait)
2432 WritePackbitsLength(psd_info,image_info,image,next_image,
2433 compact_pixels,AlphaQuantum,exception);
2435 WriteOneChannel(image_info,image,next_image,compact_pixels,
2436 IndexQuantum,MagickTrue,exception);
2437 if (next_image->alpha_trait != UndefinedPixelTrait)
2438 WriteOneChannel(image_info,image,next_image,compact_pixels,
2439 AlphaQuantum,separate,exception);
2440 (void) SetImageProgress(image,SaveImagesTag,0,1);
2444 if (next_image->colorspace == CMYKColorspace)
2445 (void) NegateCMYK(next_image,exception);
2446 if (next_image->compression == RLECompression)
2449 Packbits compression.
2451 (void) WriteBlobMSBShort(image,1);
2452 WritePackbitsLength(psd_info,image_info,image,next_image,
2453 compact_pixels,RedQuantum,exception);
2454 WritePackbitsLength(psd_info,image_info,image,next_image,
2455 compact_pixels,GreenQuantum,exception);
2456 WritePackbitsLength(psd_info,image_info,image,next_image,
2457 compact_pixels,BlueQuantum,exception);
2458 if (next_image->colorspace == CMYKColorspace)
2459 WritePackbitsLength(psd_info,image_info,image,next_image,
2460 compact_pixels,BlackQuantum,exception);
2461 if (next_image->alpha_trait != UndefinedPixelTrait)
2462 WritePackbitsLength(psd_info,image_info,image,next_image,
2463 compact_pixels,AlphaQuantum,exception);
2465 (void) SetImageProgress(image,SaveImagesTag,0,6);
2466 WriteOneChannel(image_info,image,next_image,compact_pixels,RedQuantum,
2467 MagickTrue,exception);
2468 (void) SetImageProgress(image,SaveImagesTag,1,6);
2469 WriteOneChannel(image_info,image,next_image,compact_pixels,
2470 GreenQuantum,separate,exception);
2471 (void) SetImageProgress(image,SaveImagesTag,2,6);
2472 WriteOneChannel(image_info,image,next_image,compact_pixels,BlueQuantum,
2473 separate,exception);
2474 (void) SetImageProgress(image,SaveImagesTag,3,6);
2475 if (next_image->colorspace == CMYKColorspace)
2476 WriteOneChannel(image_info,image,next_image,compact_pixels,
2477 BlackQuantum,separate,exception);
2478 (void) SetImageProgress(image,SaveImagesTag,4,6);
2479 if (next_image->alpha_trait != UndefinedPixelTrait)
2480 WriteOneChannel(image_info,image,next_image,compact_pixels,
2481 AlphaQuantum,separate,exception);
2482 (void) SetImageProgress(image,SaveImagesTag,5,6);
2483 if (next_image->colorspace == CMYKColorspace)
2484 (void) NegateCMYK(next_image,exception);
2486 if (next_image->compression == RLECompression)
2487 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2491 static void WritePascalString(Image* inImage,const char *inString,int inPad)
2502 length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
2504 (void) WriteBlobByte(inImage,0);
2507 (void) WriteBlobByte(inImage,(unsigned char) length);
2508 (void) WriteBlob(inImage, length, (const unsigned char *) inString);
2511 if ((length % inPad) == 0)
2513 for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
2514 (void) WriteBlobByte(inImage,0);
2517 static void WriteResolutionResourceBlock(Image *image)
2526 if (image->units == PixelsPerCentimeterResolution)
2528 x_resolution=2.54*65536.0*image->resolution.x+0.5;
2529 y_resolution=2.54*65536.0*image->resolution.y+0.5;
2534 x_resolution=65536.0*image->resolution.x+0.5;
2535 y_resolution=65536.0*image->resolution.y+0.5;
2538 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2539 (void) WriteBlobMSBShort(image,0x03ED);
2540 (void) WriteBlobMSBShort(image,0);
2541 (void) WriteBlobMSBLong(image,16); /* resource size */
2542 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2543 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2544 (void) WriteBlobMSBShort(image,units); /* width unit */
2545 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2546 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2547 (void) WriteBlobMSBShort(image,units); /* height unit */
2550 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2552 register const unsigned char
2569 length=GetStringInfoLength(bim_profile);
2572 datum=GetStringInfoDatum(bim_profile);
2573 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2575 register unsigned char
2578 q=(unsigned char *) p;
2579 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2581 p=PushLongPixel(MSBEndian,p,&long_sans);
2582 p=PushShortPixel(MSBEndian,p,&id);
2583 p=PushShortPixel(MSBEndian,p,&short_sans);
2584 p=PushLongPixel(MSBEndian,p,&count);
2585 if (id == 0x0000040f)
2590 quantum=PSDQuantum(count)+12;
2591 if ((quantum >= 12) && (quantum < length))
2593 if ((q+quantum < (datum+length-16)))
2594 (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
2595 SetStringInfoLength(bim_profile,length-quantum);
2600 if ((count & 0x01) != 0)
2605 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2607 register const unsigned char
2624 length=GetStringInfoLength(bim_profile);
2627 datum=GetStringInfoDatum(bim_profile);
2628 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2630 register unsigned char
2636 q=(unsigned char *) p;
2637 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2639 p=PushLongPixel(MSBEndian,p,&long_sans);
2640 p=PushShortPixel(MSBEndian,p,&id);
2641 p=PushShortPixel(MSBEndian,p,&short_sans);
2642 p=PushLongPixel(MSBEndian,p,&count);
2643 cnt=PSDQuantum(count);
2646 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
2648 (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
2649 SetStringInfoLength(bim_profile,length-(cnt+12));
2653 if ((count & 0x01) != 0)
2658 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
2659 Image *image,ExceptionInfo *exception)
2661 #define PSDKeySize 5
2662 #define PSDAllowedLength 36
2667 /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
2669 allowed[PSDAllowedLength][PSDKeySize] = {
2670 "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
2671 "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
2672 "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
2673 "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
2699 info=GetImageProfile(image,PSDAdditionalInfo);
2700 if (info == (const StringInfo *) NULL)
2701 return((const StringInfo *) NULL);
2702 option=GetImageOption(image_info,"psd:additional-info");
2703 if (LocaleCompare(option,"all") == 0)
2705 if (LocaleCompare(option,"selective") != 0)
2707 profile=RemoveImageProfile(image,PSDAdditionalInfo);
2708 return(DestroyStringInfo(profile));
2710 length=GetStringInfoLength(info);
2711 p=GetStringInfoDatum(info);
2712 remaining_length=length;
2714 while (remaining_length >= 12)
2716 /* skip over signature */
2723 size=(unsigned int) (*p++) << 24;
2724 size|=(unsigned int) (*p++) << 16;
2725 size|=(unsigned int) (*p++) << 8;
2726 size|=(unsigned int) (*p++);
2727 size=size & 0xffffffff;
2728 remaining_length-=12;
2729 if ((size_t) size > remaining_length)
2730 return((const StringInfo *) NULL);
2732 for (i=0; i < PSDAllowedLength; i++)
2734 if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
2740 remaining_length-=(size_t) size;
2741 if (found == MagickFalse)
2743 if (remaining_length > 0)
2744 p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
2747 length+=(size_t) size+12;
2750 profile=RemoveImageProfile(image,PSDAdditionalInfo);
2752 return(DestroyStringInfo(profile));
2753 SetStringInfoLength(profile,(const size_t) length);
2754 SetImageProfile(image,PSDAdditionalInfo,info,exception);
2758 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
2759 Image *image,ExceptionInfo *exception)
2762 layer_name[MagickPathExtent];
2793 rounded_layer_info_size;
2801 assert(image_info != (const ImageInfo *) NULL);
2802 assert(image_info->signature == MagickCoreSignature);
2803 assert(image != (Image *) NULL);
2804 assert(image->signature == MagickCoreSignature);
2805 if (image->debug != MagickFalse)
2806 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2807 assert(exception != (ExceptionInfo *) NULL);
2808 assert(exception->signature == MagickCoreSignature);
2809 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2810 if (status == MagickFalse)
2812 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2813 if (image->alpha_trait != UndefinedPixelTrait)
2814 packet_size+=image->depth > 8 ? 2 : 1;
2816 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2817 (image->columns > 30000) || (image->rows > 30000))
2819 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2820 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
2821 for (i=1; i <= 6; i++)
2822 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
2823 if (SetImageGray(image,exception) != MagickFalse)
2824 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2826 if ((image_info->type != TrueColorType) && (image_info->type !=
2827 TrueColorAlphaType) && (image->storage_class == PseudoClass))
2828 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2831 if (image->storage_class == PseudoClass)
2832 (void) SetImageStorageClass(image,DirectClass,exception);
2833 if (image->colorspace != CMYKColorspace)
2834 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
2836 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
2838 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2839 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2840 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2841 if (IsImageGray(image) != MagickFalse)
2849 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2850 MagickTrue : MagickFalse;
2851 (void) WriteBlobMSBShort(image,(unsigned short)
2852 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2853 (void) WriteBlobMSBShort(image,(unsigned short)
2854 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
2858 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2859 PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2861 if (((image_info->colorspace != UndefinedColorspace) ||
2862 (image->colorspace != CMYKColorspace)) &&
2863 (image_info->colorspace != CMYKColorspace))
2865 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2866 (void) WriteBlobMSBShort(image,(unsigned short)
2867 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2871 if (image->colorspace != CMYKColorspace)
2872 (void) TransformImageColorspace(image,CMYKColorspace,exception);
2873 (void) WriteBlobMSBShort(image,CMYKMode);
2876 if ((IsImageGray(image) != MagickFalse) ||
2877 (image->storage_class == DirectClass) || (image->colors > 256))
2878 (void) WriteBlobMSBLong(image,0);
2882 Write PSD raster colormap.
2884 (void) WriteBlobMSBLong(image,768);
2885 for (i=0; i < (ssize_t) image->colors; i++)
2886 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2887 for ( ; i < 256; i++)
2888 (void) WriteBlobByte(image,0);
2889 for (i=0; i < (ssize_t) image->colors; i++)
2890 (void) WriteBlobByte(image,ScaleQuantumToChar(
2891 image->colormap[i].green));
2892 for ( ; i < 256; i++)
2893 (void) WriteBlobByte(image,0);
2894 for (i=0; i < (ssize_t) image->colors; i++)
2895 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2896 for ( ; i < 256; i++)
2897 (void) WriteBlobByte(image,0);
2900 Image resource block.
2902 length=28; /* 0x03EB */
2903 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2904 icc_profile=GetImageProfile(image,"icc");
2905 if (bim_profile != (StringInfo *) NULL)
2907 bim_profile=CloneStringInfo(bim_profile);
2908 if (icc_profile != (StringInfo *) NULL)
2909 RemoveICCProfileFromResourceBlock(bim_profile);
2910 RemoveResolutionFromResourceBlock(bim_profile);
2911 length+=PSDQuantum(GetStringInfoLength(bim_profile));
2913 if (icc_profile != (const StringInfo *) NULL)
2914 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2915 (void) WriteBlobMSBLong(image,(unsigned int) length);
2916 WriteResolutionResourceBlock(image);
2917 if (bim_profile != (StringInfo *) NULL)
2919 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2920 GetStringInfoDatum(bim_profile));
2921 bim_profile=DestroyStringInfo(bim_profile);
2923 if (icc_profile != (StringInfo *) NULL)
2925 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2926 (void) WriteBlobMSBShort(image,0x0000040F);
2927 (void) WriteBlobMSBShort(image,0);
2928 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2930 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2931 GetStringInfoDatum(icc_profile));
2932 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2933 PSDQuantum(GetStringInfoLength(icc_profile)))
2934 (void) WriteBlobByte(image,0);
2938 base_image=GetNextImageInList(image);
2939 if (base_image == (Image *) NULL)
2941 next_image=base_image;
2942 while (next_image != (Image *) NULL)
2944 packet_size=next_image->depth > 8 ? 2UL : 1UL;
2945 if (IsImageGray(next_image) != MagickFalse)
2946 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2948 if (next_image->storage_class == PseudoClass)
2949 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2951 if (next_image->colorspace != CMYKColorspace)
2952 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
2954 num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
2955 channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
2956 layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
2957 16)+4*1+4+num_channels*channelLength);
2958 property=(const char *) GetImageProperty(next_image,"label",exception);
2959 if (property == (const char *) NULL)
2960 layer_info_size+=16;
2966 layer_length=strlen(property);
2967 layer_info_size+=8+layer_length+(4-(layer_length % 4));
2969 info=GetAdditionalInformation(image_info,next_image,exception);
2970 if (info != (const StringInfo *) NULL)
2971 layer_info_size+=GetStringInfoLength(info);
2973 next_image=GetNextImageInList(next_image);
2975 if (layer_count == 0)
2976 (void) SetPSDSize(&psd_info,image,0);
2982 (void) SetPSDSize(&psd_info,image,layer_info_size+
2983 (psd_info.version == 1 ? 8 : 16));
2984 if ((layer_info_size/2) != ((layer_info_size+1)/2))
2985 rounded_layer_info_size=layer_info_size+1;
2987 rounded_layer_info_size=layer_info_size;
2988 (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2989 if (image->alpha_trait != UndefinedPixelTrait)
2990 (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
2992 (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2994 compression=base_image->compression;
2995 for (next_image=base_image; next_image != NULL; )
2997 next_image->compression=NoCompression;
2998 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2999 (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
3000 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
3002 (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
3003 next_image->columns));
3004 packet_size=next_image->depth > 8 ? 2UL : 1UL;
3005 channel_size=(unsigned int) ((packet_size*next_image->rows*
3006 next_image->columns)+2);
3007 if ((IsImageGray(next_image) != MagickFalse) ||
3008 (next_image->storage_class == PseudoClass))
3010 (void) WriteBlobMSBShort(image,(unsigned short)
3011 (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
3012 (void) WriteBlobMSBShort(image,0);
3013 (void) SetPSDSize(&psd_info,image,channel_size);
3014 if (next_image->alpha_trait != UndefinedPixelTrait)
3016 (void) WriteBlobMSBShort(image,(unsigned short) -1);
3017 (void) SetPSDSize(&psd_info,image,channel_size);
3021 if (next_image->colorspace != CMYKColorspace)
3023 (void) WriteBlobMSBShort(image,(unsigned short)
3024 (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
3025 (void) WriteBlobMSBShort(image,0);
3026 (void) SetPSDSize(&psd_info,image,channel_size);
3027 (void) WriteBlobMSBShort(image,1);
3028 (void) SetPSDSize(&psd_info,image,channel_size);
3029 (void) WriteBlobMSBShort(image,2);
3030 (void) SetPSDSize(&psd_info,image,channel_size);
3031 if (next_image->alpha_trait != UndefinedPixelTrait)
3033 (void) WriteBlobMSBShort(image,(unsigned short) -1);
3034 (void) SetPSDSize(&psd_info,image,channel_size);
3039 (void) WriteBlobMSBShort(image,(unsigned short)
3040 (next_image->alpha_trait ? 5 : 4));
3041 (void) WriteBlobMSBShort(image,0);
3042 (void) SetPSDSize(&psd_info,image,channel_size);
3043 (void) WriteBlobMSBShort(image,1);
3044 (void) SetPSDSize(&psd_info,image,channel_size);
3045 (void) WriteBlobMSBShort(image,2);
3046 (void) SetPSDSize(&psd_info,image,channel_size);
3047 (void) WriteBlobMSBShort(image,3);
3048 (void) SetPSDSize(&psd_info,image,channel_size);
3049 if (next_image->alpha_trait)
3051 (void) WriteBlobMSBShort(image,(unsigned short) -1);
3052 (void) SetPSDSize(&psd_info,image,channel_size);
3055 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3056 (void) WriteBlob(image,4,(const unsigned char *)
3057 CompositeOperatorToPSDBlendMode(next_image->compose));
3058 (void) WriteBlobByte(image,255); /* layer opacity */
3059 (void) WriteBlobByte(image,0);
3060 (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
3061 1 << 0x02 : 1); /* layer properties - visible, etc. */
3062 (void) WriteBlobByte(image,0);
3063 info=GetImageProfile(next_image,PSDAdditionalInfo);
3064 property=(const char *) GetImageProperty(next_image,"label",exception);
3065 if (property == (const char *) NULL)
3067 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3068 (double) layer_count++);
3069 property=layer_name;
3071 name_length=strlen(property);
3072 name_length+=(4-(name_length % 4));
3073 if (info != (const StringInfo *) NULL)
3074 name_length+=GetStringInfoLength(info);
3075 (void) WriteBlobMSBLong(image,(unsigned int)name_length+8);
3076 (void) WriteBlobMSBLong(image,0);
3077 (void) WriteBlobMSBLong(image,0);
3078 WritePascalString(image,property,4);
3079 if (info != (const StringInfo *) NULL)
3080 (void) WriteBlob(image,GetStringInfoLength(info),GetStringInfoDatum(info));
3081 next_image=GetNextImageInList(next_image);
3086 next_image=base_image;
3087 while (next_image != NULL)
3089 status=WriteImageChannels(&psd_info,image_info,image,next_image,
3090 MagickTrue,exception);
3091 next_image=GetNextImageInList(next_image);
3093 (void) WriteBlobMSBLong(image,0); /* user mask data */
3094 base_image->compression=compression;
3097 Write composite image.
3099 if (status != MagickFalse)
3100 status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
3102 (void) CloseBlob(image);