1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   SSSSS  DDDD                               %
7 %                            P   P  SS     D   D                              %
8 %                            PPPP    SSS   D   D                              %
9 %                            P         SS  D   D                              %
10 %                            P      SSSSS  DDDD                               %
11 %                                                                             %
12 %                                                                             %
13 %                   Read/Write Adobe Photoshop Image Format                   %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                              Leonard Rosenthol                              %
18 %                                 July 1992                                   %
19 %                                Dirk Lemstra                                 %
20 %                                December 2013                                %
21 %                                                                             %
22 %                                                                             %
23 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
24 %  dedicated to making software imaging solutions freely available.           %
25 %                                                                             %
26 %  You may not use this file except in compliance with the License.  You may  %
27 %  obtain a copy of the License at                                            %
28 %                                                                             %
29 %    https://imagemagick.org/script/license.php                               %
30 %                                                                             %
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.                                             %
36 %                                                                             %
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 %
39 % Photoshop spec @ https://www.adobe.com/devnet-apps/photoshop/fileformatashtml
40 %
41 */
42 
43 /*
44   Include declarations.
45 */
46 #include "MagickCore/studio.h"
47 #include "MagickCore/artifact.h"
48 #include "MagickCore/attribute.h"
49 #include "MagickCore/blob.h"
50 #include "MagickCore/blob-private.h"
51 #include "MagickCore/cache.h"
52 #include "MagickCore/channel.h"
53 #include "MagickCore/colormap.h"
54 #include "MagickCore/colormap-private.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/enhance.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/option.h"
70 #include "MagickCore/pixel.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/policy.h"
73 #include "MagickCore/profile.h"
74 #include "MagickCore/property.h"
75 #include "MagickCore/registry.h"
76 #include "MagickCore/quantum-private.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/thread-private.h"
81 #ifdef MAGICKCORE_ZLIB_DELEGATE
82 #include <zlib.h>
83 #endif
84 #include "psd-private.h"
85 
86 /*
87   Define declaractions.
88 */
89 #define MaxPSDChannels  56
90 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
91 
92 /*
93   Enumerated declaractions.
94 */
95 typedef enum
96 {
97   Raw = 0,
98   RLE = 1,
99   ZipWithoutPrediction = 2,
100   ZipWithPrediction = 3
101 } PSDCompressionType;
102 
103 typedef enum
104 {
105   BitmapMode = 0,
106   GrayscaleMode = 1,
107   IndexedMode = 2,
108   RGBMode = 3,
109   CMYKMode = 4,
110   MultichannelMode = 7,
111   DuotoneMode = 8,
112   LabMode = 9
113 } PSDImageType;
114 
115 /*
116   Typedef declaractions.
117 */
118 typedef struct _ChannelInfo
119 {
120   short
121     type;
122 
123   size_t
124     size;
125 } ChannelInfo;
126 
127 typedef struct _MaskInfo
128 {
129   Image
130     *image;
131 
132   RectangleInfo
133     page;
134 
135   unsigned char
136     background,
137     flags;
138 } MaskInfo;
139 
140 typedef struct _LayerInfo
141 {
142   ChannelInfo
143     channel_info[MaxPSDChannels];
144 
145   char
146     blendkey[4];
147 
148   Image
149     *image;
150 
151   MaskInfo
152     mask;
153 
154   Quantum
155     opacity;
156 
157   RectangleInfo
158     page;
159 
160   size_t
161     offset_x,
162     offset_y;
163 
164   unsigned char
165     clipping,
166     flags,
167     name[257],
168     visible;
169 
170   unsigned short
171     channels;
172 
173   StringInfo
174     *info;
175 } LayerInfo;
176 
177 /*
178   Forward declarations.
179 */
180 static MagickBooleanType
181   WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
182 
183 /*
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 %                                                                             %
186 %                                                                             %
187 %                                                                             %
188 %   I s P S D                                                                 %
189 %                                                                             %
190 %                                                                             %
191 %                                                                             %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 %
194 %  IsPSD()() returns MagickTrue if the image format type, identified by the
195 %  magick string, is PSD.
196 %
197 %  The format of the IsPSD method is:
198 %
199 %      MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
200 %
201 %  A description of each parameter follows:
202 %
203 %    o magick: compare image format pattern against these bytes.
204 %
205 %    o length: Specifies the length of the magick string.
206 %
207 */
IsPSD(const unsigned char * magick,const size_t length)208 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
209 {
210   if (length < 4)
211     return(MagickFalse);
212   if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
213     return(MagickTrue);
214   return(MagickFalse);
215 }
216 
217 /*
218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 %                                                                             %
220 %                                                                             %
221 %                                                                             %
222 %   R e a d P S D I m a g e                                                   %
223 %                                                                             %
224 %                                                                             %
225 %                                                                             %
226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 %
228 %  ReadPSDImage() reads an Adobe Photoshop image file and returns it.  It
229 %  allocates the memory necessary for the new Image structure and returns a
230 %  pointer to the new image.
231 %
232 %  The format of the ReadPSDImage method is:
233 %
234 %      Image *ReadPSDImage(image_info,ExceptionInfo *exception)
235 %
236 %  A description of each parameter follows:
237 %
238 %    o image_info: the image info.
239 %
240 %    o exception: return any errors or warnings in this structure.
241 %
242 */
243 
CompositeOperatorToPSDBlendMode(Image * image)244 static const char *CompositeOperatorToPSDBlendMode(Image *image)
245 {
246   switch (image->compose)
247   {
248     case ColorBurnCompositeOp:
249       return(image->endian == LSBEndian ? "vidi" : "idiv");
250     case ColorDodgeCompositeOp:
251       return(image->endian == LSBEndian ? " vid" : "div ");
252     case ColorizeCompositeOp:
253       return(image->endian == LSBEndian ? "rloc" : "colr");
254     case DarkenCompositeOp:
255       return(image->endian == LSBEndian ? "krad" : "dark");
256     case DifferenceCompositeOp:
257       return(image->endian == LSBEndian ? "ffid" : "diff");
258     case DissolveCompositeOp:
259       return(image->endian == LSBEndian ? "ssid" : "diss");
260     case ExclusionCompositeOp:
261       return(image->endian == LSBEndian ? "dums" : "smud");
262     case HardLightCompositeOp:
263       return(image->endian == LSBEndian ? "tiLh" : "hLit");
264     case HardMixCompositeOp:
265       return(image->endian == LSBEndian ? "xiMh" : "hMix");
266     case HueCompositeOp:
267       return(image->endian == LSBEndian ? " euh" : "hue ");
268     case LightenCompositeOp:
269       return(image->endian == LSBEndian ? "etil" : "lite");
270     case LinearBurnCompositeOp:
271       return(image->endian == LSBEndian ? "nrbl" : "lbrn");
272     case LinearDodgeCompositeOp:
273       return(image->endian == LSBEndian ? "gddl" : "lddg");
274     case LinearLightCompositeOp:
275       return(image->endian == LSBEndian ? "tiLl" : "lLit");
276     case LuminizeCompositeOp:
277       return(image->endian == LSBEndian ? " mul" : "lum ");
278     case MultiplyCompositeOp:
279       return(image->endian == LSBEndian ? " lum" : "mul ");
280     case OverlayCompositeOp:
281       return(image->endian == LSBEndian ? "revo" : "over");
282     case PinLightCompositeOp:
283       return(image->endian == LSBEndian ? "tiLp" : "pLit");
284     case SaturateCompositeOp:
285       return(image->endian == LSBEndian ? " tas" : "sat ");
286     case ScreenCompositeOp:
287       return(image->endian == LSBEndian ? "nrcs" : "scrn");
288     case SoftLightCompositeOp:
289       return(image->endian == LSBEndian ? "tiLs" : "sLit");
290     case VividLightCompositeOp:
291       return(image->endian == LSBEndian ? "tiLv" : "vLit");
292     case OverCompositeOp:
293     default:
294       return(image->endian == LSBEndian ? "mron" : "norm");
295   }
296 }
297 
298 /*
299   For some reason Photoshop seems to blend semi-transparent pixels with white.
300   This method reverts the blending. This can be disabled by setting the
301   option 'psd:alpha-unblend' to off.
302 */
CorrectPSDAlphaBlend(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)303 static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
304   Image *image,ExceptionInfo* exception)
305 {
306   const char
307     *option;
308 
309   MagickBooleanType
310     status;
311 
312   ssize_t
313     y;
314 
315   if ((image->alpha_trait != BlendPixelTrait) ||
316       (image->colorspace != sRGBColorspace))
317     return(MagickTrue);
318   option=GetImageOption(image_info,"psd:alpha-unblend");
319   if (IsStringFalse(option) != MagickFalse)
320     return(MagickTrue);
321   status=MagickTrue;
322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
323 #pragma omp parallel for schedule(static) shared(status) \
324   magick_number_threads(image,image,image->rows,1)
325 #endif
326   for (y=0; y < (ssize_t) image->rows; y++)
327   {
328     Quantum
329       *magick_restrict q;
330 
331     ssize_t
332       x;
333 
334     if (status == MagickFalse)
335       continue;
336     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
337     if (q == (Quantum *) NULL)
338       {
339         status=MagickFalse;
340         continue;
341       }
342     for (x=0; x < (ssize_t) image->columns; x++)
343     {
344       double
345         gamma;
346 
347       ssize_t
348         i;
349 
350       gamma=QuantumScale*GetPixelAlpha(image, q);
351       if (gamma != 0.0 && gamma != 1.0)
352         {
353           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
354           {
355             PixelChannel channel = GetPixelChannelChannel(image,i);
356             if (channel != AlphaPixelChannel)
357               q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
358           }
359         }
360       q+=GetPixelChannels(image);
361     }
362     if (SyncAuthenticPixels(image,exception) == MagickFalse)
363       status=MagickFalse;
364   }
365 
366   return(status);
367 }
368 
ConvertPSDCompression(PSDCompressionType compression)369 static inline CompressionType ConvertPSDCompression(
370   PSDCompressionType compression)
371 {
372   switch (compression)
373   {
374     case RLE:
375       return RLECompression;
376     case ZipWithPrediction:
377     case ZipWithoutPrediction:
378       return ZipCompression;
379     default:
380       return NoCompression;
381   }
382 }
383 
ApplyPSDLayerOpacity(Image * image,Quantum opacity,MagickBooleanType revert,ExceptionInfo * exception)384 static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
385   MagickBooleanType revert,ExceptionInfo *exception)
386 {
387   MagickBooleanType
388     status;
389 
390   ssize_t
391     y;
392 
393   if (image->debug != MagickFalse)
394     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
395       "  applying layer opacity %.20g", (double) opacity);
396   if (opacity == OpaqueAlpha)
397     return(MagickTrue);
398   if (image->alpha_trait != BlendPixelTrait)
399     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
400   status=MagickTrue;
401 #if defined(MAGICKCORE_OPENMP_SUPPORT)
402 #pragma omp parallel for schedule(static) shared(status) \
403   magick_number_threads(image,image,image->rows,1)
404 #endif
405   for (y=0; y < (ssize_t) image->rows; y++)
406   {
407     Quantum
408       *magick_restrict q;
409 
410     ssize_t
411       x;
412 
413     if (status == MagickFalse)
414       continue;
415     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
416     if (q == (Quantum *) NULL)
417       {
418         status=MagickFalse;
419         continue;
420       }
421     for (x=0; x < (ssize_t) image->columns; x++)
422     {
423       if (revert == MagickFalse)
424         SetPixelAlpha(image,(Quantum) (QuantumScale*(GetPixelAlpha(image,q))*
425           opacity),q);
426       else if (opacity > 0)
427         SetPixelAlpha(image,(Quantum) (QuantumRange*(GetPixelAlpha(image,q)/
428           (MagickRealType) opacity)),q);
429       q+=GetPixelChannels(image);
430     }
431     if (SyncAuthenticPixels(image,exception) == MagickFalse)
432       status=MagickFalse;
433   }
434 
435   return(status);
436 }
437 
ApplyPSDOpacityMask(Image * image,const Image * mask,Quantum background,MagickBooleanType revert,ExceptionInfo * exception)438 static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
439   Quantum background,MagickBooleanType revert,ExceptionInfo *exception)
440 {
441   Image
442     *complete_mask;
443 
444   MagickBooleanType
445     status;
446 
447   PixelInfo
448     color;
449 
450   ssize_t
451     y;
452 
453   if (image->alpha_trait == UndefinedPixelTrait)
454     return(MagickTrue);
455   if (image->debug != MagickFalse)
456     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
457       "  applying opacity mask");
458   complete_mask=CloneImage(image,0,0,MagickTrue,exception);
459   if (complete_mask == (Image *) NULL)
460     return(MagickFalse);
461   complete_mask->alpha_trait=BlendPixelTrait;
462   GetPixelInfo(complete_mask,&color);
463   color.red=(MagickRealType) background;
464   (void) SetImageColor(complete_mask,&color,exception);
465   status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
466     mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
467   if (status == MagickFalse)
468     {
469       complete_mask=DestroyImage(complete_mask);
470       return(status);
471     }
472 
473 #if defined(MAGICKCORE_OPENMP_SUPPORT)
474 #pragma omp parallel for schedule(static) shared(status) \
475   magick_number_threads(image,image,image->rows,1)
476 #endif
477   for (y=0; y < (ssize_t) image->rows; y++)
478   {
479     Quantum
480       *magick_restrict q;
481 
482     Quantum
483       *p;
484 
485     ssize_t
486       x;
487 
488     if (status == MagickFalse)
489       continue;
490     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
491     p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception);
492     if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL))
493       {
494         status=MagickFalse;
495         continue;
496       }
497     for (x=0; x < (ssize_t) image->columns; x++)
498     {
499       MagickRealType
500         alpha,
501         intensity;
502 
503       alpha=(MagickRealType) GetPixelAlpha(image,q);
504       intensity=GetPixelIntensity(complete_mask,p);
505       if (revert == MagickFalse)
506         SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
507       else if (intensity > 0)
508         SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*QuantumRange),q);
509       q+=GetPixelChannels(image);
510       p+=GetPixelChannels(complete_mask);
511     }
512     if (SyncAuthenticPixels(image,exception) == MagickFalse)
513       status=MagickFalse;
514   }
515   complete_mask=DestroyImage(complete_mask);
516   return(status);
517 }
518 
PreservePSDOpacityMask(Image * image,LayerInfo * layer_info,ExceptionInfo * exception)519 static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info,
520   ExceptionInfo *exception)
521 {
522   char
523     *key;
524 
525   RandomInfo
526     *random_info;
527 
528   StringInfo
529     *key_info;
530 
531   if (image->debug != MagickFalse)
532     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
533       "  preserving opacity mask");
534   random_info=AcquireRandomInfo();
535   key_info=GetRandomKey(random_info,2+1);
536   key=(char *) GetStringInfoDatum(key_info);
537   key[8]=(char) layer_info->mask.background;
538   key[9]='\0';
539   layer_info->mask.image->page.x+=layer_info->page.x;
540   layer_info->mask.image->page.y+=layer_info->page.y;
541   (void) SetImageRegistry(ImageRegistryType,(const char *) key,
542     layer_info->mask.image,exception);
543   (void) SetImageArtifact(layer_info->image,"psd:opacity-mask",
544     (const char *) key);
545   key_info=DestroyStringInfo(key_info);
546   random_info=DestroyRandomInfo(random_info);
547 }
548 
DecodePSDPixels(const size_t number_compact_pixels,const unsigned char * compact_pixels,const ssize_t depth,const size_t number_pixels,unsigned char * pixels)549 static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
550   const unsigned char *compact_pixels,const ssize_t depth,
551   const size_t number_pixels,unsigned char *pixels)
552 {
553 #define CheckNumberCompactPixels \
554   if (packets == 0) \
555     return(i); \
556   packets--
557 
558 #define CheckNumberPixels(count) \
559   if (((ssize_t) i + count) > (ssize_t) number_pixels) \
560     return(i); \
561   i+=count
562 
563   int
564     pixel;
565 
566   ssize_t
567     i,
568     j;
569 
570   size_t
571     length;
572 
573   ssize_t
574     packets;
575 
576   packets=(ssize_t) number_compact_pixels;
577   for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
578   {
579     packets--;
580     length=(size_t) (*compact_pixels++);
581     if (length == 128)
582       continue;
583     if (length > 128)
584       {
585         length=256-length+1;
586         CheckNumberCompactPixels;
587         pixel=(*compact_pixels++);
588         for (j=0; j < (ssize_t) length; j++)
589         {
590           switch (depth)
591           {
592             case 1:
593             {
594               CheckNumberPixels(8);
595               *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
596               *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
597               *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
598               *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
599               *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
600               *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
601               *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
602               *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
603               break;
604             }
605             case 2:
606             {
607               CheckNumberPixels(4);
608               *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
609               *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
610               *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
611               *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
612               break;
613             }
614             case 4:
615             {
616               CheckNumberPixels(2);
617               *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
618               *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
619               break;
620             }
621             default:
622             {
623               CheckNumberPixels(1);
624               *pixels++=(unsigned char) pixel;
625               break;
626             }
627           }
628         }
629         continue;
630       }
631     length++;
632     for (j=0; j < (ssize_t) length; j++)
633     {
634       CheckNumberCompactPixels;
635       switch (depth)
636       {
637         case 1:
638         {
639           CheckNumberPixels(8);
640           *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
641           *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
642           *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
643           *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
644           *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
645           *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
646           *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
647           *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
648           break;
649         }
650         case 2:
651         {
652           CheckNumberPixels(4);
653           *pixels++=(*compact_pixels >> 6) & 0x03;
654           *pixels++=(*compact_pixels >> 4) & 0x03;
655           *pixels++=(*compact_pixels >> 2) & 0x03;
656           *pixels++=(*compact_pixels & 0x03) & 0x03;
657           break;
658         }
659         case 4:
660         {
661           CheckNumberPixels(2);
662           *pixels++=(*compact_pixels >> 4) & 0xff;
663           *pixels++=(*compact_pixels & 0x0f) & 0xff;
664           break;
665         }
666         default:
667         {
668           CheckNumberPixels(1);
669           *pixels++=(*compact_pixels);
670           break;
671         }
672       }
673       compact_pixels++;
674     }
675   }
676   return(i);
677 }
678 
DestroyLayerInfo(LayerInfo * layer_info,const ssize_t number_layers)679 static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
680   const ssize_t number_layers)
681 {
682   ssize_t
683     i;
684 
685   for (i=0; i<number_layers; i++)
686   {
687     if (layer_info[i].image != (Image *) NULL)
688       layer_info[i].image=DestroyImage(layer_info[i].image);
689     if (layer_info[i].mask.image != (Image *) NULL)
690       layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
691     if (layer_info[i].info != (StringInfo *) NULL)
692       layer_info[i].info=DestroyStringInfo(layer_info[i].info);
693   }
694 
695   return (LayerInfo *) RelinquishMagickMemory(layer_info);
696 }
697 
GetPSDPacketSize(const Image * image)698 static inline size_t GetPSDPacketSize(const Image *image)
699 {
700   if (image->storage_class == PseudoClass)
701     {
702       if (image->colors > 256)
703         return(2);
704     }
705   if (image->depth > 16)
706     return(4);
707   if (image->depth > 8)
708     return(2);
709 
710   return(1);
711 }
712 
GetPSDSize(const PSDInfo * psd_info,Image * image)713 static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
714 {
715   if (psd_info->version == 1)
716     return((MagickSizeType) ReadBlobLong(image));
717   return((MagickSizeType) ReadBlobLongLong(image));
718 }
719 
GetPSDRowSize(Image * image)720 static inline size_t GetPSDRowSize(Image *image)
721 {
722   if (image->depth == 1)
723     return(((image->columns+7)/8)*GetPSDPacketSize(image));
724   else
725     return(image->columns*GetPSDPacketSize(image));
726 }
727 
ModeToString(PSDImageType type)728 static const char *ModeToString(PSDImageType type)
729 {
730   switch (type)
731   {
732     case BitmapMode: return "Bitmap";
733     case GrayscaleMode: return "Grayscale";
734     case IndexedMode: return "Indexed";
735     case RGBMode: return "RGB";
736     case CMYKMode:  return "CMYK";
737     case MultichannelMode: return "Multichannel";
738     case DuotoneMode: return "Duotone";
739     case LabMode: return "L*A*B";
740     default: return "unknown";
741   }
742 }
743 
NegateCMYK(Image * image,ExceptionInfo * exception)744 static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
745 {
746   ChannelType
747     channel_mask;
748 
749   MagickBooleanType
750     status;
751 
752   channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
753     AlphaChannel));
754   status=NegateImage(image,MagickFalse,exception);
755   (void) SetImageChannelMask(image,channel_mask);
756   return(status);
757 }
758 
ParseImageResourceBlocks(PSDInfo * psd_info,Image * image,const unsigned char * blocks,size_t length)759 static StringInfo *ParseImageResourceBlocks(PSDInfo *psd_info,Image *image,
760   const unsigned char *blocks,size_t length)
761 {
762   const unsigned char
763     *p;
764 
765   ssize_t
766     offset;
767 
768   StringInfo
769     *profile;
770 
771   unsigned char
772     name_length;
773 
774   unsigned int
775     count;
776 
777   unsigned short
778     id,
779     short_sans;
780 
781   if (length < 16)
782     return((StringInfo *) NULL);
783   profile=BlobToStringInfo((const unsigned char *) NULL,length);
784   SetStringInfoDatum(profile,blocks);
785   SetStringInfoName(profile,"8bim");
786   for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
787   {
788     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
789       break;
790     p+=4;
791     p=PushShortPixel(MSBEndian,p,&id);
792     p=PushCharPixel(p,&name_length);
793     if ((name_length % 2) == 0)
794       name_length++;
795     p+=name_length;
796     if (p > (blocks+length-4))
797       break;
798     p=PushLongPixel(MSBEndian,p,&count);
799     offset=(ssize_t) count;
800     if (((p+offset) < blocks) || ((p+offset) > (blocks+length)))
801       break;
802     switch (id)
803     {
804       case 0x03ed:
805       {
806         unsigned short
807           resolution;
808 
809         /*
810           Resolution info.
811         */
812         if (offset < 16)
813           break;
814         p=PushShortPixel(MSBEndian,p,&resolution);
815         image->resolution.x=(double) resolution;
816         (void) FormatImageProperty(image,"tiff:XResolution","%*g",
817           GetMagickPrecision(),image->resolution.x);
818         p=PushShortPixel(MSBEndian,p,&short_sans);
819         p=PushShortPixel(MSBEndian,p,&short_sans);
820         p=PushShortPixel(MSBEndian,p,&short_sans);
821         p=PushShortPixel(MSBEndian,p,&resolution);
822         image->resolution.y=(double) resolution;
823         (void) FormatImageProperty(image,"tiff:YResolution","%*g",
824           GetMagickPrecision(),image->resolution.y);
825         p=PushShortPixel(MSBEndian,p,&short_sans);
826         p=PushShortPixel(MSBEndian,p,&short_sans);
827         p=PushShortPixel(MSBEndian,p,&short_sans);
828         image->units=PixelsPerInchResolution;
829         break;
830       }
831       case 0x0421:
832       {
833         if ((offset > 4) && (*(p+4) == 0))
834           psd_info->has_merged_image=MagickFalse;
835         p+=offset;
836         break;
837       }
838       default:
839       {
840         p+=offset;
841         break;
842       }
843     }
844     if ((offset & 0x01) != 0)
845       p++;
846   }
847   return(profile);
848 }
849 
PSDBlendModeToCompositeOperator(const char * mode)850 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
851 {
852   if (mode == (const char *) NULL)
853     return(OverCompositeOp);
854   if (LocaleNCompare(mode,"norm",4) == 0)
855     return(OverCompositeOp);
856   if (LocaleNCompare(mode,"mul ",4) == 0)
857     return(MultiplyCompositeOp);
858   if (LocaleNCompare(mode,"diss",4) == 0)
859     return(DissolveCompositeOp);
860   if (LocaleNCompare(mode,"diff",4) == 0)
861     return(DifferenceCompositeOp);
862   if (LocaleNCompare(mode,"dark",4) == 0)
863     return(DarkenCompositeOp);
864   if (LocaleNCompare(mode,"lite",4) == 0)
865     return(LightenCompositeOp);
866   if (LocaleNCompare(mode,"hue ",4) == 0)
867     return(HueCompositeOp);
868   if (LocaleNCompare(mode,"sat ",4) == 0)
869     return(SaturateCompositeOp);
870   if (LocaleNCompare(mode,"colr",4) == 0)
871     return(ColorizeCompositeOp);
872   if (LocaleNCompare(mode,"lum ",4) == 0)
873     return(LuminizeCompositeOp);
874   if (LocaleNCompare(mode,"scrn",4) == 0)
875     return(ScreenCompositeOp);
876   if (LocaleNCompare(mode,"over",4) == 0)
877     return(OverlayCompositeOp);
878   if (LocaleNCompare(mode,"hLit",4) == 0)
879     return(HardLightCompositeOp);
880   if (LocaleNCompare(mode,"sLit",4) == 0)
881     return(SoftLightCompositeOp);
882   if (LocaleNCompare(mode,"smud",4) == 0)
883     return(ExclusionCompositeOp);
884   if (LocaleNCompare(mode,"div ",4) == 0)
885     return(ColorDodgeCompositeOp);
886   if (LocaleNCompare(mode,"idiv",4) == 0)
887     return(ColorBurnCompositeOp);
888   if (LocaleNCompare(mode,"lbrn",4) == 0)
889     return(LinearBurnCompositeOp);
890   if (LocaleNCompare(mode,"lddg",4) == 0)
891     return(LinearDodgeCompositeOp);
892   if (LocaleNCompare(mode,"lLit",4) == 0)
893     return(LinearLightCompositeOp);
894   if (LocaleNCompare(mode,"vLit",4) == 0)
895     return(VividLightCompositeOp);
896   if (LocaleNCompare(mode,"pLit",4) == 0)
897     return(PinLightCompositeOp);
898   if (LocaleNCompare(mode,"hMix",4) == 0)
899     return(HardMixCompositeOp);
900   return(OverCompositeOp);
901 }
902 
ReadPSDString(Image * image,char * p,const size_t length)903 static inline ssize_t ReadPSDString(Image *image,char *p,const size_t length)
904 {
905   ssize_t
906     count;
907 
908   count=ReadBlob(image,length,(unsigned char *) p);
909   if ((count == (ssize_t) length) && (image->endian != MSBEndian))
910     {
911       char
912         *q;
913 
914       q=p+length;
915       for(--q; p < q; ++p, --q)
916       {
917         *p = *p ^ *q,
918         *q = *p ^ *q,
919         *p = *p ^ *q;
920       }
921     }
922   return(count);
923 }
924 
SetPSDPixel(Image * image,const size_t channels,const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum * q,ExceptionInfo * exception)925 static inline void SetPSDPixel(Image *image,const size_t channels,
926   const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
927   ExceptionInfo *exception)
928 {
929   if (image->storage_class == PseudoClass)
930     {
931       PixelInfo
932         *color;
933 
934       Quantum
935         index;
936 
937       index=pixel;
938       if (packet_size == 1)
939         index=(Quantum) ScaleQuantumToChar(index);
940       index=(Quantum) ConstrainColormapIndex(image,(ssize_t) index,
941         exception);
942 
943       if (type == 0)
944         SetPixelIndex(image,index,q);
945       if ((type == 0) && (channels > 1))
946         return;
947       color=image->colormap+(ssize_t) GetPixelIndex(image,q);
948       if (type != 0)
949         color->alpha=(MagickRealType) pixel;
950       SetPixelViaPixelInfo(image,color,q);
951       return;
952     }
953   switch (type)
954   {
955     case -1:
956     {
957       SetPixelAlpha(image,pixel,q);
958       break;
959     }
960     case -2:
961     case 0:
962     {
963       SetPixelRed(image,pixel,q);
964       break;
965     }
966     case -3:
967     case 1:
968     {
969       SetPixelGreen(image,pixel,q);
970       break;
971     }
972     case -4:
973     case 2:
974     {
975       SetPixelBlue(image,pixel,q);
976       break;
977     }
978     case 3:
979     {
980       if (image->colorspace == CMYKColorspace)
981         SetPixelBlack(image,pixel,q);
982       else
983         if (image->alpha_trait != UndefinedPixelTrait)
984           SetPixelAlpha(image,pixel,q);
985       break;
986     }
987     case 4:
988     {
989       if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
990           (channels > 3))
991         break;
992       if (image->alpha_trait != UndefinedPixelTrait)
993         SetPixelAlpha(image,pixel,q);
994       break;
995     }
996   }
997 }
998 
ReadPSDChannelPixels(Image * image,const size_t channels,const ssize_t row,const ssize_t type,const unsigned char * pixels,ExceptionInfo * exception)999 static MagickBooleanType ReadPSDChannelPixels(Image *image,
1000   const size_t channels,const ssize_t row,const ssize_t type,
1001   const unsigned char *pixels,ExceptionInfo *exception)
1002 {
1003   Quantum
1004     pixel;
1005 
1006   const unsigned char
1007     *p;
1008 
1009   Quantum
1010     *q;
1011 
1012   ssize_t
1013     x;
1014 
1015   size_t
1016     packet_size;
1017 
1018   p=pixels;
1019   q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
1020   if (q == (Quantum *) NULL)
1021     return MagickFalse;
1022   packet_size=GetPSDPacketSize(image);
1023   for (x=0; x < (ssize_t) image->columns; x++)
1024   {
1025     if (packet_size == 1)
1026       pixel=ScaleCharToQuantum(*p++);
1027     else
1028       if (packet_size == 2)
1029         {
1030           unsigned short
1031             nibble;
1032 
1033           p=PushShortPixel(MSBEndian,p,&nibble);
1034           pixel=ScaleShortToQuantum(nibble);
1035         }
1036       else
1037         {
1038           MagickFloatType
1039             nibble;
1040 
1041           p=PushFloatPixel(MSBEndian,p,&nibble);
1042           pixel=ClampToQuantum((MagickRealType) (QuantumRange*nibble));
1043         }
1044     if (image->depth > 1)
1045       {
1046         SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
1047         q+=GetPixelChannels(image);
1048       }
1049     else
1050       {
1051         ssize_t
1052           bit,
1053           number_bits;
1054 
1055         number_bits=(ssize_t) image->columns-x;
1056         if (number_bits > 8)
1057           number_bits=8;
1058         for (bit = 0; bit < (ssize_t) number_bits; bit++)
1059         {
1060           SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
1061             & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
1062           q+=GetPixelChannels(image);
1063           x++;
1064         }
1065         if (x != (ssize_t) image->columns)
1066           x--;
1067         continue;
1068       }
1069   }
1070   return(SyncAuthenticPixels(image,exception));
1071 }
1072 
ReadPSDChannelRaw(Image * image,const size_t channels,const ssize_t type,ExceptionInfo * exception)1073 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
1074   const ssize_t type,ExceptionInfo *exception)
1075 {
1076   MagickBooleanType
1077     status;
1078 
1079   size_t
1080     row_size;
1081 
1082   ssize_t
1083     count,
1084     y;
1085 
1086   unsigned char
1087     *pixels;
1088 
1089   if (image->debug != MagickFalse)
1090     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1091        "      layer data is RAW");
1092 
1093   row_size=GetPSDRowSize(image);
1094   pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1095   if (pixels == (unsigned char *) NULL)
1096     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1097       image->filename);
1098   (void) memset(pixels,0,row_size*sizeof(*pixels));
1099 
1100   status=MagickTrue;
1101   for (y=0; y < (ssize_t) image->rows; y++)
1102   {
1103     status=MagickFalse;
1104 
1105     count=ReadBlob(image,row_size,pixels);
1106     if (count != (ssize_t) row_size)
1107       break;
1108 
1109     status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
1110     if (status == MagickFalse)
1111       break;
1112   }
1113 
1114   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1115   return(status);
1116 }
1117 
ReadPSDRLESizes(Image * image,const PSDInfo * psd_info,const size_t size)1118 static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
1119   const PSDInfo *psd_info,const size_t size)
1120 {
1121   MagickOffsetType
1122     *sizes;
1123 
1124   ssize_t
1125     y;
1126 
1127   sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes));
1128   if(sizes != (MagickOffsetType *) NULL)
1129     {
1130       for (y=0; y < (ssize_t) size; y++)
1131       {
1132         if (psd_info->version == 1)
1133           sizes[y]=(MagickOffsetType) ReadBlobShort(image);
1134         else
1135           sizes[y]=(MagickOffsetType) ReadBlobLong(image);
1136       }
1137     }
1138   return sizes;
1139 }
1140 
ReadPSDChannelRLE(Image * image,const PSDInfo * psd_info,const ssize_t type,MagickOffsetType * sizes,ExceptionInfo * exception)1141 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
1142   const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception)
1143 {
1144   MagickBooleanType
1145     status;
1146 
1147   size_t
1148     length,
1149     row_size;
1150 
1151   ssize_t
1152     count,
1153     y;
1154 
1155   unsigned char
1156     *compact_pixels,
1157     *pixels;
1158 
1159   if (image->debug != MagickFalse)
1160     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1161        "      layer data is RLE compressed");
1162 
1163   row_size=GetPSDRowSize(image);
1164   pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1165   if (pixels == (unsigned char *) NULL)
1166     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1167       image->filename);
1168 
1169   length=0;
1170   for (y=0; y < (ssize_t) image->rows; y++)
1171     if ((MagickOffsetType) length < sizes[y])
1172       length=(size_t) sizes[y];
1173 
1174   if (length > (row_size+2048)) /* arbitrary number */
1175     {
1176       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1177       ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
1178     }
1179 
1180   compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1181   if (compact_pixels == (unsigned char *) NULL)
1182     {
1183       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1184       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1185         image->filename);
1186     }
1187 
1188   (void) memset(compact_pixels,0,length*sizeof(*compact_pixels));
1189 
1190   status=MagickTrue;
1191   for (y=0; y < (ssize_t) image->rows; y++)
1192   {
1193     status=MagickFalse;
1194 
1195     count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
1196     if (count != (ssize_t) sizes[y])
1197       break;
1198 
1199     count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
1200       (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1201     if (count != (ssize_t) row_size)
1202       break;
1203 
1204     status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1205       exception);
1206     if (status == MagickFalse)
1207       break;
1208   }
1209 
1210   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1211   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1212   return(status);
1213 }
1214 
1215 #ifdef MAGICKCORE_ZLIB_DELEGATE
Unpredict8Bit(const Image * image,unsigned char * pixels,const size_t count,const size_t row_size)1216 static void Unpredict8Bit(const Image *image,unsigned char *pixels,
1217   const size_t count,const size_t row_size)
1218 {
1219   unsigned char
1220     *p;
1221 
1222   size_t
1223     length,
1224     remaining;
1225 
1226   p=pixels;
1227   remaining=count;
1228   while (remaining > 0)
1229   {
1230     length=image->columns;
1231     while (--length)
1232     {
1233       *(p+1)+=*p;
1234       p++;
1235     }
1236     p++;
1237     remaining-=row_size;
1238   }
1239 }
1240 
Unpredict16Bit(const Image * image,unsigned char * pixels,const size_t count,const size_t row_size)1241 static void Unpredict16Bit(const Image *image,unsigned char *pixels,
1242   const size_t count,const size_t row_size)
1243 {
1244   unsigned char
1245     *p;
1246 
1247   size_t
1248     length,
1249     remaining;
1250 
1251   p=pixels;
1252   remaining=count;
1253   while (remaining > 0)
1254   {
1255     length=image->columns;
1256     while (--length)
1257     {
1258       p[2]+=p[0]+((p[1]+p[3]) >> 8);
1259       p[3]+=p[1];
1260       p+=2;
1261     }
1262     p+=2;
1263     remaining-=row_size;
1264   }
1265 }
1266 
Unpredict32Bit(const Image * image,unsigned char * pixels,unsigned char * output_pixels,const size_t row_size)1267 static void Unpredict32Bit(const Image *image,unsigned char *pixels,
1268   unsigned char *output_pixels,const size_t row_size)
1269 {
1270   unsigned char
1271     *p,
1272     *q;
1273 
1274   ssize_t
1275     y;
1276 
1277   size_t
1278     offset1,
1279     offset2,
1280     offset3,
1281     remaining;
1282 
1283   unsigned char
1284     *start;
1285 
1286   offset1=image->columns;
1287   offset2=2*offset1;
1288   offset3=3*offset1;
1289   p=pixels;
1290   q=output_pixels;
1291   for (y=0; y < (ssize_t) image->rows; y++)
1292   {
1293     start=p;
1294     remaining=row_size;
1295     while (--remaining)
1296     {
1297       *(p+1)+=*p;
1298       p++;
1299     }
1300 
1301     p=start;
1302     remaining=image->columns;
1303     while (remaining--)
1304     {
1305       *(q++)=*p;
1306       *(q++)=*(p+offset1);
1307       *(q++)=*(p+offset2);
1308       *(q++)=*(p+offset3);
1309 
1310       p++;
1311     }
1312     p=start+row_size;
1313   }
1314 }
1315 
ReadPSDChannelZip(Image * image,const size_t channels,const ssize_t type,const PSDCompressionType compression,const size_t compact_size,ExceptionInfo * exception)1316 static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1317   const ssize_t type,const PSDCompressionType compression,
1318   const size_t compact_size,ExceptionInfo *exception)
1319 {
1320   MagickBooleanType
1321     status;
1322 
1323   unsigned char
1324     *p;
1325 
1326   size_t
1327     count,
1328     packet_size,
1329     row_size;
1330 
1331   ssize_t
1332     y;
1333 
1334   unsigned char
1335     *compact_pixels,
1336     *pixels;
1337 
1338   z_stream
1339     stream;
1340 
1341   if (image->debug != MagickFalse)
1342     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1343        "      layer data is ZIP compressed");
1344 
1345   if ((MagickSizeType) compact_size > GetBlobSize(image))
1346     ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1347       image->filename);
1348   compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1349     sizeof(*compact_pixels));
1350   if (compact_pixels == (unsigned char *) NULL)
1351     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1352       image->filename);
1353 
1354   packet_size=GetPSDPacketSize(image);
1355   row_size=image->columns*packet_size;
1356   count=image->rows*row_size;
1357 
1358   pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1359   if (pixels == (unsigned char *) NULL)
1360     {
1361       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1362       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1363         image->filename);
1364     }
1365   if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
1366     {
1367       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1368       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1369       ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1370         image->filename);
1371     }
1372 
1373   memset(&stream,0,sizeof(stream));
1374   stream.data_type=Z_BINARY;
1375   stream.next_in=(Bytef *)compact_pixels;
1376   stream.avail_in=(uInt) compact_size;
1377   stream.next_out=(Bytef *)pixels;
1378   stream.avail_out=(uInt) count;
1379 
1380   if (inflateInit(&stream) == Z_OK)
1381     {
1382       int
1383         ret;
1384 
1385       while (stream.avail_out > 0)
1386       {
1387         ret=inflate(&stream,Z_SYNC_FLUSH);
1388         if ((ret != Z_OK) && (ret != Z_STREAM_END))
1389           {
1390             (void) inflateEnd(&stream);
1391             compact_pixels=(unsigned char *) RelinquishMagickMemory(
1392               compact_pixels);
1393             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1394             return(MagickFalse);
1395           }
1396         if (ret == Z_STREAM_END)
1397           break;
1398       }
1399       (void) inflateEnd(&stream);
1400     }
1401 
1402   if (compression == ZipWithPrediction)
1403     {
1404       if (packet_size == 1)
1405         Unpredict8Bit(image,pixels,count,row_size);
1406       else if (packet_size == 2)
1407         Unpredict16Bit(image,pixels,count,row_size);
1408       else if (packet_size == 4)
1409       {
1410         unsigned char
1411           *output_pixels;
1412 
1413         output_pixels=(unsigned char *) AcquireQuantumMemory(count,
1414           sizeof(*output_pixels));
1415         if (pixels == (unsigned char *) NULL)
1416           {
1417             compact_pixels=(unsigned char *) RelinquishMagickMemory(
1418               compact_pixels);
1419             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1420             ThrowBinaryException(ResourceLimitError,
1421               "MemoryAllocationFailed",image->filename);
1422           }
1423         Unpredict32Bit(image,pixels,output_pixels,row_size);
1424         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1425         pixels=output_pixels;
1426       }
1427     }
1428 
1429   status=MagickTrue;
1430   p=pixels;
1431   for (y=0; y < (ssize_t) image->rows; y++)
1432   {
1433     status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1434     if (status == MagickFalse)
1435       break;
1436 
1437     p+=row_size;
1438   }
1439 
1440   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1441   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1442   return(status);
1443 }
1444 #endif
1445 
ReadPSDChannel(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,LayerInfo * layer_info,const size_t channel,const PSDCompressionType compression,ExceptionInfo * exception)1446 static MagickBooleanType ReadPSDChannel(Image *image,
1447   const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
1448   const size_t channel,const PSDCompressionType compression,
1449   ExceptionInfo *exception)
1450 {
1451   Image
1452     *channel_image,
1453     *mask;
1454 
1455   MagickOffsetType
1456     offset;
1457 
1458   MagickBooleanType
1459     status;
1460 
1461   channel_image=image;
1462   mask=(Image *) NULL;
1463   if ((layer_info->channel_info[channel].type < -1) &&
1464       (layer_info->mask.page.width > 0) && (layer_info->mask.page.height > 0))
1465     {
1466       const char
1467         *option;
1468 
1469       /*
1470         Ignore mask that is not a user supplied layer mask, if the mask is
1471         disabled or if the flags have unsupported values.
1472       */
1473       option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1474       if ((layer_info->channel_info[channel].type != -2) ||
1475           (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
1476            (IsStringTrue(option) == MagickFalse)))
1477         {
1478           (void) SeekBlob(image,(MagickOffsetType)
1479             layer_info->channel_info[channel].size-2,SEEK_CUR);
1480           return(MagickTrue);
1481         }
1482       mask=CloneImage(image,layer_info->mask.page.width,
1483         layer_info->mask.page.height,MagickFalse,exception);
1484       if (mask != (Image *) NULL)
1485         {
1486           (void) ResetImagePixels(mask,exception);
1487           (void) SetImageType(mask,GrayscaleType,exception);
1488           channel_image=mask;
1489         }
1490     }
1491 
1492   offset=TellBlob(image);
1493   status=MagickFalse;
1494   switch(compression)
1495   {
1496     case Raw:
1497       status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1498         (ssize_t) layer_info->channel_info[channel].type,exception);
1499       break;
1500     case RLE:
1501       {
1502         MagickOffsetType
1503           *sizes;
1504 
1505         sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
1506         if (sizes == (MagickOffsetType *) NULL)
1507           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1508             image->filename);
1509         status=ReadPSDChannelRLE(channel_image,psd_info,
1510           (ssize_t) layer_info->channel_info[channel].type,sizes,exception);
1511         sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1512       }
1513       break;
1514     case ZipWithPrediction:
1515     case ZipWithoutPrediction:
1516 #ifdef MAGICKCORE_ZLIB_DELEGATE
1517       status=ReadPSDChannelZip(channel_image,layer_info->channels,
1518         (ssize_t) layer_info->channel_info[channel].type,compression,
1519         layer_info->channel_info[channel].size-2,exception);
1520 #else
1521       (void) ThrowMagickException(exception,GetMagickModule(),
1522           MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1523             "'%s' (ZLIB)",image->filename);
1524 #endif
1525       break;
1526     default:
1527       (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1528         "CompressionNotSupported","'%.20g'",(double) compression);
1529       break;
1530   }
1531 
1532   (void) SeekBlob(image,offset+layer_info->channel_info[channel].size-2,
1533     SEEK_SET);
1534   if (status == MagickFalse)
1535     {
1536       if (mask != (Image *) NULL)
1537         (void) DestroyImage(mask);
1538       ThrowBinaryException(CoderError,"UnableToDecompressImage",
1539         image->filename);
1540     }
1541   if (mask != (Image *) NULL)
1542     {
1543       if (layer_info->mask.image != (Image *) NULL)
1544         layer_info->mask.image=DestroyImage(layer_info->mask.image);
1545       layer_info->mask.image=mask;
1546     }
1547   return(status);
1548 }
1549 
ReadPSDLayer(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,LayerInfo * layer_info,ExceptionInfo * exception)1550 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1551   const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1552 {
1553   char
1554     message[MagickPathExtent];
1555 
1556   MagickBooleanType
1557     status;
1558 
1559   PSDCompressionType
1560     compression;
1561 
1562   ssize_t
1563     j;
1564 
1565   if (image->debug != MagickFalse)
1566     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1567       "    setting up new layer image");
1568   if (psd_info->mode != IndexedMode)
1569     (void) SetImageBackgroundColor(layer_info->image,exception);
1570   layer_info->image->compose=PSDBlendModeToCompositeOperator(
1571     layer_info->blendkey);
1572   if (layer_info->visible == MagickFalse)
1573     layer_info->image->compose=NoCompositeOp;
1574   /*
1575     Set up some hidden attributes for folks that need them.
1576   */
1577   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1578     (double) layer_info->page.x);
1579   (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1580   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1581     (double) layer_info->page.y);
1582   (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1583   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1584     layer_info->opacity);
1585   (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1586   (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1587     exception);
1588 
1589   status=MagickTrue;
1590   for (j=0; j < (ssize_t) layer_info->channels; j++)
1591   {
1592     if (image->debug != MagickFalse)
1593       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1594         "    reading data for channel %.20g",(double) j);
1595 
1596     compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1597     layer_info->image->compression=ConvertPSDCompression(compression);
1598     if (layer_info->channel_info[j].type == -1)
1599       layer_info->image->alpha_trait=BlendPixelTrait;
1600 
1601     status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,
1602       (size_t) j,compression,exception);
1603 
1604     if (status == MagickFalse)
1605       break;
1606   }
1607 
1608   if (status != MagickFalse)
1609     status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1610       MagickFalse,exception);
1611 
1612   if ((status != MagickFalse) &&
1613       (layer_info->image->colorspace == CMYKColorspace))
1614     status=NegateCMYK(layer_info->image,exception);
1615 
1616   if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1617     {
1618       const char
1619         *option;
1620 
1621       layer_info->mask.image->page.x=layer_info->mask.page.x;
1622       layer_info->mask.image->page.y=layer_info->mask.page.y;
1623       /* Do not composite the mask when it is disabled */
1624       if ((layer_info->mask.flags & 0x02) == 0x02)
1625         layer_info->mask.image->compose=NoCompositeOp;
1626       else
1627         status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1628           layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1629           exception);
1630       option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1631       if (IsStringTrue(option) != MagickFalse)
1632         PreservePSDOpacityMask(image,layer_info,exception);
1633       layer_info->mask.image=DestroyImage(layer_info->mask.image);
1634     }
1635 
1636   return(status);
1637 }
1638 
CheckPSDChannels(const PSDInfo * psd_info,LayerInfo * layer_info)1639 static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
1640   LayerInfo *layer_info)
1641 {
1642   int
1643     channel_type;
1644 
1645   ssize_t
1646     i;
1647 
1648   if (layer_info->channels < psd_info->min_channels)
1649     return(MagickFalse);
1650   channel_type=RedChannel;
1651   if (psd_info->min_channels >= 3)
1652     channel_type|=(GreenChannel | BlueChannel);
1653   if (psd_info->min_channels >= 4)
1654     channel_type|=BlackChannel;
1655   for (i=0; i < (ssize_t) layer_info->channels; i++)
1656   {
1657     short
1658       type;
1659 
1660     type=layer_info->channel_info[i].type;
1661     if ((i == 0) && (psd_info->mode == IndexedMode) && (type != 0))
1662       return(MagickFalse);
1663     if (type == -1)
1664       {
1665         channel_type|=AlphaChannel;
1666         continue;
1667       }
1668     if (type < -1)
1669       continue;
1670     if (type == 0)
1671       channel_type&=~RedChannel;
1672     else if (type == 1)
1673       channel_type&=~GreenChannel;
1674     else if (type == 2)
1675       channel_type&=~BlueChannel;
1676     else if (type == 3)
1677       channel_type&=~BlackChannel;
1678   }
1679   if (channel_type == 0)
1680     return(MagickTrue);
1681   if ((channel_type == AlphaChannel) &&
1682       (layer_info->channels >= psd_info->min_channels + 1))
1683     return(MagickTrue);
1684   return(MagickFalse);
1685 }
1686 
AttachPSDLayers(Image * image,LayerInfo * layer_info,ssize_t number_layers)1687 static void AttachPSDLayers(Image *image,LayerInfo *layer_info,
1688   ssize_t number_layers)
1689 {
1690   ssize_t
1691     i;
1692 
1693   ssize_t
1694     j;
1695 
1696   for (i=0; i < number_layers; i++)
1697   {
1698     if (layer_info[i].image == (Image *) NULL)
1699       {
1700         for (j=i; j < number_layers - 1; j++)
1701           layer_info[j] = layer_info[j+1];
1702         number_layers--;
1703         i--;
1704       }
1705   }
1706   if (number_layers == 0)
1707     {
1708       layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1709       return;
1710     }
1711   for (i=0; i < number_layers; i++)
1712   {
1713     if (i > 0)
1714       layer_info[i].image->previous=layer_info[i-1].image;
1715     if (i < (number_layers-1))
1716       layer_info[i].image->next=layer_info[i+1].image;
1717     layer_info[i].image->page=layer_info[i].page;
1718   }
1719   image->next=layer_info[0].image;
1720   layer_info[0].image->previous=image;
1721   layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1722 }
1723 
PSDSkipImage(const PSDInfo * psd_info,const ImageInfo * image_info,const size_t index)1724 static inline MagickBooleanType PSDSkipImage(const PSDInfo *psd_info,
1725   const ImageInfo *image_info,const size_t index)
1726 {
1727   if (psd_info->has_merged_image == MagickFalse)
1728       return(MagickFalse);
1729   if (image_info->number_scenes == 0)
1730     return(MagickFalse);
1731   if (index < image_info->scene)
1732     return(MagickTrue);
1733   if (index > image_info->scene+image_info->number_scenes-1)
1734     return(MagickTrue);
1735   return(MagickFalse);
1736 }
1737 
CheckMergedImageAlpha(const PSDInfo * psd_info,Image * image)1738 static void CheckMergedImageAlpha(const PSDInfo *psd_info,Image *image)
1739 {
1740   /*
1741     The number of layers cannot be used to determine if the merged image
1742     contains an alpha channel. So we enable it when we think we should.
1743   */
1744   if (((psd_info->mode == GrayscaleMode) && (psd_info->channels > 1)) ||
1745       ((psd_info->mode == RGBMode) && (psd_info->channels > 3)) ||
1746       ((psd_info->mode == CMYKMode) && (psd_info->channels > 4)))
1747     image->alpha_trait=BlendPixelTrait;
1748 }
1749 
ParseAdditionalInfo(LayerInfo * layer_info)1750 static void ParseAdditionalInfo(LayerInfo *layer_info)
1751 {
1752   char
1753     key[5];
1754 
1755   size_t
1756     remaining_length;
1757 
1758   unsigned char
1759     *p;
1760 
1761   unsigned int
1762     size;
1763 
1764   p=GetStringInfoDatum(layer_info->info);
1765   remaining_length=GetStringInfoLength(layer_info->info);
1766   while (remaining_length >= 12)
1767   {
1768     /* skip over signature */
1769     p+=4;
1770     key[0]=(char) (*p++);
1771     key[1]=(char) (*p++);
1772     key[2]=(char) (*p++);
1773     key[3]=(char) (*p++);
1774     key[4]='\0';
1775     size=(unsigned int) (*p++) << 24;
1776     size|=(unsigned int) (*p++) << 16;
1777     size|=(unsigned int) (*p++) << 8;
1778     size|=(unsigned int) (*p++);
1779     size=size & 0xffffffff;
1780     remaining_length-=12;
1781     if ((size_t) size > remaining_length)
1782       break;
1783     if (LocaleNCompare(key,"luni",sizeof(key)) == 0)
1784       {
1785         unsigned char
1786           *name;
1787 
1788         unsigned int
1789           length;
1790 
1791         length=(unsigned int) (*p++) << 24;
1792         length|=(unsigned int) (*p++) << 16;
1793         length|=(unsigned int) (*p++) << 8;
1794         length|=(unsigned int) (*p++);
1795         if (length * 2 > size - 4)
1796           break;
1797         if (sizeof(layer_info->name) <= length)
1798           break;
1799         name=layer_info->name;
1800         while (length > 0)
1801         {
1802           /* Only ASCII strings are supported */
1803           if (*p++ != '\0')
1804             break;
1805           *name++=*p++;
1806           length--;
1807         }
1808         if (length == 0)
1809           *name='\0';
1810         break;
1811       }
1812     else
1813       p+=size;
1814     remaining_length-=(size_t) size;
1815   }
1816 }
1817 
GetLayerInfoSize(const PSDInfo * psd_info,Image * image)1818 static MagickSizeType GetLayerInfoSize(const PSDInfo *psd_info,Image *image)
1819 {
1820   char
1821     type[4];
1822 
1823   MagickSizeType
1824     size;
1825 
1826   ssize_t
1827     count;
1828 
1829   size=GetPSDSize(psd_info,image);
1830   if (size != 0)
1831     return(size);
1832   (void) ReadBlobLong(image);
1833   count=ReadPSDString(image,type,4);
1834   if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
1835     return(0);
1836   count=ReadPSDString(image,type,4);
1837   if ((count == 4) && ((LocaleNCompare(type,"Mt16",4) == 0) ||
1838       (LocaleNCompare(type,"Mt32",4) == 0) ||
1839       (LocaleNCompare(type,"Mtrn",4) == 0)))
1840     {
1841       size=GetPSDSize(psd_info,image);
1842       if (size != 0)
1843         return(0);
1844       image->alpha_trait=BlendPixelTrait;
1845       count=ReadPSDString(image,type,4);
1846       if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
1847         return(0);
1848       count=ReadPSDString(image,type,4);
1849     }
1850   if ((count == 4) && ((LocaleNCompare(type,"Lr16",4) == 0) ||
1851       (LocaleNCompare(type,"Lr32",4) == 0)))
1852     size=GetPSDSize(psd_info,image);
1853   return(size);
1854 }
1855 
ReadPSDLayersInternal(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,const MagickBooleanType skip_layers,ExceptionInfo * exception)1856 static MagickBooleanType ReadPSDLayersInternal(Image *image,
1857   const ImageInfo *image_info,const PSDInfo *psd_info,
1858   const MagickBooleanType skip_layers,ExceptionInfo *exception)
1859 {
1860   char
1861     type[4];
1862 
1863   LayerInfo
1864     *layer_info;
1865 
1866   MagickSizeType
1867     size;
1868 
1869   MagickBooleanType
1870     status;
1871 
1872   ssize_t
1873     i;
1874 
1875   ssize_t
1876     count,
1877     index,
1878     j,
1879     number_layers;
1880 
1881   size=GetLayerInfoSize(psd_info,image);
1882   if (size == 0)
1883     {
1884       CheckMergedImageAlpha(psd_info,image);
1885       return(MagickTrue);
1886     }
1887 
1888   layer_info=(LayerInfo *) NULL;
1889   number_layers=(ssize_t) ReadBlobSignedShort(image);
1890 
1891   if (number_layers < 0)
1892     {
1893       /*
1894         The first alpha channel in the merged result contains the
1895         transparency data for the merged result.
1896       */
1897       number_layers=MagickAbsoluteValue(number_layers);
1898       if (image->debug != MagickFalse)
1899         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1900           "  negative layer count corrected for");
1901       image->alpha_trait=BlendPixelTrait;
1902     }
1903 
1904   /*
1905     We only need to know if the image has an alpha channel
1906   */
1907   if (skip_layers != MagickFalse)
1908     return(MagickTrue);
1909 
1910   if (image->debug != MagickFalse)
1911     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1912       "  image contains %.20g layers",(double) number_layers);
1913 
1914   if (number_layers == 0)
1915     ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1916       image->filename);
1917 
1918   layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1919     sizeof(*layer_info));
1920   if (layer_info == (LayerInfo *) NULL)
1921     {
1922       if (image->debug != MagickFalse)
1923         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1924           "  allocation of LayerInfo failed");
1925       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1926         image->filename);
1927     }
1928   (void) memset(layer_info,0,(size_t) number_layers*sizeof(*layer_info));
1929 
1930   for (i=0; i < number_layers; i++)
1931   {
1932     ssize_t
1933       top,
1934       left,
1935       bottom,
1936       right;
1937 
1938     if (image->debug != MagickFalse)
1939       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1940         "  reading layer #%.20g",(double) i+1);
1941     top=(ssize_t) ReadBlobSignedLong(image);
1942     left=(ssize_t) ReadBlobSignedLong(image);
1943     bottom=(ssize_t) ReadBlobSignedLong(image);
1944     right=(ssize_t) ReadBlobSignedLong(image);
1945     if ((right < left) || (bottom < top))
1946       {
1947         layer_info=DestroyLayerInfo(layer_info,number_layers);
1948         ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1949           image->filename);
1950       }
1951     layer_info[i].page.y=top;
1952     layer_info[i].page.x=left;
1953     layer_info[i].page.width=(size_t) (right-left);
1954     layer_info[i].page.height=(size_t) (bottom-top);
1955     layer_info[i].channels=ReadBlobShort(image);
1956     if (layer_info[i].channels > MaxPSDChannels)
1957       {
1958         layer_info=DestroyLayerInfo(layer_info,number_layers);
1959         ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1960           image->filename);
1961       }
1962     if (image->debug != MagickFalse)
1963       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1964         "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1965         (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1966         (double) layer_info[i].page.height,(double)
1967         layer_info[i].page.width,(double) layer_info[i].channels);
1968     for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1969     {
1970       layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1971       if ((layer_info[i].channel_info[j].type < -4) ||
1972           (layer_info[i].channel_info[j].type > 4))
1973         {
1974           layer_info=DestroyLayerInfo(layer_info,number_layers);
1975           ThrowBinaryException(CorruptImageError,"NoSuchImageChannel",
1976             image->filename);
1977         }
1978       layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1979         image);
1980       if (image->debug != MagickFalse)
1981         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1982           "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1983           (double) layer_info[i].channel_info[j].type,
1984           (double) layer_info[i].channel_info[j].size);
1985     }
1986     if (CheckPSDChannels(psd_info,&layer_info[i]) == MagickFalse)
1987       {
1988         layer_info=DestroyLayerInfo(layer_info,number_layers);
1989         ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1990           image->filename);
1991       }
1992     count=ReadPSDString(image,type,4);
1993     if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
1994       {
1995         if (image->debug != MagickFalse)
1996           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1997             "  layer type was %.4s instead of 8BIM", type);
1998         layer_info=DestroyLayerInfo(layer_info,number_layers);
1999         ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2000           image->filename);
2001       }
2002     count=ReadPSDString(image,layer_info[i].blendkey,4);
2003     if (count != 4)
2004       {
2005         layer_info=DestroyLayerInfo(layer_info,number_layers);
2006         ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2007           image->filename);
2008       }
2009     layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
2010       ReadBlobByte(image));
2011     layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
2012     layer_info[i].flags=(unsigned char) ReadBlobByte(image);
2013     layer_info[i].visible=!(layer_info[i].flags & 0x02);
2014     if (image->debug != MagickFalse)
2015       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2016         "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
2017         layer_info[i].blendkey,(double) layer_info[i].opacity,
2018         layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
2019         layer_info[i].visible ? "true" : "false");
2020     (void) ReadBlobByte(image);  /* filler */
2021 
2022     size=ReadBlobLong(image);
2023     if (size != 0)
2024       {
2025         MagickSizeType
2026           combined_length,
2027           length;
2028 
2029         if (image->debug != MagickFalse)
2030           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2031             "    layer contains additional info");
2032         length=ReadBlobLong(image);
2033         combined_length=length+4;
2034         if (length != 0)
2035           {
2036             /*
2037               Layer mask info.
2038             */
2039             layer_info[i].mask.page.y=(ssize_t) ReadBlobSignedLong(image);
2040             layer_info[i].mask.page.x=(ssize_t) ReadBlobSignedLong(image);
2041             layer_info[i].mask.page.height=(size_t)
2042               (ReadBlobSignedLong(image)-layer_info[i].mask.page.y);
2043             layer_info[i].mask.page.width=(size_t) (
2044               ReadBlobSignedLong(image)-layer_info[i].mask.page.x);
2045             layer_info[i].mask.background=(unsigned char) ReadBlobByte(
2046               image);
2047             layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
2048             if (!(layer_info[i].mask.flags & 0x01))
2049               {
2050                 layer_info[i].mask.page.y=layer_info[i].mask.page.y-
2051                   layer_info[i].page.y;
2052                 layer_info[i].mask.page.x=layer_info[i].mask.page.x-
2053                   layer_info[i].page.x;
2054               }
2055             if (image->debug != MagickFalse)
2056               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2057                 "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
2058                 (double) layer_info[i].mask.page.x,(double)
2059                 layer_info[i].mask.page.y,(double)
2060                 layer_info[i].mask.page.width,(double)
2061                 layer_info[i].mask.page.height,(double) ((MagickOffsetType)
2062                 length)-18);
2063             /*
2064               Skip over the rest of the layer mask information.
2065             */
2066             if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
2067               {
2068                 layer_info=DestroyLayerInfo(layer_info,number_layers);
2069                 ThrowBinaryException(CorruptImageError,
2070                   "UnexpectedEndOfFile",image->filename);
2071               }
2072           }
2073         length=ReadBlobLong(image);
2074         combined_length+=length+4;
2075         if (length != 0)
2076           {
2077             /*
2078               Layer blending ranges info.
2079             */
2080             if (image->debug != MagickFalse)
2081               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082                 "      layer blending ranges: length=%.20g",(double)
2083                 ((MagickOffsetType) length));
2084             if (DiscardBlobBytes(image,length) == MagickFalse)
2085               {
2086                 layer_info=DestroyLayerInfo(layer_info,number_layers);
2087                 ThrowBinaryException(CorruptImageError,
2088                   "UnexpectedEndOfFile",image->filename);
2089               }
2090           }
2091         /*
2092           Layer name.
2093         */
2094         length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
2095         combined_length+=length+1;
2096         if (length > 0)
2097           (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
2098         layer_info[i].name[length]='\0';
2099         if (image->debug != MagickFalse)
2100           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2101             "      layer name: %s",layer_info[i].name);
2102         if ((length % 4) != 0)
2103           {
2104             length=4-(length % 4);
2105             combined_length+=length;
2106             /* Skip over the padding of the layer name */
2107             if (DiscardBlobBytes(image,length) == MagickFalse)
2108               {
2109                 layer_info=DestroyLayerInfo(layer_info,number_layers);
2110                 ThrowBinaryException(CorruptImageError,
2111                   "UnexpectedEndOfFile",image->filename);
2112               }
2113           }
2114         length=(MagickSizeType) size-combined_length;
2115         if (length > 0)
2116           {
2117             unsigned char
2118               *info;
2119 
2120             if (length > GetBlobSize(image))
2121               {
2122                 layer_info=DestroyLayerInfo(layer_info,number_layers);
2123                 ThrowBinaryException(CorruptImageError,
2124                   "InsufficientImageDataInFile",image->filename);
2125               }
2126             layer_info[i].info=AcquireStringInfo((const size_t) length);
2127             info=GetStringInfoDatum(layer_info[i].info);
2128             (void) ReadBlob(image,(const size_t) length,info);
2129             ParseAdditionalInfo(&layer_info[i]);
2130           }
2131       }
2132   }
2133 
2134   for (i=0; i < number_layers; i++)
2135   {
2136     if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0))
2137       {
2138         if (image->debug != MagickFalse)
2139           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2140             "      layer data is empty");
2141         if (layer_info[i].info != (StringInfo *) NULL)
2142           layer_info[i].info=DestroyStringInfo(layer_info[i].info);
2143         continue;
2144       }
2145 
2146     /*
2147       Allocate layered image.
2148     */
2149     layer_info[i].image=CloneImage(image,layer_info[i].page.width,
2150       layer_info[i].page.height,MagickFalse,exception);
2151     if (layer_info[i].image == (Image *) NULL)
2152       {
2153         layer_info=DestroyLayerInfo(layer_info,number_layers);
2154         if (image->debug != MagickFalse)
2155           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156             "  allocation of image for layer %.20g failed",(double) i);
2157         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2158           image->filename);
2159       }
2160     if (layer_info[i].info != (StringInfo *) NULL)
2161       {
2162         (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
2163           layer_info[i].info,exception);
2164         layer_info[i].info=DestroyStringInfo(layer_info[i].info);
2165       }
2166   }
2167   if (image_info->ping != MagickFalse)
2168     {
2169       AttachPSDLayers(image,layer_info,number_layers);
2170       return(MagickTrue);
2171     }
2172   status=MagickTrue;
2173   index=0;
2174   for (i=0; i < number_layers; i++)
2175   {
2176     if ((layer_info[i].image == (Image *) NULL) ||
2177         (PSDSkipImage(psd_info, image_info,++index) != MagickFalse))
2178       {
2179         for (j=0; j < (ssize_t) layer_info[i].channels; j++)
2180         {
2181           if (DiscardBlobBytes(image,(MagickSizeType)
2182               layer_info[i].channel_info[j].size) == MagickFalse)
2183             {
2184               layer_info=DestroyLayerInfo(layer_info,number_layers);
2185               ThrowBinaryException(CorruptImageError,
2186                 "UnexpectedEndOfFile",image->filename);
2187             }
2188         }
2189         continue;
2190       }
2191 
2192     if (image->debug != MagickFalse)
2193       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2194         "  reading data for layer %.20g",(double) i);
2195 
2196     status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
2197       exception);
2198     if (status == MagickFalse)
2199       break;
2200 
2201     status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
2202       (MagickSizeType) number_layers);
2203     if (status == MagickFalse)
2204       break;
2205   }
2206 
2207   if (status != MagickFalse)
2208     AttachPSDLayers(image,layer_info,number_layers);
2209   else
2210     layer_info=DestroyLayerInfo(layer_info,number_layers);
2211 
2212   return(status);
2213 }
2214 
ReadPSDLayers(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,ExceptionInfo * exception)2215 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
2216   const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
2217 {
2218   PolicyDomain
2219     domain;
2220 
2221   PolicyRights
2222     rights;
2223 
2224   domain=CoderPolicyDomain;
2225   rights=ReadPolicyRights;
2226   if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
2227     return(MagickTrue);
2228   return(ReadPSDLayersInternal(image,image_info,psd_info,MagickFalse,
2229     exception));
2230 }
2231 
ReadPSDMergedImage(const ImageInfo * image_info,Image * image,const PSDInfo * psd_info,ExceptionInfo * exception)2232 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
2233   Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
2234 {
2235   MagickOffsetType
2236     *sizes;
2237 
2238   MagickBooleanType
2239     status;
2240 
2241   PSDCompressionType
2242     compression;
2243 
2244   ssize_t
2245     i;
2246 
2247   if ((image_info->number_scenes != 0) && (image_info->scene != 0))
2248     return(MagickTrue);
2249   compression=(PSDCompressionType) ReadBlobMSBShort(image);
2250   image->compression=ConvertPSDCompression(compression);
2251 
2252   if (compression != Raw && compression != RLE)
2253     {
2254       (void) ThrowMagickException(exception,GetMagickModule(),
2255         TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
2256       return(MagickFalse);
2257     }
2258 
2259   sizes=(MagickOffsetType *) NULL;
2260   if (compression == RLE)
2261     {
2262       sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
2263       if (sizes == (MagickOffsetType *) NULL)
2264         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2265           image->filename);
2266     }
2267 
2268   status=MagickTrue;
2269   for (i=0; i < (ssize_t) psd_info->channels; i++)
2270   {
2271     ssize_t
2272       type;
2273 
2274     type=i;
2275     if ((type == 1) && (psd_info->channels == 2))
2276       type=-1;
2277 
2278     if (compression == RLE)
2279       status=ReadPSDChannelRLE(image,psd_info,type,sizes+(i*image->rows),
2280         exception);
2281     else
2282       status=ReadPSDChannelRaw(image,psd_info->channels,type,exception);
2283 
2284     if (status != MagickFalse)
2285       status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
2286         psd_info->channels);
2287 
2288     if (status == MagickFalse)
2289       break;
2290   }
2291 
2292   if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
2293     status=NegateCMYK(image,exception);
2294 
2295   if (status != MagickFalse)
2296     status=CorrectPSDAlphaBlend(image_info,image,exception);
2297 
2298   sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
2299 
2300   return(status);
2301 }
2302 
ReadPSDImage(const ImageInfo * image_info,ExceptionInfo * exception)2303 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
2304 {
2305   Image
2306     *image;
2307 
2308   MagickBooleanType
2309     skip_layers;
2310 
2311   MagickOffsetType
2312     offset;
2313 
2314   MagickSizeType
2315     length;
2316 
2317   MagickBooleanType
2318     status;
2319 
2320   PSDInfo
2321     psd_info;
2322 
2323   ssize_t
2324     i;
2325 
2326   size_t
2327     image_list_length;
2328 
2329   ssize_t
2330     count;
2331 
2332   StringInfo
2333     *profile;
2334 
2335   /*
2336     Open image file.
2337   */
2338   assert(image_info != (const ImageInfo *) NULL);
2339   assert(image_info->signature == MagickCoreSignature);
2340   if (image_info->debug != MagickFalse)
2341     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2342       image_info->filename);
2343   assert(exception != (ExceptionInfo *) NULL);
2344   assert(exception->signature == MagickCoreSignature);
2345 
2346   image=AcquireImage(image_info,exception);
2347   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2348   if (status == MagickFalse)
2349     {
2350       image=DestroyImageList(image);
2351       return((Image *) NULL);
2352     }
2353   /*
2354     Read image header.
2355   */
2356   image->endian=MSBEndian;
2357   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
2358   psd_info.version=ReadBlobMSBShort(image);
2359   if ((count != 4) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
2360       ((psd_info.version != 1) && (psd_info.version != 2)))
2361     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2362   (void) ReadBlob(image,6,psd_info.reserved);
2363   psd_info.channels=ReadBlobMSBShort(image);
2364   if (psd_info.channels < 1)
2365     ThrowReaderException(CorruptImageError,"MissingImageChannel");
2366   if (psd_info.channels > MaxPSDChannels)
2367     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
2368   psd_info.rows=ReadBlobMSBLong(image);
2369   psd_info.columns=ReadBlobMSBLong(image);
2370   if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
2371       (psd_info.columns > 30000)))
2372     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2373   psd_info.depth=ReadBlobMSBShort(image);
2374   if ((psd_info.depth != 1) && (psd_info.depth != 8) &&
2375       (psd_info.depth != 16) && (psd_info.depth != 32))
2376     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2377   psd_info.mode=ReadBlobMSBShort(image);
2378   if ((psd_info.mode == IndexedMode) && (psd_info.channels > 3))
2379     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2380   if (image->debug != MagickFalse)
2381     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2382       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
2383       (double) psd_info.columns,(double) psd_info.rows,(double)
2384       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
2385       psd_info.mode));
2386   if (EOFBlob(image) != MagickFalse)
2387     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2388   /*
2389     Initialize image.
2390   */
2391   image->depth=psd_info.depth;
2392   image->columns=psd_info.columns;
2393   image->rows=psd_info.rows;
2394   status=SetImageExtent(image,image->columns,image->rows,exception);
2395   if (status == MagickFalse)
2396     return(DestroyImageList(image));
2397   status=ResetImagePixels(image,exception);
2398   if (status == MagickFalse)
2399     return(DestroyImageList(image));
2400   psd_info.min_channels=3;
2401   switch (psd_info.mode)
2402   {
2403     case LabMode:
2404     {
2405       (void) SetImageColorspace(image,LabColorspace,exception);
2406       break;
2407     }
2408     case CMYKMode:
2409     {
2410       psd_info.min_channels=4;
2411       (void) SetImageColorspace(image,CMYKColorspace,exception);
2412       break;
2413     }
2414     case BitmapMode:
2415     case GrayscaleMode:
2416     case DuotoneMode:
2417     {
2418       if (psd_info.depth != 32)
2419         {
2420           status=AcquireImageColormap(image,MagickMin((size_t)
2421             (psd_info.depth < 16 ? 256 : 65536), MaxColormapSize),exception);
2422           if (status == MagickFalse)
2423             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2424           if (image->debug != MagickFalse)
2425             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2426               "  Image colormap allocated");
2427         }
2428       psd_info.min_channels=1;
2429       (void) SetImageColorspace(image,GRAYColorspace,exception);
2430       break;
2431     }
2432     case IndexedMode:
2433     {
2434       psd_info.min_channels=1;
2435       break;
2436     }
2437     case MultichannelMode:
2438     {
2439       if ((psd_info.channels > 0) && (psd_info.channels < 3))
2440         {
2441           psd_info.min_channels=psd_info.channels;
2442           (void) SetImageColorspace(image,GRAYColorspace,exception);
2443         }
2444       break;
2445     }
2446   }
2447   if (psd_info.channels < psd_info.min_channels)
2448     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2449   /*
2450     Read PSD raster colormap only present for indexed and duotone images.
2451   */
2452   length=ReadBlobMSBLong(image);
2453   if ((psd_info.mode == IndexedMode) && (length < 3))
2454     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2455   if (length != 0)
2456     {
2457       if (image->debug != MagickFalse)
2458         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459           "  reading colormap");
2460       if ((psd_info.mode == DuotoneMode) || (psd_info.depth == 32))
2461         {
2462           /*
2463             Duotone image data;  the format of this data is undocumented.
2464             32 bits per pixel;  the colormap is ignored.
2465           */
2466           (void) SeekBlob(image,(const MagickOffsetType) length,SEEK_CUR);
2467         }
2468       else
2469         {
2470           size_t
2471             number_colors;
2472 
2473           /*
2474             Read PSD raster colormap.
2475           */
2476           number_colors=(size_t) length/3;
2477           if (number_colors > 65536)
2478             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2479           if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2480             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2481           for (i=0; i < (ssize_t) image->colors; i++)
2482             image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(
2483               (unsigned char) ReadBlobByte(image));
2484           for (i=0; i < (ssize_t) image->colors; i++)
2485             image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(
2486               (unsigned char) ReadBlobByte(image));
2487           for (i=0; i < (ssize_t) image->colors; i++)
2488             image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(
2489               (unsigned char) ReadBlobByte(image));
2490           image->alpha_trait=UndefinedPixelTrait;
2491         }
2492     }
2493   if ((image->depth == 1) && (image->storage_class != PseudoClass))
2494     ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2495   psd_info.has_merged_image=MagickTrue;
2496   profile=(StringInfo *) NULL;
2497   length=ReadBlobMSBLong(image);
2498   if (length != 0)
2499     {
2500       unsigned char
2501         *blocks;
2502 
2503       /*
2504         Image resources block.
2505       */
2506       if (image->debug != MagickFalse)
2507         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2508           "  reading image resource blocks - %.20g bytes",(double)
2509           ((MagickOffsetType) length));
2510       if (length > GetBlobSize(image))
2511         ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2512       blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2513         sizeof(*blocks));
2514       if (blocks == (unsigned char *) NULL)
2515         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2516       count=ReadBlob(image,(size_t) length,blocks);
2517       if ((count != (ssize_t) length) || (length < 4) ||
2518           (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2519         {
2520           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2521           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2522         }
2523       profile=ParseImageResourceBlocks(&psd_info,image,blocks,(size_t) length);
2524       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2525     }
2526   /*
2527     Layer and mask block.
2528   */
2529   length=GetPSDSize(&psd_info,image);
2530   if (length == 8)
2531     {
2532       length=ReadBlobMSBLong(image);
2533       length=ReadBlobMSBLong(image);
2534     }
2535   offset=TellBlob(image);
2536   skip_layers=MagickFalse;
2537   if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2538       (psd_info.has_merged_image != MagickFalse))
2539     {
2540       if (image->debug != MagickFalse)
2541         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2542           "  read composite only");
2543       skip_layers=MagickTrue;
2544     }
2545   if (length == 0)
2546     {
2547       if (image->debug != MagickFalse)
2548         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549           "  image has no layers");
2550     }
2551   else
2552     {
2553       if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,
2554             exception) != MagickTrue)
2555         {
2556           if (profile != (StringInfo *) NULL)
2557             profile=DestroyStringInfo(profile);
2558           (void) CloseBlob(image);
2559           image=DestroyImageList(image);
2560           return((Image *) NULL);
2561         }
2562 
2563       /*
2564          Skip the rest of the layer and mask information.
2565       */
2566       (void) SeekBlob(image,offset+length,SEEK_SET);
2567     }
2568   /*
2569     If we are only "pinging" the image, then we're done - so return.
2570   */
2571   if (EOFBlob(image) != MagickFalse)
2572     {
2573       if (profile != (StringInfo *) NULL)
2574         profile=DestroyStringInfo(profile);
2575       ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
2576     }
2577   if (image_info->ping != MagickFalse)
2578     {
2579       if (profile != (StringInfo *) NULL)
2580         profile=DestroyStringInfo(profile);
2581       (void) CloseBlob(image);
2582       return(GetFirstImageInList(image));
2583     }
2584   /*
2585     Read the precombined layer, present for PSD < 4 compatibility.
2586   */
2587   if (image->debug != MagickFalse)
2588     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2589       "  reading the precombined layer");
2590   image_list_length=GetImageListLength(image);
2591   if ((psd_info.has_merged_image != MagickFalse) || (image_list_length == 1))
2592     psd_info.has_merged_image=(MagickBooleanType) ReadPSDMergedImage(
2593       image_info,image,&psd_info,exception);
2594   if ((psd_info.has_merged_image == MagickFalse) && (image_list_length == 1) &&
2595       (length != 0))
2596     {
2597       (void) SeekBlob(image,offset,SEEK_SET);
2598       status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
2599         exception);
2600       if (status != MagickTrue)
2601         {
2602           if (profile != (StringInfo *) NULL)
2603             profile=DestroyStringInfo(profile);
2604           (void) CloseBlob(image);
2605           image=DestroyImageList(image);
2606           return((Image *) NULL);
2607         }
2608       image_list_length=GetImageListLength(image);
2609     }
2610   if (psd_info.has_merged_image == MagickFalse)
2611     {
2612       Image
2613         *merged;
2614 
2615       if (image_list_length == 1)
2616         {
2617           if (profile != (StringInfo *) NULL)
2618             profile=DestroyStringInfo(profile);
2619           ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2620         }
2621       image->background_color.alpha=(MagickRealType) TransparentAlpha;
2622       image->background_color.alpha_trait=BlendPixelTrait;
2623       (void) SetImageBackgroundColor(image,exception);
2624       merged=MergeImageLayers(image,FlattenLayer,exception);
2625       if (merged == (Image *) NULL)
2626         {
2627           (void) CloseBlob(image);
2628           image=DestroyImageList(image);
2629           return((Image *) NULL);
2630         }
2631       ReplaceImageInList(&image,merged);
2632     }
2633   if (profile != (StringInfo *) NULL)
2634     {
2635       Image
2636         *next;
2637 
2638       i=0;
2639       next=image;
2640       while (next != (Image *) NULL)
2641       {
2642         if (PSDSkipImage(&psd_info,image_info,i++) == MagickFalse)
2643           (void) SetImageProfile(next,GetStringInfoName(profile),profile,
2644             exception);
2645         next=next->next;
2646       }
2647       profile=DestroyStringInfo(profile);
2648     }
2649   (void) CloseBlob(image);
2650   return(GetFirstImageInList(image));
2651 }
2652 
2653 /*
2654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655 %                                                                             %
2656 %                                                                             %
2657 %                                                                             %
2658 %   R e g i s t e r P S D I m a g e                                           %
2659 %                                                                             %
2660 %                                                                             %
2661 %                                                                             %
2662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663 %
2664 %  RegisterPSDImage() adds properties for the PSD image format to
2665 %  the list of supported formats.  The properties include the image format
2666 %  tag, a method to read and/or write the format, whether the format
2667 %  supports the saving of more than one frame to the same file or blob,
2668 %  whether the format supports native in-memory I/O, and a brief
2669 %  description of the format.
2670 %
2671 %  The format of the RegisterPSDImage method is:
2672 %
2673 %      size_t RegisterPSDImage(void)
2674 %
2675 */
RegisterPSDImage(void)2676 ModuleExport size_t RegisterPSDImage(void)
2677 {
2678   MagickInfo
2679     *entry;
2680 
2681   entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2682   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2683   entry->encoder=(EncodeImageHandler *) WritePSDImage;
2684   entry->magick=(IsImageFormatHandler *) IsPSD;
2685   entry->flags|=CoderDecoderSeekableStreamFlag;
2686   entry->flags|=CoderEncoderSeekableStreamFlag;
2687   (void) RegisterMagickInfo(entry);
2688   entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2689   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2690   entry->encoder=(EncodeImageHandler *) WritePSDImage;
2691   entry->magick=(IsImageFormatHandler *) IsPSD;
2692   entry->flags|=CoderDecoderSeekableStreamFlag;
2693   entry->flags|=CoderEncoderSeekableStreamFlag;
2694   (void) RegisterMagickInfo(entry);
2695   return(MagickImageCoderSignature);
2696 }
2697 
2698 /*
2699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700 %                                                                             %
2701 %                                                                             %
2702 %                                                                             %
2703 %   U n r e g i s t e r P S D I m a g e                                       %
2704 %                                                                             %
2705 %                                                                             %
2706 %                                                                             %
2707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708 %
2709 %  UnregisterPSDImage() removes format registrations made by the
2710 %  PSD module from the list of supported formats.
2711 %
2712 %  The format of the UnregisterPSDImage method is:
2713 %
2714 %      UnregisterPSDImage(void)
2715 %
2716 */
UnregisterPSDImage(void)2717 ModuleExport void UnregisterPSDImage(void)
2718 {
2719   (void) UnregisterMagickInfo("PSB");
2720   (void) UnregisterMagickInfo("PSD");
2721 }
2722 
2723 /*
2724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2725 %                                                                             %
2726 %                                                                             %
2727 %                                                                             %
2728 %   W r i t e P S D I m a g e                                                 %
2729 %                                                                             %
2730 %                                                                             %
2731 %                                                                             %
2732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2733 %
2734 %  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2735 %
2736 %  The format of the WritePSDImage method is:
2737 %
2738 %      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2739 %        ExceptionInfo *exception)
2740 %
2741 %  A description of each parameter follows.
2742 %
2743 %    o image_info: the image info.
2744 %
2745 %    o image:  The image.
2746 %
2747 %    o exception: return any errors or warnings in this structure.
2748 %
2749 */
2750 
SetPSDOffset(const PSDInfo * psd_info,Image * image,const size_t offset)2751 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2752   const size_t offset)
2753 {
2754   if (psd_info->version == 1)
2755     return(WriteBlobMSBShort(image,(unsigned short) offset));
2756   return(WriteBlobMSBLong(image,(unsigned int) offset));
2757 }
2758 
WritePSDOffset(const PSDInfo * psd_info,Image * image,const MagickSizeType size,const MagickOffsetType offset)2759 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2760   const MagickSizeType size,const MagickOffsetType offset)
2761 {
2762   MagickOffsetType
2763     current_offset;
2764 
2765   ssize_t
2766     result;
2767 
2768   current_offset=TellBlob(image);
2769   (void) SeekBlob(image,offset,SEEK_SET);
2770   if (psd_info->version == 1)
2771     result=WriteBlobMSBShort(image,(unsigned short) size);
2772   else
2773     result=WriteBlobMSBLong(image,(unsigned int) size);
2774   (void) SeekBlob(image,current_offset,SEEK_SET);
2775   return(result);
2776 }
2777 
SetPSDSize(const PSDInfo * psd_info,Image * image,const MagickSizeType size)2778 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2779   const MagickSizeType size)
2780 {
2781   if (psd_info->version == 1)
2782     return(WriteBlobLong(image,(unsigned int) size));
2783   return(WriteBlobLongLong(image,size));
2784 }
2785 
WritePSDSize(const PSDInfo * psd_info,Image * image,const MagickSizeType size,const MagickOffsetType offset)2786 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2787   const MagickSizeType size,const MagickOffsetType offset)
2788 {
2789   MagickOffsetType
2790     current_offset;
2791 
2792   ssize_t
2793     result;
2794 
2795   current_offset=TellBlob(image);
2796   (void) SeekBlob(image,offset,SEEK_SET);
2797   result=SetPSDSize(psd_info,image,size);
2798   (void) SeekBlob(image,current_offset,SEEK_SET);
2799   return(result);
2800 }
2801 
PSDPackbitsEncodeImage(Image * image,const size_t length,const unsigned char * pixels,unsigned char * compact_pixels,ExceptionInfo * exception)2802 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2803   const unsigned char *pixels,unsigned char *compact_pixels,
2804   ExceptionInfo *exception)
2805 {
2806   int
2807     count;
2808 
2809   ssize_t
2810     i,
2811     j;
2812 
2813   unsigned char
2814     *q;
2815 
2816   unsigned char
2817     *packbits;
2818 
2819   /*
2820     Compress pixels with Packbits encoding.
2821   */
2822   assert(image != (Image *) NULL);
2823   assert(image->signature == MagickCoreSignature);
2824   if (image->debug != MagickFalse)
2825     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2826   assert(pixels != (unsigned char *) NULL);
2827   assert(compact_pixels != (unsigned char *) NULL);
2828   packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2829   if (packbits == (unsigned char *) NULL)
2830     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2831       image->filename);
2832   q=compact_pixels;
2833   for (i=(ssize_t) length; i != 0; )
2834   {
2835     switch (i)
2836     {
2837       case 1:
2838       {
2839         i--;
2840         *q++=(unsigned char) 0;
2841         *q++=(*pixels);
2842         break;
2843       }
2844       case 2:
2845       {
2846         i-=2;
2847         *q++=(unsigned char) 1;
2848         *q++=(*pixels);
2849         *q++=pixels[1];
2850         break;
2851       }
2852       case 3:
2853       {
2854         i-=3;
2855         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2856           {
2857             *q++=(unsigned char) ((256-3)+1);
2858             *q++=(*pixels);
2859             break;
2860           }
2861         *q++=(unsigned char) 2;
2862         *q++=(*pixels);
2863         *q++=pixels[1];
2864         *q++=pixels[2];
2865         break;
2866       }
2867       default:
2868       {
2869         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2870           {
2871             /*
2872               Packed run.
2873             */
2874             count=3;
2875             while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2876             {
2877               count++;
2878               if (count >= 127)
2879                 break;
2880             }
2881             i-=count;
2882             *q++=(unsigned char) ((256-count)+1);
2883             *q++=(*pixels);
2884             pixels+=count;
2885             break;
2886           }
2887         /*
2888           Literal run.
2889         */
2890         count=0;
2891         while ((*(pixels+count) != *(pixels+count+1)) ||
2892                (*(pixels+count+1) != *(pixels+count+2)))
2893         {
2894           packbits[count+1]=pixels[count];
2895           count++;
2896           if (((ssize_t) count >= (i-3)) || (count >= 127))
2897             break;
2898         }
2899         i-=count;
2900         *packbits=(unsigned char) (count-1);
2901         for (j=0; j <= (ssize_t) count; j++)
2902           *q++=packbits[j];
2903         pixels+=count;
2904         break;
2905       }
2906     }
2907   }
2908   *q++=(unsigned char) 128;  /* EOD marker */
2909   packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2910   return((size_t) (q-compact_pixels));
2911 }
2912 
WriteCompressionStart(const PSDInfo * psd_info,Image * image,const Image * next_image,const CompressionType compression,const ssize_t channels)2913 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
2914   const Image *next_image,const CompressionType compression,
2915   const ssize_t channels)
2916 {
2917   size_t
2918     length;
2919 
2920   ssize_t
2921     i,
2922     y;
2923 
2924   if (compression == RLECompression)
2925     {
2926       length=(size_t) WriteBlobShort(image,RLE);
2927       for (i=0; i < channels; i++)
2928         for (y=0; y < (ssize_t) next_image->rows; y++)
2929           length+=SetPSDOffset(psd_info,image,0);
2930     }
2931 #ifdef MAGICKCORE_ZLIB_DELEGATE
2932   else if (compression == ZipCompression)
2933     length=(size_t) WriteBlobShort(image,ZipWithoutPrediction);
2934 #endif
2935   else
2936     length=(size_t) WriteBlobShort(image,Raw);
2937   return(length);
2938 }
2939 
WritePSDChannel(const PSDInfo * psd_info,const ImageInfo * image_info,Image * image,Image * next_image,const QuantumType quantum_type,unsigned char * compact_pixels,MagickOffsetType size_offset,const MagickBooleanType separate,const CompressionType compression,ExceptionInfo * exception)2940 static size_t WritePSDChannel(const PSDInfo *psd_info,
2941   const ImageInfo *image_info,Image *image,Image *next_image,
2942   const QuantumType quantum_type, unsigned char *compact_pixels,
2943   MagickOffsetType size_offset,const MagickBooleanType separate,
2944   const CompressionType compression,ExceptionInfo *exception)
2945 {
2946   MagickBooleanType
2947     monochrome;
2948 
2949   QuantumInfo
2950     *quantum_info;
2951 
2952   const Quantum
2953     *p;
2954 
2955   ssize_t
2956     i;
2957 
2958   size_t
2959     count,
2960     length;
2961 
2962   ssize_t
2963     y;
2964 
2965   unsigned char
2966     *pixels;
2967 
2968 #ifdef MAGICKCORE_ZLIB_DELEGATE
2969 
2970   int
2971     flush,
2972     level;
2973 
2974   unsigned char
2975     *compressed_pixels;
2976 
2977   z_stream
2978     stream;
2979 
2980   compressed_pixels=(unsigned char *) NULL;
2981   flush=Z_NO_FLUSH;
2982 #endif
2983   count=0;
2984   if (separate != MagickFalse)
2985     {
2986       size_offset=TellBlob(image)+2;
2987       count+=WriteCompressionStart(psd_info,image,next_image,compression,1);
2988     }
2989   if (next_image->depth > 8)
2990     next_image->depth=16;
2991   monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2992     MagickTrue : MagickFalse;
2993   quantum_info=AcquireQuantumInfo(image_info,next_image);
2994   if (quantum_info == (QuantumInfo *) NULL)
2995     return(0);
2996   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2997 #ifdef MAGICKCORE_ZLIB_DELEGATE
2998   if (compression == ZipCompression)
2999     {
3000       compressed_pixels=(unsigned char *) AcquireQuantumMemory(
3001         MagickMinBufferExtent,sizeof(*compressed_pixels));
3002       if (compressed_pixels == (unsigned char *) NULL)
3003         {
3004           quantum_info=DestroyQuantumInfo(quantum_info);
3005           return(0);
3006         }
3007       memset(&stream,0,sizeof(stream));
3008       stream.data_type=Z_BINARY;
3009       level=Z_DEFAULT_COMPRESSION;
3010       if ((image_info->quality > 0 && image_info->quality < 10))
3011         level=(int) image_info->quality;
3012       if (deflateInit(&stream,level) != Z_OK)
3013         {
3014           quantum_info=DestroyQuantumInfo(quantum_info);
3015           compressed_pixels=(unsigned char *) RelinquishMagickMemory(
3016             compressed_pixels);
3017           return(0);
3018         }
3019     }
3020 #endif
3021   for (y=0; y < (ssize_t) next_image->rows; y++)
3022   {
3023     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
3024     if (p == (const Quantum *) NULL)
3025       break;
3026     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
3027       quantum_type,pixels,exception);
3028     if (monochrome != MagickFalse)
3029       for (i=0; i < (ssize_t) length; i++)
3030         pixels[i]=(~pixels[i]);
3031     if (compression == RLECompression)
3032       {
3033         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
3034           exception);
3035         count+=WriteBlob(image,length,compact_pixels);
3036         size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
3037       }
3038 #ifdef MAGICKCORE_ZLIB_DELEGATE
3039     else if (compression == ZipCompression)
3040       {
3041         stream.avail_in=(uInt) length;
3042         stream.next_in=(Bytef *) pixels;
3043         if (y == (ssize_t) next_image->rows-1)
3044           flush=Z_FINISH;
3045         do {
3046             stream.avail_out=(uInt) MagickMinBufferExtent;
3047             stream.next_out=(Bytef *) compressed_pixels;
3048             if (deflate(&stream,flush) == Z_STREAM_ERROR)
3049               break;
3050             length=(size_t) MagickMinBufferExtent-stream.avail_out;
3051             if (length > 0)
3052               count+=WriteBlob(image,length,compressed_pixels);
3053         } while (stream.avail_out == 0);
3054       }
3055 #endif
3056     else
3057       count+=WriteBlob(image,length,pixels);
3058   }
3059 #ifdef MAGICKCORE_ZLIB_DELEGATE
3060   if (compression == ZipCompression)
3061     {
3062       (void) deflateEnd(&stream);
3063       compressed_pixels=(unsigned char *) RelinquishMagickMemory(
3064         compressed_pixels);
3065     }
3066 #endif
3067   quantum_info=DestroyQuantumInfo(quantum_info);
3068   return(count);
3069 }
3070 
AcquireCompactPixels(const Image * image,ExceptionInfo * exception)3071 static unsigned char *AcquireCompactPixels(const Image *image,
3072   ExceptionInfo *exception)
3073 {
3074   size_t
3075     packet_size;
3076 
3077   unsigned char
3078     *compact_pixels;
3079 
3080   packet_size=image->depth > 8UL ? 2UL : 1UL;
3081   compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
3082     image->columns)+1,packet_size*sizeof(*compact_pixels));
3083   if (compact_pixels == (unsigned char *) NULL)
3084     {
3085       (void) ThrowMagickException(exception,GetMagickModule(),
3086         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
3087     }
3088   return(compact_pixels);
3089 }
3090 
WritePSDChannels(const PSDInfo * psd_info,const ImageInfo * image_info,Image * image,Image * next_image,MagickOffsetType size_offset,const MagickBooleanType separate,ExceptionInfo * exception)3091 static size_t WritePSDChannels(const PSDInfo *psd_info,
3092   const ImageInfo *image_info,Image *image,Image *next_image,
3093   MagickOffsetType size_offset,const MagickBooleanType separate,
3094   ExceptionInfo *exception)
3095 {
3096   CompressionType
3097     compression;
3098 
3099   Image
3100     *mask;
3101 
3102   MagickOffsetType
3103     rows_offset;
3104 
3105   size_t
3106     channels,
3107     count,
3108     length,
3109     offset_length;
3110 
3111   unsigned char
3112     *compact_pixels;
3113 
3114   count=0;
3115   offset_length=0;
3116   rows_offset=0;
3117   compact_pixels=(unsigned char *) NULL;
3118   compression=next_image->compression;
3119   if (image_info->compression != UndefinedCompression)
3120     compression=image_info->compression;
3121   if (compression == RLECompression)
3122     {
3123       compact_pixels=AcquireCompactPixels(next_image,exception);
3124       if (compact_pixels == (unsigned char *) NULL)
3125         return(0);
3126     }
3127   channels=1;
3128   if (separate == MagickFalse)
3129     {
3130       if ((next_image->storage_class != PseudoClass) ||
3131           (IsImageGray(next_image) != MagickFalse))
3132         {
3133           if (IsImageGray(next_image) == MagickFalse)
3134             channels=(size_t) (next_image->colorspace == CMYKColorspace ? 4 :
3135               3);
3136           if (next_image->alpha_trait != UndefinedPixelTrait)
3137             channels++;
3138         }
3139       rows_offset=TellBlob(image)+2;
3140       count+=WriteCompressionStart(psd_info,image,next_image,compression,
3141         (ssize_t) channels);
3142       offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
3143     }
3144   size_offset+=2;
3145   if ((next_image->storage_class == PseudoClass) &&
3146       (IsImageGray(next_image) == MagickFalse))
3147     {
3148       length=WritePSDChannel(psd_info,image_info,image,next_image,
3149         IndexQuantum,compact_pixels,rows_offset,separate,compression,
3150         exception);
3151       if (separate != MagickFalse)
3152         size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3153       else
3154         rows_offset+=offset_length;
3155       count+=length;
3156     }
3157   else
3158     {
3159       if (IsImageGray(next_image) != MagickFalse)
3160         {
3161           length=WritePSDChannel(psd_info,image_info,image,next_image,
3162             GrayQuantum,compact_pixels,rows_offset,separate,compression,
3163             exception);
3164           if (separate != MagickFalse)
3165             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3166           else
3167             rows_offset+=offset_length;
3168           count+=length;
3169         }
3170       else
3171         {
3172           if (next_image->colorspace == CMYKColorspace)
3173             (void) NegateCMYK(next_image,exception);
3174 
3175           length=WritePSDChannel(psd_info,image_info,image,next_image,
3176             RedQuantum,compact_pixels,rows_offset,separate,compression,
3177             exception);
3178           if (separate != MagickFalse)
3179             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3180           else
3181             rows_offset+=offset_length;
3182           count+=length;
3183 
3184           length=WritePSDChannel(psd_info,image_info,image,next_image,
3185             GreenQuantum,compact_pixels,rows_offset,separate,compression,
3186             exception);
3187           if (separate != MagickFalse)
3188             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3189           else
3190             rows_offset+=offset_length;
3191           count+=length;
3192 
3193           length=WritePSDChannel(psd_info,image_info,image,next_image,
3194             BlueQuantum,compact_pixels,rows_offset,separate,compression,
3195             exception);
3196           if (separate != MagickFalse)
3197             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3198           else
3199             rows_offset+=offset_length;
3200           count+=length;
3201 
3202           if (next_image->colorspace == CMYKColorspace)
3203             {
3204               length=WritePSDChannel(psd_info,image_info,image,next_image,
3205                 BlackQuantum,compact_pixels,rows_offset,separate,compression,
3206                 exception);
3207               if (separate != MagickFalse)
3208                 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3209               else
3210                 rows_offset+=offset_length;
3211               count+=length;
3212             }
3213         }
3214       if (next_image->alpha_trait != UndefinedPixelTrait)
3215         {
3216           length=WritePSDChannel(psd_info,image_info,image,next_image,
3217             AlphaQuantum,compact_pixels,rows_offset,separate,compression,
3218             exception);
3219           if (separate != MagickFalse)
3220             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3221           else
3222             rows_offset+=offset_length;
3223           count+=length;
3224         }
3225     }
3226   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
3227   if (next_image->colorspace == CMYKColorspace)
3228     (void) NegateCMYK(next_image,exception);
3229   if (separate != MagickFalse)
3230     {
3231       const char
3232         *property;
3233 
3234       property=GetImageArtifact(next_image,"psd:opacity-mask");
3235       if (property != (const char *) NULL)
3236         {
3237           mask=(Image *) GetImageRegistry(ImageRegistryType,property,
3238             exception);
3239           if (mask != (Image *) NULL)
3240             {
3241               if (compression == RLECompression)
3242                 {
3243                   compact_pixels=AcquireCompactPixels(mask,exception);
3244                   if (compact_pixels == (unsigned char *) NULL)
3245                     return(0);
3246                 }
3247               length=WritePSDChannel(psd_info,image_info,image,mask,
3248                 RedQuantum,compact_pixels,rows_offset,MagickTrue,compression,
3249                 exception);
3250               (void) WritePSDSize(psd_info,image,length,size_offset);
3251               count+=length;
3252               compact_pixels=(unsigned char *) RelinquishMagickMemory(
3253                 compact_pixels);
3254             }
3255         }
3256     }
3257   return(count);
3258 }
3259 
WritePascalString(Image * image,const char * value,size_t padding)3260 static size_t WritePascalString(Image *image,const char *value,size_t padding)
3261 {
3262   size_t
3263     count,
3264     length;
3265 
3266   ssize_t
3267     i;
3268 
3269   /*
3270     Max length is 255.
3271   */
3272   count=0;
3273   length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
3274   if (length ==  0)
3275     count+=WriteBlobByte(image,0);
3276   else
3277     {
3278       count+=WriteBlobByte(image,(unsigned char) length);
3279       count+=WriteBlob(image,length,(const unsigned char *) value);
3280     }
3281   length++;
3282   if ((length % padding) == 0)
3283     return(count);
3284   for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
3285     count+=WriteBlobByte(image,0);
3286   return(count);
3287 }
3288 
WriteResolutionResourceBlock(Image * image)3289 static void WriteResolutionResourceBlock(Image *image)
3290 {
3291   double
3292     x_resolution,
3293     y_resolution;
3294 
3295   unsigned short
3296     units;
3297 
3298   if (image->units == PixelsPerCentimeterResolution)
3299     {
3300       x_resolution=2.54*65536.0*image->resolution.x+0.5;
3301       y_resolution=2.54*65536.0*image->resolution.y+0.5;
3302       units=2;
3303     }
3304   else
3305     {
3306       x_resolution=65536.0*image->resolution.x+0.5;
3307       y_resolution=65536.0*image->resolution.y+0.5;
3308       units=1;
3309     }
3310   (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3311   (void) WriteBlobMSBShort(image,0x03ED);
3312   (void) WriteBlobMSBShort(image,0);
3313   (void) WriteBlobMSBLong(image,16); /* resource size */
3314   (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
3315   (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
3316   (void) WriteBlobMSBShort(image,units); /* width unit */
3317   (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
3318   (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
3319   (void) WriteBlobMSBShort(image,units); /* height unit */
3320 }
3321 
WriteChannelSize(const PSDInfo * psd_info,Image * image,const signed short channel)3322 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
3323   const signed short channel)
3324 {
3325   size_t
3326     count;
3327 
3328   count=(size_t) WriteBlobShort(image,(const unsigned short) channel);
3329   count+=SetPSDSize(psd_info,image,0);
3330   return(count);
3331 }
3332 
RemoveICCProfileFromResourceBlock(StringInfo * bim_profile)3333 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
3334 {
3335   const unsigned char
3336     *p;
3337 
3338   size_t
3339     length;
3340 
3341   unsigned char
3342     *datum;
3343 
3344   unsigned int
3345     count,
3346     long_sans;
3347 
3348   unsigned short
3349     id,
3350     short_sans;
3351 
3352   length=GetStringInfoLength(bim_profile);
3353   if (length < 16)
3354     return;
3355   datum=GetStringInfoDatum(bim_profile);
3356   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3357   {
3358     unsigned char
3359       *q;
3360 
3361     q=(unsigned char *) p;
3362     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3363       break;
3364     p=PushLongPixel(MSBEndian,p,&long_sans);
3365     p=PushShortPixel(MSBEndian,p,&id);
3366     p=PushShortPixel(MSBEndian,p,&short_sans);
3367     p=PushLongPixel(MSBEndian,p,&count);
3368     if (id == 0x0000040f)
3369       {
3370         ssize_t
3371           quantum;
3372 
3373         quantum=PSDQuantum(count)+12;
3374         if ((quantum >= 12) && (quantum < (ssize_t) length))
3375           {
3376             if ((q+quantum < (datum+length-16)))
3377               (void) memmove(q,q+quantum,length-quantum-(q-datum));
3378             SetStringInfoLength(bim_profile,length-quantum);
3379           }
3380         break;
3381       }
3382     p+=count;
3383     if ((count & 0x01) != 0)
3384       p++;
3385   }
3386 }
3387 
RemoveResolutionFromResourceBlock(StringInfo * bim_profile)3388 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
3389 {
3390   const unsigned char
3391     *p;
3392 
3393   size_t
3394     length;
3395 
3396   unsigned char
3397     *datum;
3398 
3399   unsigned int
3400     count,
3401     long_sans;
3402 
3403   unsigned short
3404     id,
3405     short_sans;
3406 
3407   length=GetStringInfoLength(bim_profile);
3408   if (length < 16)
3409     return;
3410   datum=GetStringInfoDatum(bim_profile);
3411   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3412   {
3413     unsigned char
3414       *q;
3415 
3416     ssize_t
3417       cnt;
3418 
3419     q=(unsigned char *) p;
3420     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3421       return;
3422     p=PushLongPixel(MSBEndian,p,&long_sans);
3423     p=PushShortPixel(MSBEndian,p,&id);
3424     p=PushShortPixel(MSBEndian,p,&short_sans);
3425     p=PushLongPixel(MSBEndian,p,&count);
3426     cnt=PSDQuantum(count);
3427     if (cnt < 0)
3428       return;
3429     if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)) &&
3430         ((ssize_t) length-(cnt+12)-(q-datum)) > 0)
3431       {
3432         (void) memmove(q,q+cnt+12,length-(cnt+12)-(q-datum));
3433         SetStringInfoLength(bim_profile,length-(cnt+12));
3434         break;
3435       }
3436     p+=count;
3437     if ((count & 0x01) != 0)
3438       p++;
3439   }
3440 }
3441 
GetAdditionalInformation(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)3442 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
3443   Image *image,ExceptionInfo *exception)
3444 {
3445 #define PSDKeySize 5
3446 #define PSDAllowedLength 36
3447 
3448   char
3449     key[PSDKeySize];
3450 
3451   /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
3452   const char
3453     allowed[PSDAllowedLength][PSDKeySize] = {
3454       "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
3455       "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
3456       "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
3457       "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
3458     },
3459     *option;
3460 
3461   const StringInfo
3462     *info;
3463 
3464   MagickBooleanType
3465     found;
3466 
3467   size_t
3468     i;
3469 
3470   size_t
3471     remaining_length,
3472     length;
3473 
3474   StringInfo
3475     *profile;
3476 
3477   unsigned char
3478     *p;
3479 
3480   unsigned int
3481     size;
3482 
3483   info=GetImageProfile(image,"psd:additional-info");
3484   if (info == (const StringInfo *) NULL)
3485     return((const StringInfo *) NULL);
3486   option=GetImageOption(image_info,"psd:additional-info");
3487   if (LocaleCompare(option,"all") == 0)
3488     return(info);
3489   if (LocaleCompare(option,"selective") != 0)
3490     {
3491       profile=RemoveImageProfile(image,"psd:additional-info");
3492       return(DestroyStringInfo(profile));
3493     }
3494   length=GetStringInfoLength(info);
3495   p=GetStringInfoDatum(info);
3496   remaining_length=length;
3497   length=0;
3498   while (remaining_length >= 12)
3499   {
3500     /* skip over signature */
3501     p+=4;
3502     key[0]=(char) (*p++);
3503     key[1]=(char) (*p++);
3504     key[2]=(char) (*p++);
3505     key[3]=(char) (*p++);
3506     key[4]='\0';
3507     size=(unsigned int) (*p++) << 24;
3508     size|=(unsigned int) (*p++) << 16;
3509     size|=(unsigned int) (*p++) << 8;
3510     size|=(unsigned int) (*p++);
3511     size=size & 0xffffffff;
3512     remaining_length-=12;
3513     if ((size_t) size > remaining_length)
3514       return((const StringInfo *) NULL);
3515     found=MagickFalse;
3516     for (i=0; i < PSDAllowedLength; i++)
3517     {
3518       if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3519         continue;
3520 
3521       found=MagickTrue;
3522       break;
3523     }
3524     remaining_length-=(size_t) size;
3525     if (found == MagickFalse)
3526       {
3527         if (remaining_length > 0)
3528           p=(unsigned char *) memmove(p-12,p+size,remaining_length);
3529         continue;
3530       }
3531     length+=(size_t) size+12;
3532     p+=size;
3533   }
3534   profile=RemoveImageProfile(image,"psd:additional-info");
3535   if (length == 0)
3536     return(DestroyStringInfo(profile));
3537   SetStringInfoLength(profile,(const size_t) length);
3538   (void) SetImageProfile(image,"psd:additional-info",info,exception);
3539   return(profile);
3540 }
3541 
WritePSDLayersInternal(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,size_t * layers_size,ExceptionInfo * exception)3542 static MagickBooleanType WritePSDLayersInternal(Image *image,
3543   const ImageInfo *image_info,const PSDInfo *psd_info,size_t *layers_size,
3544   ExceptionInfo *exception)
3545 {
3546   char
3547     layer_name[MagickPathExtent];
3548 
3549   const char
3550     *property;
3551 
3552   const StringInfo
3553     *info;
3554 
3555   Image
3556     *base_image,
3557     *next_image;
3558 
3559   MagickBooleanType
3560     status;
3561 
3562   MagickOffsetType
3563     *layer_size_offsets,
3564     size_offset;
3565 
3566   ssize_t
3567     i;
3568 
3569   size_t
3570     layer_count,
3571     layer_index,
3572     length,
3573     name_length,
3574     rounded_size,
3575     size;
3576 
3577   status=MagickTrue;
3578   base_image=GetNextImageInList(image);
3579   if (base_image == (Image *) NULL)
3580     base_image=image;
3581   size=0;
3582   size_offset=TellBlob(image);
3583   (void) SetPSDSize(psd_info,image,0);
3584   layer_count=0;
3585   for (next_image=base_image; next_image != NULL; )
3586   {
3587     layer_count++;
3588     next_image=GetNextImageInList(next_image);
3589   }
3590   if (image->alpha_trait != UndefinedPixelTrait)
3591     size+=WriteBlobShort(image,-(unsigned short) layer_count);
3592   else
3593     size+=WriteBlobShort(image,(unsigned short) layer_count);
3594   layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3595     (size_t) layer_count,sizeof(MagickOffsetType));
3596   if (layer_size_offsets == (MagickOffsetType *) NULL)
3597     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3598   layer_index=0;
3599   for (next_image=base_image; next_image != NULL; )
3600   {
3601     Image
3602       *mask;
3603 
3604     unsigned char
3605       default_color;
3606 
3607     unsigned short
3608       channels,
3609       total_channels;
3610 
3611     mask=(Image *) NULL;
3612     property=GetImageArtifact(next_image,"psd:opacity-mask");
3613     default_color=0;
3614     if (property != (const char *) NULL)
3615       {
3616         mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3617         default_color=(unsigned char) (strlen(property) == 9 ? 255 : 0);
3618       }
3619     size+=WriteBlobSignedLong(image,(signed int) next_image->page.y);
3620     size+=WriteBlobSignedLong(image,(signed int) next_image->page.x);
3621     size+=WriteBlobSignedLong(image,(signed int) (next_image->page.y+
3622       next_image->rows));
3623     size+=WriteBlobSignedLong(image,(signed int) (next_image->page.x+
3624       next_image->columns));
3625     channels=1;
3626     if ((next_image->storage_class != PseudoClass) &&
3627         (IsImageGray(next_image) == MagickFalse))
3628       channels=(unsigned short) (next_image->colorspace == CMYKColorspace ? 4 :
3629         3);
3630     total_channels=channels;
3631     if (next_image->alpha_trait != UndefinedPixelTrait)
3632       total_channels++;
3633     if (mask != (Image *) NULL)
3634       total_channels++;
3635     size+=WriteBlobShort(image,total_channels);
3636     layer_size_offsets[layer_index++]=TellBlob(image);
3637     for (i=0; i < (ssize_t) channels; i++)
3638       size+=WriteChannelSize(psd_info,image,(signed short) i);
3639     if (next_image->alpha_trait != UndefinedPixelTrait)
3640       size+=WriteChannelSize(psd_info,image,-1);
3641     if (mask != (Image *) NULL)
3642       size+=WriteChannelSize(psd_info,image,-2);
3643     size+=WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :"8BIM");
3644     size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(next_image));
3645     property=GetImageArtifact(next_image,"psd:layer.opacity");
3646     if (property != (const char *) NULL)
3647       {
3648         Quantum
3649           opacity;
3650 
3651         opacity=(Quantum) StringToInteger(property);
3652         size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
3653         (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3654       }
3655     else
3656       size+=WriteBlobByte(image,255);
3657     size+=WriteBlobByte(image,0);
3658     size+=WriteBlobByte(image,(const unsigned char)
3659       (next_image->compose == NoCompositeOp ? 1 << 0x02 : 1)); /* layer properties - visible, etc. */
3660     size+=WriteBlobByte(image,0);
3661     info=GetAdditionalInformation(image_info,next_image,exception);
3662     property=(const char *) GetImageProperty(next_image,"label",exception);
3663     if (property == (const char *) NULL)
3664       {
3665         (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3666           (double) layer_index);
3667         property=layer_name;
3668       }
3669     name_length=strlen(property)+1;
3670     if ((name_length % 4) != 0)
3671       name_length+=(4-(name_length % 4));
3672     if (info != (const StringInfo *) NULL)
3673       name_length+=GetStringInfoLength(info);
3674     name_length+=8;
3675     if (mask != (Image *) NULL)
3676       name_length+=20;
3677     size+=WriteBlobLong(image,(unsigned int) name_length);
3678     if (mask == (Image *) NULL)
3679       size+=WriteBlobLong(image,0);
3680     else
3681       {
3682         if (mask->compose != NoCompositeOp)
3683           (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3684             default_color),MagickTrue,exception);
3685         mask->page.y+=image->page.y;
3686         mask->page.x+=image->page.x;
3687         size+=WriteBlobLong(image,20);
3688         size+=WriteBlobSignedLong(image,(const signed int) mask->page.y);
3689         size+=WriteBlobSignedLong(image,(const signed int) mask->page.x);
3690         size+=WriteBlobSignedLong(image,(const signed int) (mask->rows+
3691           mask->page.y));
3692         size+=WriteBlobSignedLong(image,(const signed int) (mask->columns+
3693           mask->page.x));
3694         size+=WriteBlobByte(image,default_color);
3695         size+=WriteBlobByte(image,(const unsigned char)
3696           (mask->compose == NoCompositeOp ? 2 : 0));
3697         size+=WriteBlobMSBShort(image,0);
3698       }
3699     size+=WriteBlobLong(image,0);
3700     size+=WritePascalString(image,property,4);
3701     if (info != (const StringInfo *) NULL)
3702       size+=WriteBlob(image,GetStringInfoLength(info),
3703         GetStringInfoDatum(info));
3704     next_image=GetNextImageInList(next_image);
3705   }
3706   /*
3707     Now the image data!
3708   */
3709   next_image=base_image;
3710   layer_index=0;
3711   while (next_image != NULL)
3712   {
3713     length=WritePSDChannels(psd_info,image_info,image,next_image,
3714       layer_size_offsets[layer_index++],MagickTrue,exception);
3715     if (length == 0)
3716       {
3717         status=MagickFalse;
3718         break;
3719       }
3720     size+=length;
3721     next_image=GetNextImageInList(next_image);
3722   }
3723   /*
3724     Write the total size
3725   */
3726   if (layers_size != (size_t*) NULL)
3727     *layers_size=size;
3728   if ((size/2) != ((size+1)/2))
3729     rounded_size=size+1;
3730   else
3731     rounded_size=size;
3732   (void) WritePSDSize(psd_info,image,rounded_size,size_offset);
3733   layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3734     layer_size_offsets);
3735   /*
3736     Remove the opacity mask from the registry
3737   */
3738   next_image=base_image;
3739   while (next_image != (Image *) NULL)
3740   {
3741     property=GetImageArtifact(next_image,"psd:opacity-mask");
3742     if (property != (const char *) NULL)
3743       (void) DeleteImageRegistry(property);
3744     next_image=GetNextImageInList(next_image);
3745   }
3746 
3747   return(status);
3748 }
3749 
WritePSDLayers(Image * image,const ImageInfo * image_info,const PSDInfo * psd_info,ExceptionInfo * exception)3750 ModuleExport MagickBooleanType WritePSDLayers(Image * image,
3751   const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
3752 {
3753   PolicyDomain
3754     domain;
3755 
3756   PolicyRights
3757     rights;
3758 
3759   domain=CoderPolicyDomain;
3760   rights=WritePolicyRights;
3761   if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
3762     return(MagickTrue);
3763   return WritePSDLayersInternal(image,image_info,psd_info,(size_t*) NULL,
3764     exception);
3765 }
3766 
WritePSDImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)3767 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3768   Image *image,ExceptionInfo *exception)
3769 {
3770   const StringInfo
3771     *icc_profile;
3772 
3773   MagickBooleanType
3774     status;
3775 
3776   PSDInfo
3777     psd_info;
3778 
3779   ssize_t
3780     i;
3781 
3782   size_t
3783     length,
3784     num_channels,
3785     packet_size;
3786 
3787   StringInfo
3788     *bim_profile;
3789 
3790   /*
3791     Open image file.
3792   */
3793   assert(image_info != (const ImageInfo *) NULL);
3794   assert(image_info->signature == MagickCoreSignature);
3795   assert(image != (Image *) NULL);
3796   assert(image->signature == MagickCoreSignature);
3797   if (image->debug != MagickFalse)
3798     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3799   assert(exception != (ExceptionInfo *) NULL);
3800   assert(exception->signature == MagickCoreSignature);
3801   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3802   if (status == MagickFalse)
3803     return(status);
3804   packet_size=(size_t) (image->depth > 8 ? 6 : 3);
3805   if (image->alpha_trait != UndefinedPixelTrait)
3806     packet_size+=image->depth > 8 ? 2 : 1;
3807   psd_info.version=1;
3808   if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3809       (image->columns > 30000) || (image->rows > 30000))
3810     psd_info.version=2;
3811   (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3812   (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
3813   for (i=1; i <= 6; i++)
3814     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
3815   /* When the image has a color profile it won't be converted to gray scale */
3816   if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
3817       (SetImageGray(image,exception) != MagickFalse))
3818     num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3819   else
3820     if ((image_info->type != TrueColorType) && (image_info->type !=
3821          TrueColorAlphaType) && (image->storage_class == PseudoClass))
3822       num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3823     else
3824       {
3825         if (image->storage_class == PseudoClass)
3826           (void) SetImageStorageClass(image,DirectClass,exception);
3827         if (image->colorspace != CMYKColorspace)
3828           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3829         else
3830           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3831       }
3832   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3833   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3834   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3835   if (IsImageGray(image) != MagickFalse)
3836     {
3837       MagickBooleanType
3838         monochrome;
3839 
3840       /*
3841         Write depth & mode.
3842       */
3843       monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3844         MagickTrue : MagickFalse;
3845       (void) WriteBlobMSBShort(image,(unsigned short)
3846         (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3847       (void) WriteBlobMSBShort(image,(unsigned short)
3848         (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3849     }
3850   else
3851     {
3852       (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3853         PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3854 
3855       if (((image_info->colorspace != UndefinedColorspace) ||
3856            (image->colorspace != CMYKColorspace)) &&
3857           (image_info->colorspace != CMYKColorspace))
3858         {
3859           (void) TransformImageColorspace(image,sRGBColorspace,exception);
3860           (void) WriteBlobMSBShort(image,(unsigned short)
3861             (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3862         }
3863       else
3864         {
3865           if (image->colorspace != CMYKColorspace)
3866             (void) TransformImageColorspace(image,CMYKColorspace,exception);
3867           (void) WriteBlobMSBShort(image,CMYKMode);
3868         }
3869     }
3870   if ((IsImageGray(image) != MagickFalse) ||
3871       (image->storage_class == DirectClass) || (image->colors > 256))
3872     (void) WriteBlobMSBLong(image,0);
3873   else
3874     {
3875       /*
3876         Write PSD raster colormap.
3877       */
3878       (void) WriteBlobMSBLong(image,768);
3879       for (i=0; i < (ssize_t) image->colors; i++)
3880         (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3881           image->colormap[i].red)));
3882       for ( ; i < 256; i++)
3883         (void) WriteBlobByte(image,0);
3884       for (i=0; i < (ssize_t) image->colors; i++)
3885         (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3886           image->colormap[i].green)));
3887       for ( ; i < 256; i++)
3888         (void) WriteBlobByte(image,0);
3889       for (i=0; i < (ssize_t) image->colors; i++)
3890         (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3891           image->colormap[i].blue)));
3892       for ( ; i < 256; i++)
3893         (void) WriteBlobByte(image,0);
3894     }
3895   /*
3896     Image resource block.
3897   */
3898   length=28; /* 0x03EB */
3899   bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
3900   icc_profile=GetImageProfile(image,"icc");
3901   if (bim_profile != (StringInfo *) NULL)
3902     {
3903       bim_profile=CloneStringInfo(bim_profile);
3904       if (icc_profile != (StringInfo *) NULL)
3905         RemoveICCProfileFromResourceBlock(bim_profile);
3906       RemoveResolutionFromResourceBlock(bim_profile);
3907       length+=PSDQuantum(GetStringInfoLength(bim_profile));
3908     }
3909   if (icc_profile != (const StringInfo *) NULL)
3910     length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
3911   (void) WriteBlobMSBLong(image,(unsigned int) length);
3912   WriteResolutionResourceBlock(image);
3913   if (bim_profile != (StringInfo *) NULL)
3914     {
3915       (void) WriteBlob(image,GetStringInfoLength(bim_profile),
3916         GetStringInfoDatum(bim_profile));
3917       bim_profile=DestroyStringInfo(bim_profile);
3918     }
3919   if (icc_profile != (StringInfo *) NULL)
3920     {
3921       (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3922       (void) WriteBlobMSBShort(image,0x0000040F);
3923       (void) WriteBlobMSBShort(image,0);
3924       (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
3925         icc_profile));
3926       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
3927         GetStringInfoDatum(icc_profile));
3928       if ((ssize_t) GetStringInfoLength(icc_profile) != PSDQuantum(GetStringInfoLength(icc_profile)))
3929         (void) WriteBlobByte(image,0);
3930     }
3931   if (status != MagickFalse)
3932     {
3933       const char
3934         *option;
3935 
3936       MagickOffsetType
3937         size_offset;
3938 
3939       size_t
3940         size;
3941 
3942       size_offset=TellBlob(image);
3943       (void) SetPSDSize(&psd_info,image,0);
3944       option=GetImageOption(image_info,"psd:write-layers");
3945       if (IsStringFalse(option) != MagickTrue)
3946         {
3947           status=WritePSDLayersInternal(image,image_info,&psd_info,&size,
3948             exception);
3949           (void) WritePSDSize(&psd_info,image,size+
3950             (psd_info.version == 1 ? 8 : 12),size_offset);
3951         }
3952     }
3953   (void) WriteBlobMSBLong(image,0);  /* user mask data */
3954   /*
3955     Write composite image.
3956   */
3957   if (status != MagickFalse)
3958     {
3959       CompressionType
3960         compression;
3961 
3962       compression=image->compression;
3963       if (image_info->compression != UndefinedCompression)
3964         image->compression=image_info->compression;
3965       if (image->compression == ZipCompression)
3966         image->compression=RLECompression;
3967       if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
3968           exception) == 0)
3969         status=MagickFalse;
3970       image->compression=compression;
3971     }
3972   (void) CloseBlob(image);
3973   return(status);
3974 }
3975