2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Adobe Photoshop Image Format %
23 % Copyright 1999-2017 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/registry.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/static.h"
76 #include "MagickCore/string_.h"
77 #include "MagickCore/string-private.h"
78 #include "MagickCore/thread-private.h"
79 #ifdef MAGICKCORE_ZLIB_DELEGATE
82 #include "psd-private.h"
87 #define MaxPSDChannels 56
88 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
91 Enumerated declaractions.
97 ZipWithoutPrediction = 2,
108 MultichannelMode = 7,
114 Typedef declaractions.
116 typedef struct _ChannelInfo
125 typedef struct _MaskInfo
138 typedef struct _LayerInfo
141 channel_info[MaxPSDChannels];
176 Forward declarations.
178 static MagickBooleanType
179 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 % IsPSD()() returns MagickTrue if the image format type, identified by the
193 % magick string, is PSD.
195 % The format of the IsPSD method is:
197 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
199 % A description of each parameter follows:
201 % o magick: compare image format pattern against these bytes.
203 % o length: Specifies the length of the magick string.
206 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
210 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % R e a d P S D I m a g e %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It
227 % allocates the memory necessary for the new Image structure and returns a
228 % pointer to the new image.
230 % The format of the ReadPSDImage method is:
232 % Image *ReadPSDImage(image_info,ExceptionInfo *exception)
234 % A description of each parameter follows:
236 % o image_info: the image info.
238 % o exception: return any errors or warnings in this structure.
242 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
249 case ColorBurnCompositeOp: blend_mode = "idiv"; break;
250 case ColorDodgeCompositeOp: blend_mode = "div "; break;
251 case ColorizeCompositeOp: blend_mode = "colr"; break;
252 case DarkenCompositeOp: blend_mode = "dark"; break;
253 case DifferenceCompositeOp: blend_mode = "diff"; break;
254 case DissolveCompositeOp: blend_mode = "diss"; break;
255 case ExclusionCompositeOp: blend_mode = "smud"; break;
256 case HardLightCompositeOp: blend_mode = "hLit"; break;
257 case HardMixCompositeOp: blend_mode = "hMix"; break;
258 case HueCompositeOp: blend_mode = "hue "; break;
259 case LightenCompositeOp: blend_mode = "lite"; break;
260 case LinearBurnCompositeOp: blend_mode = "lbrn"; break;
261 case LinearDodgeCompositeOp:blend_mode = "lddg"; break;
262 case LinearLightCompositeOp:blend_mode = "lLit"; break;
263 case LuminizeCompositeOp: blend_mode = "lum "; break;
264 case MultiplyCompositeOp: blend_mode = "mul "; break;
265 case OverCompositeOp: blend_mode = "norm"; break;
266 case OverlayCompositeOp: blend_mode = "over"; break;
267 case PinLightCompositeOp: blend_mode = "pLit"; break;
268 case SaturateCompositeOp: blend_mode = "sat "; break;
269 case ScreenCompositeOp: blend_mode = "scrn"; break;
270 case SoftLightCompositeOp: blend_mode = "sLit"; break;
271 case VividLightCompositeOp: blend_mode = "vLit"; break;
272 default: blend_mode = "norm";
278 For some reason Photoshop seems to blend semi-transparent pixels with white.
279 This method reverts the blending. This can be disabled by setting the
280 option 'psd:alpha-unblend' to off.
282 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
283 Image *image,ExceptionInfo* exception)
294 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace)
296 option=GetImageOption(image_info,"psd:alpha-unblend");
297 if (IsStringFalse(option) != MagickFalse)
300 #if defined(MAGICKCORE_OPENMP_SUPPORT)
301 #pragma omp parallel for schedule(static,4) shared(status) \
302 magick_threads(image,image,image->rows,1)
304 for (y=0; y < (ssize_t) image->rows; y++)
312 if (status == MagickFalse)
314 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
315 if (q == (Quantum *) NULL)
320 for (x=0; x < (ssize_t) image->columns; x++)
328 gamma=QuantumScale*GetPixelAlpha(image, q);
329 if (gamma != 0.0 && gamma != 1.0)
331 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
333 PixelChannel channel=GetPixelChannelChannel(image,i);
334 if (channel != AlphaPixelChannel)
335 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
338 q+=GetPixelChannels(image);
340 if (SyncAuthenticPixels(image,exception) == MagickFalse)
347 static inline CompressionType ConvertPSDCompression(
348 PSDCompressionType compression)
353 return RLECompression;
354 case ZipWithPrediction:
355 case ZipWithoutPrediction:
356 return ZipCompression;
358 return NoCompression;
362 static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
363 MagickBooleanType revert,ExceptionInfo *exception)
371 if (image->debug != MagickFalse)
372 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
373 " applying layer opacity %.20g", (double) opacity);
374 if (opacity == OpaqueAlpha)
376 image->alpha_trait=BlendPixelTrait;
378 #if defined(MAGICKCORE_OPENMP_SUPPORT)
379 #pragma omp parallel for schedule(static,4) shared(status) \
380 magick_threads(image,image,image->rows,1)
382 for (y=0; y < (ssize_t) image->rows; y++)
390 if (status == MagickFalse)
392 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
393 if (q == (Quantum *) NULL)
398 for (x=0; x < (ssize_t) image->columns; x++)
400 if (revert == MagickFalse)
401 SetPixelAlpha(image,(Quantum) (QuantumScale*(GetPixelAlpha(image,q))*
403 else if (opacity > 0)
404 SetPixelAlpha(image,(Quantum) (QuantumRange*(GetPixelAlpha(image,q)/
405 (MagickRealType) opacity)),q);
406 q+=GetPixelChannels(image);
408 if (SyncAuthenticPixels(image,exception) == MagickFalse)
415 static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
416 Quantum background,MagickBooleanType revert,ExceptionInfo *exception)
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
432 " applying opacity mask");
433 complete_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
435 complete_mask->alpha_trait=BlendPixelTrait;
436 GetPixelInfo(complete_mask,&color);
437 color.red=background;
438 SetImageColor(complete_mask,&color,exception);
439 status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
440 mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
441 if (status == MagickFalse)
443 complete_mask=DestroyImage(complete_mask);
446 image->alpha_trait=BlendPixelTrait;
447 #if defined(MAGICKCORE_OPENMP_SUPPORT)
448 #pragma omp parallel for schedule(static,4) shared(status) \
449 magick_threads(image,image,image->rows,1)
451 for (y=0; y < (ssize_t) image->rows; y++)
462 if (status == MagickFalse)
464 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
465 p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception);
466 if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL))
471 for (x=0; x < (ssize_t) image->columns; x++)
477 alpha=GetPixelAlpha(image,q);
478 intensity=GetPixelIntensity(complete_mask,p);
479 if (revert == MagickFalse)
480 SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
481 else if (intensity > 0)
482 SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*QuantumRange),q);
483 q+=GetPixelChannels(image);
484 p+=GetPixelChannels(complete_mask);
486 if (SyncAuthenticPixels(image,exception) == MagickFalse)
489 complete_mask=DestroyImage(complete_mask);
493 static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info,
494 ExceptionInfo *exception)
505 if (image->debug != MagickFalse)
506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
507 " preserving opacity mask");
508 random_info=AcquireRandomInfo();
509 key_info=GetRandomKey(random_info,2+1);
510 key=(char *) GetStringInfoDatum(key_info);
511 key[8]=layer_info->mask.background;
513 layer_info->mask.image->page.x+=layer_info->page.x;
514 layer_info->mask.image->page.y+=layer_info->page.y;
515 (void) SetImageRegistry(ImageRegistryType,(const char *) key,
516 layer_info->mask.image,exception);
517 (void) SetImageArtifact(layer_info->image,"psd:opacity-mask",
519 key_info=DestroyStringInfo(key_info);
520 random_info=DestroyRandomInfo(random_info);
523 static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
524 const unsigned char *compact_pixels,const ssize_t depth,
525 const size_t number_pixels,unsigned char *pixels)
527 #define CheckNumberCompactPixels \
532 #define CheckNumberPixels(count) \
533 if (((ssize_t) i + count) > (ssize_t) number_pixels) \
550 packets=(ssize_t) number_compact_pixels;
551 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
554 length=(size_t) (*compact_pixels++);
560 CheckNumberCompactPixels;
561 pixel=(*compact_pixels++);
562 for (j=0; j < (ssize_t) length; j++)
568 CheckNumberPixels(8);
569 *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
570 *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
571 *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
572 *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
573 *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
574 *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
575 *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
576 *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
581 CheckNumberPixels(4);
582 *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
583 *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
584 *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
585 *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
590 CheckNumberPixels(2);
591 *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
592 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
597 CheckNumberPixels(1);
598 *pixels++=(unsigned char) pixel;
606 for (j=0; j < (ssize_t) length; j++)
608 CheckNumberCompactPixels;
613 CheckNumberPixels(8);
614 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
615 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
616 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
617 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
618 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
619 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
620 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
621 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
626 CheckNumberPixels(4);
627 *pixels++=(*compact_pixels >> 6) & 0x03;
628 *pixels++=(*compact_pixels >> 4) & 0x03;
629 *pixels++=(*compact_pixels >> 2) & 0x03;
630 *pixels++=(*compact_pixels & 0x03) & 0x03;
635 CheckNumberPixels(2);
636 *pixels++=(*compact_pixels >> 4) & 0xff;
637 *pixels++=(*compact_pixels & 0x0f) & 0xff;
642 CheckNumberPixels(1);
643 *pixels++=(*compact_pixels);
653 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
654 const ssize_t number_layers)
659 for (i=0; i<number_layers; i++)
661 if (layer_info[i].image != (Image *) NULL)
662 layer_info[i].image=DestroyImage(layer_info[i].image);
663 if (layer_info[i].mask.image != (Image *) NULL)
664 layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
665 if (layer_info[i].info != (StringInfo *) NULL)
666 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
669 return (LayerInfo *) RelinquishMagickMemory(layer_info);
672 static inline size_t GetPSDPacketSize(Image *image)
674 if (image->storage_class == PseudoClass)
676 if (image->colors > 256)
678 else if (image->depth > 8)
682 if (image->depth > 8)
688 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
690 if (psd_info->version == 1)
691 return((MagickSizeType) ReadBlobLong(image));
692 return((MagickSizeType) ReadBlobLongLong(image));
695 static inline size_t GetPSDRowSize(Image *image)
697 if (image->depth == 1)
698 return(((image->columns+7)/8)*GetPSDPacketSize(image));
700 return(image->columns*GetPSDPacketSize(image));
703 static const char *ModeToString(PSDImageType type)
707 case BitmapMode: return "Bitmap";
708 case GrayscaleMode: return "Grayscale";
709 case IndexedMode: return "Indexed";
710 case RGBMode: return "RGB";
711 case CMYKMode: return "CMYK";
712 case MultichannelMode: return "Multichannel";
713 case DuotoneMode: return "Duotone";
714 case LabMode: return "L*A*B";
715 default: return "unknown";
719 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
727 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
729 status=NegateImage(image,MagickFalse,exception);
730 (void) SetImageChannelMask(image,channel_mask);
734 static void ParseImageResourceBlocks(Image *image,
735 const unsigned char *blocks,size_t length,
736 MagickBooleanType *has_merged_image,ExceptionInfo *exception)
754 profile=BlobToStringInfo((const unsigned char *) NULL,length);
755 SetStringInfoDatum(profile,blocks);
756 (void) SetImageProfile(image,"8bim",profile,exception);
757 profile=DestroyStringInfo(profile);
758 for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); )
760 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
762 p=PushLongPixel(MSBEndian,p,&long_sans);
763 p=PushShortPixel(MSBEndian,p,&id);
764 p=PushShortPixel(MSBEndian,p,&short_sans);
765 p=PushLongPixel(MSBEndian,p,&count);
766 if ((p+count) > (blocks+length-16))
773 value[MagickPathExtent];
781 p=PushShortPixel(MSBEndian,p,&resolution);
782 image->resolution.x=(double) resolution;
783 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.x);
784 (void) SetImageProperty(image,"tiff:XResolution",value,exception);
785 p=PushShortPixel(MSBEndian,p,&short_sans);
786 p=PushShortPixel(MSBEndian,p,&short_sans);
787 p=PushShortPixel(MSBEndian,p,&short_sans);
788 p=PushShortPixel(MSBEndian,p,&resolution);
789 image->resolution.y=(double) resolution;
790 (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.y);
791 (void) SetImageProperty(image,"tiff:YResolution",value,exception);
792 p=PushShortPixel(MSBEndian,p,&short_sans);
793 p=PushShortPixel(MSBEndian,p,&short_sans);
794 p=PushShortPixel(MSBEndian,p,&short_sans);
795 image->units=PixelsPerInchResolution;
801 *has_merged_image=MagickFalse;
811 if ((count & 0x01) != 0)
817 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
819 if (mode == (const char *) NULL)
820 return(OverCompositeOp);
821 if (LocaleNCompare(mode,"norm",4) == 0)
822 return(OverCompositeOp);
823 if (LocaleNCompare(mode,"mul ",4) == 0)
824 return(MultiplyCompositeOp);
825 if (LocaleNCompare(mode,"diss",4) == 0)
826 return(DissolveCompositeOp);
827 if (LocaleNCompare(mode,"diff",4) == 0)
828 return(DifferenceCompositeOp);
829 if (LocaleNCompare(mode,"dark",4) == 0)
830 return(DarkenCompositeOp);
831 if (LocaleNCompare(mode,"lite",4) == 0)
832 return(LightenCompositeOp);
833 if (LocaleNCompare(mode,"hue ",4) == 0)
834 return(HueCompositeOp);
835 if (LocaleNCompare(mode,"sat ",4) == 0)
836 return(SaturateCompositeOp);
837 if (LocaleNCompare(mode,"colr",4) == 0)
838 return(ColorizeCompositeOp);
839 if (LocaleNCompare(mode,"lum ",4) == 0)
840 return(LuminizeCompositeOp);
841 if (LocaleNCompare(mode,"scrn",4) == 0)
842 return(ScreenCompositeOp);
843 if (LocaleNCompare(mode,"over",4) == 0)
844 return(OverlayCompositeOp);
845 if (LocaleNCompare(mode,"hLit",4) == 0)
846 return(HardLightCompositeOp);
847 if (LocaleNCompare(mode,"sLit",4) == 0)
848 return(SoftLightCompositeOp);
849 if (LocaleNCompare(mode,"smud",4) == 0)
850 return(ExclusionCompositeOp);
851 if (LocaleNCompare(mode,"div ",4) == 0)
852 return(ColorDodgeCompositeOp);
853 if (LocaleNCompare(mode,"idiv",4) == 0)
854 return(ColorBurnCompositeOp);
855 if (LocaleNCompare(mode,"lbrn",4) == 0)
856 return(LinearBurnCompositeOp);
857 if (LocaleNCompare(mode,"lddg",4) == 0)
858 return(LinearDodgeCompositeOp);
859 if (LocaleNCompare(mode,"lLit",4) == 0)
860 return(LinearLightCompositeOp);
861 if (LocaleNCompare(mode,"vLit",4) == 0)
862 return(VividLightCompositeOp);
863 if (LocaleNCompare(mode,"pLit",4) == 0)
864 return(PinLightCompositeOp);
865 if (LocaleNCompare(mode,"hMix",4) == 0)
866 return(HardMixCompositeOp);
867 return(OverCompositeOp);
870 static inline void ReversePSDString(Image *image,char *p,size_t length)
875 if (image->endian == MSBEndian)
879 for(--q; p < q; ++p, --q)
887 static inline void SetPSDPixel(Image *image,const size_t channels,
888 const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
889 ExceptionInfo *exception)
891 if (image->storage_class == PseudoClass)
893 if (packet_size == 1)
894 SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
896 SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
897 SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
898 ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
905 SetPixelAlpha(image, pixel,q);
911 SetPixelRed(image,pixel,q);
912 if (channels == 1 || type == -2)
913 SetPixelGray(image,pixel,q);
918 if (image->storage_class == PseudoClass)
919 SetPixelAlpha(image,pixel,q);
921 SetPixelGreen(image,pixel,q);
926 if (image->storage_class == PseudoClass)
927 SetPixelAlpha(image,pixel,q);
929 SetPixelBlue(image,pixel,q);
934 if (image->colorspace == CMYKColorspace)
935 SetPixelBlack(image,pixel,q);
937 if (image->alpha_trait != UndefinedPixelTrait)
938 SetPixelAlpha(image,pixel,q);
943 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
946 if (image->alpha_trait != UndefinedPixelTrait)
947 SetPixelAlpha(image,pixel,q);
953 static MagickBooleanType ReadPSDChannelPixels(Image *image,
954 const size_t channels,const size_t row,const ssize_t type,
955 const unsigned char *pixels,ExceptionInfo *exception)
960 register const unsigned char
976 q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
977 if (q == (Quantum *) NULL)
979 packet_size=GetPSDPacketSize(image);
980 for (x=0; x < (ssize_t) image->columns; x++)
982 if (packet_size == 1)
983 pixel=ScaleCharToQuantum(*p++);
986 p=PushShortPixel(MSBEndian,p,&nibble);
987 pixel=ScaleShortToQuantum(nibble);
989 if (image->depth > 1)
991 SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
992 q+=GetPixelChannels(image);
1000 number_bits=image->columns-x;
1001 if (number_bits > 8)
1003 for (bit = 0; bit < number_bits; bit++)
1005 SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
1006 & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
1007 q+=GetPixelChannels(image);
1010 if (x != (ssize_t) image->columns)
1015 return(SyncAuthenticPixels(image,exception));
1018 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
1019 const ssize_t type,ExceptionInfo *exception)
1034 if (image->debug != MagickFalse)
1035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1036 " layer data is RAW");
1038 row_size=GetPSDRowSize(image);
1039 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1040 if (pixels == (unsigned char *) NULL)
1041 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1045 for (y=0; y < (ssize_t) image->rows; y++)
1049 count=ReadBlob(image,row_size,pixels);
1050 if (count != row_size)
1053 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
1054 if (status == MagickFalse)
1058 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1062 static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
1063 const PSDInfo *psd_info,const size_t size)
1071 sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes));
1072 if(sizes != (MagickOffsetType *) NULL)
1074 for (y=0; y < (ssize_t) size; y++)
1076 if (psd_info->version == 1)
1077 sizes[y]=(MagickOffsetType) ReadBlobShort(image);
1079 sizes[y]=(MagickOffsetType) ReadBlobLong(image);
1085 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
1086 const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception)
1103 if (image->debug != MagickFalse)
1104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1105 " layer data is RLE compressed");
1107 row_size=GetPSDRowSize(image);
1108 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1109 if (pixels == (unsigned char *) NULL)
1110 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1114 for (y=0; y < (ssize_t) image->rows; y++)
1115 if ((MagickOffsetType) length < sizes[y])
1116 length=(size_t) sizes[y];
1118 if (length > row_size + 256) // arbitrary number
1120 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1121 ThrowBinaryException(ResourceLimitError,"InvalidLength",
1125 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1126 if (compact_pixels == (unsigned char *) NULL)
1128 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1129 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1133 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
1136 for (y=0; y < (ssize_t) image->rows; y++)
1140 count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
1141 if (count != (ssize_t) sizes[y])
1144 count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
1145 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1146 if (count != (ssize_t) row_size)
1149 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1151 if (status == MagickFalse)
1155 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1156 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1160 #ifdef MAGICKCORE_ZLIB_DELEGATE
1161 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1162 const ssize_t type,const PSDCompressionType compression,
1163 const size_t compact_size,ExceptionInfo *exception)
1168 register unsigned char
1187 if (image->debug != MagickFalse)
1188 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1189 " layer data is ZIP compressed");
1191 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1192 sizeof(*compact_pixels));
1193 if (compact_pixels == (unsigned char *) NULL)
1194 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1197 packet_size=GetPSDPacketSize(image);
1198 row_size=image->columns*packet_size;
1199 count=image->rows*row_size;
1201 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1202 if (pixels == (unsigned char *) NULL)
1204 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1205 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1209 ResetMagickMemory(&stream,0,sizeof(stream));
1210 stream.data_type=Z_BINARY;
1211 (void) ReadBlob(image,compact_size,compact_pixels);
1213 stream.next_in=(Bytef *)compact_pixels;
1214 stream.avail_in=(uInt) compact_size;
1215 stream.next_out=(Bytef *)pixels;
1216 stream.avail_out=(uInt) count;
1218 if (inflateInit(&stream) == Z_OK)
1223 while (stream.avail_out > 0)
1225 ret=inflate(&stream,Z_SYNC_FLUSH);
1226 if ((ret != Z_OK) && (ret != Z_STREAM_END))
1228 compact_pixels=(unsigned char *) RelinquishMagickMemory(
1230 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1231 return(MagickFalse);
1236 if (compression == ZipWithPrediction)
1241 length=image->columns;
1244 if (packet_size == 2)
1246 p[2]+=p[0]+((p[1]+p[3]) >> 8);
1260 for (y=0; y < (ssize_t) image->rows; y++)
1262 status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1263 if (status == MagickFalse)
1269 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1270 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1275 static MagickBooleanType ReadPSDChannel(Image *image,
1276 const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
1277 const size_t channel,const PSDCompressionType compression,
1278 ExceptionInfo *exception)
1290 channel_image=image;
1291 mask=(Image *) NULL;
1292 if (layer_info->channel_info[channel].type < -1)
1297 Ignore mask that is not a user supplied layer mask, if the mask is
1298 disabled or if the flags have unsupported values.
1300 option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1301 if ((layer_info->channel_info[channel].type != -2) ||
1302 (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
1303 (IsStringTrue(option) == MagickFalse)))
1305 SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1308 mask=CloneImage(image,layer_info->mask.page.width,
1309 layer_info->mask.page.height,MagickFalse,exception);
1310 SetImageType(mask,GrayscaleType,exception);
1314 offset=TellBlob(image);
1319 status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1320 layer_info->channel_info[channel].type,exception);
1327 sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
1328 if (sizes == (MagickOffsetType *) NULL)
1329 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1331 status=ReadPSDChannelRLE(channel_image,psd_info,
1332 layer_info->channel_info[channel].type,sizes,exception);
1333 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1336 case ZipWithPrediction:
1337 case ZipWithoutPrediction:
1338 #ifdef MAGICKCORE_ZLIB_DELEGATE
1339 status=ReadPSDChannelZip(channel_image,layer_info->channels,
1340 layer_info->channel_info[channel].type,compression,
1341 layer_info->channel_info[channel].size-2,exception);
1343 (void) ThrowMagickException(exception,GetMagickModule(),
1344 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1345 "'%s' (ZLIB)",image->filename);
1349 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1350 "CompressionNotSupported","'%.20g'",(double) compression);
1354 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1355 if (status == MagickFalse)
1357 if (mask != (Image *) NULL)
1359 ThrowBinaryException(CoderError,"UnableToDecompressImage",
1362 if (mask != (Image *) NULL)
1364 if (status != MagickFalse)
1365 layer_info->mask.image=mask;
1367 mask=DestroyImage(mask);
1373 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1374 const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1377 message[MagickPathExtent];
1388 if (image->debug != MagickFalse)
1389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1390 " setting up new layer image");
1391 if (psd_info->mode != IndexedMode)
1392 (void) SetImageBackgroundColor(layer_info->image,exception);
1393 layer_info->image->compose=PSDBlendModeToCompositeOperator(
1394 layer_info->blendkey);
1395 if (layer_info->visible == MagickFalse)
1396 layer_info->image->compose=NoCompositeOp;
1397 if (psd_info->mode == CMYKMode)
1398 SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1399 else if ((psd_info->mode == BitmapMode) || (psd_info->mode == DuotoneMode) ||
1400 (psd_info->mode == GrayscaleMode))
1401 SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1403 Set up some hidden attributes for folks that need them.
1405 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1406 (double) layer_info->page.x);
1407 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1408 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1409 (double) layer_info->page.y);
1410 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1411 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1412 layer_info->opacity);
1413 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1414 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1418 for (j=0; j < (ssize_t) layer_info->channels; j++)
1420 if (image->debug != MagickFalse)
1421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1422 " reading data for channel %.20g",(double) j);
1424 compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1425 layer_info->image->compression=ConvertPSDCompression(compression);
1426 if (layer_info->channel_info[j].type == -1)
1427 layer_info->image->alpha_trait=BlendPixelTrait;
1429 status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
1430 compression,exception);
1432 if (status == MagickFalse)
1436 if (status != MagickFalse)
1437 status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1438 MagickFalse,exception);
1440 if ((status != MagickFalse) &&
1441 (layer_info->image->colorspace == CMYKColorspace))
1442 status=NegateCMYK(layer_info->image,exception);
1444 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1449 layer_info->mask.image->page.x=layer_info->mask.page.x;
1450 layer_info->mask.image->page.y=layer_info->mask.page.y;
1451 /* Do not composite the mask when it is disabled */
1452 if ((layer_info->mask.flags & 0x02) == 0x02)
1453 layer_info->mask.image->compose=NoCompositeOp;
1455 status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1456 layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1458 option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1459 if (IsStringTrue(option) != MagickFalse)
1460 PreservePSDOpacityMask(image,layer_info,exception);
1461 layer_info->mask.image=DestroyImage(layer_info->mask.image);
1467 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1468 const ImageInfo *image_info,const PSDInfo *psd_info,
1469 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1491 size=GetPSDSize(psd_info,image);
1495 Skip layers & masks.
1497 (void) ReadBlobLong(image);
1498 count=ReadBlob(image,4,(unsigned char *) type);
1499 ReversePSDString(image,type,4);
1501 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1505 count=ReadBlob(image,4,(unsigned char *) type);
1506 ReversePSDString(image,type,4);
1507 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1508 size=GetPSDSize(psd_info,image);
1516 layer_info=(LayerInfo *) NULL;
1517 number_layers=(short) ReadBlobShort(image);
1519 if (number_layers < 0)
1522 The first alpha channel in the merged result contains the
1523 transparency data for the merged result.
1525 number_layers=MagickAbsoluteValue(number_layers);
1526 if (image->debug != MagickFalse)
1527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1528 " negative layer count corrected for");
1529 image->alpha_trait=BlendPixelTrait;
1533 We only need to know if the image has an alpha channel
1535 if (skip_layers != MagickFalse)
1538 if (image->debug != MagickFalse)
1539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1540 " image contains %.20g layers",(double) number_layers);
1542 if (number_layers == 0)
1543 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1546 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1547 sizeof(*layer_info));
1548 if (layer_info == (LayerInfo *) NULL)
1550 if (image->debug != MagickFalse)
1551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1552 " allocation of LayerInfo failed");
1553 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1556 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1557 sizeof(*layer_info));
1559 for (i=0; i < number_layers; i++)
1565 if (image->debug != MagickFalse)
1566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1567 " reading layer #%.20g",(double) i+1);
1568 layer_info[i].page.y=ReadBlobSignedLong(image);
1569 layer_info[i].page.x=ReadBlobSignedLong(image);
1570 y=ReadBlobSignedLong(image);
1571 x=ReadBlobSignedLong(image);
1572 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1573 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1574 layer_info[i].channels=ReadBlobShort(image);
1575 if (layer_info[i].channels > MaxPSDChannels)
1577 layer_info=DestroyLayerInfo(layer_info,number_layers);
1578 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1581 if (image->debug != MagickFalse)
1582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1583 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1584 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1585 (double) layer_info[i].page.height,(double)
1586 layer_info[i].page.width,(double) layer_info[i].channels);
1587 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1589 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1590 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1592 if (image->debug != MagickFalse)
1593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1594 " channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1595 (double) layer_info[i].channel_info[j].type,
1596 (double) layer_info[i].channel_info[j].size);
1598 count=ReadBlob(image,4,(unsigned char *) type);
1599 ReversePSDString(image,type,4);
1600 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1602 if (image->debug != MagickFalse)
1603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1604 " layer type was %.4s instead of 8BIM", type);
1605 layer_info=DestroyLayerInfo(layer_info,number_layers);
1606 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1609 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1610 ReversePSDString(image,layer_info[i].blendkey,4);
1611 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1612 ReadBlobByte(image));
1613 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1614 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1615 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1616 if (image->debug != MagickFalse)
1617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1618 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1619 layer_info[i].blendkey,(double) layer_info[i].opacity,
1620 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1621 layer_info[i].visible ? "true" : "false");
1622 (void) ReadBlobByte(image); /* filler */
1624 size=ReadBlobLong(image);
1631 if (image->debug != MagickFalse)
1632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1633 " layer contains additional info");
1634 length=ReadBlobLong(image);
1635 combined_length=length+4;
1641 layer_info[i].mask.page.y=ReadBlobSignedLong(image);
1642 layer_info[i].mask.page.x=ReadBlobSignedLong(image);
1643 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
1644 layer_info[i].mask.page.y);
1645 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
1646 layer_info[i].mask.page.x);
1647 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1649 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1650 if (!(layer_info[i].mask.flags & 0x01))
1652 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1653 layer_info[i].page.y;
1654 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1655 layer_info[i].page.x;
1657 if (image->debug != MagickFalse)
1658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1659 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1660 (double) layer_info[i].mask.page.x,(double)
1661 layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1662 (double) layer_info[i].mask.page.height,(double)
1663 ((MagickOffsetType) length)-18);
1665 Skip over the rest of the layer mask information.
1667 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1669 layer_info=DestroyLayerInfo(layer_info,number_layers);
1670 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1674 length=ReadBlobLong(image);
1675 combined_length+=length+4;
1679 Layer blending ranges info.
1681 if (image->debug != MagickFalse)
1682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1683 " layer blending ranges: length=%.20g",(double)
1684 ((MagickOffsetType) length));
1686 We read it, but don't use it...
1688 for (j=0; j < (ssize_t) length; j+=8)
1690 size_t blend_source=ReadBlobLong(image);
1691 size_t blend_dest=ReadBlobLong(image);
1692 if (image->debug != MagickFalse)
1693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1694 " source(%x), dest(%x)",(unsigned int)
1695 blend_source,(unsigned int) blend_dest);
1701 length=(MagickSizeType) ReadBlobByte(image);
1702 combined_length+=length+1;
1704 (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1705 layer_info[i].name[length]='\0';
1706 if (image->debug != MagickFalse)
1707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1708 " layer name: %s",layer_info[i].name);
1709 if ((length % 4) != 0)
1711 length=4-(length % 4);
1712 combined_length+=length;
1713 /* Skip over the padding of the layer name */
1714 if (DiscardBlobBytes(image,length) == MagickFalse)
1716 layer_info=DestroyLayerInfo(layer_info,number_layers);
1717 ThrowBinaryException(CorruptImageError,
1718 "UnexpectedEndOfFile",image->filename);
1721 length=(MagickSizeType) size-combined_length;
1727 layer_info[i].info=AcquireStringInfo((const size_t) length);
1728 info=GetStringInfoDatum(layer_info[i].info);
1729 (void) ReadBlob(image,(const size_t) length,info);
1734 for (i=0; i < number_layers; i++)
1736 if ((layer_info[i].page.width == 0) ||
1737 (layer_info[i].page.height == 0))
1739 if (image->debug != MagickFalse)
1740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1741 " layer data is empty");
1742 if (layer_info[i].info != (StringInfo *) NULL)
1743 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1748 Allocate layered image.
1750 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1751 layer_info[i].page.height,MagickFalse,exception);
1752 if (layer_info[i].image == (Image *) NULL)
1754 layer_info=DestroyLayerInfo(layer_info,number_layers);
1755 if (image->debug != MagickFalse)
1756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1757 " allocation of image for layer %.20g failed",(double) i);
1758 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1762 if (layer_info[i].info != (StringInfo *) NULL)
1764 (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
1765 layer_info[i].info,exception);
1766 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1770 if (image_info->ping == MagickFalse)
1772 for (i=0; i < number_layers; i++)
1774 if (layer_info[i].image == (Image *) NULL)
1776 for (j=0; j < layer_info[i].channels; j++)
1778 if (DiscardBlobBytes(image,(MagickSizeType)
1779 layer_info[i].channel_info[j].size) == MagickFalse)
1781 layer_info=DestroyLayerInfo(layer_info,number_layers);
1782 ThrowBinaryException(CorruptImageError,
1783 "UnexpectedEndOfFile",image->filename);
1789 if (image->debug != MagickFalse)
1790 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1791 " reading data for layer %.20g",(double) i);
1793 status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
1795 if (status == MagickFalse)
1798 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1800 if (status == MagickFalse)
1805 if (status != MagickFalse)
1807 for (i=0; i < number_layers; i++)
1809 if (layer_info[i].image == (Image *) NULL)
1811 for (j=i; j < number_layers - 1; j++)
1812 layer_info[j] = layer_info[j+1];
1818 if (number_layers > 0)
1820 for (i=0; i < number_layers; i++)
1823 layer_info[i].image->previous=layer_info[i-1].image;
1824 if (i < (number_layers-1))
1825 layer_info[i].image->next=layer_info[i+1].image;
1826 layer_info[i].image->page=layer_info[i].page;
1828 image->next=layer_info[0].image;
1829 layer_info[0].image->previous=image;
1831 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1834 layer_info=DestroyLayerInfo(layer_info,number_layers);
1840 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1841 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1855 compression=(PSDCompressionType) ReadBlobMSBShort(image);
1856 image->compression=ConvertPSDCompression(compression);
1858 if (compression != Raw && compression != RLE)
1860 (void) ThrowMagickException(exception,GetMagickModule(),
1861 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1862 return(MagickFalse);
1865 sizes=(MagickOffsetType *) NULL;
1866 if (compression == RLE)
1868 sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
1869 if (sizes == (MagickOffsetType *) NULL)
1870 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1875 for (i=0; i < (ssize_t) psd_info->channels; i++)
1877 if (compression == RLE)
1878 status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
1881 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1883 if (status != MagickFalse)
1884 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1886 if (status == MagickFalse)
1890 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1891 status=NegateCMYK(image,exception);
1893 if (status != MagickFalse)
1894 status=CorrectPSDAlphaBlend(image_info,image,exception);
1896 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1901 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1934 assert(image_info != (const ImageInfo *) NULL);
1935 assert(image_info->signature == MagickCoreSignature);
1936 if (image_info->debug != MagickFalse)
1937 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1938 image_info->filename);
1939 assert(exception != (ExceptionInfo *) NULL);
1940 assert(exception->signature == MagickCoreSignature);
1942 image=AcquireImage(image_info,exception);
1943 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1944 if (status == MagickFalse)
1946 image=DestroyImageList(image);
1947 return((Image *) NULL);
1952 image->endian=MSBEndian;
1953 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1954 psd_info.version=ReadBlobMSBShort(image);
1955 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1956 ((psd_info.version != 1) && (psd_info.version != 2)))
1957 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1958 (void) ReadBlob(image,6,psd_info.reserved);
1959 psd_info.channels=ReadBlobMSBShort(image);
1960 if (psd_info.channels > MaxPSDChannels)
1961 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1962 psd_info.rows=ReadBlobMSBLong(image);
1963 psd_info.columns=ReadBlobMSBLong(image);
1964 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1965 (psd_info.columns > 30000)))
1966 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1967 psd_info.depth=ReadBlobMSBShort(image);
1968 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1969 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1970 psd_info.mode=ReadBlobMSBShort(image);
1971 if (image->debug != MagickFalse)
1972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1973 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1974 (double) psd_info.columns,(double) psd_info.rows,(double)
1975 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1980 image->depth=psd_info.depth;
1981 image->columns=psd_info.columns;
1982 image->rows=psd_info.rows;
1983 status=SetImageExtent(image,image->columns,image->rows,exception);
1984 if (status == MagickFalse)
1985 return(DestroyImageList(image));
1986 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1988 image=DestroyImageList(image);
1989 return((Image *) NULL);
1991 if (psd_info.mode == LabMode)
1992 SetImageColorspace(image,LabColorspace,exception);
1993 if (psd_info.mode == CMYKMode)
1995 SetImageColorspace(image,CMYKColorspace,exception);
1996 if (psd_info.channels > 4)
1997 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1999 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
2000 (psd_info.mode == DuotoneMode))
2002 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
2004 if (status == MagickFalse)
2005 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2006 if (image->debug != MagickFalse)
2007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2008 " Image colormap allocated");
2009 SetImageColorspace(image,GRAYColorspace,exception);
2010 if (psd_info.channels > 1)
2011 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2014 if (psd_info.channels > 3)
2015 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2017 Read PSD raster colormap only present for indexed and duotone images.
2019 length=ReadBlobMSBLong(image);
2022 if (image->debug != MagickFalse)
2023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2024 " reading colormap");
2025 if (psd_info.mode == DuotoneMode)
2028 Duotone image data; the format of this data is undocumented.
2030 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
2032 if (data == (unsigned char *) NULL)
2033 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2034 (void) ReadBlob(image,(size_t) length,data);
2035 data=(unsigned char *) RelinquishMagickMemory(data);
2043 Read PSD raster colormap.
2045 number_colors=length/3;
2046 if (number_colors > 65536)
2047 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2048 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2049 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2050 for (i=0; i < (ssize_t) image->colors; i++)
2051 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
2052 ReadBlobByte(image));
2053 for (i=0; i < (ssize_t) image->colors; i++)
2054 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
2055 ReadBlobByte(image));
2056 for (i=0; i < (ssize_t) image->colors; i++)
2057 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
2058 ReadBlobByte(image));
2059 image->alpha_trait=UndefinedPixelTrait;
2062 if ((image->depth == 1) && (image->storage_class != PseudoClass))
2063 ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2064 has_merged_image=MagickTrue;
2065 length=ReadBlobMSBLong(image);
2072 Image resources block.
2074 if (image->debug != MagickFalse)
2075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2076 " reading image resource blocks - %.20g bytes",(double)
2077 ((MagickOffsetType) length));
2078 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2080 if (blocks == (unsigned char *) NULL)
2081 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2082 count=ReadBlob(image,(size_t) length,blocks);
2083 if ((count != (ssize_t) length) || (length < 4) ||
2084 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2086 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2087 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2089 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
2091 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2094 Layer and mask block.
2096 length=GetPSDSize(&psd_info,image);
2099 length=ReadBlobMSBLong(image);
2100 length=ReadBlobMSBLong(image);
2102 offset=TellBlob(image);
2103 skip_layers=MagickFalse;
2104 if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2105 (has_merged_image != MagickFalse))
2107 if (image->debug != MagickFalse)
2108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2109 " read composite only");
2110 skip_layers=MagickTrue;
2114 if (image->debug != MagickFalse)
2115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2116 " image has no layers");
2120 if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
2123 (void) CloseBlob(image);
2124 image=DestroyImageList(image);
2125 return((Image *) NULL);
2129 Skip the rest of the layer and mask information.
2131 SeekBlob(image,offset+length,SEEK_SET);
2134 If we are only "pinging" the image, then we're done - so return.
2136 if (image_info->ping != MagickFalse)
2138 (void) CloseBlob(image);
2139 return(GetFirstImageInList(image));
2142 Read the precombined layer, present for PSD < 4 compatibility.
2144 if (image->debug != MagickFalse)
2145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2146 " reading the precombined layer");
2147 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2148 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2149 &psd_info,exception);
2150 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
2153 SeekBlob(image,offset,SEEK_SET);
2154 status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
2155 if (status != MagickTrue)
2157 (void) CloseBlob(image);
2158 image=DestroyImageList(image);
2159 return((Image *) NULL);
2162 if (has_merged_image == MagickFalse)
2167 if (GetImageListLength(image) == 1)
2168 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2169 SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2170 image->background_color.alpha=TransparentAlpha;
2171 image->background_color.alpha_trait=BlendPixelTrait;
2172 merged=MergeImageLayers(image,FlattenLayer,exception);
2173 ReplaceImageInList(&image,merged);
2175 (void) CloseBlob(image);
2176 return(GetFirstImageInList(image));
2180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 % R e g i s t e r P S D I m a g e %
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 % RegisterPSDImage() adds properties for the PSD image format to
2191 % the list of supported formats. The properties include the image format
2192 % tag, a method to read and/or write the format, whether the format
2193 % supports the saving of more than one frame to the same file or blob,
2194 % whether the format supports native in-memory I/O, and a brief
2195 % description of the format.
2197 % The format of the RegisterPSDImage method is:
2199 % size_t RegisterPSDImage(void)
2202 ModuleExport size_t RegisterPSDImage(void)
2207 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2208 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2209 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2210 entry->magick=(IsImageFormatHandler *) IsPSD;
2211 entry->flags|=CoderSeekableStreamFlag;
2212 (void) RegisterMagickInfo(entry);
2213 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2214 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2215 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2216 entry->magick=(IsImageFormatHandler *) IsPSD;
2217 entry->flags|=CoderSeekableStreamFlag;
2218 (void) RegisterMagickInfo(entry);
2219 return(MagickImageCoderSignature);
2223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2227 % U n r e g i s t e r P S D I m a g e %
2231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2233 % UnregisterPSDImage() removes format registrations made by the
2234 % PSD module from the list of supported formats.
2236 % The format of the UnregisterPSDImage method is:
2238 % UnregisterPSDImage(void)
2241 ModuleExport void UnregisterPSDImage(void)
2243 (void) UnregisterMagickInfo("PSB");
2244 (void) UnregisterMagickInfo("PSD");
2248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 % W r i t e P S D I m a g e %
2256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2258 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2260 % The format of the WritePSDImage method is:
2262 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2263 % ExceptionInfo *exception)
2265 % A description of each parameter follows.
2267 % o image_info: the image info.
2269 % o image: The image.
2271 % o exception: return any errors or warnings in this structure.
2275 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2276 const size_t offset)
2278 if (psd_info->version == 1)
2279 return(WriteBlobMSBShort(image,(unsigned short) offset));
2280 return(WriteBlobMSBLong(image,(unsigned short) offset));
2283 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2284 const MagickSizeType size,const MagickSizeType offset)
2292 current_offset=TellBlob(image);
2293 SeekBlob(image,offset,SEEK_SET);
2294 if (psd_info->version == 1)
2295 result=WriteBlobMSBShort(image,(unsigned short) size);
2297 result=(WriteBlobMSBLong(image,(unsigned short) size));
2298 SeekBlob(image,current_offset,SEEK_SET);
2302 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2303 const MagickSizeType size)
2305 if (psd_info->version == 1)
2306 return(WriteBlobMSBLong(image,(unsigned int) size));
2307 return(WriteBlobMSBLongLong(image,size));
2310 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2311 const MagickSizeType size,const MagickSizeType offset)
2319 current_offset=TellBlob(image);
2320 SeekBlob(image,offset,SEEK_SET);
2321 if (psd_info->version == 1)
2322 result=WriteBlobMSBLong(image,(unsigned int) size);
2324 result=WriteBlobMSBLongLong(image,size);
2325 SeekBlob(image,current_offset,SEEK_SET);
2329 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2330 const unsigned char *pixels,unsigned char *compact_pixels,
2331 ExceptionInfo *exception)
2340 register unsigned char
2347 Compress pixels with Packbits encoding.
2349 assert(image != (Image *) NULL);
2350 assert(image->signature == MagickCoreSignature);
2351 if (image->debug != MagickFalse)
2352 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2353 assert(pixels != (unsigned char *) NULL);
2354 assert(compact_pixels != (unsigned char *) NULL);
2355 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2356 if (packbits == (unsigned char *) NULL)
2357 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2360 for (i=(ssize_t) length; i != 0; )
2367 *q++=(unsigned char) 0;
2374 *q++=(unsigned char) 1;
2382 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2384 *q++=(unsigned char) ((256-3)+1);
2388 *q++=(unsigned char) 2;
2396 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2402 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2409 *q++=(unsigned char) ((256-count)+1);
2418 while ((*(pixels+count) != *(pixels+count+1)) ||
2419 (*(pixels+count+1) != *(pixels+count+2)))
2421 packbits[count+1]=pixels[count];
2423 if (((ssize_t) count >= (i-3)) || (count >= 127))
2427 *packbits=(unsigned char) (count-1);
2428 for (j=0; j <= (ssize_t) count; j++)
2435 *q++=(unsigned char) 128; /* EOD marker */
2436 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2437 return((size_t) (q-compact_pixels));
2440 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
2441 const Image *next_image,const ssize_t channels)
2450 if (next_image->compression == RLECompression)
2452 length=WriteBlobMSBShort(image,RLE);
2453 for (i=0; i < channels; i++)
2454 for (y=0; y < (ssize_t) next_image->rows; y++)
2455 length+=SetPSDOffset(psd_info,image,0);
2457 #ifdef MAGICKCORE_ZLIB_DELEGATE
2458 else if (next_image->compression == ZipCompression)
2459 length=WriteBlobMSBShort(image,ZipWithoutPrediction);
2462 length=WriteBlobMSBShort(image,Raw);
2466 static size_t WritePSDChannel(const PSDInfo *psd_info,
2467 const ImageInfo *image_info,Image *image,Image *next_image,
2468 const QuantumType quantum_type, unsigned char *compact_pixels,
2469 MagickOffsetType size_offset,const MagickBooleanType separate,
2470 ExceptionInfo *exception)
2481 register const Quantum
2494 #ifdef MAGICKCORE_ZLIB_DELEGATE
2508 compressed_pixels=(unsigned char *) NULL;
2512 if (separate != MagickFalse)
2514 size_offset=TellBlob(image)+2;
2515 count+=WriteCompressionStart(psd_info,image,next_image,1);
2517 if (next_image->depth > 8)
2518 next_image->depth=16;
2519 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2520 MagickTrue : MagickFalse;
2521 quantum_info=AcquireQuantumInfo(image_info,image);
2522 if (quantum_info == (QuantumInfo *) NULL)
2524 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2525 #ifdef MAGICKCORE_ZLIB_DELEGATE
2526 if (next_image->compression == ZipCompression)
2528 compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
2529 sizeof(*compressed_pixels));
2530 if (compressed_pixels == (unsigned char *) NULL)
2532 quantum_info=DestroyQuantumInfo(quantum_info);
2535 ResetMagickMemory(&stream,0,sizeof(stream));
2536 stream.data_type=Z_BINARY;
2537 level=Z_DEFAULT_COMPRESSION;
2538 if ((image_info->quality > 0 && image_info->quality < 10))
2539 level=(int) image_info->quality;
2540 if (deflateInit(&stream,level) != Z_OK)
2542 quantum_info=DestroyQuantumInfo(quantum_info);
2547 for (y=0; y < (ssize_t) next_image->rows; y++)
2549 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2550 if (p == (const Quantum *) NULL)
2552 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2553 quantum_type,pixels,exception);
2554 if (monochrome != MagickFalse)
2555 for (i=0; i < (ssize_t) length; i++)
2556 pixels[i]=(~pixels[i]);
2557 if (next_image->compression == RLECompression)
2559 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2561 count+=WriteBlob(image,length,compact_pixels);
2562 size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
2564 #ifdef MAGICKCORE_ZLIB_DELEGATE
2565 else if (next_image->compression == ZipCompression)
2567 stream.avail_in=(uInt) length;
2568 stream.next_in=(Bytef *) pixels;
2569 if (y == (ssize_t) next_image->rows-1)
2572 stream.avail_out=(uInt) CHUNK;
2573 stream.next_out=(Bytef *) compressed_pixels;
2574 if (deflate(&stream,flush) == Z_STREAM_ERROR)
2576 length=(size_t) CHUNK-stream.avail_out;
2578 count+=WriteBlob(image,length,compressed_pixels);
2579 } while (stream.avail_out == 0);
2583 count+=WriteBlob(image,length,pixels);
2585 #ifdef MAGICKCORE_ZLIB_DELEGATE
2586 if (next_image->compression == ZipCompression)
2588 (void) deflateEnd(&stream);
2589 compressed_pixels=(unsigned char *) RelinquishMagickMemory(
2593 quantum_info=DestroyQuantumInfo(quantum_info);
2597 static unsigned char *AcquireCompactPixels(const Image *image,
2598 ExceptionInfo *exception)
2606 packet_size=image->depth > 8UL ? 2UL : 1UL;
2607 compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
2608 image->columns)+1,packet_size*sizeof(*compact_pixels));
2609 if (compact_pixels == (unsigned char *) NULL)
2611 (void) ThrowMagickException(exception,GetMagickModule(),
2612 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2615 return(compact_pixels);
2618 static size_t WritePSDChannels(const PSDInfo *psd_info,
2619 const ImageInfo *image_info,Image *image,Image *next_image,
2620 MagickOffsetType size_offset,const MagickBooleanType separate,
2621 ExceptionInfo *exception)
2641 compact_pixels=(unsigned char *) NULL;
2642 if (next_image->compression == RLECompression)
2644 compact_pixels=AcquireCompactPixels(image,exception);
2645 if (compact_pixels == (unsigned char *) NULL)
2649 if (separate == MagickFalse)
2651 if (next_image->storage_class != PseudoClass)
2653 if (IsImageGray(next_image) == MagickFalse)
2654 channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
2655 if (next_image->alpha_trait != UndefinedPixelTrait)
2658 rows_offset=TellBlob(image)+2;
2659 count+=WriteCompressionStart(psd_info,image,next_image,channels);
2660 offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
2663 if (next_image->storage_class == PseudoClass)
2665 length=WritePSDChannel(psd_info,image_info,image,next_image,
2666 IndexQuantum,compact_pixels,rows_offset,separate,exception);
2667 if (separate != MagickFalse)
2668 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2670 rows_offset+=offset_length;
2675 if (IsImageGray(next_image) != MagickFalse)
2677 length=WritePSDChannel(psd_info,image_info,image,next_image,
2678 GrayQuantum,compact_pixels,rows_offset,separate,exception);
2679 if (separate != MagickFalse)
2680 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2682 rows_offset+=offset_length;
2687 if (next_image->colorspace == CMYKColorspace)
2688 (void) NegateCMYK(next_image,exception);
2690 length=WritePSDChannel(psd_info,image_info,image,next_image,
2691 RedQuantum,compact_pixels,rows_offset,separate,exception);
2692 if (separate != MagickFalse)
2693 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2695 rows_offset+=offset_length;
2698 length=WritePSDChannel(psd_info,image_info,image,next_image,
2699 GreenQuantum,compact_pixels,rows_offset,separate,exception);
2700 if (separate != MagickFalse)
2701 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2703 rows_offset+=offset_length;
2706 length=WritePSDChannel(psd_info,image_info,image,next_image,
2707 BlueQuantum,compact_pixels,rows_offset,separate,exception);
2708 if (separate != MagickFalse)
2709 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2711 rows_offset+=offset_length;
2714 if (next_image->colorspace == CMYKColorspace)
2716 length=WritePSDChannel(psd_info,image_info,image,next_image,
2717 BlackQuantum,compact_pixels,rows_offset,separate,exception);
2718 if (separate != MagickFalse)
2719 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2721 rows_offset+=offset_length;
2725 if (next_image->alpha_trait != UndefinedPixelTrait)
2727 length=WritePSDChannel(psd_info,image_info,image,next_image,
2728 AlphaQuantum,compact_pixels,rows_offset,separate,exception);
2729 if (separate != MagickFalse)
2730 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2732 rows_offset+=offset_length;
2736 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2737 if (next_image->colorspace == CMYKColorspace)
2738 (void) NegateCMYK(next_image,exception);
2739 if (separate != MagickFalse)
2744 property=GetImageArtifact(next_image,"psd:opacity-mask");
2745 if (property != (const char *) NULL)
2747 mask=(Image *) GetImageRegistry(ImageRegistryType,property,
2749 if (mask != (Image *) NULL)
2751 if (mask->compression == RLECompression)
2753 compact_pixels=AcquireCompactPixels(mask,exception);
2754 if (compact_pixels == (unsigned char *) NULL)
2757 length=WritePSDChannel(psd_info,image_info,image,mask,
2758 RedQuantum,compact_pixels,rows_offset,MagickTrue,exception);
2759 (void) WritePSDSize(psd_info,image,length,size_offset);
2761 compact_pixels=(unsigned char *) RelinquishMagickMemory(
2769 static size_t WritePascalString(Image *image,const char *value,size_t padding)
2782 length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
2784 count+=WriteBlobByte(image,0);
2787 count+=WriteBlobByte(image,(unsigned char) length);
2788 count+=WriteBlob(image,length,(const unsigned char *) value);
2791 if ((length % padding) == 0)
2793 for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
2794 count+=WriteBlobByte(image,0);
2798 static void WriteResolutionResourceBlock(Image *image)
2807 if (image->units == PixelsPerCentimeterResolution)
2809 x_resolution=2.54*65536.0*image->resolution.x+0.5;
2810 y_resolution=2.54*65536.0*image->resolution.y+0.5;
2815 x_resolution=65536.0*image->resolution.x+0.5;
2816 y_resolution=65536.0*image->resolution.y+0.5;
2819 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2820 (void) WriteBlobMSBShort(image,0x03ED);
2821 (void) WriteBlobMSBShort(image,0);
2822 (void) WriteBlobMSBLong(image,16); /* resource size */
2823 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2824 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2825 (void) WriteBlobMSBShort(image,units); /* width unit */
2826 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2827 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2828 (void) WriteBlobMSBShort(image,units); /* height unit */
2831 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
2832 const signed short channel)
2837 count=WriteBlobMSBSignedShort(image,channel);
2838 count+=SetPSDSize(psd_info,image,0);
2842 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2844 register const unsigned char
2861 length=GetStringInfoLength(bim_profile);
2864 datum=GetStringInfoDatum(bim_profile);
2865 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2867 register unsigned char
2870 q=(unsigned char *) p;
2871 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2873 p=PushLongPixel(MSBEndian,p,&long_sans);
2874 p=PushShortPixel(MSBEndian,p,&id);
2875 p=PushShortPixel(MSBEndian,p,&short_sans);
2876 p=PushLongPixel(MSBEndian,p,&count);
2877 if (id == 0x0000040f)
2882 quantum=PSDQuantum(count)+12;
2883 if ((quantum >= 12) && (quantum < (ssize_t) length))
2885 if ((q+quantum < (datum+length-16)))
2886 (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
2887 SetStringInfoLength(bim_profile,length-quantum);
2892 if ((count & 0x01) != 0)
2897 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2899 register const unsigned char
2916 length=GetStringInfoLength(bim_profile);
2919 datum=GetStringInfoDatum(bim_profile);
2920 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2922 register unsigned char
2928 q=(unsigned char *) p;
2929 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2931 p=PushLongPixel(MSBEndian,p,&long_sans);
2932 p=PushShortPixel(MSBEndian,p,&id);
2933 p=PushShortPixel(MSBEndian,p,&short_sans);
2934 p=PushLongPixel(MSBEndian,p,&count);
2935 cnt=PSDQuantum(count);
2938 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
2940 (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
2941 SetStringInfoLength(bim_profile,length-(cnt+12));
2945 if ((count & 0x01) != 0)
2950 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
2951 Image *image,ExceptionInfo *exception)
2953 #define PSDKeySize 5
2954 #define PSDAllowedLength 36
2959 /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
2961 allowed[PSDAllowedLength][PSDKeySize] = {
2962 "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
2963 "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
2964 "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
2965 "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
2991 info=GetImageProfile(image,"psd:additional-info");
2992 if (info == (const StringInfo *) NULL)
2993 return((const StringInfo *) NULL);
2994 option=GetImageOption(image_info,"psd:additional-info");
2995 if (LocaleCompare(option,"all") == 0)
2997 if (LocaleCompare(option,"selective") != 0)
2999 profile=RemoveImageProfile(image,"psd:additional-info");
3000 return(DestroyStringInfo(profile));
3002 length=GetStringInfoLength(info);
3003 p=GetStringInfoDatum(info);
3004 remaining_length=length;
3006 while (remaining_length >= 12)
3008 /* skip over signature */
3015 size=(unsigned int) (*p++) << 24;
3016 size|=(unsigned int) (*p++) << 16;
3017 size|=(unsigned int) (*p++) << 8;
3018 size|=(unsigned int) (*p++);
3019 size=size & 0xffffffff;
3020 remaining_length-=12;
3021 if ((size_t) size > remaining_length)
3022 return((const StringInfo *) NULL);
3024 for (i=0; i < PSDAllowedLength; i++)
3026 if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3032 remaining_length-=(size_t) size;
3033 if (found == MagickFalse)
3035 if (remaining_length > 0)
3036 p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
3039 length+=(size_t) size+12;
3042 profile=RemoveImageProfile(image,"psd:additional-info");
3044 return(DestroyStringInfo(profile));
3045 SetStringInfoLength(profile,(const size_t) length);
3046 SetImageProfile(image,"psd:additional-info",info,exception);
3050 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3051 Image *image,ExceptionInfo *exception)
3054 layer_name[MagickPathExtent];
3071 *layer_size_offsets,
3096 assert(image_info != (const ImageInfo *) NULL);
3097 assert(image_info->signature == MagickCoreSignature);
3098 assert(image != (Image *) NULL);
3099 assert(image->signature == MagickCoreSignature);
3100 if (image->debug != MagickFalse)
3101 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3102 assert(exception != (ExceptionInfo *) NULL);
3103 assert(exception->signature == MagickCoreSignature);
3104 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3105 if (status == MagickFalse)
3107 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
3108 if (image->alpha_trait != UndefinedPixelTrait)
3109 packet_size+=image->depth > 8 ? 2 : 1;
3111 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3112 (image->columns > 30000) || (image->rows > 30000))
3114 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3115 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
3116 for (i=1; i <= 6; i++)
3117 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
3118 if (SetImageGray(image,exception) != MagickFalse)
3119 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3121 if ((image_info->type != TrueColorType) && (image_info->type !=
3122 TrueColorAlphaType) && (image->storage_class == PseudoClass))
3123 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3126 if (image->storage_class == PseudoClass)
3127 (void) SetImageStorageClass(image,DirectClass,exception);
3128 if (image->colorspace != CMYKColorspace)
3129 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3131 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3133 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3134 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3135 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3136 if (IsImageGray(image) != MagickFalse)
3144 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3145 MagickTrue : MagickFalse;
3146 (void) WriteBlobMSBShort(image,(unsigned short)
3147 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3148 (void) WriteBlobMSBShort(image,(unsigned short)
3149 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3153 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3154 PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3156 if (((image_info->colorspace != UndefinedColorspace) ||
3157 (image->colorspace != CMYKColorspace)) &&
3158 (image_info->colorspace != CMYKColorspace))
3160 (void) TransformImageColorspace(image,sRGBColorspace,exception);
3161 (void) WriteBlobMSBShort(image,(unsigned short)
3162 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3166 if (image->colorspace != CMYKColorspace)
3167 (void) TransformImageColorspace(image,CMYKColorspace,exception);
3168 (void) WriteBlobMSBShort(image,CMYKMode);
3171 if ((IsImageGray(image) != MagickFalse) ||
3172 (image->storage_class == DirectClass) || (image->colors > 256))
3173 (void) WriteBlobMSBLong(image,0);
3177 Write PSD raster colormap.
3179 (void) WriteBlobMSBLong(image,768);
3180 for (i=0; i < (ssize_t) image->colors; i++)
3181 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
3182 for ( ; i < 256; i++)
3183 (void) WriteBlobByte(image,0);
3184 for (i=0; i < (ssize_t) image->colors; i++)
3185 (void) WriteBlobByte(image,ScaleQuantumToChar(
3186 image->colormap[i].green));
3187 for ( ; i < 256; i++)
3188 (void) WriteBlobByte(image,0);
3189 for (i=0; i < (ssize_t) image->colors; i++)
3190 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
3191 for ( ; i < 256; i++)
3192 (void) WriteBlobByte(image,0);
3195 Image resource block.
3197 length=28; /* 0x03EB */
3198 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
3199 icc_profile=GetImageProfile(image,"icc");
3200 if (bim_profile != (StringInfo *) NULL)
3202 bim_profile=CloneStringInfo(bim_profile);
3203 if (icc_profile != (StringInfo *) NULL)
3204 RemoveICCProfileFromResourceBlock(bim_profile);
3205 RemoveResolutionFromResourceBlock(bim_profile);
3206 length+=PSDQuantum(GetStringInfoLength(bim_profile));
3208 if (icc_profile != (const StringInfo *) NULL)
3209 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
3210 (void) WriteBlobMSBLong(image,(unsigned int) length);
3211 WriteResolutionResourceBlock(image);
3212 if (bim_profile != (StringInfo *) NULL)
3214 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
3215 GetStringInfoDatum(bim_profile));
3216 bim_profile=DestroyStringInfo(bim_profile);
3218 if (icc_profile != (StringInfo *) NULL)
3220 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3221 (void) WriteBlobMSBShort(image,0x0000040F);
3222 (void) WriteBlobMSBShort(image,0);
3223 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
3225 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
3226 GetStringInfoDatum(icc_profile));
3227 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
3228 PSDQuantum(GetStringInfoLength(icc_profile)))
3229 (void) WriteBlobByte(image,0);
3231 base_image=GetNextImageInList(image);
3232 if (base_image == (Image *) NULL)
3235 size_offset=TellBlob(image);
3236 SetPSDSize(&psd_info,image,0);
3237 SetPSDSize(&psd_info,image,0);
3239 for (next_image=base_image; next_image != NULL; )
3242 next_image=GetNextImageInList(next_image);
3244 if (image->alpha_trait != UndefinedPixelTrait)
3245 size+=WriteBlobMSBShort(image,-(unsigned short) layer_count);
3247 size+=WriteBlobMSBShort(image,(unsigned short) layer_count);
3248 layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3249 (size_t) layer_count,sizeof(MagickOffsetType));
3250 if (layer_size_offsets == (MagickOffsetType *) NULL)
3251 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3253 for (next_image=base_image; next_image != NULL; )
3265 mask=(Image *) NULL;
3266 property=GetImageArtifact(next_image,"psd:opacity-mask");
3268 if (property != (const char *) NULL)
3270 mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3271 default_color=strlen(property) == 9 ? 255 : 0;
3273 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
3274 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
3275 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
3277 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
3278 next_image->columns));
3280 if ((next_image->storage_class != PseudoClass) &&
3281 (IsImageGray(next_image) == MagickFalse))
3282 channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
3283 total_channels=channels;
3284 if (next_image->alpha_trait != UndefinedPixelTrait)
3286 if (mask != (Image *) NULL)
3288 size+=WriteBlobMSBShort(image,total_channels);
3289 layer_size_offsets[layer_index++]=TellBlob(image);
3290 for (i=0; i < (ssize_t) channels; i++)
3291 size+=WriteChannelSize(&psd_info,image,(signed short) i);
3292 if (next_image->alpha_trait != UndefinedPixelTrait)
3293 size+=WriteChannelSize(&psd_info,image,-1);
3294 if (mask != (Image *) NULL)
3295 size+=WriteChannelSize(&psd_info,image,-2);
3296 size+=WriteBlob(image,4,(const unsigned char *) "8BIM");
3297 size+=WriteBlob(image,4,(const unsigned char *)
3298 CompositeOperatorToPSDBlendMode(next_image->compose));
3299 property=GetImageArtifact(next_image,"psd:layer.opacity");
3300 if (property != (const char *) NULL)
3305 opacity=(Quantum) StringToInteger(property);
3306 size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
3307 (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3310 size+=WriteBlobByte(image,255);
3311 size+=WriteBlobByte(image,0);
3312 size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
3313 1 << 0x02 : 1); /* layer properties - visible, etc. */
3314 size+=WriteBlobByte(image,0);
3315 info=GetAdditionalInformation(image_info,next_image,exception);
3316 property=(const char *) GetImageProperty(next_image,"label",exception);
3317 if (property == (const char *) NULL)
3319 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3320 (double) layer_index);
3321 property=layer_name;
3323 name_length=strlen(property)+1;
3324 if ((name_length % 4) != 0)
3325 name_length+=(4-(name_length % 4));
3326 if (info != (const StringInfo *) NULL)
3327 name_length+=GetStringInfoLength(info);
3329 if (mask != (Image *) NULL)
3331 size+=WriteBlobMSBLong(image,(unsigned int) name_length);
3332 if (mask == (Image *) NULL)
3333 size+=WriteBlobMSBLong(image,0);
3336 if (mask->compose != NoCompositeOp)
3337 (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3338 default_color),MagickTrue,exception);
3339 mask->page.y+=image->page.y;
3340 mask->page.x+=image->page.x;
3341 size+=WriteBlobMSBLong(image,20);
3342 size+=WriteBlobMSBSignedLong(image,mask->page.y);
3343 size+=WriteBlobMSBSignedLong(image,mask->page.x);
3344 size+=WriteBlobMSBLong(image,(const unsigned int) mask->rows+
3346 size+=WriteBlobMSBLong(image,(const unsigned int) mask->columns+
3348 size+=WriteBlobByte(image,default_color);
3349 size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
3350 size+=WriteBlobMSBShort(image,0);
3352 size+=WriteBlobMSBLong(image,0);
3353 size+=WritePascalString(image,property,4);
3354 if (info != (const StringInfo *) NULL)
3355 size+=WriteBlob(image,GetStringInfoLength(info),
3356 GetStringInfoDatum(info));
3357 next_image=GetNextImageInList(next_image);
3362 next_image=base_image;
3364 while (next_image != NULL)
3366 length=WritePSDChannels(&psd_info,image_info,image,next_image,
3367 layer_size_offsets[layer_index++],MagickTrue,exception);
3374 next_image=GetNextImageInList(next_image);
3376 (void) WriteBlobMSBLong(image,0); /* user mask data */
3378 Write the total size
3380 size_offset+=WritePSDSize(&psd_info,image,size+
3381 (psd_info.version == 1 ? 8 : 16),size_offset);
3382 if ((size/2) != ((size+1)/2))
3383 rounded_size=size+1;
3386 (void) WritePSDSize(&psd_info,image,rounded_size,size_offset);
3387 layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3388 layer_size_offsets);
3390 Remove the opacity mask from the registry
3392 next_image=base_image;
3393 while (next_image != (Image *) NULL)
3395 property=GetImageArtifact(next_image,"psd:opacity-mask");
3396 if (property != (const char *) NULL)
3397 DeleteImageRegistry(property);
3398 next_image=GetNextImageInList(next_image);
3401 Write composite image.
3403 if (status != MagickFalse)
3408 compression=image->compression;
3409 if (image->compression == ZipCompression)
3410 image->compression=RLECompression;
3411 if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
3414 image->compression=compression;
3416 (void) CloseBlob(image);