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