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 % https://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/policy.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/registry.h"
75 #include "MagickCore/quantum-private.h"
76 #include "MagickCore/static.h"
77 #include "MagickCore/string_.h"
78 #include "MagickCore/string-private.h"
79 #include "MagickCore/thread-private.h"
80 #ifdef MAGICKCORE_ZLIB_DELEGATE
83 #include "psd-private.h"
88 #define MaxPSDChannels 56
89 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
92 Enumerated declaractions.
98 ZipWithoutPrediction = 2,
100 } PSDCompressionType;
109 MultichannelMode = 7,
115 Typedef declaractions.
117 typedef struct _ChannelInfo
126 typedef struct _MaskInfo
139 typedef struct _LayerInfo
142 channel_info[MaxPSDChannels];
177 Forward declarations.
179 static MagickBooleanType
180 WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 % IsPSD()() returns MagickTrue if the image format type, identified by the
194 % magick string, is PSD.
196 % The format of the IsPSD method is:
198 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
200 % A description of each parameter follows:
202 % o magick: compare image format pattern against these bytes.
204 % o length: Specifies the length of the magick string.
207 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
211 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221 % R e a d P S D I m a g e %
225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It
228 % allocates the memory necessary for the new Image structure and returns a
229 % pointer to the new image.
231 % The format of the ReadPSDImage method is:
233 % Image *ReadPSDImage(image_info,ExceptionInfo *exception)
235 % A description of each parameter follows:
237 % o image_info: the image info.
239 % o exception: return any errors or warnings in this structure.
243 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
250 case ColorBurnCompositeOp: blend_mode = "idiv"; break;
251 case ColorDodgeCompositeOp: blend_mode = "div "; break;
252 case ColorizeCompositeOp: blend_mode = "colr"; break;
253 case DarkenCompositeOp: blend_mode = "dark"; break;
254 case DifferenceCompositeOp: blend_mode = "diff"; break;
255 case DissolveCompositeOp: blend_mode = "diss"; break;
256 case ExclusionCompositeOp: blend_mode = "smud"; break;
257 case HardLightCompositeOp: blend_mode = "hLit"; break;
258 case HardMixCompositeOp: blend_mode = "hMix"; break;
259 case HueCompositeOp: blend_mode = "hue "; break;
260 case LightenCompositeOp: blend_mode = "lite"; break;
261 case LinearBurnCompositeOp: blend_mode = "lbrn"; break;
262 case LinearDodgeCompositeOp:blend_mode = "lddg"; break;
263 case LinearLightCompositeOp:blend_mode = "lLit"; break;
264 case LuminizeCompositeOp: blend_mode = "lum "; break;
265 case MultiplyCompositeOp: blend_mode = "mul "; break;
266 case OverCompositeOp: blend_mode = "norm"; break;
267 case OverlayCompositeOp: blend_mode = "over"; break;
268 case PinLightCompositeOp: blend_mode = "pLit"; break;
269 case SaturateCompositeOp: blend_mode = "sat "; break;
270 case ScreenCompositeOp: blend_mode = "scrn"; break;
271 case SoftLightCompositeOp: blend_mode = "sLit"; break;
272 case VividLightCompositeOp: blend_mode = "vLit"; break;
273 default: blend_mode = "norm";
279 For some reason Photoshop seems to blend semi-transparent pixels with white.
280 This method reverts the blending. This can be disabled by setting the
281 option 'psd:alpha-unblend' to off.
283 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
284 Image *image,ExceptionInfo* exception)
295 if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace)
297 option=GetImageOption(image_info,"psd:alpha-unblend");
298 if (IsStringFalse(option) != MagickFalse)
301 #if defined(MAGICKCORE_OPENMP_SUPPORT)
302 #pragma omp parallel for schedule(static,4) shared(status) \
303 magick_threads(image,image,image->rows,1)
305 for (y=0; y < (ssize_t) image->rows; y++)
313 if (status == MagickFalse)
315 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
316 if (q == (Quantum *) NULL)
321 for (x=0; x < (ssize_t) image->columns; x++)
329 gamma=QuantumScale*GetPixelAlpha(image, q);
330 if (gamma != 0.0 && gamma != 1.0)
332 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
334 PixelChannel channel = GetPixelChannelChannel(image,i);
335 if (channel != AlphaPixelChannel)
336 q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
339 q+=GetPixelChannels(image);
341 if (SyncAuthenticPixels(image,exception) == MagickFalse)
348 static inline CompressionType ConvertPSDCompression(
349 PSDCompressionType compression)
354 return RLECompression;
355 case ZipWithPrediction:
356 case ZipWithoutPrediction:
357 return ZipCompression;
359 return NoCompression;
363 static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
364 MagickBooleanType revert,ExceptionInfo *exception)
372 if (image->debug != MagickFalse)
373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
374 " applying layer opacity %.20g", (double) opacity);
375 if (opacity == OpaqueAlpha)
377 image->alpha_trait=BlendPixelTrait;
379 #if defined(MAGICKCORE_OPENMP_SUPPORT)
380 #pragma omp parallel for schedule(static,4) shared(status) \
381 magick_threads(image,image,image->rows,1)
383 for (y=0; y < (ssize_t) image->rows; y++)
391 if (status == MagickFalse)
393 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
394 if (q == (Quantum *) NULL)
399 for (x=0; x < (ssize_t) image->columns; x++)
401 if (revert == MagickFalse)
402 SetPixelAlpha(image,(Quantum) (QuantumScale*(GetPixelAlpha(image,q))*
404 else if (opacity > 0)
405 SetPixelAlpha(image,(Quantum) (QuantumRange*(GetPixelAlpha(image,q)/
406 (MagickRealType) opacity)),q);
407 q+=GetPixelChannels(image);
409 if (SyncAuthenticPixels(image,exception) == MagickFalse)
416 static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
417 Quantum background,MagickBooleanType revert,ExceptionInfo *exception)
431 if (image->debug != MagickFalse)
432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
433 " applying opacity mask");
434 complete_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
436 complete_mask->alpha_trait=BlendPixelTrait;
437 GetPixelInfo(complete_mask,&color);
438 color.red=background;
439 SetImageColor(complete_mask,&color,exception);
440 status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
441 mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
442 if (status == MagickFalse)
444 complete_mask=DestroyImage(complete_mask);
447 image->alpha_trait=BlendPixelTrait;
448 #if defined(MAGICKCORE_OPENMP_SUPPORT)
449 #pragma omp parallel for schedule(static,4) shared(status) \
450 magick_threads(image,image,image->rows,1)
452 for (y=0; y < (ssize_t) image->rows; y++)
463 if (status == MagickFalse)
465 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
466 p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception);
467 if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL))
472 for (x=0; x < (ssize_t) image->columns; x++)
478 alpha=GetPixelAlpha(image,q);
479 intensity=GetPixelIntensity(complete_mask,p);
480 if (revert == MagickFalse)
481 SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
482 else if (intensity > 0)
483 SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*QuantumRange),q);
484 q+=GetPixelChannels(image);
485 p+=GetPixelChannels(complete_mask);
487 if (SyncAuthenticPixels(image,exception) == MagickFalse)
490 complete_mask=DestroyImage(complete_mask);
494 static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info,
495 ExceptionInfo *exception)
506 if (image->debug != MagickFalse)
507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
508 " preserving opacity mask");
509 random_info=AcquireRandomInfo();
510 key_info=GetRandomKey(random_info,2+1);
511 key=(char *) GetStringInfoDatum(key_info);
512 key[8]=layer_info->mask.background;
514 layer_info->mask.image->page.x+=layer_info->page.x;
515 layer_info->mask.image->page.y+=layer_info->page.y;
516 (void) SetImageRegistry(ImageRegistryType,(const char *) key,
517 layer_info->mask.image,exception);
518 (void) SetImageArtifact(layer_info->image,"psd:opacity-mask",
520 key_info=DestroyStringInfo(key_info);
521 random_info=DestroyRandomInfo(random_info);
524 static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
525 const unsigned char *compact_pixels,const ssize_t depth,
526 const size_t number_pixels,unsigned char *pixels)
528 #define CheckNumberCompactPixels \
533 #define CheckNumberPixels(count) \
534 if (((ssize_t) i + count) > (ssize_t) number_pixels) \
551 packets=(ssize_t) number_compact_pixels;
552 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
555 length=(size_t) (*compact_pixels++);
561 CheckNumberCompactPixels;
562 pixel=(*compact_pixels++);
563 for (j=0; j < (ssize_t) length; j++)
569 CheckNumberPixels(8);
570 *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
571 *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
572 *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
573 *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
574 *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
575 *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
576 *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
577 *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
582 CheckNumberPixels(4);
583 *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
584 *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
585 *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
586 *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
591 CheckNumberPixels(2);
592 *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
593 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
598 CheckNumberPixels(1);
599 *pixels++=(unsigned char) pixel;
607 for (j=0; j < (ssize_t) length; j++)
609 CheckNumberCompactPixels;
614 CheckNumberPixels(8);
615 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
616 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
617 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
618 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
619 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
620 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
621 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
622 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
627 CheckNumberPixels(4);
628 *pixels++=(*compact_pixels >> 6) & 0x03;
629 *pixels++=(*compact_pixels >> 4) & 0x03;
630 *pixels++=(*compact_pixels >> 2) & 0x03;
631 *pixels++=(*compact_pixels & 0x03) & 0x03;
636 CheckNumberPixels(2);
637 *pixels++=(*compact_pixels >> 4) & 0xff;
638 *pixels++=(*compact_pixels & 0x0f) & 0xff;
643 CheckNumberPixels(1);
644 *pixels++=(*compact_pixels);
654 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
655 const ssize_t number_layers)
660 for (i=0; i<number_layers; i++)
662 if (layer_info[i].image != (Image *) NULL)
663 layer_info[i].image=DestroyImage(layer_info[i].image);
664 if (layer_info[i].mask.image != (Image *) NULL)
665 layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
666 if (layer_info[i].info != (StringInfo *) NULL)
667 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
670 return (LayerInfo *) RelinquishMagickMemory(layer_info);
673 static inline size_t GetPSDPacketSize(Image *image)
675 if (image->storage_class == PseudoClass)
677 if (image->colors > 256)
679 else if (image->depth > 8)
683 if (image->depth > 8)
689 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
691 if (psd_info->version == 1)
692 return((MagickSizeType) ReadBlobLong(image));
693 return((MagickSizeType) ReadBlobLongLong(image));
696 static inline size_t GetPSDRowSize(Image *image)
698 if (image->depth == 1)
699 return(((image->columns+7)/8)*GetPSDPacketSize(image));
701 return(image->columns*GetPSDPacketSize(image));
704 static const char *ModeToString(PSDImageType type)
708 case BitmapMode: return "Bitmap";
709 case GrayscaleMode: return "Grayscale";
710 case IndexedMode: return "Indexed";
711 case RGBMode: return "RGB";
712 case CMYKMode: return "CMYK";
713 case MultichannelMode: return "Multichannel";
714 case DuotoneMode: return "Duotone";
715 case LabMode: return "L*A*B";
716 default: return "unknown";
720 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
728 channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
730 status=NegateImage(image,MagickFalse,exception);
731 (void) SetImageChannelMask(image,channel_mask);
735 static void ParseImageResourceBlocks(Image *image,
736 const unsigned char *blocks,size_t length,
737 MagickBooleanType *has_merged_image,ExceptionInfo *exception)
757 profile=BlobToStringInfo((const unsigned char *) NULL,length);
758 SetStringInfoDatum(profile,blocks);
759 (void) SetImageProfile(image,"8bim",profile,exception);
760 profile=DestroyStringInfo(profile);
761 for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
763 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
766 p=PushShortPixel(MSBEndian,p,&id);
767 p=PushCharPixel(p,&name_length);
768 if ((name_length % 2) == 0)
771 if (p > (blocks+length-4))
773 p=PushLongPixel(MSBEndian,p,&count);
774 if ((p+count) > (blocks+length))
781 value[MagickPathExtent];
791 p=PushShortPixel(MSBEndian,p,&resolution);
792 image->resolution.x=(double) resolution;
793 (void) FormatLocaleString(value,MagickPathExtent,"%g",
794 image->resolution.x);
795 (void) SetImageProperty(image,"tiff:XResolution",value,exception);
796 p=PushShortPixel(MSBEndian,p,&short_sans);
797 p=PushShortPixel(MSBEndian,p,&short_sans);
798 p=PushShortPixel(MSBEndian,p,&short_sans);
799 p=PushShortPixel(MSBEndian,p,&resolution);
800 image->resolution.y=(double) resolution;
801 (void) FormatLocaleString(value,MagickPathExtent,"%g",
802 image->resolution.y);
803 (void) SetImageProperty(image,"tiff:YResolution",value,exception);
804 p=PushShortPixel(MSBEndian,p,&short_sans);
805 p=PushShortPixel(MSBEndian,p,&short_sans);
806 p=PushShortPixel(MSBEndian,p,&short_sans);
807 image->units=PixelsPerInchResolution;
812 if ((count > 3) && (*(p+4) == 0))
813 *has_merged_image=MagickFalse;
823 if ((count & 0x01) != 0)
829 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
831 if (mode == (const char *) NULL)
832 return(OverCompositeOp);
833 if (LocaleNCompare(mode,"norm",4) == 0)
834 return(OverCompositeOp);
835 if (LocaleNCompare(mode,"mul ",4) == 0)
836 return(MultiplyCompositeOp);
837 if (LocaleNCompare(mode,"diss",4) == 0)
838 return(DissolveCompositeOp);
839 if (LocaleNCompare(mode,"diff",4) == 0)
840 return(DifferenceCompositeOp);
841 if (LocaleNCompare(mode,"dark",4) == 0)
842 return(DarkenCompositeOp);
843 if (LocaleNCompare(mode,"lite",4) == 0)
844 return(LightenCompositeOp);
845 if (LocaleNCompare(mode,"hue ",4) == 0)
846 return(HueCompositeOp);
847 if (LocaleNCompare(mode,"sat ",4) == 0)
848 return(SaturateCompositeOp);
849 if (LocaleNCompare(mode,"colr",4) == 0)
850 return(ColorizeCompositeOp);
851 if (LocaleNCompare(mode,"lum ",4) == 0)
852 return(LuminizeCompositeOp);
853 if (LocaleNCompare(mode,"scrn",4) == 0)
854 return(ScreenCompositeOp);
855 if (LocaleNCompare(mode,"over",4) == 0)
856 return(OverlayCompositeOp);
857 if (LocaleNCompare(mode,"hLit",4) == 0)
858 return(HardLightCompositeOp);
859 if (LocaleNCompare(mode,"sLit",4) == 0)
860 return(SoftLightCompositeOp);
861 if (LocaleNCompare(mode,"smud",4) == 0)
862 return(ExclusionCompositeOp);
863 if (LocaleNCompare(mode,"div ",4) == 0)
864 return(ColorDodgeCompositeOp);
865 if (LocaleNCompare(mode,"idiv",4) == 0)
866 return(ColorBurnCompositeOp);
867 if (LocaleNCompare(mode,"lbrn",4) == 0)
868 return(LinearBurnCompositeOp);
869 if (LocaleNCompare(mode,"lddg",4) == 0)
870 return(LinearDodgeCompositeOp);
871 if (LocaleNCompare(mode,"lLit",4) == 0)
872 return(LinearLightCompositeOp);
873 if (LocaleNCompare(mode,"vLit",4) == 0)
874 return(VividLightCompositeOp);
875 if (LocaleNCompare(mode,"pLit",4) == 0)
876 return(PinLightCompositeOp);
877 if (LocaleNCompare(mode,"hMix",4) == 0)
878 return(HardMixCompositeOp);
879 return(OverCompositeOp);
882 static inline void ReversePSDString(Image *image,char *p,size_t length)
887 if (image->endian == MSBEndian)
891 for(--q; p < q; ++p, --q)
899 static inline void SetPSDPixel(Image *image,const size_t channels,
900 const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
901 ExceptionInfo *exception)
903 if (image->storage_class == PseudoClass)
910 if (packet_size == 1)
911 SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
913 SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
915 color=image->colormap+(ssize_t) ConstrainColormapIndex(image,
916 GetPixelIndex(image,q),exception);
917 if ((type == 0) && (channels > 1))
920 color->alpha=(MagickRealType) pixel;
921 SetPixelViaPixelInfo(image,color,q);
928 SetPixelAlpha(image,pixel,q);
934 SetPixelRed(image,pixel,q);
939 SetPixelGreen(image,pixel,q);
944 SetPixelBlue(image,pixel,q);
949 if (image->colorspace == CMYKColorspace)
950 SetPixelBlack(image,pixel,q);
952 if (image->alpha_trait != UndefinedPixelTrait)
953 SetPixelAlpha(image,pixel,q);
958 if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
961 if (image->alpha_trait != UndefinedPixelTrait)
962 SetPixelAlpha(image,pixel,q);
968 static MagickBooleanType ReadPSDChannelPixels(Image *image,
969 const size_t channels,const size_t row,const ssize_t type,
970 const unsigned char *pixels,ExceptionInfo *exception)
975 register const unsigned char
991 q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
992 if (q == (Quantum *) NULL)
994 packet_size=GetPSDPacketSize(image);
995 for (x=0; x < (ssize_t) image->columns; x++)
997 if (packet_size == 1)
998 pixel=ScaleCharToQuantum(*p++);
1001 p=PushShortPixel(MSBEndian,p,&nibble);
1002 pixel=ScaleShortToQuantum(nibble);
1004 if (image->depth > 1)
1006 SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
1007 q+=GetPixelChannels(image);
1015 number_bits=image->columns-x;
1016 if (number_bits > 8)
1018 for (bit = 0; bit < number_bits; bit++)
1020 SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
1021 & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
1022 q+=GetPixelChannels(image);
1025 if (x != (ssize_t) image->columns)
1030 return(SyncAuthenticPixels(image,exception));
1033 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
1034 const ssize_t type,ExceptionInfo *exception)
1049 if (image->debug != MagickFalse)
1050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1051 " layer data is RAW");
1053 row_size=GetPSDRowSize(image);
1054 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1055 if (pixels == (unsigned char *) NULL)
1056 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1060 for (y=0; y < (ssize_t) image->rows; y++)
1064 count=ReadBlob(image,row_size,pixels);
1065 if (count != row_size)
1068 status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
1069 if (status == MagickFalse)
1073 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1077 static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
1078 const PSDInfo *psd_info,const size_t size)
1086 sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes));
1087 if(sizes != (MagickOffsetType *) NULL)
1089 for (y=0; y < (ssize_t) size; y++)
1091 if (psd_info->version == 1)
1092 sizes[y]=(MagickOffsetType) ReadBlobShort(image);
1094 sizes[y]=(MagickOffsetType) ReadBlobLong(image);
1100 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
1101 const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception)
1118 if (image->debug != MagickFalse)
1119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1120 " layer data is RLE compressed");
1122 row_size=GetPSDRowSize(image);
1123 pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1124 if (pixels == (unsigned char *) NULL)
1125 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1129 for (y=0; y < (ssize_t) image->rows; y++)
1130 if ((MagickOffsetType) length < sizes[y])
1131 length=(size_t) sizes[y];
1133 if (length > row_size + 256) // arbitrary number
1135 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1136 ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
1139 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1140 if (compact_pixels == (unsigned char *) NULL)
1142 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1143 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1147 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
1150 for (y=0; y < (ssize_t) image->rows; y++)
1154 count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
1155 if (count != (ssize_t) sizes[y])
1158 count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
1159 (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1160 if (count != (ssize_t) row_size)
1163 status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1165 if (status == MagickFalse)
1169 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1170 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1174 #ifdef MAGICKCORE_ZLIB_DELEGATE
1175 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1176 const ssize_t type,const PSDCompressionType compression,
1177 const size_t compact_size,ExceptionInfo *exception)
1182 register unsigned char
1201 if (image->debug != MagickFalse)
1202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1203 " layer data is ZIP compressed");
1205 compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1206 sizeof(*compact_pixels));
1207 if (compact_pixels == (unsigned char *) NULL)
1208 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1211 packet_size=GetPSDPacketSize(image);
1212 row_size=image->columns*packet_size;
1213 count=image->rows*row_size;
1215 pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1216 if (pixels == (unsigned char *) NULL)
1218 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1219 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1222 if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
1224 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1225 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1229 ResetMagickMemory(&stream,0,sizeof(stream));
1230 stream.data_type=Z_BINARY;
1231 stream.next_in=(Bytef *)compact_pixels;
1232 stream.avail_in=(uInt) compact_size;
1233 stream.next_out=(Bytef *)pixels;
1234 stream.avail_out=(uInt) count;
1236 if (inflateInit(&stream) == Z_OK)
1241 while (stream.avail_out > 0)
1243 ret=inflate(&stream,Z_SYNC_FLUSH);
1244 if ((ret != Z_OK) && (ret != Z_STREAM_END))
1246 (void) inflateEnd(&stream);
1247 compact_pixels=(unsigned char *) RelinquishMagickMemory(
1249 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1250 return(MagickFalse);
1253 (void) inflateEnd(&stream);
1256 if (compression == ZipWithPrediction)
1261 length=image->columns;
1264 if (packet_size == 2)
1266 p[2]+=p[0]+((p[1]+p[3]) >> 8);
1280 for (y=0; y < (ssize_t) image->rows; y++)
1282 status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1283 if (status == MagickFalse)
1289 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1290 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1295 static MagickBooleanType ReadPSDChannel(Image *image,
1296 const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
1297 const size_t channel,const PSDCompressionType compression,
1298 ExceptionInfo *exception)
1310 channel_image=image;
1311 mask=(Image *) NULL;
1312 if ((layer_info->channel_info[channel].type < -1) &&
1313 (layer_info->mask.page.width > 0) && (layer_info->mask.page.height > 0))
1319 Ignore mask that is not a user supplied layer mask, if the mask is
1320 disabled or if the flags have unsupported values.
1322 option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1323 if ((layer_info->channel_info[channel].type != -2) ||
1324 (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
1325 (IsStringTrue(option) == MagickFalse)))
1327 SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1330 mask=CloneImage(image,layer_info->mask.page.width,
1331 layer_info->mask.page.height,MagickFalse,exception);
1332 if (mask != (Image *) NULL)
1334 SetImageType(mask,GrayscaleType,exception);
1339 offset=TellBlob(image);
1344 status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1345 layer_info->channel_info[channel].type,exception);
1352 sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
1353 if (sizes == (MagickOffsetType *) NULL)
1354 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1356 status=ReadPSDChannelRLE(channel_image,psd_info,
1357 layer_info->channel_info[channel].type,sizes,exception);
1358 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1361 case ZipWithPrediction:
1362 case ZipWithoutPrediction:
1363 #ifdef MAGICKCORE_ZLIB_DELEGATE
1364 status=ReadPSDChannelZip(channel_image,layer_info->channels,
1365 layer_info->channel_info[channel].type,compression,
1366 layer_info->channel_info[channel].size-2,exception);
1368 (void) ThrowMagickException(exception,GetMagickModule(),
1369 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1370 "'%s' (ZLIB)",image->filename);
1374 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1375 "CompressionNotSupported","'%.20g'",(double) compression);
1379 SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1380 if (status == MagickFalse)
1382 if (mask != (Image *) NULL)
1384 ThrowBinaryException(CoderError,"UnableToDecompressImage",
1387 layer_info->mask.image=mask;
1391 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1392 const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1395 message[MagickPathExtent];
1406 if (image->debug != MagickFalse)
1407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1408 " setting up new layer image");
1409 if (psd_info->mode != IndexedMode)
1410 (void) SetImageBackgroundColor(layer_info->image,exception);
1411 layer_info->image->compose=PSDBlendModeToCompositeOperator(
1412 layer_info->blendkey);
1413 if (layer_info->visible == MagickFalse)
1414 layer_info->image->compose=NoCompositeOp;
1415 if (psd_info->mode == CMYKMode)
1416 SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1417 else if ((psd_info->mode == BitmapMode) || (psd_info->mode == DuotoneMode) ||
1418 (psd_info->mode == GrayscaleMode))
1419 SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1421 Set up some hidden attributes for folks that need them.
1423 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1424 (double) layer_info->page.x);
1425 (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1426 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1427 (double) layer_info->page.y);
1428 (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1429 (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1430 layer_info->opacity);
1431 (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1432 (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1436 for (j=0; j < (ssize_t) layer_info->channels; j++)
1438 if (image->debug != MagickFalse)
1439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1440 " reading data for channel %.20g",(double) j);
1442 compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1443 layer_info->image->compression=ConvertPSDCompression(compression);
1444 if (layer_info->channel_info[j].type == -1)
1445 layer_info->image->alpha_trait=BlendPixelTrait;
1447 status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
1448 compression,exception);
1450 if (status == MagickFalse)
1454 if (status != MagickFalse)
1455 status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1456 MagickFalse,exception);
1458 if ((status != MagickFalse) &&
1459 (layer_info->image->colorspace == CMYKColorspace))
1460 status=NegateCMYK(layer_info->image,exception);
1462 if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1467 layer_info->mask.image->page.x=layer_info->mask.page.x;
1468 layer_info->mask.image->page.y=layer_info->mask.page.y;
1469 /* Do not composite the mask when it is disabled */
1470 if ((layer_info->mask.flags & 0x02) == 0x02)
1471 layer_info->mask.image->compose=NoCompositeOp;
1473 status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1474 layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1476 option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1477 if (IsStringTrue(option) != MagickFalse)
1478 PreservePSDOpacityMask(image,layer_info,exception);
1479 layer_info->mask.image=DestroyImage(layer_info->mask.image);
1485 static MagickBooleanType ReadPSDLayersInternal(Image *image,
1486 const ImageInfo *image_info,const PSDInfo *psd_info,
1487 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1509 size=GetPSDSize(psd_info,image);
1513 Skip layers & masks.
1515 (void) ReadBlobLong(image);
1516 count=ReadBlob(image,4,(unsigned char *) type);
1517 ReversePSDString(image,type,4);
1519 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1523 count=ReadBlob(image,4,(unsigned char *) type);
1524 ReversePSDString(image,type,4);
1525 if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1526 size=GetPSDSize(psd_info,image);
1534 layer_info=(LayerInfo *) NULL;
1535 number_layers=(short) ReadBlobShort(image);
1537 if (number_layers < 0)
1540 The first alpha channel in the merged result contains the
1541 transparency data for the merged result.
1543 number_layers=MagickAbsoluteValue(number_layers);
1544 if (image->debug != MagickFalse)
1545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1546 " negative layer count corrected for");
1547 image->alpha_trait=BlendPixelTrait;
1551 We only need to know if the image has an alpha channel
1553 if (skip_layers != MagickFalse)
1556 if (image->debug != MagickFalse)
1557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1558 " image contains %.20g layers",(double) number_layers);
1560 if (number_layers == 0)
1561 ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1564 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1565 sizeof(*layer_info));
1566 if (layer_info == (LayerInfo *) NULL)
1568 if (image->debug != MagickFalse)
1569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1570 " allocation of LayerInfo failed");
1571 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1574 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1575 sizeof(*layer_info));
1577 for (i=0; i < number_layers; i++)
1583 if (image->debug != MagickFalse)
1584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1585 " reading layer #%.20g",(double) i+1);
1586 layer_info[i].page.y=ReadBlobSignedLong(image);
1587 layer_info[i].page.x=ReadBlobSignedLong(image);
1588 y=ReadBlobSignedLong(image);
1589 x=ReadBlobSignedLong(image);
1590 layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1591 layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1592 layer_info[i].channels=ReadBlobShort(image);
1593 if (layer_info[i].channels > MaxPSDChannels)
1595 layer_info=DestroyLayerInfo(layer_info,number_layers);
1596 ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1599 if (image->debug != MagickFalse)
1600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1601 " offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1602 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1603 (double) layer_info[i].page.height,(double)
1604 layer_info[i].page.width,(double) layer_info[i].channels);
1605 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1607 layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1608 layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1610 if (image->debug != MagickFalse)
1611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1612 " channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1613 (double) layer_info[i].channel_info[j].type,
1614 (double) layer_info[i].channel_info[j].size);
1616 count=ReadBlob(image,4,(unsigned char *) type);
1617 ReversePSDString(image,type,4);
1618 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1620 if (image->debug != MagickFalse)
1621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1622 " layer type was %.4s instead of 8BIM", type);
1623 layer_info=DestroyLayerInfo(layer_info,number_layers);
1624 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1627 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1628 ReversePSDString(image,layer_info[i].blendkey,4);
1629 layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1630 ReadBlobByte(image));
1631 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1632 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1633 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1634 if (image->debug != MagickFalse)
1635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1636 " blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1637 layer_info[i].blendkey,(double) layer_info[i].opacity,
1638 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1639 layer_info[i].visible ? "true" : "false");
1640 (void) ReadBlobByte(image); /* filler */
1642 size=ReadBlobLong(image);
1649 if (image->debug != MagickFalse)
1650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1651 " layer contains additional info");
1652 length=ReadBlobLong(image);
1653 combined_length=length+4;
1659 layer_info[i].mask.page.y=ReadBlobSignedLong(image);
1660 layer_info[i].mask.page.x=ReadBlobSignedLong(image);
1661 layer_info[i].mask.page.height=(size_t) (ReadBlobSignedLong(image)-
1662 layer_info[i].mask.page.y);
1663 layer_info[i].mask.page.width=(size_t) (ReadBlobSignedLong(image)-
1664 layer_info[i].mask.page.x);
1665 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1667 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1668 if (!(layer_info[i].mask.flags & 0x01))
1670 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1671 layer_info[i].page.y;
1672 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1673 layer_info[i].page.x;
1675 if (image->debug != MagickFalse)
1676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1677 " layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1678 (double) layer_info[i].mask.page.x,(double)
1679 layer_info[i].mask.page.y,(double)
1680 layer_info[i].mask.page.width,(double)
1681 layer_info[i].mask.page.height,(double) ((MagickOffsetType)
1684 Skip over the rest of the layer mask information.
1686 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1688 layer_info=DestroyLayerInfo(layer_info,number_layers);
1689 ThrowBinaryException(CorruptImageError,
1690 "UnexpectedEndOfFile",image->filename);
1693 length=ReadBlobLong(image);
1694 combined_length+=length+4;
1698 Layer blending ranges info.
1700 if (image->debug != MagickFalse)
1701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1702 " layer blending ranges: length=%.20g",(double)
1703 ((MagickOffsetType) length));
1704 if (DiscardBlobBytes(image,length) == MagickFalse)
1706 layer_info=DestroyLayerInfo(layer_info,number_layers);
1707 ThrowBinaryException(CorruptImageError,
1708 "UnexpectedEndOfFile",image->filename);
1714 length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
1715 combined_length+=length+1;
1717 (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1718 layer_info[i].name[length]='\0';
1719 if (image->debug != MagickFalse)
1720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1721 " layer name: %s",layer_info[i].name);
1722 if ((length % 4) != 0)
1724 length=4-(length % 4);
1725 combined_length+=length;
1726 /* Skip over the padding of the layer name */
1727 if (DiscardBlobBytes(image,length) == MagickFalse)
1729 layer_info=DestroyLayerInfo(layer_info,number_layers);
1730 ThrowBinaryException(CorruptImageError,
1731 "UnexpectedEndOfFile",image->filename);
1734 length=(MagickSizeType) size-combined_length;
1740 if (length > GetBlobSize(image))
1742 layer_info=DestroyLayerInfo(layer_info,number_layers);
1743 ThrowBinaryException(CorruptImageError,
1744 "InsufficientImageDataInFile",image->filename);
1746 layer_info[i].info=AcquireStringInfo((const size_t) length);
1747 info=GetStringInfoDatum(layer_info[i].info);
1748 (void) ReadBlob(image,(const size_t) length,info);
1753 for (i=0; i < number_layers; i++)
1755 if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0))
1757 if (image->debug != MagickFalse)
1758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1759 " layer data is empty");
1760 if (layer_info[i].info != (StringInfo *) NULL)
1761 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1766 Allocate layered image.
1768 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1769 layer_info[i].page.height,MagickFalse,exception);
1770 if (layer_info[i].image == (Image *) NULL)
1772 layer_info=DestroyLayerInfo(layer_info,number_layers);
1773 if (image->debug != MagickFalse)
1774 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1775 " allocation of image for layer %.20g failed",(double) i);
1776 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1780 if (layer_info[i].info != (StringInfo *) NULL)
1782 (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
1783 layer_info[i].info,exception);
1784 layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1788 if (image_info->ping == MagickFalse)
1790 for (i=0; i < number_layers; i++)
1792 if (layer_info[i].image == (Image *) NULL)
1794 for (j=0; j < layer_info[i].channels; j++)
1796 if (DiscardBlobBytes(image,(MagickSizeType)
1797 layer_info[i].channel_info[j].size) == MagickFalse)
1799 layer_info=DestroyLayerInfo(layer_info,number_layers);
1800 ThrowBinaryException(CorruptImageError,
1801 "UnexpectedEndOfFile",image->filename);
1807 if (image->debug != MagickFalse)
1808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1809 " reading data for layer %.20g",(double) i);
1811 status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
1813 if (status == MagickFalse)
1816 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1818 if (status == MagickFalse)
1823 if (status != MagickFalse)
1825 for (i=0; i < number_layers; i++)
1827 if (layer_info[i].image == (Image *) NULL)
1829 for (j=i; j < number_layers - 1; j++)
1830 layer_info[j] = layer_info[j+1];
1836 if (number_layers > 0)
1838 for (i=0; i < number_layers; i++)
1841 layer_info[i].image->previous=layer_info[i-1].image;
1842 if (i < (number_layers-1))
1843 layer_info[i].image->next=layer_info[i+1].image;
1844 layer_info[i].image->page=layer_info[i].page;
1846 image->next=layer_info[0].image;
1847 layer_info[0].image->previous=image;
1849 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1852 layer_info=DestroyLayerInfo(layer_info,number_layers);
1858 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1859 const ImageInfo *image_info,const PSDInfo *psd_info,
1860 const MagickBooleanType skip_layers,ExceptionInfo *exception)
1868 domain=CoderPolicyDomain;
1869 rights=ReadPolicyRights;
1870 if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
1871 return(MagickFalse);
1872 return(ReadPSDLayersInternal(image,image_info,psd_info,skip_layers,
1876 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1877 Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1891 compression=(PSDCompressionType) ReadBlobMSBShort(image);
1892 image->compression=ConvertPSDCompression(compression);
1894 if (compression != Raw && compression != RLE)
1896 (void) ThrowMagickException(exception,GetMagickModule(),
1897 TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1898 return(MagickFalse);
1901 sizes=(MagickOffsetType *) NULL;
1902 if (compression == RLE)
1904 sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
1905 if (sizes == (MagickOffsetType *) NULL)
1906 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1911 for (i=0; i < (ssize_t) psd_info->channels; i++)
1913 if (compression == RLE)
1914 status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
1917 status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1919 if (status != MagickFalse)
1920 status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1922 if (status == MagickFalse)
1926 if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1927 status=NegateCMYK(image,exception);
1929 if (status != MagickFalse)
1930 status=CorrectPSDAlphaBlend(image_info,image,exception);
1932 sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1937 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1970 assert(image_info != (const ImageInfo *) NULL);
1971 assert(image_info->signature == MagickCoreSignature);
1972 if (image_info->debug != MagickFalse)
1973 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1974 image_info->filename);
1975 assert(exception != (ExceptionInfo *) NULL);
1976 assert(exception->signature == MagickCoreSignature);
1978 image=AcquireImage(image_info,exception);
1979 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1980 if (status == MagickFalse)
1982 image=DestroyImageList(image);
1983 return((Image *) NULL);
1988 image->endian=MSBEndian;
1989 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1990 psd_info.version=ReadBlobMSBShort(image);
1991 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1992 ((psd_info.version != 1) && (psd_info.version != 2)))
1993 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1994 (void) ReadBlob(image,6,psd_info.reserved);
1995 psd_info.channels=ReadBlobMSBShort(image);
1996 if (psd_info.channels > MaxPSDChannels)
1997 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1998 psd_info.rows=ReadBlobMSBLong(image);
1999 psd_info.columns=ReadBlobMSBLong(image);
2000 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
2001 (psd_info.columns > 30000)))
2002 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2003 psd_info.depth=ReadBlobMSBShort(image);
2004 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
2005 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2006 psd_info.mode=ReadBlobMSBShort(image);
2007 if (image->debug != MagickFalse)
2008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2009 " Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
2010 (double) psd_info.columns,(double) psd_info.rows,(double)
2011 psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
2016 image->depth=psd_info.depth;
2017 image->columns=psd_info.columns;
2018 image->rows=psd_info.rows;
2019 status=SetImageExtent(image,image->columns,image->rows,exception);
2020 if (status == MagickFalse)
2021 return(DestroyImageList(image));
2022 if (SetImageBackgroundColor(image,exception) == MagickFalse)
2024 image=DestroyImageList(image);
2025 return((Image *) NULL);
2027 if (psd_info.mode == LabMode)
2028 SetImageColorspace(image,LabColorspace,exception);
2029 if (psd_info.mode == CMYKMode)
2031 SetImageColorspace(image,CMYKColorspace,exception);
2032 if (psd_info.channels > 4)
2033 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2035 else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
2036 (psd_info.mode == DuotoneMode))
2038 status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
2040 if (status == MagickFalse)
2041 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2042 if (image->debug != MagickFalse)
2043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2044 " Image colormap allocated");
2045 SetImageColorspace(image,GRAYColorspace,exception);
2046 if (psd_info.channels > 1)
2047 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2050 if (psd_info.channels > 3)
2051 SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2053 Read PSD raster colormap only present for indexed and duotone images.
2055 length=ReadBlobMSBLong(image);
2058 if (image->debug != MagickFalse)
2059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2060 " reading colormap");
2061 if (psd_info.mode == DuotoneMode)
2064 Duotone image data; the format of this data is undocumented.
2066 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
2068 if (data == (unsigned char *) NULL)
2069 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2070 (void) ReadBlob(image,(size_t) length,data);
2071 data=(unsigned char *) RelinquishMagickMemory(data);
2079 Read PSD raster colormap.
2081 number_colors=length/3;
2082 if (number_colors > 65536)
2083 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2084 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2085 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2086 for (i=0; i < (ssize_t) image->colors; i++)
2087 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
2088 ReadBlobByte(image));
2089 for (i=0; i < (ssize_t) image->colors; i++)
2090 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
2091 ReadBlobByte(image));
2092 for (i=0; i < (ssize_t) image->colors; i++)
2093 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
2094 ReadBlobByte(image));
2095 image->alpha_trait=UndefinedPixelTrait;
2098 if ((image->depth == 1) && (image->storage_class != PseudoClass))
2099 ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2100 has_merged_image=MagickTrue;
2101 length=ReadBlobMSBLong(image);
2108 Image resources block.
2110 if (image->debug != MagickFalse)
2111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2112 " reading image resource blocks - %.20g bytes",(double)
2113 ((MagickOffsetType) length));
2114 if (length > GetBlobSize(image))
2115 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2116 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2118 if (blocks == (unsigned char *) NULL)
2119 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2120 count=ReadBlob(image,(size_t) length,blocks);
2121 if ((count != (ssize_t) length) || (length < 4) ||
2122 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2124 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2125 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2127 ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
2129 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2132 Layer and mask block.
2134 length=GetPSDSize(&psd_info,image);
2137 length=ReadBlobMSBLong(image);
2138 length=ReadBlobMSBLong(image);
2140 offset=TellBlob(image);
2141 skip_layers=MagickFalse;
2142 if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2143 (has_merged_image != MagickFalse))
2145 if (image->debug != MagickFalse)
2146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2147 " read composite only");
2148 skip_layers=MagickTrue;
2152 if (image->debug != MagickFalse)
2153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2154 " image has no layers");
2158 if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,
2159 exception) != MagickTrue)
2161 (void) CloseBlob(image);
2162 image=DestroyImageList(image);
2163 return((Image *) NULL);
2167 Skip the rest of the layer and mask information.
2169 SeekBlob(image,offset+length,SEEK_SET);
2172 If we are only "pinging" the image, then we're done - so return.
2174 if (image_info->ping != MagickFalse)
2176 (void) CloseBlob(image);
2177 return(GetFirstImageInList(image));
2180 Read the precombined layer, present for PSD < 4 compatibility.
2182 if (image->debug != MagickFalse)
2183 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2184 " reading the precombined layer");
2185 if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2186 has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2187 &psd_info,exception);
2188 if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
2191 SeekBlob(image,offset,SEEK_SET);
2192 status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
2194 if (status != MagickTrue)
2196 (void) CloseBlob(image);
2197 image=DestroyImageList(image);
2198 return((Image *) NULL);
2201 if (has_merged_image == MagickFalse)
2206 if (GetImageListLength(image) == 1)
2207 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2208 SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2209 image->background_color.alpha=TransparentAlpha;
2210 image->background_color.alpha_trait=BlendPixelTrait;
2211 merged=MergeImageLayers(image,FlattenLayer,exception);
2212 ReplaceImageInList(&image,merged);
2214 (void) CloseBlob(image);
2215 return(GetFirstImageInList(image));
2219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223 % R e g i s t e r P S D I m a g e %
2227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2229 % RegisterPSDImage() adds properties for the PSD image format to
2230 % the list of supported formats. The properties include the image format
2231 % tag, a method to read and/or write the format, whether the format
2232 % supports the saving of more than one frame to the same file or blob,
2233 % whether the format supports native in-memory I/O, and a brief
2234 % description of the format.
2236 % The format of the RegisterPSDImage method is:
2238 % size_t RegisterPSDImage(void)
2241 ModuleExport size_t RegisterPSDImage(void)
2246 entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2247 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2248 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2249 entry->magick=(IsImageFormatHandler *) IsPSD;
2250 entry->flags|=CoderDecoderSeekableStreamFlag;
2251 entry->flags|=CoderEncoderSeekableStreamFlag;
2252 (void) RegisterMagickInfo(entry);
2253 entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2254 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2255 entry->encoder=(EncodeImageHandler *) WritePSDImage;
2256 entry->magick=(IsImageFormatHandler *) IsPSD;
2257 entry->flags|=CoderDecoderSeekableStreamFlag;
2258 entry->flags|=CoderEncoderSeekableStreamFlag;
2259 (void) RegisterMagickInfo(entry);
2260 return(MagickImageCoderSignature);
2264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268 % U n r e g i s t e r P S D I m a g e %
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274 % UnregisterPSDImage() removes format registrations made by the
2275 % PSD module from the list of supported formats.
2277 % The format of the UnregisterPSDImage method is:
2279 % UnregisterPSDImage(void)
2282 ModuleExport void UnregisterPSDImage(void)
2284 (void) UnregisterMagickInfo("PSB");
2285 (void) UnregisterMagickInfo("PSD");
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2293 % W r i t e P S D I m a g e %
2297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2301 % The format of the WritePSDImage method is:
2303 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2304 % ExceptionInfo *exception)
2306 % A description of each parameter follows.
2308 % o image_info: the image info.
2310 % o image: The image.
2312 % o exception: return any errors or warnings in this structure.
2316 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2317 const size_t offset)
2319 if (psd_info->version == 1)
2320 return(WriteBlobMSBShort(image,(unsigned short) offset));
2321 return(WriteBlobMSBLong(image,(unsigned short) offset));
2324 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2325 const MagickSizeType size,const MagickSizeType offset)
2333 current_offset=TellBlob(image);
2334 SeekBlob(image,offset,SEEK_SET);
2335 if (psd_info->version == 1)
2336 result=WriteBlobMSBShort(image,(unsigned short) size);
2338 result=(WriteBlobMSBLong(image,(unsigned short) size));
2339 SeekBlob(image,current_offset,SEEK_SET);
2343 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2344 const MagickSizeType size)
2346 if (psd_info->version == 1)
2347 return(WriteBlobMSBLong(image,(unsigned int) size));
2348 return(WriteBlobMSBLongLong(image,size));
2351 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2352 const MagickSizeType size,const MagickSizeType offset)
2360 current_offset=TellBlob(image);
2361 SeekBlob(image,offset,SEEK_SET);
2362 if (psd_info->version == 1)
2363 result=WriteBlobMSBLong(image,(unsigned int) size);
2365 result=WriteBlobMSBLongLong(image,size);
2366 SeekBlob(image,current_offset,SEEK_SET);
2370 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2371 const unsigned char *pixels,unsigned char *compact_pixels,
2372 ExceptionInfo *exception)
2381 register unsigned char
2388 Compress pixels with Packbits encoding.
2390 assert(image != (Image *) NULL);
2391 assert(image->signature == MagickCoreSignature);
2392 if (image->debug != MagickFalse)
2393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2394 assert(pixels != (unsigned char *) NULL);
2395 assert(compact_pixels != (unsigned char *) NULL);
2396 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2397 if (packbits == (unsigned char *) NULL)
2398 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2401 for (i=(ssize_t) length; i != 0; )
2408 *q++=(unsigned char) 0;
2415 *q++=(unsigned char) 1;
2423 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2425 *q++=(unsigned char) ((256-3)+1);
2429 *q++=(unsigned char) 2;
2437 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2443 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2450 *q++=(unsigned char) ((256-count)+1);
2459 while ((*(pixels+count) != *(pixels+count+1)) ||
2460 (*(pixels+count+1) != *(pixels+count+2)))
2462 packbits[count+1]=pixels[count];
2464 if (((ssize_t) count >= (i-3)) || (count >= 127))
2468 *packbits=(unsigned char) (count-1);
2469 for (j=0; j <= (ssize_t) count; j++)
2476 *q++=(unsigned char) 128; /* EOD marker */
2477 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2478 return((size_t) (q-compact_pixels));
2481 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
2482 const Image *next_image,const ssize_t channels)
2491 if (next_image->compression == RLECompression)
2493 length=WriteBlobMSBShort(image,RLE);
2494 for (i=0; i < channels; i++)
2495 for (y=0; y < (ssize_t) next_image->rows; y++)
2496 length+=SetPSDOffset(psd_info,image,0);
2498 #ifdef MAGICKCORE_ZLIB_DELEGATE
2499 else if (next_image->compression == ZipCompression)
2500 length=WriteBlobMSBShort(image,ZipWithoutPrediction);
2503 length=WriteBlobMSBShort(image,Raw);
2507 static size_t WritePSDChannel(const PSDInfo *psd_info,
2508 const ImageInfo *image_info,Image *image,Image *next_image,
2509 const QuantumType quantum_type, unsigned char *compact_pixels,
2510 MagickOffsetType size_offset,const MagickBooleanType separate,
2511 ExceptionInfo *exception)
2522 register const Quantum
2535 #ifdef MAGICKCORE_ZLIB_DELEGATE
2549 compressed_pixels=(unsigned char *) NULL;
2553 if (separate != MagickFalse)
2555 size_offset=TellBlob(image)+2;
2556 count+=WriteCompressionStart(psd_info,image,next_image,1);
2558 if (next_image->depth > 8)
2559 next_image->depth=16;
2560 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2561 MagickTrue : MagickFalse;
2562 quantum_info=AcquireQuantumInfo(image_info,next_image);
2563 if (quantum_info == (QuantumInfo *) NULL)
2565 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2566 #ifdef MAGICKCORE_ZLIB_DELEGATE
2567 if (next_image->compression == ZipCompression)
2569 compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
2570 sizeof(*compressed_pixels));
2571 if (compressed_pixels == (unsigned char *) NULL)
2573 quantum_info=DestroyQuantumInfo(quantum_info);
2576 ResetMagickMemory(&stream,0,sizeof(stream));
2577 stream.data_type=Z_BINARY;
2578 level=Z_DEFAULT_COMPRESSION;
2579 if ((image_info->quality > 0 && image_info->quality < 10))
2580 level=(int) image_info->quality;
2581 if (deflateInit(&stream,level) != Z_OK)
2583 quantum_info=DestroyQuantumInfo(quantum_info);
2588 for (y=0; y < (ssize_t) next_image->rows; y++)
2590 p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2591 if (p == (const Quantum *) NULL)
2593 length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2594 quantum_type,pixels,exception);
2595 if (monochrome != MagickFalse)
2596 for (i=0; i < (ssize_t) length; i++)
2597 pixels[i]=(~pixels[i]);
2598 if (next_image->compression == RLECompression)
2600 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2602 count+=WriteBlob(image,length,compact_pixels);
2603 size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
2605 #ifdef MAGICKCORE_ZLIB_DELEGATE
2606 else if (next_image->compression == ZipCompression)
2608 stream.avail_in=(uInt) length;
2609 stream.next_in=(Bytef *) pixels;
2610 if (y == (ssize_t) next_image->rows-1)
2613 stream.avail_out=(uInt) CHUNK;
2614 stream.next_out=(Bytef *) compressed_pixels;
2615 if (deflate(&stream,flush) == Z_STREAM_ERROR)
2617 length=(size_t) CHUNK-stream.avail_out;
2619 count+=WriteBlob(image,length,compressed_pixels);
2620 } while (stream.avail_out == 0);
2624 count+=WriteBlob(image,length,pixels);
2626 #ifdef MAGICKCORE_ZLIB_DELEGATE
2627 if (next_image->compression == ZipCompression)
2629 (void) deflateEnd(&stream);
2630 compressed_pixels=(unsigned char *) RelinquishMagickMemory(
2634 quantum_info=DestroyQuantumInfo(quantum_info);
2638 static unsigned char *AcquireCompactPixels(const Image *image,
2639 ExceptionInfo *exception)
2647 packet_size=image->depth > 8UL ? 2UL : 1UL;
2648 compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
2649 image->columns)+1,packet_size*sizeof(*compact_pixels));
2650 if (compact_pixels == (unsigned char *) NULL)
2652 (void) ThrowMagickException(exception,GetMagickModule(),
2653 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2655 return(compact_pixels);
2658 static size_t WritePSDChannels(const PSDInfo *psd_info,
2659 const ImageInfo *image_info,Image *image,Image *next_image,
2660 MagickOffsetType size_offset,const MagickBooleanType separate,
2661 ExceptionInfo *exception)
2681 compact_pixels=(unsigned char *) NULL;
2682 if (next_image->compression == RLECompression)
2684 compact_pixels=AcquireCompactPixels(next_image,exception);
2685 if (compact_pixels == (unsigned char *) NULL)
2689 if (separate == MagickFalse)
2691 if (next_image->storage_class != PseudoClass)
2693 if (IsImageGray(next_image) == MagickFalse)
2694 channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
2695 if (next_image->alpha_trait != UndefinedPixelTrait)
2698 rows_offset=TellBlob(image)+2;
2699 count+=WriteCompressionStart(psd_info,image,next_image,channels);
2700 offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
2703 if (next_image->storage_class == PseudoClass)
2705 length=WritePSDChannel(psd_info,image_info,image,next_image,
2706 IndexQuantum,compact_pixels,rows_offset,separate,exception);
2707 if (separate != MagickFalse)
2708 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2710 rows_offset+=offset_length;
2715 if (IsImageGray(next_image) != MagickFalse)
2717 length=WritePSDChannel(psd_info,image_info,image,next_image,
2718 GrayQuantum,compact_pixels,rows_offset,separate,exception);
2719 if (separate != MagickFalse)
2720 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2722 rows_offset+=offset_length;
2727 if (next_image->colorspace == CMYKColorspace)
2728 (void) NegateCMYK(next_image,exception);
2730 length=WritePSDChannel(psd_info,image_info,image,next_image,
2731 RedQuantum,compact_pixels,rows_offset,separate,exception);
2732 if (separate != MagickFalse)
2733 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2735 rows_offset+=offset_length;
2738 length=WritePSDChannel(psd_info,image_info,image,next_image,
2739 GreenQuantum,compact_pixels,rows_offset,separate,exception);
2740 if (separate != MagickFalse)
2741 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2743 rows_offset+=offset_length;
2746 length=WritePSDChannel(psd_info,image_info,image,next_image,
2747 BlueQuantum,compact_pixels,rows_offset,separate,exception);
2748 if (separate != MagickFalse)
2749 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2751 rows_offset+=offset_length;
2754 if (next_image->colorspace == CMYKColorspace)
2756 length=WritePSDChannel(psd_info,image_info,image,next_image,
2757 BlackQuantum,compact_pixels,rows_offset,separate,exception);
2758 if (separate != MagickFalse)
2759 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2761 rows_offset+=offset_length;
2765 if (next_image->alpha_trait != UndefinedPixelTrait)
2767 length=WritePSDChannel(psd_info,image_info,image,next_image,
2768 AlphaQuantum,compact_pixels,rows_offset,separate,exception);
2769 if (separate != MagickFalse)
2770 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2772 rows_offset+=offset_length;
2776 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2777 if (next_image->colorspace == CMYKColorspace)
2778 (void) NegateCMYK(next_image,exception);
2779 if (separate != MagickFalse)
2784 property=GetImageArtifact(next_image,"psd:opacity-mask");
2785 if (property != (const char *) NULL)
2787 mask=(Image *) GetImageRegistry(ImageRegistryType,property,
2789 if (mask != (Image *) NULL)
2791 if (mask->compression == RLECompression)
2793 compact_pixels=AcquireCompactPixels(mask,exception);
2794 if (compact_pixels == (unsigned char *) NULL)
2797 length=WritePSDChannel(psd_info,image_info,image,mask,
2798 RedQuantum,compact_pixels,rows_offset,MagickTrue,exception);
2799 (void) WritePSDSize(psd_info,image,length,size_offset);
2801 compact_pixels=(unsigned char *) RelinquishMagickMemory(
2809 static size_t WritePascalString(Image *image,const char *value,size_t padding)
2822 length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
2824 count+=WriteBlobByte(image,0);
2827 count+=WriteBlobByte(image,(unsigned char) length);
2828 count+=WriteBlob(image,length,(const unsigned char *) value);
2831 if ((length % padding) == 0)
2833 for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
2834 count+=WriteBlobByte(image,0);
2838 static void WriteResolutionResourceBlock(Image *image)
2847 if (image->units == PixelsPerCentimeterResolution)
2849 x_resolution=2.54*65536.0*image->resolution.x+0.5;
2850 y_resolution=2.54*65536.0*image->resolution.y+0.5;
2855 x_resolution=65536.0*image->resolution.x+0.5;
2856 y_resolution=65536.0*image->resolution.y+0.5;
2859 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2860 (void) WriteBlobMSBShort(image,0x03ED);
2861 (void) WriteBlobMSBShort(image,0);
2862 (void) WriteBlobMSBLong(image,16); /* resource size */
2863 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2864 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2865 (void) WriteBlobMSBShort(image,units); /* width unit */
2866 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2867 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2868 (void) WriteBlobMSBShort(image,units); /* height unit */
2871 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
2872 const signed short channel)
2877 count=WriteBlobMSBSignedShort(image,channel);
2878 count+=SetPSDSize(psd_info,image,0);
2882 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2884 register const unsigned char
2901 length=GetStringInfoLength(bim_profile);
2904 datum=GetStringInfoDatum(bim_profile);
2905 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2907 register unsigned char
2910 q=(unsigned char *) p;
2911 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2913 p=PushLongPixel(MSBEndian,p,&long_sans);
2914 p=PushShortPixel(MSBEndian,p,&id);
2915 p=PushShortPixel(MSBEndian,p,&short_sans);
2916 p=PushLongPixel(MSBEndian,p,&count);
2917 if (id == 0x0000040f)
2922 quantum=PSDQuantum(count)+12;
2923 if ((quantum >= 12) && (quantum < (ssize_t) length))
2925 if ((q+quantum < (datum+length-16)))
2926 (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
2927 SetStringInfoLength(bim_profile,length-quantum);
2932 if ((count & 0x01) != 0)
2937 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2939 register const unsigned char
2956 length=GetStringInfoLength(bim_profile);
2959 datum=GetStringInfoDatum(bim_profile);
2960 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2962 register unsigned char
2968 q=(unsigned char *) p;
2969 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2971 p=PushLongPixel(MSBEndian,p,&long_sans);
2972 p=PushShortPixel(MSBEndian,p,&id);
2973 p=PushShortPixel(MSBEndian,p,&short_sans);
2974 p=PushLongPixel(MSBEndian,p,&count);
2975 cnt=PSDQuantum(count);
2978 if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
2980 (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
2981 SetStringInfoLength(bim_profile,length-(cnt+12));
2985 if ((count & 0x01) != 0)
2990 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
2991 Image *image,ExceptionInfo *exception)
2993 #define PSDKeySize 5
2994 #define PSDAllowedLength 36
2999 /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
3001 allowed[PSDAllowedLength][PSDKeySize] = {
3002 "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
3003 "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
3004 "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
3005 "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
3031 info=GetImageProfile(image,"psd:additional-info");
3032 if (info == (const StringInfo *) NULL)
3033 return((const StringInfo *) NULL);
3034 option=GetImageOption(image_info,"psd:additional-info");
3035 if (LocaleCompare(option,"all") == 0)
3037 if (LocaleCompare(option,"selective") != 0)
3039 profile=RemoveImageProfile(image,"psd:additional-info");
3040 return(DestroyStringInfo(profile));
3042 length=GetStringInfoLength(info);
3043 p=GetStringInfoDatum(info);
3044 remaining_length=length;
3046 while (remaining_length >= 12)
3048 /* skip over signature */
3055 size=(unsigned int) (*p++) << 24;
3056 size|=(unsigned int) (*p++) << 16;
3057 size|=(unsigned int) (*p++) << 8;
3058 size|=(unsigned int) (*p++);
3059 size=size & 0xffffffff;
3060 remaining_length-=12;
3061 if ((size_t) size > remaining_length)
3062 return((const StringInfo *) NULL);
3064 for (i=0; i < PSDAllowedLength; i++)
3066 if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3072 remaining_length-=(size_t) size;
3073 if (found == MagickFalse)
3075 if (remaining_length > 0)
3076 p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
3079 length+=(size_t) size+12;
3082 profile=RemoveImageProfile(image,"psd:additional-info");
3084 return(DestroyStringInfo(profile));
3085 SetStringInfoLength(profile,(const size_t) length);
3086 SetImageProfile(image,"psd:additional-info",info,exception);
3090 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3091 Image *image,ExceptionInfo *exception)
3094 layer_name[MagickPathExtent];
3111 *layer_size_offsets,
3136 assert(image_info != (const ImageInfo *) NULL);
3137 assert(image_info->signature == MagickCoreSignature);
3138 assert(image != (Image *) NULL);
3139 assert(image->signature == MagickCoreSignature);
3140 if (image->debug != MagickFalse)
3141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3142 assert(exception != (ExceptionInfo *) NULL);
3143 assert(exception->signature == MagickCoreSignature);
3144 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3145 if (status == MagickFalse)
3147 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
3148 if (image->alpha_trait != UndefinedPixelTrait)
3149 packet_size+=image->depth > 8 ? 2 : 1;
3151 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3152 (image->columns > 30000) || (image->rows > 30000))
3154 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3155 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
3156 for (i=1; i <= 6; i++)
3157 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
3158 /* When the image has a color profile it won't be converted to gray scale */
3159 if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
3160 (SetImageGray(image,exception) != MagickFalse))
3161 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3163 if ((image_info->type != TrueColorType) && (image_info->type !=
3164 TrueColorAlphaType) && (image->storage_class == PseudoClass))
3165 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3168 if (image->storage_class == PseudoClass)
3169 (void) SetImageStorageClass(image,DirectClass,exception);
3170 if (image->colorspace != CMYKColorspace)
3171 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3173 num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3175 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3176 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3177 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3178 if (IsImageGray(image) != MagickFalse)
3186 monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3187 MagickTrue : MagickFalse;
3188 (void) WriteBlobMSBShort(image,(unsigned short)
3189 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3190 (void) WriteBlobMSBShort(image,(unsigned short)
3191 (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3195 (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3196 PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3198 if (((image_info->colorspace != UndefinedColorspace) ||
3199 (image->colorspace != CMYKColorspace)) &&
3200 (image_info->colorspace != CMYKColorspace))
3202 (void) TransformImageColorspace(image,sRGBColorspace,exception);
3203 (void) WriteBlobMSBShort(image,(unsigned short)
3204 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3208 if (image->colorspace != CMYKColorspace)
3209 (void) TransformImageColorspace(image,CMYKColorspace,exception);
3210 (void) WriteBlobMSBShort(image,CMYKMode);
3213 if ((IsImageGray(image) != MagickFalse) ||
3214 (image->storage_class == DirectClass) || (image->colors > 256))
3215 (void) WriteBlobMSBLong(image,0);
3219 Write PSD raster colormap.
3221 (void) WriteBlobMSBLong(image,768);
3222 for (i=0; i < (ssize_t) image->colors; i++)
3223 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
3224 for ( ; i < 256; i++)
3225 (void) WriteBlobByte(image,0);
3226 for (i=0; i < (ssize_t) image->colors; i++)
3227 (void) WriteBlobByte(image,ScaleQuantumToChar(
3228 image->colormap[i].green));
3229 for ( ; i < 256; i++)
3230 (void) WriteBlobByte(image,0);
3231 for (i=0; i < (ssize_t) image->colors; i++)
3232 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
3233 for ( ; i < 256; i++)
3234 (void) WriteBlobByte(image,0);
3237 Image resource block.
3239 length=28; /* 0x03EB */
3240 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
3241 icc_profile=GetImageProfile(image,"icc");
3242 if (bim_profile != (StringInfo *) NULL)
3244 bim_profile=CloneStringInfo(bim_profile);
3245 if (icc_profile != (StringInfo *) NULL)
3246 RemoveICCProfileFromResourceBlock(bim_profile);
3247 RemoveResolutionFromResourceBlock(bim_profile);
3248 length+=PSDQuantum(GetStringInfoLength(bim_profile));
3250 if (icc_profile != (const StringInfo *) NULL)
3251 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
3252 (void) WriteBlobMSBLong(image,(unsigned int) length);
3253 WriteResolutionResourceBlock(image);
3254 if (bim_profile != (StringInfo *) NULL)
3256 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
3257 GetStringInfoDatum(bim_profile));
3258 bim_profile=DestroyStringInfo(bim_profile);
3260 if (icc_profile != (StringInfo *) NULL)
3262 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3263 (void) WriteBlobMSBShort(image,0x0000040F);
3264 (void) WriteBlobMSBShort(image,0);
3265 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
3267 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
3268 GetStringInfoDatum(icc_profile));
3269 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
3270 PSDQuantum(GetStringInfoLength(icc_profile)))
3271 (void) WriteBlobByte(image,0);
3273 base_image=GetNextImageInList(image);
3274 if (base_image == (Image *) NULL)
3277 size_offset=TellBlob(image);
3278 SetPSDSize(&psd_info,image,0);
3279 SetPSDSize(&psd_info,image,0);
3281 for (next_image=base_image; next_image != NULL; )
3284 next_image=GetNextImageInList(next_image);
3286 if (image->alpha_trait != UndefinedPixelTrait)
3287 size+=WriteBlobMSBShort(image,-(unsigned short) layer_count);
3289 size+=WriteBlobMSBShort(image,(unsigned short) layer_count);
3290 layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3291 (size_t) layer_count,sizeof(MagickOffsetType));
3292 if (layer_size_offsets == (MagickOffsetType *) NULL)
3293 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3295 for (next_image=base_image; next_image != NULL; )
3307 mask=(Image *) NULL;
3308 property=GetImageArtifact(next_image,"psd:opacity-mask");
3310 if (property != (const char *) NULL)
3312 mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3313 default_color=strlen(property) == 9 ? 255 : 0;
3315 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
3316 size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
3317 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
3319 size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
3320 next_image->columns));
3322 if ((next_image->storage_class != PseudoClass) &&
3323 (IsImageGray(next_image) == MagickFalse))
3324 channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
3325 total_channels=channels;
3326 if (next_image->alpha_trait != UndefinedPixelTrait)
3328 if (mask != (Image *) NULL)
3330 size+=WriteBlobMSBShort(image,total_channels);
3331 layer_size_offsets[layer_index++]=TellBlob(image);
3332 for (i=0; i < (ssize_t) channels; i++)
3333 size+=WriteChannelSize(&psd_info,image,(signed short) i);
3334 if (next_image->alpha_trait != UndefinedPixelTrait)
3335 size+=WriteChannelSize(&psd_info,image,-1);
3336 if (mask != (Image *) NULL)
3337 size+=WriteChannelSize(&psd_info,image,-2);
3338 size+=WriteBlob(image,4,(const unsigned char *) "8BIM");
3339 size+=WriteBlob(image,4,(const unsigned char *)
3340 CompositeOperatorToPSDBlendMode(next_image->compose));
3341 property=GetImageArtifact(next_image,"psd:layer.opacity");
3342 if (property != (const char *) NULL)
3347 opacity=(Quantum) StringToInteger(property);
3348 size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
3349 (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3352 size+=WriteBlobByte(image,255);
3353 size+=WriteBlobByte(image,0);
3354 size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
3355 1 << 0x02 : 1); /* layer properties - visible, etc. */
3356 size+=WriteBlobByte(image,0);
3357 info=GetAdditionalInformation(image_info,next_image,exception);
3358 property=(const char *) GetImageProperty(next_image,"label",exception);
3359 if (property == (const char *) NULL)
3361 (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3362 (double) layer_index);
3363 property=layer_name;
3365 name_length=strlen(property)+1;
3366 if ((name_length % 4) != 0)
3367 name_length+=(4-(name_length % 4));
3368 if (info != (const StringInfo *) NULL)
3369 name_length+=GetStringInfoLength(info);
3371 if (mask != (Image *) NULL)
3373 size+=WriteBlobMSBLong(image,(unsigned int) name_length);
3374 if (mask == (Image *) NULL)
3375 size+=WriteBlobMSBLong(image,0);
3378 if (mask->compose != NoCompositeOp)
3379 (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3380 default_color),MagickTrue,exception);
3381 mask->page.y+=image->page.y;
3382 mask->page.x+=image->page.x;
3383 size+=WriteBlobMSBLong(image,20);
3384 size+=WriteBlobMSBSignedLong(image,mask->page.y);
3385 size+=WriteBlobMSBSignedLong(image,mask->page.x);
3386 size+=WriteBlobMSBSignedLong(image,(const signed int) mask->rows+
3388 size+=WriteBlobMSBSignedLong(image,(const signed int) mask->columns+
3390 size+=WriteBlobByte(image,default_color);
3391 size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
3392 size+=WriteBlobMSBShort(image,0);
3394 size+=WriteBlobMSBLong(image,0);
3395 size+=WritePascalString(image,property,4);
3396 if (info != (const StringInfo *) NULL)
3397 size+=WriteBlob(image,GetStringInfoLength(info),
3398 GetStringInfoDatum(info));
3399 next_image=GetNextImageInList(next_image);
3404 next_image=base_image;
3406 while (next_image != NULL)
3408 length=WritePSDChannels(&psd_info,image_info,image,next_image,
3409 layer_size_offsets[layer_index++],MagickTrue,exception);
3416 next_image=GetNextImageInList(next_image);
3418 (void) WriteBlobMSBLong(image,0); /* user mask data */
3420 Write the total size
3422 size_offset+=WritePSDSize(&psd_info,image,size+
3423 (psd_info.version == 1 ? 8 : 16),size_offset);
3424 if ((size/2) != ((size+1)/2))
3425 rounded_size=size+1;
3428 (void) WritePSDSize(&psd_info,image,rounded_size,size_offset);
3429 layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3430 layer_size_offsets);
3432 Remove the opacity mask from the registry
3434 next_image=base_image;
3435 while (next_image != (Image *) NULL)
3437 property=GetImageArtifact(next_image,"psd:opacity-mask");
3438 if (property != (const char *) NULL)
3439 DeleteImageRegistry(property);
3440 next_image=GetNextImageInList(next_image);
3443 Write composite image.
3445 if (status != MagickFalse)
3450 compression=image->compression;
3451 if (image->compression == ZipCompression)
3452 image->compression=RLECompression;
3453 if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
3456 image->compression=compression;
3458 (void) CloseBlob(image);