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