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 layer_info->mask.image=mask;
1366 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1367 const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1370 message[MagickPathExtent];
1381 if (image->debug != MagickFalse)
1382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1383 " setting up new layer image");
1384 if (psd_info->mode != IndexedMode)
1385 (void) SetImageBackgroundColor(layer_info->image,exception);
1386 layer_info->image->compose=PSDBlendModeToCompositeOperator(
1387 layer_info->blendkey);
1388 if (layer_info->visible == MagickFalse)
1389 layer_info->image->compose=NoCompositeOp;
1390 if (psd_info->mode == CMYKMode)
1391 SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1392 else if ((psd_info->mode == BitmapMode) || (psd_info->mode == DuotoneMode) ||
1393 (psd_info->mode == GrayscaleMode))
1394 SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1396 Set up some hidden attributes for folks that need them.
1398 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1399 (double) layer_info->page.x);
1400 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1401 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1402 (double) layer_info->page.y);
1403 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1404 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1405 layer_info->opacity);
1406 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1407 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1411 for (j=0; j < (ssize_t) layer_info->channels; j++)
1413 if (image->debug != MagickFalse)
1414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1415 " reading data for channel %.20g",(double) j);
1417 compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1418 layer_info->image->compression=ConvertPSDCompression(compression);
1419 if (layer_info->channel_info[j].type == -1)
1420 layer_info->image->alpha_trait=BlendPixelTrait;
1422 status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
1423 compression,exception);
1425 if (status == MagickFalse)
1429 if (status != MagickFalse)
1430 status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1431 MagickFalse,exception);
1433 if ((status != MagickFalse) &&
1434 (layer_info->image->colorspace == CMYKColorspace))
1435 status=NegateCMYK(layer_info->image,exception);
1437 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1442 layer_info->mask.image->page.x=layer_info->mask.page.x;
1443 layer_info->mask.image->page.y=layer_info->mask.page.y;
1444 /* Do not composite the mask when it is disabled */
1445 if ((layer_info->mask.flags & 0x02) == 0x02)
1446 layer_info->mask.image->compose=NoCompositeOp;
1448 status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1449 layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1451 option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1452 if (IsStringTrue(option) != MagickFalse)
1453 PreservePSDOpacityMask(image,layer_info,exception);
1454 layer_info->mask.image=DestroyImage(layer_info->mask.image);
1460 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1461 const ImageInfo *image_info,const PSDInfo *psd_info,
1462 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1484 size=GetPSDSize(psd_info,image);
1488 Skip layers & masks.
1490 (void) ReadBlobLong(image);
1491 count=ReadBlob(image,4,(unsigned char *) type);
1492 ReversePSDString(image,type,4);
1494 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1498 count=ReadBlob(image,4,(unsigned char *) type);
1499 ReversePSDString(image,type,4);
1500 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1501 size=GetPSDSize(psd_info,image);
1509 layer_info=(LayerInfo *) NULL;
1510 number_layers=(short) ReadBlobShort(image);
1512 if (number_layers < 0)
1515 The first alpha channel in the merged result contains the
1516 transparency data for the merged result.
1518 number_layers=MagickAbsoluteValue(number_layers);
1519 if (image->debug != MagickFalse)
1520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1521 " negative layer count corrected for");
1522 image->alpha_trait=BlendPixelTrait;
1526 We only need to know if the image has an alpha channel
1528 if (skip_layers != MagickFalse)
1531 if (image->debug != MagickFalse)
1532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1533 " image contains %.20g layers",(double) number_layers);
1535 if (number_layers == 0)
1536 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1539 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1540 sizeof(*layer_info));
1541 if (layer_info == (LayerInfo *) NULL)
1543 if (image->debug != MagickFalse)
1544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1545 " allocation of LayerInfo failed");
1546 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1549 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1550 sizeof(*layer_info));
1552 for (i=0; i < number_layers; i++)
1558 if (image->debug != MagickFalse)
1559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1560 " reading layer #%.20g",(double) i+1);
1561 layer_info[i].page.y=ReadBlobSignedLong(image);
1562 layer_info[i].page.x=ReadBlobSignedLong(image);
1563 y=ReadBlobSignedLong(image);
1564 x=ReadBlobSignedLong(image);
1565 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1566 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1567 layer_info[i].channels=ReadBlobShort(image);
1568 if (layer_info[i].channels > MaxPSDChannels)
1570 layer_info=DestroyLayerInfo(layer_info,number_layers);
1571 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1574 if (image->debug != MagickFalse)
1575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1576 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1577 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1578 (double) layer_info[i].page.height,(double)
1579 layer_info[i].page.width,(double) layer_info[i].channels);
1580 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1582 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1583 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1585 if (image->debug != MagickFalse)
1586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1587 " channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1588 (double) layer_info[i].channel_info[j].type,
1589 (double) layer_info[i].channel_info[j].size);
1591 count=ReadBlob(image,4,(unsigned char *) type);
1592 ReversePSDString(image,type,4);
1593 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1595 if (image->debug != MagickFalse)
1596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1597 " layer type was %.4s instead of 8BIM", type);
1598 layer_info=DestroyLayerInfo(layer_info,number_layers);
1599 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1602 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1603 ReversePSDString(image,layer_info[i].blendkey,4);
1604 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1605 ReadBlobByte(image));
1606 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1607 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1608 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1609 if (image->debug != MagickFalse)
1610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1611 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1612 layer_info[i].blendkey,(double) layer_info[i].opacity,
1613 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1614 layer_info[i].visible ? "true" : "false");
1615 (void) ReadBlobByte(image); /* filler */
1617 size=ReadBlobLong(image);
1624 if (image->debug != MagickFalse)
1625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1626 " layer contains additional info");
1627 length=ReadBlobLong(image);
1628 combined_length=length+4;
1634 layer_info[i].mask.page.y=ReadBlobSignedLong(image);
1635 layer_info[i].mask.page.x=ReadBlobSignedLong(image);
1636 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
1637 layer_info[i].mask.page.y);
1638 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
1639 layer_info[i].mask.page.x);
1640 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1642 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1643 if (!(layer_info[i].mask.flags & 0x01))
1645 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1646 layer_info[i].page.y;
1647 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1648 layer_info[i].page.x;
1650 if (image->debug != MagickFalse)
1651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1652 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1653 (double) layer_info[i].mask.page.x,(double)
1654 layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1655 (double) layer_info[i].mask.page.height,(double)
1656 ((MagickOffsetType) length)-18);
1658 Skip over the rest of the layer mask information.
1660 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1662 layer_info=DestroyLayerInfo(layer_info,number_layers);
1663 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1667 length=ReadBlobLong(image);
1668 combined_length+=length+4;
1672 Layer blending ranges info.
1674 if (image->debug != MagickFalse)
1675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1676 " layer blending ranges: length=%.20g",(double)
1677 ((MagickOffsetType) length));
1679 We read it, but don't use it...
1681 for (j=0; j < (ssize_t) length; j+=8)
1683 size_t blend_source=ReadBlobLong(image);
1684 size_t blend_dest=ReadBlobLong(image);
1685 if (image->debug != MagickFalse)
1686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1687 " source(%x), dest(%x)",(unsigned int)
1688 blend_source,(unsigned int) blend_dest);
1694 length=(MagickSizeType) ReadBlobByte(image);
1695 combined_length+=length+1;
1697 (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1698 layer_info[i].name[length]='\0';
1699 if (image->debug != MagickFalse)
1700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1701 " layer name: %s",layer_info[i].name);
1702 if ((length % 4) != 0)
1704 length=4-(length % 4);
1705 combined_length+=length;
1706 /* Skip over the padding of the layer name */
1707 if (DiscardBlobBytes(image,length) == MagickFalse)
1709 layer_info=DestroyLayerInfo(layer_info,number_layers);
1710 ThrowBinaryException(CorruptImageError,
1711 "UnexpectedEndOfFile",image->filename);
1714 length=(MagickSizeType) size-combined_length;
1720 layer_info[i].info=AcquireStringInfo((const size_t) length);
1721 info=GetStringInfoDatum(layer_info[i].info);
1722 (void) ReadBlob(image,(const size_t) length,info);
1727 for (i=0; i < number_layers; i++)
1729 if ((layer_info[i].page.width == 0) ||
1730 (layer_info[i].page.height == 0))
1732 if (image->debug != MagickFalse)
1733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1734 " layer data is empty");
1735 if (layer_info[i].info != (StringInfo *) NULL)
1736 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1741 Allocate layered image.
1743 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1744 layer_info[i].page.height,MagickFalse,exception);
1745 if (layer_info[i].image == (Image *) NULL)
1747 layer_info=DestroyLayerInfo(layer_info,number_layers);
1748 if (image->debug != MagickFalse)
1749 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1750 " allocation of image for layer %.20g failed",(double) i);
1751 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1755 if (layer_info[i].info != (StringInfo *) NULL)
1757 (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
1758 layer_info[i].info,exception);
1759 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1763 if (image_info->ping == MagickFalse)
1765 for (i=0; i < number_layers; i++)
1767 if (layer_info[i].image == (Image *) NULL)
1769 for (j=0; j < layer_info[i].channels; j++)
1771 if (DiscardBlobBytes(image,(MagickSizeType)
1772 layer_info[i].channel_info[j].size) == MagickFalse)
1774 layer_info=DestroyLayerInfo(layer_info,number_layers);
1775 ThrowBinaryException(CorruptImageError,
1776 "UnexpectedEndOfFile",image->filename);
1782 if (image->debug != MagickFalse)
1783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1784 " reading data for layer %.20g",(double) i);
1786 status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
1788 if (status == MagickFalse)
1791 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1793 if (status == MagickFalse)
1798 if (status != MagickFalse)
1800 for (i=0; i < number_layers; i++)
1802 if (layer_info[i].image == (Image *) NULL)
1804 for (j=i; j < number_layers - 1; j++)
1805 layer_info[j] = layer_info[j+1];
1811 if (number_layers > 0)
1813 for (i=0; i < number_layers; i++)
1816 layer_info[i].image->previous=layer_info[i-1].image;
1817 if (i < (number_layers-1))
1818 layer_info[i].image->next=layer_info[i+1].image;
1819 layer_info[i].image->page=layer_info[i].page;
1821 image->next=layer_info[0].image;
1822 layer_info[0].image->previous=image;
1824 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1827 layer_info=DestroyLayerInfo(layer_info,number_layers);
1833 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1834 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1848 compression=(PSDCompressionType) ReadBlobMSBShort(image);
1849 image->compression=ConvertPSDCompression(compression);
1851 if (compression != Raw && compression != RLE)
1853 (void) ThrowMagickException(exception,GetMagickModule(),
1854 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1855 return(MagickFalse);
1858 sizes=(MagickOffsetType *) NULL;
1859 if (compression == RLE)
1861 sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
1862 if (sizes == (MagickOffsetType *) NULL)
1863 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1868 for (i=0; i < (ssize_t) psd_info->channels; i++)
1870 if (compression == RLE)
1871 status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
1874 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1876 if (status != MagickFalse)
1877 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1879 if (status == MagickFalse)
1883 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1884 status=NegateCMYK(image,exception);
1886 if (status != MagickFalse)
1887 status=CorrectPSDAlphaBlend(image_info,image,exception);
1889 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1894 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1927 assert(image_info != (const ImageInfo *) NULL);
1928 assert(image_info->signature == MagickCoreSignature);
1929 if (image_info->debug != MagickFalse)
1930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1931 image_info->filename);
1932 assert(exception != (ExceptionInfo *) NULL);
1933 assert(exception->signature == MagickCoreSignature);
1935 image=AcquireImage(image_info,exception);
1936 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1937 if (status == MagickFalse)
1939 image=DestroyImageList(image);
1940 return((Image *) NULL);
1945 image->endian=MSBEndian;
1946 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1947 psd_info.version=ReadBlobMSBShort(image);
1948 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1949 ((psd_info.version != 1) && (psd_info.version != 2)))
1950 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1951 (void) ReadBlob(image,6,psd_info.reserved);
1952 psd_info.channels=ReadBlobMSBShort(image);
1953 if (psd_info.channels > MaxPSDChannels)
1954 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1955 psd_info.rows=ReadBlobMSBLong(image);
1956 psd_info.columns=ReadBlobMSBLong(image);
1957 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1958 (psd_info.columns > 30000)))
1959 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1960 psd_info.depth=ReadBlobMSBShort(image);
1961 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1962 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1963 psd_info.mode=ReadBlobMSBShort(image);
1964 if (image->debug != MagickFalse)
1965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1966 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1967 (double) psd_info.columns,(double) psd_info.rows,(double)
1968 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1973 image->depth=psd_info.depth;
1974 image->columns=psd_info.columns;
1975 image->rows=psd_info.rows;
1976 status=SetImageExtent(image,image->columns,image->rows,exception);
1977 if (status == MagickFalse)
1978 return(DestroyImageList(image));
1979 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1981 image=DestroyImageList(image);
1982 return((Image *) NULL);
1984 if (psd_info.mode == LabMode)
1985 SetImageColorspace(image,LabColorspace,exception);
1986 if (psd_info.mode == CMYKMode)
1988 SetImageColorspace(image,CMYKColorspace,exception);
1989 if (psd_info.channels > 4)
1990 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1992 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
1993 (psd_info.mode == DuotoneMode))
1995 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1997 if (status == MagickFalse)
1998 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1999 if (image->debug != MagickFalse)
2000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2001 " Image colormap allocated");
2002 SetImageColorspace(image,GRAYColorspace,exception);
2003 if (psd_info.channels > 1)
2004 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2007 if (psd_info.channels > 3)
2008 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2010 Read PSD raster colormap only present for indexed and duotone images.
2012 length=ReadBlobMSBLong(image);
2015 if (image->debug != MagickFalse)
2016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2017 " reading colormap");
2018 if (psd_info.mode == DuotoneMode)
2021 Duotone image data; the format of this data is undocumented.
2023 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
2025 if (data == (unsigned char *) NULL)
2026 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2027 (void) ReadBlob(image,(size_t) length,data);
2028 data=(unsigned char *) RelinquishMagickMemory(data);
2036 Read PSD raster colormap.
2038 number_colors=length/3;
2039 if (number_colors > 65536)
2040 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2041 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2042 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2043 for (i=0; i < (ssize_t) image->colors; i++)
2044 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
2045 ReadBlobByte(image));
2046 for (i=0; i < (ssize_t) image->colors; i++)
2047 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
2048 ReadBlobByte(image));
2049 for (i=0; i < (ssize_t) image->colors; i++)
2050 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
2051 ReadBlobByte(image));
2052 image->alpha_trait=UndefinedPixelTrait;
2055 if ((image->depth == 1) && (image->storage_class != PseudoClass))
2056 ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2057 has_merged_image=MagickTrue;
2058 length=ReadBlobMSBLong(image);
2065 Image resources block.
2067 if (image->debug != MagickFalse)
2068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2069 " reading image resource blocks - %.20g bytes",(double)
2070 ((MagickOffsetType) length));
2071 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2073 if (blocks == (unsigned char *) NULL)
2074 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2075 count=ReadBlob(image,(size_t) length,blocks);
2076 if ((count != (ssize_t) length) || (length < 4) ||
2077 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2079 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2080 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2082 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
2084 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2087 Layer and mask block.
2089 length=GetPSDSize(&psd_info,image);
2092 length=ReadBlobMSBLong(image);
2093 length=ReadBlobMSBLong(image);
2095 offset=TellBlob(image);
2096 skip_layers=MagickFalse;
2097 if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2098 (has_merged_image != MagickFalse))
2100 if (image->debug != MagickFalse)
2101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2102 " read composite only");
2103 skip_layers=MagickTrue;
2107 if (image->debug != MagickFalse)
2108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2109 " image has no layers");
2113 if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
2116 (void) CloseBlob(image);
2117 image=DestroyImageList(image);
2118 return((Image *) NULL);
2122 Skip the rest of the layer and mask information.
2124 SeekBlob(image,offset+length,SEEK_SET);
2127 If we are only "pinging" the image, then we're done - so return.
2129 if (image_info->ping != MagickFalse)
2131 (void) CloseBlob(image);
2132 return(GetFirstImageInList(image));
2135 Read the precombined layer, present for PSD < 4 compatibility.
2137 if (image->debug != MagickFalse)
2138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2139 " reading the precombined layer");
2140 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2141 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2142 &psd_info,exception);
2143 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
2146 SeekBlob(image,offset,SEEK_SET);
2147 status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
2148 if (status != MagickTrue)
2150 (void) CloseBlob(image);
2151 image=DestroyImageList(image);
2152 return((Image *) NULL);
2155 if (has_merged_image == MagickFalse)
2160 if (GetImageListLength(image) == 1)
2161 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2162 SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2163 image->background_color.alpha=TransparentAlpha;
2164 image->background_color.alpha_trait=BlendPixelTrait;
2165 merged=MergeImageLayers(image,FlattenLayer,exception);
2166 ReplaceImageInList(&image,merged);
2168 (void) CloseBlob(image);
2169 return(GetFirstImageInList(image));
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2177 % R e g i s t e r P S D I m a g e %
2181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2183 % RegisterPSDImage() adds properties for the PSD image format to
2184 % the list of supported formats. The properties include the image format
2185 % tag, a method to read and/or write the format, whether the format
2186 % supports the saving of more than one frame to the same file or blob,
2187 % whether the format supports native in-memory I/O, and a brief
2188 % description of the format.
2190 % The format of the RegisterPSDImage method is:
2192 % size_t RegisterPSDImage(void)
2195 ModuleExport size_t RegisterPSDImage(void)
2200 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2201 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2202 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2203 entry->magick=(IsImageFormatHandler *) IsPSD;
2204 entry->flags|=CoderSeekableStreamFlag;
2205 (void) RegisterMagickInfo(entry);
2206 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2207 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2208 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2209 entry->magick=(IsImageFormatHandler *) IsPSD;
2210 entry->flags|=CoderSeekableStreamFlag;
2211 (void) RegisterMagickInfo(entry);
2212 return(MagickImageCoderSignature);
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 % U n r e g i s t e r P S D I m a g e %
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226 % UnregisterPSDImage() removes format registrations made by the
2227 % PSD module from the list of supported formats.
2229 % The format of the UnregisterPSDImage method is:
2231 % UnregisterPSDImage(void)
2234 ModuleExport void UnregisterPSDImage(void)
2236 (void) UnregisterMagickInfo("PSB");
2237 (void) UnregisterMagickInfo("PSD");
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2245 % W r i t e P S D I m a g e %
2249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2253 % The format of the WritePSDImage method is:
2255 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2256 % ExceptionInfo *exception)
2258 % A description of each parameter follows.
2260 % o image_info: the image info.
2262 % o image: The image.
2264 % o exception: return any errors or warnings in this structure.
2268 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2269 const size_t offset)
2271 if (psd_info->version == 1)
2272 return(WriteBlobMSBShort(image,(unsigned short) offset));
2273 return(WriteBlobMSBLong(image,(unsigned short) offset));
2276 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2277 const MagickSizeType size,const MagickSizeType offset)
2285 current_offset=TellBlob(image);
2286 SeekBlob(image,offset,SEEK_SET);
2287 if (psd_info->version == 1)
2288 result=WriteBlobMSBShort(image,(unsigned short) size);
2290 result=(WriteBlobMSBLong(image,(unsigned short) size));
2291 SeekBlob(image,current_offset,SEEK_SET);
2295 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2296 const MagickSizeType size)
2298 if (psd_info->version == 1)
2299 return(WriteBlobMSBLong(image,(unsigned int) size));
2300 return(WriteBlobMSBLongLong(image,size));
2303 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2304 const MagickSizeType size,const MagickSizeType offset)
2312 current_offset=TellBlob(image);
2313 SeekBlob(image,offset,SEEK_SET);
2314 if (psd_info->version == 1)
2315 result=WriteBlobMSBLong(image,(unsigned int) size);
2317 result=WriteBlobMSBLongLong(image,size);
2318 SeekBlob(image,current_offset,SEEK_SET);
2322 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2323 const unsigned char *pixels,unsigned char *compact_pixels,
2324 ExceptionInfo *exception)
2333 register unsigned char
2340 Compress pixels with Packbits encoding.
2342 assert(image != (Image *) NULL);
2343 assert(image->signature == MagickCoreSignature);
2344 if (image->debug != MagickFalse)
2345 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2346 assert(pixels != (unsigned char *) NULL);
2347 assert(compact_pixels != (unsigned char *) NULL);
2348 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2349 if (packbits == (unsigned char *) NULL)
2350 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2353 for (i=(ssize_t) length; i != 0; )
2360 *q++=(unsigned char) 0;
2367 *q++=(unsigned char) 1;
2375 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2377 *q++=(unsigned char) ((256-3)+1);
2381 *q++=(unsigned char) 2;
2389 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2395 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2402 *q++=(unsigned char) ((256-count)+1);
2411 while ((*(pixels+count) != *(pixels+count+1)) ||
2412 (*(pixels+count+1) != *(pixels+count+2)))
2414 packbits[count+1]=pixels[count];
2416 if (((ssize_t) count >= (i-3)) || (count >= 127))
2420 *packbits=(unsigned char) (count-1);
2421 for (j=0; j <= (ssize_t) count; j++)
2428 *q++=(unsigned char) 128; /* EOD marker */
2429 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2430 return((size_t) (q-compact_pixels));
2433 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
2434 const Image *next_image,const ssize_t channels)
2443 if (next_image->compression == RLECompression)
2445 length=WriteBlobMSBShort(image,RLE);
2446 for (i=0; i < channels; i++)
2447 for (y=0; y < (ssize_t) next_image->rows; y++)
2448 length+=SetPSDOffset(psd_info,image,0);
2450 #ifdef MAGICKCORE_ZLIB_DELEGATE
2451 else if (next_image->compression == ZipCompression)
2452 length=WriteBlobMSBShort(image,ZipWithoutPrediction);
2455 length=WriteBlobMSBShort(image,Raw);
2459 static size_t WritePSDChannel(const PSDInfo *psd_info,
2460 const ImageInfo *image_info,Image *image,Image *next_image,
2461 const QuantumType quantum_type, unsigned char *compact_pixels,
2462 MagickOffsetType size_offset,const MagickBooleanType separate,
2463 ExceptionInfo *exception)
2474 register const Quantum
2487 #ifdef MAGICKCORE_ZLIB_DELEGATE
2501 compressed_pixels=(unsigned char *) NULL;
2505 if (separate != MagickFalse)
2507 size_offset=TellBlob(image)+2;
2508 count+=WriteCompressionStart(psd_info,image,next_image,1);
2510 if (next_image->depth > 8)
2511 next_image->depth=16;
2512 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2513 MagickTrue : MagickFalse;
2514 quantum_info=AcquireQuantumInfo(image_info,image);
2515 if (quantum_info == (QuantumInfo *) NULL)
2517 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2518 #ifdef MAGICKCORE_ZLIB_DELEGATE
2519 if (next_image->compression == ZipCompression)
2521 compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
2522 sizeof(*compressed_pixels));
2523 if (compressed_pixels == (unsigned char *) NULL)
2525 quantum_info=DestroyQuantumInfo(quantum_info);
2528 ResetMagickMemory(&stream,0,sizeof(stream));
2529 stream.data_type=Z_BINARY;
2530 level=Z_DEFAULT_COMPRESSION;
2531 if ((image_info->quality > 0 && image_info->quality < 10))
2532 level=(int) image_info->quality;
2533 if (deflateInit(&stream,level) != Z_OK)
2535 quantum_info=DestroyQuantumInfo(quantum_info);
2540 for (y=0; y < (ssize_t) next_image->rows; y++)
2542 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2543 if (p == (const Quantum *) NULL)
2545 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2546 quantum_type,pixels,exception);
2547 if (monochrome != MagickFalse)
2548 for (i=0; i < (ssize_t) length; i++)
2549 pixels[i]=(~pixels[i]);
2550 if (next_image->compression == RLECompression)
2552 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2554 count+=WriteBlob(image,length,compact_pixels);
2555 size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
2557 #ifdef MAGICKCORE_ZLIB_DELEGATE
2558 else if (next_image->compression == ZipCompression)
2560 stream.avail_in=(uInt) length;
2561 stream.next_in=(Bytef *) pixels;
2562 if (y == (ssize_t) next_image->rows-1)
2565 stream.avail_out=(uInt) CHUNK;
2566 stream.next_out=(Bytef *) compressed_pixels;
2567 if (deflate(&stream,flush) == Z_STREAM_ERROR)
2569 length=(size_t) CHUNK-stream.avail_out;
2571 count+=WriteBlob(image,length,compressed_pixels);
2572 } while (stream.avail_out == 0);
2576 count+=WriteBlob(image,length,pixels);
2578 #ifdef MAGICKCORE_ZLIB_DELEGATE
2579 if (next_image->compression == ZipCompression)
2581 (void) deflateEnd(&stream);
2582 compressed_pixels=(unsigned char *) RelinquishMagickMemory(
2586 quantum_info=DestroyQuantumInfo(quantum_info);
2590 static unsigned char *AcquireCompactPixels(const Image *image,
2591 ExceptionInfo *exception)
2599 packet_size=image->depth > 8UL ? 2UL : 1UL;
2600 compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
2601 image->columns)+1,packet_size*sizeof(*compact_pixels));
2602 if (compact_pixels == (unsigned char *) NULL)
2604 (void) ThrowMagickException(exception,GetMagickModule(),
2605 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2608 return(compact_pixels);
2611 static size_t WritePSDChannels(const PSDInfo *psd_info,
2612 const ImageInfo *image_info,Image *image,Image *next_image,
2613 MagickOffsetType size_offset,const MagickBooleanType separate,
2614 ExceptionInfo *exception)
2634 compact_pixels=(unsigned char *) NULL;
2635 if (next_image->compression == RLECompression)
2637 compact_pixels=AcquireCompactPixels(image,exception);
2638 if (compact_pixels == (unsigned char *) NULL)
2642 if (separate == MagickFalse)
2644 if (next_image->storage_class != PseudoClass)
2646 if (IsImageGray(next_image) == MagickFalse)
2647 channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
2648 if (next_image->alpha_trait != UndefinedPixelTrait)
2651 rows_offset=TellBlob(image)+2;
2652 count+=WriteCompressionStart(psd_info,image,next_image,channels);
2653 offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
2656 if (next_image->storage_class == PseudoClass)
2658 length=WritePSDChannel(psd_info,image_info,image,next_image,
2659 IndexQuantum,compact_pixels,rows_offset,separate,exception);
2660 if (separate != MagickFalse)
2661 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2663 rows_offset+=offset_length;
2668 if (IsImageGray(next_image) != MagickFalse)
2670 length=WritePSDChannel(psd_info,image_info,image,next_image,
2671 GrayQuantum,compact_pixels,rows_offset,separate,exception);
2672 if (separate != MagickFalse)
2673 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2675 rows_offset+=offset_length;
2680 if (next_image->colorspace == CMYKColorspace)
2681 (void) NegateCMYK(next_image,exception);
2683 length=WritePSDChannel(psd_info,image_info,image,next_image,
2684 RedQuantum,compact_pixels,rows_offset,separate,exception);
2685 if (separate != MagickFalse)
2686 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2688 rows_offset+=offset_length;
2691 length=WritePSDChannel(psd_info,image_info,image,next_image,
2692 GreenQuantum,compact_pixels,rows_offset,separate,exception);
2693 if (separate != MagickFalse)
2694 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2696 rows_offset+=offset_length;
2699 length=WritePSDChannel(psd_info,image_info,image,next_image,
2700 BlueQuantum,compact_pixels,rows_offset,separate,exception);
2701 if (separate != MagickFalse)
2702 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2704 rows_offset+=offset_length;
2707 if (next_image->colorspace == CMYKColorspace)
2709 length=WritePSDChannel(psd_info,image_info,image,next_image,
2710 BlackQuantum,compact_pixels,rows_offset,separate,exception);
2711 if (separate != MagickFalse)
2712 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2714 rows_offset+=offset_length;
2718 if (next_image->alpha_trait != UndefinedPixelTrait)
2720 length=WritePSDChannel(psd_info,image_info,image,next_image,
2721 AlphaQuantum,compact_pixels,rows_offset,separate,exception);
2722 if (separate != MagickFalse)
2723 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2725 rows_offset+=offset_length;
2729 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2730 if (next_image->colorspace == CMYKColorspace)
2731 (void) NegateCMYK(next_image,exception);
2732 if (separate != MagickFalse)
2737 property=GetImageArtifact(next_image,"psd:opacity-mask");
2738 if (property != (const char *) NULL)
2740 mask=(Image *) GetImageRegistry(ImageRegistryType,property,
2742 if (mask != (Image *) NULL)
2744 if (mask->compression == RLECompression)
2746 compact_pixels=AcquireCompactPixels(mask,exception);
2747 if (compact_pixels == (unsigned char *) NULL)
2750 length=WritePSDChannel(psd_info,image_info,image,mask,
2751 RedQuantum,compact_pixels,rows_offset,MagickTrue,exception);
2752 (void) WritePSDSize(psd_info,image,length,size_offset);
2754 compact_pixels=(unsigned char *) RelinquishMagickMemory(
2762 static size_t WritePascalString(Image *image,const char *value,size_t padding)
2775 length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
2777 count+=WriteBlobByte(image,0);
2780 count+=WriteBlobByte(image,(unsigned char) length);
2781 count+=WriteBlob(image,length,(const unsigned char *) value);
2784 if ((length % padding) == 0)
2786 for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
2787 count+=WriteBlobByte(image,0);
2791 static void WriteResolutionResourceBlock(Image *image)
2800 if (image->units == PixelsPerCentimeterResolution)
2802 x_resolution=2.54*65536.0*image->resolution.x+0.5;
2803 y_resolution=2.54*65536.0*image->resolution.y+0.5;
2808 x_resolution=65536.0*image->resolution.x+0.5;
2809 y_resolution=65536.0*image->resolution.y+0.5;
2812 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2813 (void) WriteBlobMSBShort(image,0x03ED);
2814 (void) WriteBlobMSBShort(image,0);
2815 (void) WriteBlobMSBLong(image,16); /* resource size */
2816 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2817 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2818 (void) WriteBlobMSBShort(image,units); /* width unit */
2819 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2820 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2821 (void) WriteBlobMSBShort(image,units); /* height unit */
2824 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
2825 const signed short channel)
2830 count=WriteBlobMSBSignedShort(image,channel);
2831 count+=SetPSDSize(psd_info,image,0);
2835 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2837 register const unsigned char
2854 length=GetStringInfoLength(bim_profile);
2857 datum=GetStringInfoDatum(bim_profile);
2858 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2860 register unsigned char
2863 q=(unsigned char *) p;
2864 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2866 p=PushLongPixel(MSBEndian,p,&long_sans);
2867 p=PushShortPixel(MSBEndian,p,&id);
2868 p=PushShortPixel(MSBEndian,p,&short_sans);
2869 p=PushLongPixel(MSBEndian,p,&count);
2870 if (id == 0x0000040f)
2875 quantum=PSDQuantum(count)+12;
2876 if ((quantum >= 12) && (quantum < (ssize_t) length))
2878 if ((q+quantum < (datum+length-16)))
2879 (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
2880 SetStringInfoLength(bim_profile,length-quantum);
2885 if ((count & 0x01) != 0)
2890 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2892 register const unsigned char
2909 length=GetStringInfoLength(bim_profile);
2912 datum=GetStringInfoDatum(bim_profile);
2913 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2915 register unsigned char
2921 q=(unsigned char *) p;
2922 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2924 p=PushLongPixel(MSBEndian,p,&long_sans);
2925 p=PushShortPixel(MSBEndian,p,&id);
2926 p=PushShortPixel(MSBEndian,p,&short_sans);
2927 p=PushLongPixel(MSBEndian,p,&count);
2928 cnt=PSDQuantum(count);
2931 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
2933 (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
2934 SetStringInfoLength(bim_profile,length-(cnt+12));
2938 if ((count & 0x01) != 0)
2943 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
2944 Image *image,ExceptionInfo *exception)
2946 #define PSDKeySize 5
2947 #define PSDAllowedLength 36
2952 /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
2954 allowed[PSDAllowedLength][PSDKeySize] = {
2955 "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
2956 "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
2957 "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
2958 "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
2984 info=GetImageProfile(image,"psd:additional-info");
2985 if (info == (const StringInfo *) NULL)
2986 return((const StringInfo *) NULL);
2987 option=GetImageOption(image_info,"psd:additional-info");
2988 if (LocaleCompare(option,"all") == 0)
2990 if (LocaleCompare(option,"selective") != 0)
2992 profile=RemoveImageProfile(image,"psd:additional-info");
2993 return(DestroyStringInfo(profile));
2995 length=GetStringInfoLength(info);
2996 p=GetStringInfoDatum(info);
2997 remaining_length=length;
2999 while (remaining_length >= 12)
3001 /* skip over signature */
3008 size=(unsigned int) (*p++) << 24;
3009 size|=(unsigned int) (*p++) << 16;
3010 size|=(unsigned int) (*p++) << 8;
3011 size|=(unsigned int) (*p++);
3012 size=size & 0xffffffff;
3013 remaining_length-=12;
3014 if ((size_t) size > remaining_length)
3015 return((const StringInfo *) NULL);
3017 for (i=0; i < PSDAllowedLength; i++)
3019 if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3025 remaining_length-=(size_t) size;
3026 if (found == MagickFalse)
3028 if (remaining_length > 0)
3029 p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
3032 length+=(size_t) size+12;
3035 profile=RemoveImageProfile(image,"psd:additional-info");
3037 return(DestroyStringInfo(profile));
3038 SetStringInfoLength(profile,(const size_t) length);
3039 SetImageProfile(image,"psd:additional-info",info,exception);
3043 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3044 Image *image,ExceptionInfo *exception)
3047 layer_name[MagickPathExtent];
3064 *layer_size_offsets,
3089 assert(image_info != (const ImageInfo *) NULL);
3090 assert(image_info->signature == MagickCoreSignature);
3091 assert(image != (Image *) NULL);
3092 assert(image->signature == MagickCoreSignature);
3093 if (image->debug != MagickFalse)
3094 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3095 assert(exception != (ExceptionInfo *) NULL);
3096 assert(exception->signature == MagickCoreSignature);
3097 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3098 if (status == MagickFalse)
3100 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
3101 if (image->alpha_trait != UndefinedPixelTrait)
3102 packet_size+=image->depth > 8 ? 2 : 1;
3104 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3105 (image->columns > 30000) || (image->rows > 30000))
3107 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3108 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
3109 for (i=1; i <= 6; i++)
3110 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
3111 if (SetImageGray(image,exception) != MagickFalse)
3112 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3114 if ((image_info->type != TrueColorType) && (image_info->type !=
3115 TrueColorAlphaType) && (image->storage_class == PseudoClass))
3116 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3119 if (image->storage_class == PseudoClass)
3120 (void) SetImageStorageClass(image,DirectClass,exception);
3121 if (image->colorspace != CMYKColorspace)
3122 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3124 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3126 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3127 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3128 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3129 if (IsImageGray(image) != MagickFalse)
3137 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3138 MagickTrue : MagickFalse;
3139 (void) WriteBlobMSBShort(image,(unsigned short)
3140 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3141 (void) WriteBlobMSBShort(image,(unsigned short)
3142 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3146 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3147 PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3149 if (((image_info->colorspace != UndefinedColorspace) ||
3150 (image->colorspace != CMYKColorspace)) &&
3151 (image_info->colorspace != CMYKColorspace))
3153 (void) TransformImageColorspace(image,sRGBColorspace,exception);
3154 (void) WriteBlobMSBShort(image,(unsigned short)
3155 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3159 if (image->colorspace != CMYKColorspace)
3160 (void) TransformImageColorspace(image,CMYKColorspace,exception);
3161 (void) WriteBlobMSBShort(image,CMYKMode);
3164 if ((IsImageGray(image) != MagickFalse) ||
3165 (image->storage_class == DirectClass) || (image->colors > 256))
3166 (void) WriteBlobMSBLong(image,0);
3170 Write PSD raster colormap.
3172 (void) WriteBlobMSBLong(image,768);
3173 for (i=0; i < (ssize_t) image->colors; i++)
3174 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
3175 for ( ; i < 256; i++)
3176 (void) WriteBlobByte(image,0);
3177 for (i=0; i < (ssize_t) image->colors; i++)
3178 (void) WriteBlobByte(image,ScaleQuantumToChar(
3179 image->colormap[i].green));
3180 for ( ; i < 256; i++)
3181 (void) WriteBlobByte(image,0);
3182 for (i=0; i < (ssize_t) image->colors; i++)
3183 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
3184 for ( ; i < 256; i++)
3185 (void) WriteBlobByte(image,0);
3188 Image resource block.
3190 length=28; /* 0x03EB */
3191 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
3192 icc_profile=GetImageProfile(image,"icc");
3193 if (bim_profile != (StringInfo *) NULL)
3195 bim_profile=CloneStringInfo(bim_profile);
3196 if (icc_profile != (StringInfo *) NULL)
3197 RemoveICCProfileFromResourceBlock(bim_profile);
3198 RemoveResolutionFromResourceBlock(bim_profile);
3199 length+=PSDQuantum(GetStringInfoLength(bim_profile));
3201 if (icc_profile != (const StringInfo *) NULL)
3202 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
3203 (void) WriteBlobMSBLong(image,(unsigned int) length);
3204 WriteResolutionResourceBlock(image);
3205 if (bim_profile != (StringInfo *) NULL)
3207 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
3208 GetStringInfoDatum(bim_profile));
3209 bim_profile=DestroyStringInfo(bim_profile);
3211 if (icc_profile != (StringInfo *) NULL)
3213 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3214 (void) WriteBlobMSBShort(image,0x0000040F);
3215 (void) WriteBlobMSBShort(image,0);
3216 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
3218 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
3219 GetStringInfoDatum(icc_profile));
3220 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
3221 PSDQuantum(GetStringInfoLength(icc_profile)))
3222 (void) WriteBlobByte(image,0);
3224 base_image=GetNextImageInList(image);
3225 if (base_image == (Image *) NULL)
3228 size_offset=TellBlob(image);
3229 SetPSDSize(&psd_info,image,0);
3230 SetPSDSize(&psd_info,image,0);
3232 for (next_image=base_image; next_image != NULL; )
3235 next_image=GetNextImageInList(next_image);
3237 if (image->alpha_trait != UndefinedPixelTrait)
3238 size+=WriteBlobMSBShort(image,-(unsigned short) layer_count);
3240 size+=WriteBlobMSBShort(image,(unsigned short) layer_count);
3241 layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3242 (size_t) layer_count,sizeof(MagickOffsetType));
3243 if (layer_size_offsets == (MagickOffsetType *) NULL)
3244 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3246 for (next_image=base_image; next_image != NULL; )
3258 mask=(Image *) NULL;
3259 property=GetImageArtifact(next_image,"psd:opacity-mask");
3261 if (property != (const char *) NULL)
3263 mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3264 default_color=strlen(property) == 9 ? 255 : 0;
3266 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
3267 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
3268 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
3270 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
3271 next_image->columns));
3273 if ((next_image->storage_class != PseudoClass) &&
3274 (IsImageGray(next_image) == MagickFalse))
3275 channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
3276 total_channels=channels;
3277 if (next_image->alpha_trait != UndefinedPixelTrait)
3279 if (mask != (Image *) NULL)
3281 size+=WriteBlobMSBShort(image,total_channels);
3282 layer_size_offsets[layer_index++]=TellBlob(image);
3283 for (i=0; i < (ssize_t) channels; i++)
3284 size+=WriteChannelSize(&psd_info,image,(signed short) i);
3285 if (next_image->alpha_trait != UndefinedPixelTrait)
3286 size+=WriteChannelSize(&psd_info,image,-1);
3287 if (mask != (Image *) NULL)
3288 size+=WriteChannelSize(&psd_info,image,-2);
3289 size+=WriteBlob(image,4,(const unsigned char *) "8BIM");
3290 size+=WriteBlob(image,4,(const unsigned char *)
3291 CompositeOperatorToPSDBlendMode(next_image->compose));
3292 property=GetImageArtifact(next_image,"psd:layer.opacity");
3293 if (property != (const char *) NULL)
3298 opacity=(Quantum) StringToInteger(property);
3299 size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
3300 (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3303 size+=WriteBlobByte(image,255);
3304 size+=WriteBlobByte(image,0);
3305 size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
3306 1 << 0x02 : 1); /* layer properties - visible, etc. */
3307 size+=WriteBlobByte(image,0);
3308 info=GetAdditionalInformation(image_info,next_image,exception);
3309 property=(const char *) GetImageProperty(next_image,"label",exception);
3310 if (property == (const char *) NULL)
3312 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3313 (double) layer_index);
3314 property=layer_name;
3316 name_length=strlen(property)+1;
3317 if ((name_length % 4) != 0)
3318 name_length+=(4-(name_length % 4));
3319 if (info != (const StringInfo *) NULL)
3320 name_length+=GetStringInfoLength(info);
3322 if (mask != (Image *) NULL)
3324 size+=WriteBlobMSBLong(image,(unsigned int) name_length);
3325 if (mask == (Image *) NULL)
3326 size+=WriteBlobMSBLong(image,0);
3329 if (mask->compose != NoCompositeOp)
3330 (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3331 default_color),MagickTrue,exception);
3332 mask->page.y+=image->page.y;
3333 mask->page.x+=image->page.x;
3334 size+=WriteBlobMSBLong(image,20);
3335 size+=WriteBlobMSBSignedLong(image,mask->page.y);
3336 size+=WriteBlobMSBSignedLong(image,mask->page.x);
3337 size+=WriteBlobMSBLong(image,(const unsigned int) mask->rows+
3339 size+=WriteBlobMSBLong(image,(const unsigned int) mask->columns+
3341 size+=WriteBlobByte(image,default_color);
3342 size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
3343 size+=WriteBlobMSBShort(image,0);
3345 size+=WriteBlobMSBLong(image,0);
3346 size+=WritePascalString(image,property,4);
3347 if (info != (const StringInfo *) NULL)
3348 size+=WriteBlob(image,GetStringInfoLength(info),
3349 GetStringInfoDatum(info));
3350 next_image=GetNextImageInList(next_image);
3355 next_image=base_image;
3357 while (next_image != NULL)
3359 length=WritePSDChannels(&psd_info,image_info,image,next_image,
3360 layer_size_offsets[layer_index++],MagickTrue,exception);
3367 next_image=GetNextImageInList(next_image);
3369 (void) WriteBlobMSBLong(image,0); /* user mask data */
3371 Write the total size
3373 size_offset+=WritePSDSize(&psd_info,image,size+
3374 (psd_info.version == 1 ? 8 : 16),size_offset);
3375 if ((size/2) != ((size+1)/2))
3376 rounded_size=size+1;
3379 (void) WritePSDSize(&psd_info,image,rounded_size,size_offset);
3380 layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3381 layer_size_offsets);
3383 Remove the opacity mask from the registry
3385 next_image=base_image;
3386 while (next_image != (Image *) NULL)
3388 property=GetImageArtifact(next_image,"psd:opacity-mask");
3389 if (property != (const char *) NULL)
3390 DeleteImageRegistry(property);
3391 next_image=GetNextImageInList(next_image);
3394 Write composite image.
3396 if (status != MagickFalse)
3401 compression=image->compression;
3402 if (image->compression == ZipCompression)
3403 image->compression=RLECompression;
3404 if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
3407 image->compression=compression;
3409 (void) CloseBlob(image);