]> granicus.if.org Git - imagemagick/blob - coders/psd.c
Fixed memory leak (https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=6869)
[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[256],
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,4) 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,4) 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,4) 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   compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1239     sizeof(*compact_pixels));
1240   if (compact_pixels == (unsigned char *) NULL)
1241     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1242       image->filename);
1243
1244   packet_size=GetPSDPacketSize(image);
1245   row_size=image->columns*packet_size;
1246   count=image->rows*row_size;
1247
1248   pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1249   if (pixels == (unsigned char *) NULL)
1250     {
1251       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1252       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1253         image->filename);
1254     }
1255   if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
1256     {
1257       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1258       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1259       ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1260         image->filename);
1261     }
1262
1263   memset(&stream,0,sizeof(stream));
1264   stream.data_type=Z_BINARY;
1265   stream.next_in=(Bytef *)compact_pixels;
1266   stream.avail_in=(uInt) compact_size;
1267   stream.next_out=(Bytef *)pixels;
1268   stream.avail_out=(uInt) count;
1269
1270   if (inflateInit(&stream) == Z_OK)
1271     {
1272       int
1273         ret;
1274
1275       while (stream.avail_out > 0)
1276       {
1277         ret=inflate(&stream,Z_SYNC_FLUSH);
1278         if ((ret != Z_OK) && (ret != Z_STREAM_END))
1279           {
1280             (void) inflateEnd(&stream);
1281             compact_pixels=(unsigned char *) RelinquishMagickMemory(
1282               compact_pixels);
1283             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1284             return(MagickFalse);
1285           }
1286         if (ret == Z_STREAM_END)
1287           break;
1288       }
1289       (void) inflateEnd(&stream);
1290     }
1291
1292   if (compression == ZipWithPrediction)
1293     {
1294       p=pixels;
1295       while (count > 0)
1296       {
1297         length=image->columns;
1298         while (--length)
1299         {
1300           if (packet_size == 2)
1301             {
1302               p[2]+=p[0]+((p[1]+p[3]) >> 8);
1303               p[3]+=p[1];
1304             }
1305           // else if (packet_size == 4)
1306           //   {
1307           //     TODO: Figure out what to do there.
1308           //   }
1309           else
1310             *(p+1)+=*p;
1311           p+=packet_size;
1312         }
1313         p+=packet_size;
1314         count-=row_size;
1315       }
1316     }
1317
1318   status=MagickTrue;
1319   p=pixels;
1320   for (y=0; y < (ssize_t) image->rows; y++)
1321   {
1322     status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1323     if (status == MagickFalse)
1324       break;
1325
1326     p+=row_size;
1327   }
1328
1329   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1330   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1331   return(status);
1332 }
1333 #endif
1334
1335 static MagickBooleanType ReadPSDChannel(Image *image,
1336   const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
1337   const size_t channel,const PSDCompressionType compression,
1338   ExceptionInfo *exception)
1339 {
1340   Image
1341     *channel_image,
1342     *mask;
1343
1344   MagickOffsetType
1345     offset;
1346
1347   MagickBooleanType
1348     status;
1349
1350   channel_image=image;
1351   mask=(Image *) NULL;
1352   if ((layer_info->channel_info[channel].type < -1) &&
1353       (layer_info->mask.page.width > 0) && (layer_info->mask.page.height > 0))
1354     {
1355       const char
1356         *option;
1357
1358       /*
1359         Ignore mask that is not a user supplied layer mask, if the mask is
1360         disabled or if the flags have unsupported values.
1361       */
1362       option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1363       if ((layer_info->channel_info[channel].type != -2) ||
1364           (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
1365            (IsStringTrue(option) == MagickFalse)))
1366         {
1367           SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1368           return(MagickTrue);
1369         }
1370       mask=CloneImage(image,layer_info->mask.page.width,
1371         layer_info->mask.page.height,MagickFalse,exception);
1372       if (mask != (Image *) NULL)
1373         {
1374           SetImageType(mask,GrayscaleType,exception);
1375           channel_image=mask;
1376         }
1377     }
1378
1379   offset=TellBlob(image);
1380   status=MagickFalse;
1381   switch(compression)
1382   {
1383     case Raw:
1384       status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1385         layer_info->channel_info[channel].type,exception);
1386       break;
1387     case RLE:
1388       {
1389         MagickOffsetType
1390           *sizes;
1391
1392         sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
1393         if (sizes == (MagickOffsetType *) NULL)
1394           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1395             image->filename);
1396         status=ReadPSDChannelRLE(channel_image,psd_info,
1397           layer_info->channel_info[channel].type,sizes,exception);
1398         sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1399       }
1400       break;
1401     case ZipWithPrediction:
1402     case ZipWithoutPrediction:
1403 #ifdef MAGICKCORE_ZLIB_DELEGATE
1404       status=ReadPSDChannelZip(channel_image,layer_info->channels,
1405         layer_info->channel_info[channel].type,compression,
1406         layer_info->channel_info[channel].size-2,exception);
1407 #else
1408       (void) ThrowMagickException(exception,GetMagickModule(),
1409           MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1410             "'%s' (ZLIB)",image->filename);
1411 #endif
1412       break;
1413     default:
1414       (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1415         "CompressionNotSupported","'%.20g'",(double) compression);
1416       break;
1417   }
1418
1419   SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1420   if (status == MagickFalse)
1421     {
1422       if (mask != (Image *) NULL)
1423         DestroyImage(mask);
1424       ThrowBinaryException(CoderError,"UnableToDecompressImage",
1425         image->filename);
1426     }
1427   layer_info->mask.image=mask;
1428   return(status);
1429 }
1430
1431 static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1432   const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1433 {
1434   char
1435     message[MagickPathExtent];
1436
1437   MagickBooleanType
1438     status;
1439
1440   PSDCompressionType
1441     compression;
1442
1443   ssize_t
1444     j;
1445
1446   if (image->debug != MagickFalse)
1447     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1448       "    setting up new layer image");
1449   if (psd_info->mode != IndexedMode)
1450     (void) SetImageBackgroundColor(layer_info->image,exception);
1451   layer_info->image->compose=PSDBlendModeToCompositeOperator(
1452     layer_info->blendkey);
1453   if (layer_info->visible == MagickFalse)
1454     layer_info->image->compose=NoCompositeOp;
1455   /*
1456     Set up some hidden attributes for folks that need them.
1457   */
1458   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1459     (double) layer_info->page.x);
1460   (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1461   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1462     (double) layer_info->page.y);
1463   (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1464   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1465     layer_info->opacity);
1466   (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1467   (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1468     exception);
1469
1470   status=MagickTrue;
1471   for (j=0; j < (ssize_t) layer_info->channels; j++)
1472   {
1473     if (image->debug != MagickFalse)
1474       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1475         "    reading data for channel %.20g",(double) j);
1476
1477     compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1478
1479     /* TODO: Remove this when we figure out how to support this */
1480     if ((compression == ZipWithPrediction) && (image->depth == 32))
1481       {
1482         (void) ThrowMagickException(exception,GetMagickModule(),
1483           TypeError,"CompressionNotSupported","ZipWithPrediction(32 bit)");
1484         return(MagickFalse);
1485       }
1486
1487     layer_info->image->compression=ConvertPSDCompression(compression);
1488     if (layer_info->channel_info[j].type == -1)
1489       layer_info->image->alpha_trait=BlendPixelTrait;
1490
1491     status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
1492       compression,exception);
1493
1494     if (status == MagickFalse)
1495       break;
1496   }
1497
1498   if (status != MagickFalse)
1499     status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1500       MagickFalse,exception);
1501
1502   if ((status != MagickFalse) &&
1503       (layer_info->image->colorspace == CMYKColorspace))
1504     status=NegateCMYK(layer_info->image,exception);
1505
1506   if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1507     {
1508       const char
1509         *option;
1510
1511       layer_info->mask.image->page.x=layer_info->mask.page.x;
1512       layer_info->mask.image->page.y=layer_info->mask.page.y;
1513       /* Do not composite the mask when it is disabled */
1514       if ((layer_info->mask.flags & 0x02) == 0x02)
1515         layer_info->mask.image->compose=NoCompositeOp;
1516       else
1517         status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1518           layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1519           exception);
1520       option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1521       if (IsStringTrue(option) != MagickFalse)
1522         PreservePSDOpacityMask(image,layer_info,exception);
1523       layer_info->mask.image=DestroyImage(layer_info->mask.image);
1524     }
1525
1526   return(status);
1527 }
1528
1529 static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
1530   LayerInfo *layer_info)
1531 {
1532   int
1533     channel_type;
1534
1535   register ssize_t
1536     i;
1537
1538   if (layer_info->channels < psd_info->min_channels)
1539     return(MagickFalse);
1540   channel_type=RedChannel;
1541   if (psd_info->min_channels >= 3)
1542     channel_type|=(GreenChannel | BlueChannel);
1543   if (psd_info->min_channels >= 4)
1544     channel_type|=BlackChannel;
1545   for (i=0; i < layer_info->channels; i++)
1546   {
1547     short
1548       type;
1549
1550     type=layer_info->channel_info[i].type;
1551     if (type == -1)
1552       {
1553         channel_type|=AlphaChannel;
1554         continue;
1555       }
1556     if (type < -1)
1557       continue;
1558     if (type == 0)
1559       channel_type&=~RedChannel;
1560     else if (type == 1)
1561       channel_type&=~GreenChannel;
1562     else if (type == 2)
1563       channel_type&=~BlueChannel;
1564     else if (type == 3)
1565       channel_type&=~BlackChannel;
1566   }
1567   if (channel_type == 0)
1568     return(MagickTrue);
1569   if ((channel_type == AlphaChannel) &&
1570       (layer_info->channels >= psd_info->min_channels + 1))
1571     return(MagickTrue);
1572   return(MagickFalse);
1573 }
1574
1575 static MagickBooleanType ReadPSDLayersInternal(Image *image,
1576   const ImageInfo *image_info,const PSDInfo *psd_info,
1577   const MagickBooleanType skip_layers,ExceptionInfo *exception)
1578 {
1579   char
1580     type[4];
1581
1582   LayerInfo
1583     *layer_info;
1584
1585   MagickSizeType
1586     size;
1587
1588   MagickBooleanType
1589     status;
1590
1591   register ssize_t
1592     i;
1593
1594   ssize_t
1595     count,
1596     j,
1597     number_layers;
1598
1599   size=GetPSDSize(psd_info,image);
1600   if (size == 0)
1601     {
1602       /*
1603         Skip layers & masks.
1604       */
1605       (void) ReadBlobLong(image);
1606       count=ReadBlob(image,4,(unsigned char *) type);
1607       ReversePSDString(image,type,4);
1608       status=MagickFalse;
1609       if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1610         return(MagickTrue);
1611       else
1612         {
1613           count=ReadBlob(image,4,(unsigned char *) type);
1614           ReversePSDString(image,type,4);
1615           if ((count != 0) && ((LocaleNCompare(type,"Lr16",4) == 0) ||
1616               (LocaleNCompare(type,"Lr32",4) == 0)))
1617             size=GetPSDSize(psd_info,image);
1618           else
1619             return(MagickTrue);
1620         }
1621     }
1622   status=MagickTrue;
1623   if (size != 0)
1624     {
1625       layer_info=(LayerInfo *) NULL;
1626       number_layers=(short) ReadBlobShort(image);
1627
1628       if (number_layers < 0)
1629         {
1630           /*
1631             The first alpha channel in the merged result contains the
1632             transparency data for the merged result.
1633           */
1634           number_layers=MagickAbsoluteValue(number_layers);
1635           if (image->debug != MagickFalse)
1636             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1637               "  negative layer count corrected for");
1638           image->alpha_trait=BlendPixelTrait;
1639         }
1640
1641       /*
1642         We only need to know if the image has an alpha channel
1643       */
1644       if (skip_layers != MagickFalse)
1645         return(MagickTrue);
1646
1647       if (image->debug != MagickFalse)
1648         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1649           "  image contains %.20g layers",(double) number_layers);
1650
1651       if (number_layers == 0)
1652         ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1653           image->filename);
1654
1655       layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1656         sizeof(*layer_info));
1657       if (layer_info == (LayerInfo *) NULL)
1658         {
1659           if (image->debug != MagickFalse)
1660             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1661               "  allocation of LayerInfo failed");
1662           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1663             image->filename);
1664         }
1665       (void) memset(layer_info,0,(size_t) number_layers*
1666         sizeof(*layer_info));
1667
1668       for (i=0; i < number_layers; i++)
1669       {
1670         ssize_t
1671           x,
1672           y;
1673
1674         if (image->debug != MagickFalse)
1675           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1676             "  reading layer #%.20g",(double) i+1);
1677         layer_info[i].page.y=ReadBlobSignedLong(image);
1678         layer_info[i].page.x=ReadBlobSignedLong(image);
1679         y=ReadBlobSignedLong(image);
1680         x=ReadBlobSignedLong(image);
1681         layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1682         layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1683         layer_info[i].channels=ReadBlobShort(image);
1684         if (layer_info[i].channels > MaxPSDChannels)
1685           {
1686             layer_info=DestroyLayerInfo(layer_info,number_layers);
1687             ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1688               image->filename);
1689           }
1690         if (image->debug != MagickFalse)
1691           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1692             "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1693             (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1694             (double) layer_info[i].page.height,(double)
1695             layer_info[i].page.width,(double) layer_info[i].channels);
1696         for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1697         {
1698           layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1699           if ((layer_info[i].channel_info[j].type < -4) ||
1700               (layer_info[i].channel_info[j].type > 4))
1701             {
1702               layer_info=DestroyLayerInfo(layer_info,number_layers);
1703               ThrowBinaryException(CorruptImageError,"NoSuchImageChannel",
1704                 image->filename);
1705             }
1706           layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1707             image);
1708           if (image->debug != MagickFalse)
1709             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1710               "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1711               (double) layer_info[i].channel_info[j].type,
1712               (double) layer_info[i].channel_info[j].size);
1713         }
1714         if (CheckPSDChannels(psd_info,&layer_info[i]) == MagickFalse)
1715           {
1716             layer_info=DestroyLayerInfo(layer_info,number_layers);
1717             ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1718               image->filename);
1719           }
1720         count=ReadBlob(image,4,(unsigned char *) type);
1721         ReversePSDString(image,type,4);
1722         if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1723           {
1724             if (image->debug != MagickFalse)
1725               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1726                 "  layer type was %.4s instead of 8BIM", type);
1727             layer_info=DestroyLayerInfo(layer_info,number_layers);
1728             ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1729               image->filename);
1730           }
1731         count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1732         ReversePSDString(image,layer_info[i].blendkey,4);
1733         layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1734           ReadBlobByte(image));
1735         layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1736         layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1737         layer_info[i].visible=!(layer_info[i].flags & 0x02);
1738         if (image->debug != MagickFalse)
1739           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1740             "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1741             layer_info[i].blendkey,(double) layer_info[i].opacity,
1742             layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1743             layer_info[i].visible ? "true" : "false");
1744         (void) ReadBlobByte(image);  /* filler */
1745
1746         size=ReadBlobLong(image);
1747         if (size != 0)
1748           {
1749             MagickSizeType
1750               combined_length,
1751               length;
1752
1753             if (image->debug != MagickFalse)
1754               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1755                 "    layer contains additional info");
1756             length=ReadBlobLong(image);
1757             combined_length=length+4;
1758             if (length != 0)
1759               {
1760                 /*
1761                   Layer mask info.
1762                 */
1763                 layer_info[i].mask.page.y=ReadBlobSignedLong(image);
1764                 layer_info[i].mask.page.x=ReadBlobSignedLong(image);
1765                 layer_info[i].mask.page.height=(size_t) (ReadBlobSignedLong(image)-
1766                   layer_info[i].mask.page.y);
1767                 layer_info[i].mask.page.width=(size_t) (ReadBlobSignedLong(image)-
1768                   layer_info[i].mask.page.x);
1769                 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1770                   image);
1771                 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1772                 if (!(layer_info[i].mask.flags & 0x01))
1773                   {
1774                     layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1775                       layer_info[i].page.y;
1776                     layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1777                       layer_info[i].page.x;
1778                   }
1779                 if (image->debug != MagickFalse)
1780                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781                     "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1782                     (double) layer_info[i].mask.page.x,(double)
1783                     layer_info[i].mask.page.y,(double)
1784                     layer_info[i].mask.page.width,(double)
1785                     layer_info[i].mask.page.height,(double) ((MagickOffsetType)
1786                     length)-18);
1787                 /*
1788                   Skip over the rest of the layer mask information.
1789                 */
1790                 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1791                   {
1792                     layer_info=DestroyLayerInfo(layer_info,number_layers);
1793                     ThrowBinaryException(CorruptImageError,
1794                       "UnexpectedEndOfFile",image->filename);
1795                   }
1796               }
1797             length=ReadBlobLong(image);
1798             combined_length+=length+4;
1799             if (length != 0)
1800               {
1801                 /*
1802                   Layer blending ranges info.
1803                 */
1804                 if (image->debug != MagickFalse)
1805                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1806                     "      layer blending ranges: length=%.20g",(double)
1807                     ((MagickOffsetType) length));
1808                 if (DiscardBlobBytes(image,length) == MagickFalse)
1809                   {
1810                     layer_info=DestroyLayerInfo(layer_info,number_layers);
1811                     ThrowBinaryException(CorruptImageError,
1812                       "UnexpectedEndOfFile",image->filename);
1813                   }
1814               }
1815             /*
1816               Layer name.
1817             */
1818             length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
1819             combined_length+=length+1;
1820             if (length > 0)
1821               (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1822             layer_info[i].name[length]='\0';
1823             if (image->debug != MagickFalse)
1824               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1825                 "      layer name: %s",layer_info[i].name);
1826             if ((length % 4) != 0)
1827               {
1828                 length=4-(length % 4);
1829                 combined_length+=length;
1830                 /* Skip over the padding of the layer name */
1831                 if (DiscardBlobBytes(image,length) == MagickFalse)
1832                   {
1833                     layer_info=DestroyLayerInfo(layer_info,number_layers);
1834                     ThrowBinaryException(CorruptImageError,
1835                       "UnexpectedEndOfFile",image->filename);
1836                   }
1837               }
1838             length=(MagickSizeType) size-combined_length;
1839             if (length > 0)
1840               {
1841                 unsigned char
1842                   *info;
1843
1844                 if (length > GetBlobSize(image))
1845                   {
1846                     layer_info=DestroyLayerInfo(layer_info,number_layers);
1847                     ThrowBinaryException(CorruptImageError,
1848                       "InsufficientImageDataInFile",image->filename);
1849                   }
1850                 layer_info[i].info=AcquireStringInfo((const size_t) length);
1851                 info=GetStringInfoDatum(layer_info[i].info);
1852                 (void) ReadBlob(image,(const size_t) length,info);
1853               }
1854           }
1855       }
1856
1857       for (i=0; i < number_layers; i++)
1858       {
1859         if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0))
1860           {
1861             if (image->debug != MagickFalse)
1862               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1863                 "      layer data is empty");
1864             if (layer_info[i].info != (StringInfo *) NULL)
1865               layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1866             continue;
1867           }
1868
1869         /*
1870           Allocate layered image.
1871         */
1872         layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1873           layer_info[i].page.height,MagickFalse,exception);
1874         if (layer_info[i].image == (Image *) NULL)
1875           {
1876             layer_info=DestroyLayerInfo(layer_info,number_layers);
1877             if (image->debug != MagickFalse)
1878               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1879                 "  allocation of image for layer %.20g failed",(double) i);
1880             ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1881               image->filename);
1882           }
1883         if (layer_info[i].info != (StringInfo *) NULL)
1884           {
1885             (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
1886               layer_info[i].info,exception);
1887             layer_info[i].info=DestroyStringInfo(layer_info[i].info);
1888           }
1889       }
1890
1891       if (image_info->ping == MagickFalse)
1892         {
1893           for (i=0; i < number_layers; i++)
1894           {
1895             if (layer_info[i].image == (Image *) NULL)
1896               {
1897                 for (j=0; j < layer_info[i].channels; j++)
1898                 {
1899                   if (DiscardBlobBytes(image,(MagickSizeType)
1900                       layer_info[i].channel_info[j].size) == MagickFalse)
1901                     {
1902                       layer_info=DestroyLayerInfo(layer_info,number_layers);
1903                       ThrowBinaryException(CorruptImageError,
1904                         "UnexpectedEndOfFile",image->filename);
1905                     }
1906                 }
1907                 continue;
1908               }
1909
1910             if (image->debug != MagickFalse)
1911               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1912                 "  reading data for layer %.20g",(double) i);
1913
1914             status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
1915               exception);
1916             if (status == MagickFalse)
1917               break;
1918
1919             status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1920               number_layers);
1921             if (status == MagickFalse)
1922               break;
1923           }
1924         }
1925
1926       if (status != MagickFalse)
1927         {
1928           for (i=0; i < number_layers; i++)
1929           {
1930             if (layer_info[i].image == (Image *) NULL)
1931               {
1932                 for (j=i; j < number_layers - 1; j++)
1933                   layer_info[j] = layer_info[j+1];
1934                 number_layers--;
1935                 i--;
1936               }
1937           }
1938
1939           if (number_layers > 0)
1940             {
1941               for (i=0; i < number_layers; i++)
1942               {
1943                 if (i > 0)
1944                   layer_info[i].image->previous=layer_info[i-1].image;
1945                 if (i < (number_layers-1))
1946                   layer_info[i].image->next=layer_info[i+1].image;
1947                 layer_info[i].image->page=layer_info[i].page;
1948               }
1949               image->next=layer_info[0].image;
1950               layer_info[0].image->previous=image;
1951             }
1952           layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1953         }
1954       else
1955         layer_info=DestroyLayerInfo(layer_info,number_layers);
1956     }
1957
1958   return(status);
1959 }
1960
1961 ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
1962   const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
1963 {
1964   PolicyDomain
1965     domain;
1966
1967   PolicyRights
1968     rights;
1969
1970   domain=CoderPolicyDomain;
1971   rights=ReadPolicyRights;
1972   if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
1973     return(MagickTrue);
1974   return(ReadPSDLayersInternal(image,image_info,psd_info,MagickFalse,
1975     exception));
1976 }
1977
1978 static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1979   Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1980 {
1981   MagickOffsetType
1982     *sizes;
1983
1984   MagickBooleanType
1985     status;
1986
1987   PSDCompressionType
1988     compression;
1989
1990   register ssize_t
1991     i;
1992
1993   compression=(PSDCompressionType) ReadBlobMSBShort(image);
1994   image->compression=ConvertPSDCompression(compression);
1995
1996   if (compression != Raw && compression != RLE)
1997     {
1998       (void) ThrowMagickException(exception,GetMagickModule(),
1999         TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
2000       return(MagickFalse);
2001     }
2002
2003   sizes=(MagickOffsetType *) NULL;
2004   if (compression == RLE)
2005     {
2006       sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
2007       if (sizes == (MagickOffsetType *) NULL)
2008         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2009           image->filename);
2010     }
2011
2012   status=MagickTrue;
2013   for (i=0; i < (ssize_t) psd_info->channels; i++)
2014   {
2015     ssize_t
2016       type;
2017
2018     type=i;
2019     if ((type == 1) && (psd_info->channels == 2))
2020       type=-1;
2021
2022     if (compression == RLE)
2023       status=ReadPSDChannelRLE(image,psd_info,type,sizes+(i*image->rows),
2024         exception);
2025     else
2026       status=ReadPSDChannelRaw(image,psd_info->channels,type,exception);
2027
2028     if (status != MagickFalse)
2029       status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
2030
2031     if (status == MagickFalse)
2032       break;
2033   }
2034
2035   if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
2036     status=NegateCMYK(image,exception);
2037
2038   if (status != MagickFalse)
2039     status=CorrectPSDAlphaBlend(image_info,image,exception);
2040
2041   sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
2042
2043   return(status);
2044 }
2045
2046 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
2047 {
2048   Image
2049     *image;
2050
2051   MagickBooleanType
2052     has_merged_image,
2053     skip_layers;
2054
2055   MagickOffsetType
2056     offset;
2057
2058   MagickSizeType
2059     length;
2060
2061   MagickBooleanType
2062     status;
2063
2064   PSDInfo
2065     psd_info;
2066
2067   register ssize_t
2068     i;
2069
2070   ssize_t
2071     count;
2072
2073   StringInfo
2074     *profile;
2075
2076   /*
2077     Open image file.
2078   */
2079   assert(image_info != (const ImageInfo *) NULL);
2080   assert(image_info->signature == MagickCoreSignature);
2081   if (image_info->debug != MagickFalse)
2082     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2083       image_info->filename);
2084   assert(exception != (ExceptionInfo *) NULL);
2085   assert(exception->signature == MagickCoreSignature);
2086
2087   image=AcquireImage(image_info,exception);
2088   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2089   if (status == MagickFalse)
2090     {
2091       image=DestroyImageList(image);
2092       return((Image *) NULL);
2093     }
2094   /*
2095     Read image header.
2096   */
2097   image->endian=MSBEndian;
2098   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
2099   psd_info.version=ReadBlobMSBShort(image);
2100   if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
2101       ((psd_info.version != 1) && (psd_info.version != 2)))
2102     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2103   (void) ReadBlob(image,6,psd_info.reserved);
2104   psd_info.channels=ReadBlobMSBShort(image);
2105   if (psd_info.channels < 1)
2106     ThrowReaderException(CorruptImageError,"MissingImageChannel");
2107   if (psd_info.channels > MaxPSDChannels)
2108     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
2109   psd_info.rows=ReadBlobMSBLong(image);
2110   psd_info.columns=ReadBlobMSBLong(image);
2111   if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
2112       (psd_info.columns > 30000)))
2113     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2114   psd_info.depth=ReadBlobMSBShort(image);
2115   if ((psd_info.depth != 1) && (psd_info.depth != 8) &&
2116       (psd_info.depth != 16) && (psd_info.depth != 32))
2117     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2118   psd_info.mode=ReadBlobMSBShort(image);
2119   if ((psd_info.mode == IndexedMode) && (psd_info.channels > 3))
2120     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2121   if (image->debug != MagickFalse)
2122     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2123       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
2124       (double) psd_info.columns,(double) psd_info.rows,(double)
2125       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
2126       psd_info.mode));
2127   if (EOFBlob(image) != MagickFalse)
2128     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2129   /*
2130     Initialize image.
2131   */
2132   image->depth=psd_info.depth;
2133   image->columns=psd_info.columns;
2134   image->rows=psd_info.rows;
2135   status=SetImageExtent(image,image->columns,image->rows,exception);
2136   if (status == MagickFalse)
2137     return(DestroyImageList(image));
2138   status=ResetImagePixels(image,exception);
2139   if (status == MagickFalse)
2140     return(DestroyImageList(image));
2141   psd_info.min_channels=3;
2142   if (psd_info.mode == LabMode)
2143     SetImageColorspace(image,LabColorspace,exception);
2144   if (psd_info.mode == CMYKMode)
2145     {
2146       psd_info.min_channels=4;
2147       SetImageColorspace(image,CMYKColorspace,exception);
2148       if (psd_info.channels > 4)
2149         SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2150     }
2151   else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
2152            (psd_info.mode == DuotoneMode))
2153     {
2154       if (psd_info.depth != 32)
2155         {
2156           status=AcquireImageColormap(image,psd_info.depth < 16 ? 256 : 65536,
2157             exception);
2158           if (status == MagickFalse)
2159             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2160           if (image->debug != MagickFalse)
2161             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2162               "  Image colormap allocated");
2163         }
2164       psd_info.min_channels=1;
2165       SetImageColorspace(image,GRAYColorspace,exception);
2166       if (psd_info.channels > 1)
2167         SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2168     }
2169   else
2170     if (psd_info.channels > 3)
2171       SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2172   if (psd_info.channels < psd_info.min_channels)
2173     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2174   /*
2175     Read PSD raster colormap only present for indexed and duotone images.
2176   */
2177   length=ReadBlobMSBLong(image);
2178   if ((psd_info.mode == IndexedMode) && (length < 3))
2179     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2180   if (length != 0)
2181     {
2182       if (image->debug != MagickFalse)
2183         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2184           "  reading colormap");
2185       if ((psd_info.mode == DuotoneMode) || (psd_info.depth == 32))
2186         {
2187           /*
2188             Duotone image data;  the format of this data is undocumented.
2189             32 bits per pixel;  the colormap is ignored.
2190           */
2191           (void) SeekBlob(image,(const MagickOffsetType) length,SEEK_CUR);
2192         }
2193       else
2194         {
2195           size_t
2196             number_colors;
2197
2198           /*
2199             Read PSD raster colormap.
2200           */
2201           number_colors=length/3;
2202           if (number_colors > 65536)
2203             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2204           if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2205             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2206           for (i=0; i < (ssize_t) image->colors; i++)
2207             image->colormap[i].red=ScaleCharToQuantum((unsigned char)
2208               ReadBlobByte(image));
2209           for (i=0; i < (ssize_t) image->colors; i++)
2210             image->colormap[i].green=ScaleCharToQuantum((unsigned char)
2211               ReadBlobByte(image));
2212           for (i=0; i < (ssize_t) image->colors; i++)
2213             image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
2214               ReadBlobByte(image));
2215           image->alpha_trait=UndefinedPixelTrait;
2216         }
2217     }
2218   if ((image->depth == 1) && (image->storage_class != PseudoClass))
2219     ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2220   has_merged_image=MagickTrue;
2221   profile=(StringInfo *) NULL;
2222   length=ReadBlobMSBLong(image);
2223   if (length != 0)
2224     {
2225       unsigned char
2226         *blocks;
2227
2228       /*
2229         Image resources block.
2230       */
2231       if (image->debug != MagickFalse)
2232         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233           "  reading image resource blocks - %.20g bytes",(double)
2234           ((MagickOffsetType) length));
2235       if (length > GetBlobSize(image))
2236         ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2237       blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2238         sizeof(*blocks));
2239       if (blocks == (unsigned char *) NULL)
2240         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2241       count=ReadBlob(image,(size_t) length,blocks);
2242       if ((count != (ssize_t) length) || (length < 4) ||
2243           (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2244         {
2245           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2246           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2247         }
2248       profile=ParseImageResourceBlocks(image,blocks,(size_t) length,
2249         &has_merged_image,exception);
2250       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2251     }
2252   /*
2253     Layer and mask block.
2254   */
2255   length=GetPSDSize(&psd_info,image);
2256   if (length == 8)
2257     {
2258       length=ReadBlobMSBLong(image);
2259       length=ReadBlobMSBLong(image);
2260     }
2261   offset=TellBlob(image);
2262   skip_layers=MagickFalse;
2263   if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2264       (has_merged_image != MagickFalse))
2265     {
2266       if (image->debug != MagickFalse)
2267         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2268           "  read composite only");
2269       skip_layers=MagickTrue;
2270     }
2271   if (length == 0)
2272     {
2273       if (image->debug != MagickFalse)
2274         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2275           "  image has no layers");
2276     }
2277   else
2278     {
2279       if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,
2280             exception) != MagickTrue)
2281         {
2282           if (profile != (StringInfo *) NULL)
2283             profile=DestroyStringInfo(profile);
2284           (void) CloseBlob(image);
2285           image=DestroyImageList(image);
2286           return((Image *) NULL);
2287         }
2288
2289       /*
2290          Skip the rest of the layer and mask information.
2291       */
2292       SeekBlob(image,offset+length,SEEK_SET);
2293     }
2294   /*
2295     If we are only "pinging" the image, then we're done - so return.
2296   */
2297   if (EOFBlob(image) != MagickFalse)
2298     {
2299       if (profile != (StringInfo *) NULL)
2300         profile=DestroyStringInfo(profile);
2301       ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
2302     }
2303   if (image_info->ping != MagickFalse)
2304     {
2305       if (profile != (StringInfo *) NULL)
2306         profile=DestroyStringInfo(profile);
2307       (void) CloseBlob(image);
2308       return(GetFirstImageInList(image));
2309     }
2310   /*
2311     Read the precombined layer, present for PSD < 4 compatibility.
2312   */
2313   if (image->debug != MagickFalse)
2314     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2315       "  reading the precombined layer");
2316   if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2317     has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2318       &psd_info,exception);
2319   if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
2320       (length != 0))
2321     {
2322       SeekBlob(image,offset,SEEK_SET);
2323       status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
2324         exception);
2325       if (status != MagickTrue)
2326         {
2327           if (profile != (StringInfo *) NULL)
2328             profile=DestroyStringInfo(profile);
2329           (void) CloseBlob(image);
2330           image=DestroyImageList(image);
2331           return((Image *) NULL);
2332         }
2333     }
2334   if (has_merged_image == MagickFalse)
2335     {
2336       Image
2337         *merged;
2338
2339       if (GetImageListLength(image) == 1)
2340         {
2341           if (profile != (StringInfo *) NULL)
2342             profile=DestroyStringInfo(profile);
2343           ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2344         }
2345       SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
2346       image->background_color.alpha=TransparentAlpha;
2347       image->background_color.alpha_trait=BlendPixelTrait;
2348       merged=MergeImageLayers(image,FlattenLayer,exception);
2349       ReplaceImageInList(&image,merged);
2350     }
2351   if (profile != (StringInfo *) NULL)
2352     {
2353       (void) SetImageProfile(image,GetStringInfoName(profile),profile,
2354         exception);
2355       profile=DestroyStringInfo(profile);
2356     }
2357   (void) CloseBlob(image);
2358   return(GetFirstImageInList(image));
2359 }
2360 \f
2361 /*
2362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2363 %                                                                             %
2364 %                                                                             %
2365 %                                                                             %
2366 %   R e g i s t e r P S D I m a g e                                           %
2367 %                                                                             %
2368 %                                                                             %
2369 %                                                                             %
2370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2371 %
2372 %  RegisterPSDImage() adds properties for the PSD image format to
2373 %  the list of supported formats.  The properties include the image format
2374 %  tag, a method to read and/or write the format, whether the format
2375 %  supports the saving of more than one frame to the same file or blob,
2376 %  whether the format supports native in-memory I/O, and a brief
2377 %  description of the format.
2378 %
2379 %  The format of the RegisterPSDImage method is:
2380 %
2381 %      size_t RegisterPSDImage(void)
2382 %
2383 */
2384 ModuleExport size_t RegisterPSDImage(void)
2385 {
2386   MagickInfo
2387     *entry;
2388
2389   entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2390   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2391   entry->encoder=(EncodeImageHandler *) WritePSDImage;
2392   entry->magick=(IsImageFormatHandler *) IsPSD;
2393   entry->flags|=CoderDecoderSeekableStreamFlag;
2394   entry->flags|=CoderEncoderSeekableStreamFlag;
2395   (void) RegisterMagickInfo(entry);
2396   entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2397   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2398   entry->encoder=(EncodeImageHandler *) WritePSDImage;
2399   entry->magick=(IsImageFormatHandler *) IsPSD;
2400   entry->flags|=CoderDecoderSeekableStreamFlag;
2401   entry->flags|=CoderEncoderSeekableStreamFlag;
2402   (void) RegisterMagickInfo(entry);
2403   return(MagickImageCoderSignature);
2404 }
2405 \f
2406 /*
2407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408 %                                                                             %
2409 %                                                                             %
2410 %                                                                             %
2411 %   U n r e g i s t e r P S D I m a g e                                       %
2412 %                                                                             %
2413 %                                                                             %
2414 %                                                                             %
2415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416 %
2417 %  UnregisterPSDImage() removes format registrations made by the
2418 %  PSD module from the list of supported formats.
2419 %
2420 %  The format of the UnregisterPSDImage method is:
2421 %
2422 %      UnregisterPSDImage(void)
2423 %
2424 */
2425 ModuleExport void UnregisterPSDImage(void)
2426 {
2427   (void) UnregisterMagickInfo("PSB");
2428   (void) UnregisterMagickInfo("PSD");
2429 }
2430 \f
2431 /*
2432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433 %                                                                             %
2434 %                                                                             %
2435 %                                                                             %
2436 %   W r i t e P S D I m a g e                                                 %
2437 %                                                                             %
2438 %                                                                             %
2439 %                                                                             %
2440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2441 %
2442 %  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2443 %
2444 %  The format of the WritePSDImage method is:
2445 %
2446 %      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2447 %        ExceptionInfo *exception)
2448 %
2449 %  A description of each parameter follows.
2450 %
2451 %    o image_info: the image info.
2452 %
2453 %    o image:  The image.
2454 %
2455 %    o exception: return any errors or warnings in this structure.
2456 %
2457 */
2458
2459 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2460   const size_t offset)
2461 {
2462   if (psd_info->version == 1)
2463     return(WriteBlobMSBShort(image,(unsigned short) offset));
2464   return(WriteBlobMSBLong(image,(unsigned int) offset));
2465 }
2466
2467 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2468   const MagickSizeType size,const MagickSizeType offset)
2469 {
2470   MagickSizeType
2471     current_offset;
2472
2473   ssize_t
2474     result;
2475
2476   current_offset=TellBlob(image);
2477   SeekBlob(image,offset,SEEK_SET);
2478   if (psd_info->version == 1)
2479     result=WriteBlobMSBShort(image,(unsigned short) size);
2480   else
2481     result=WriteBlobMSBLong(image,(unsigned int) size);
2482   SeekBlob(image,current_offset,SEEK_SET);
2483   return(result);
2484 }
2485
2486 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2487   const MagickSizeType size)
2488 {
2489   if (psd_info->version == 1)
2490     return(WriteBlobLong(image,(unsigned int) size));
2491   return(WriteBlobLongLong(image,size));
2492 }
2493
2494 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2495   const MagickSizeType size,const MagickSizeType offset)
2496 {
2497   MagickSizeType
2498     current_offset;
2499
2500   ssize_t
2501     result;
2502
2503   current_offset=TellBlob(image);
2504   SeekBlob(image,offset,SEEK_SET);
2505   result=SetPSDSize(psd_info, image, size);
2506   SeekBlob(image,current_offset,SEEK_SET);
2507   return(result);
2508 }
2509
2510 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2511   const unsigned char *pixels,unsigned char *compact_pixels,
2512   ExceptionInfo *exception)
2513 {
2514   int
2515     count;
2516
2517   register ssize_t
2518     i,
2519     j;
2520
2521   register unsigned char
2522     *q;
2523
2524   unsigned char
2525     *packbits;
2526
2527   /*
2528     Compress pixels with Packbits encoding.
2529   */
2530   assert(image != (Image *) NULL);
2531   assert(image->signature == MagickCoreSignature);
2532   if (image->debug != MagickFalse)
2533     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2534   assert(pixels != (unsigned char *) NULL);
2535   assert(compact_pixels != (unsigned char *) NULL);
2536   packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2537   if (packbits == (unsigned char *) NULL)
2538     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2539       image->filename);
2540   q=compact_pixels;
2541   for (i=(ssize_t) length; i != 0; )
2542   {
2543     switch (i)
2544     {
2545       case 1:
2546       {
2547         i--;
2548         *q++=(unsigned char) 0;
2549         *q++=(*pixels);
2550         break;
2551       }
2552       case 2:
2553       {
2554         i-=2;
2555         *q++=(unsigned char) 1;
2556         *q++=(*pixels);
2557         *q++=pixels[1];
2558         break;
2559       }
2560       case 3:
2561       {
2562         i-=3;
2563         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2564           {
2565             *q++=(unsigned char) ((256-3)+1);
2566             *q++=(*pixels);
2567             break;
2568           }
2569         *q++=(unsigned char) 2;
2570         *q++=(*pixels);
2571         *q++=pixels[1];
2572         *q++=pixels[2];
2573         break;
2574       }
2575       default:
2576       {
2577         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2578           {
2579             /*
2580               Packed run.
2581             */
2582             count=3;
2583             while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2584             {
2585               count++;
2586               if (count >= 127)
2587                 break;
2588             }
2589             i-=count;
2590             *q++=(unsigned char) ((256-count)+1);
2591             *q++=(*pixels);
2592             pixels+=count;
2593             break;
2594           }
2595         /*
2596           Literal run.
2597         */
2598         count=0;
2599         while ((*(pixels+count) != *(pixels+count+1)) ||
2600                (*(pixels+count+1) != *(pixels+count+2)))
2601         {
2602           packbits[count+1]=pixels[count];
2603           count++;
2604           if (((ssize_t) count >= (i-3)) || (count >= 127))
2605             break;
2606         }
2607         i-=count;
2608         *packbits=(unsigned char) (count-1);
2609         for (j=0; j <= (ssize_t) count; j++)
2610           *q++=packbits[j];
2611         pixels+=count;
2612         break;
2613       }
2614     }
2615   }
2616   *q++=(unsigned char) 128;  /* EOD marker */
2617   packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2618   return((size_t) (q-compact_pixels));
2619 }
2620
2621 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
2622   const Image *next_image,const CompressionType compression,
2623   const ssize_t channels)
2624 {
2625   size_t
2626     length;
2627
2628   ssize_t
2629     i,
2630     y;
2631
2632   if (compression == RLECompression)
2633     {
2634       length=WriteBlobShort(image,RLE);
2635       for (i=0; i < channels; i++)
2636         for (y=0; y < (ssize_t) next_image->rows; y++)
2637           length+=SetPSDOffset(psd_info,image,0);
2638     }
2639 #ifdef MAGICKCORE_ZLIB_DELEGATE
2640   else if (compression == ZipCompression)
2641     length=WriteBlobShort(image,ZipWithoutPrediction);
2642 #endif
2643   else
2644     length=WriteBlobShort(image,Raw);
2645   return(length);
2646 }
2647
2648 static size_t WritePSDChannel(const PSDInfo *psd_info,
2649   const ImageInfo *image_info,Image *image,Image *next_image,
2650   const QuantumType quantum_type, unsigned char *compact_pixels,
2651   MagickOffsetType size_offset,const MagickBooleanType separate,
2652   const CompressionType compression,ExceptionInfo *exception)
2653 {
2654   int
2655     y;
2656
2657   MagickBooleanType
2658     monochrome;
2659
2660   QuantumInfo
2661     *quantum_info;
2662
2663   register const Quantum
2664     *p;
2665
2666   register ssize_t
2667     i;
2668
2669   size_t
2670     count,
2671     length;
2672
2673   unsigned char
2674     *pixels;
2675
2676 #ifdef MAGICKCORE_ZLIB_DELEGATE
2677
2678 #define CHUNK 16384
2679
2680   int
2681     flush,
2682     level;
2683
2684   unsigned char
2685     *compressed_pixels;
2686
2687   z_stream
2688     stream;
2689
2690   compressed_pixels=(unsigned char *) NULL;
2691   flush=Z_NO_FLUSH;
2692 #endif
2693   count=0;
2694   if (separate != MagickFalse)
2695     {
2696       size_offset=TellBlob(image)+2;
2697       count+=WriteCompressionStart(psd_info,image,next_image,compression,1);
2698     }
2699   if (next_image->depth > 8)
2700     next_image->depth=16;
2701   monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2702     MagickTrue : MagickFalse;
2703   quantum_info=AcquireQuantumInfo(image_info,next_image);
2704   if (quantum_info == (QuantumInfo *) NULL)
2705     return(0);
2706   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2707 #ifdef MAGICKCORE_ZLIB_DELEGATE
2708   if (compression == ZipCompression)
2709     {
2710       compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
2711         sizeof(*compressed_pixels));
2712       if (compressed_pixels == (unsigned char *) NULL)
2713         {
2714           quantum_info=DestroyQuantumInfo(quantum_info);
2715           return(0);
2716         }
2717       memset(&stream,0,sizeof(stream));
2718       stream.data_type=Z_BINARY;
2719       level=Z_DEFAULT_COMPRESSION;
2720       if ((image_info->quality > 0 && image_info->quality < 10))
2721         level=(int) image_info->quality;
2722       if (deflateInit(&stream,level) != Z_OK)
2723         {
2724           quantum_info=DestroyQuantumInfo(quantum_info);
2725           return(0);
2726         }
2727     }
2728 #endif
2729   for (y=0; y < (ssize_t) next_image->rows; y++)
2730   {
2731     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2732     if (p == (const Quantum *) NULL)
2733       break;
2734     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2735       quantum_type,pixels,exception);
2736     if (monochrome != MagickFalse)
2737       for (i=0; i < (ssize_t) length; i++)
2738         pixels[i]=(~pixels[i]);
2739     if (compression == RLECompression)
2740       {
2741         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2742           exception);
2743         count+=WriteBlob(image,length,compact_pixels);
2744         size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
2745       }
2746 #ifdef MAGICKCORE_ZLIB_DELEGATE
2747     else if (compression == ZipCompression)
2748       {
2749         stream.avail_in=(uInt) length;
2750         stream.next_in=(Bytef *) pixels;
2751         if (y == (ssize_t) next_image->rows-1)
2752           flush=Z_FINISH;
2753         do {
2754             stream.avail_out=(uInt) CHUNK;
2755             stream.next_out=(Bytef *) compressed_pixels;
2756             if (deflate(&stream,flush) == Z_STREAM_ERROR)
2757               break;
2758             length=(size_t) CHUNK-stream.avail_out;
2759             if (length > 0)
2760               count+=WriteBlob(image,length,compressed_pixels);
2761         } while (stream.avail_out == 0);
2762       }
2763 #endif
2764     else
2765       count+=WriteBlob(image,length,pixels);
2766   }
2767 #ifdef MAGICKCORE_ZLIB_DELEGATE
2768   if (compression == ZipCompression)
2769     {
2770       (void) deflateEnd(&stream);
2771       compressed_pixels=(unsigned char *) RelinquishMagickMemory(
2772         compressed_pixels);
2773     }
2774 #endif
2775   quantum_info=DestroyQuantumInfo(quantum_info);
2776   return(count);
2777 }
2778
2779 static unsigned char *AcquireCompactPixels(const Image *image,
2780   ExceptionInfo *exception)
2781 {
2782   size_t
2783     packet_size;
2784
2785   unsigned char
2786     *compact_pixels;
2787
2788   packet_size=image->depth > 8UL ? 2UL : 1UL;
2789   compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
2790     image->columns)+1,packet_size*sizeof(*compact_pixels));
2791   if (compact_pixels == (unsigned char *) NULL)
2792     {
2793       (void) ThrowMagickException(exception,GetMagickModule(),
2794         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2795     }
2796   return(compact_pixels);
2797 }
2798
2799 static size_t WritePSDChannels(const PSDInfo *psd_info,
2800   const ImageInfo *image_info,Image *image,Image *next_image,
2801   MagickOffsetType size_offset,const MagickBooleanType separate,
2802   ExceptionInfo *exception)
2803 {
2804   CompressionType
2805     compression;
2806
2807   Image
2808     *mask;
2809
2810   MagickOffsetType
2811     rows_offset;
2812
2813   size_t
2814     channels,
2815     count,
2816     length,
2817     offset_length;
2818
2819   unsigned char
2820     *compact_pixels;
2821
2822   count=0;
2823   offset_length=0;
2824   rows_offset=0;
2825   compact_pixels=(unsigned char *) NULL;
2826   compression=next_image->compression;
2827   if (image_info->compression != UndefinedCompression)
2828     compression=image_info->compression;
2829   if (compression == RLECompression)
2830     {
2831       compact_pixels=AcquireCompactPixels(next_image,exception);
2832       if (compact_pixels == (unsigned char *) NULL)
2833         return(0);
2834     }
2835   channels=1;
2836   if (separate == MagickFalse)
2837     {
2838       if (next_image->storage_class != PseudoClass)
2839         {
2840           if (IsImageGray(next_image) == MagickFalse)
2841             channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
2842           if (next_image->alpha_trait != UndefinedPixelTrait)
2843             channels++;
2844         }
2845       rows_offset=TellBlob(image)+2;
2846       count+=WriteCompressionStart(psd_info,image,next_image,compression,
2847         channels);
2848       offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
2849     }
2850   size_offset+=2;
2851   if (next_image->storage_class == PseudoClass)
2852     {
2853       length=WritePSDChannel(psd_info,image_info,image,next_image,
2854         IndexQuantum,compact_pixels,rows_offset,separate,compression,
2855         exception);
2856       if (separate != MagickFalse)
2857         size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2858       else
2859         rows_offset+=offset_length;
2860       count+=length;
2861     }
2862   else
2863     {
2864       if (IsImageGray(next_image) != MagickFalse)
2865         {
2866           length=WritePSDChannel(psd_info,image_info,image,next_image,
2867             GrayQuantum,compact_pixels,rows_offset,separate,compression,
2868             exception);
2869           if (separate != MagickFalse)
2870             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2871           else
2872             rows_offset+=offset_length;
2873           count+=length;
2874         }
2875       else
2876         {
2877           if (next_image->colorspace == CMYKColorspace)
2878             (void) NegateCMYK(next_image,exception);
2879
2880           length=WritePSDChannel(psd_info,image_info,image,next_image,
2881             RedQuantum,compact_pixels,rows_offset,separate,compression,
2882             exception);
2883           if (separate != MagickFalse)
2884             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2885           else
2886             rows_offset+=offset_length;
2887           count+=length;
2888
2889           length=WritePSDChannel(psd_info,image_info,image,next_image,
2890             GreenQuantum,compact_pixels,rows_offset,separate,compression,
2891             exception);
2892           if (separate != MagickFalse)
2893             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2894           else
2895             rows_offset+=offset_length;
2896           count+=length;
2897
2898           length=WritePSDChannel(psd_info,image_info,image,next_image,
2899             BlueQuantum,compact_pixels,rows_offset,separate,compression,
2900             exception);
2901           if (separate != MagickFalse)
2902             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2903           else
2904             rows_offset+=offset_length;
2905           count+=length;
2906
2907           if (next_image->colorspace == CMYKColorspace)
2908             {
2909               length=WritePSDChannel(psd_info,image_info,image,next_image,
2910                 BlackQuantum,compact_pixels,rows_offset,separate,compression,
2911                 exception);
2912               if (separate != MagickFalse)
2913                 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
2914               else
2915                 rows_offset+=offset_length;
2916               count+=length;
2917             }
2918         }
2919       if (next_image->alpha_trait != UndefinedPixelTrait)
2920         {
2921           length=WritePSDChannel(psd_info,image_info,image,next_image,
2922             AlphaQuantum,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   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2932   if (next_image->colorspace == CMYKColorspace)
2933     (void) NegateCMYK(next_image,exception);
2934   if (separate != MagickFalse)
2935     {
2936       const char
2937         *property;
2938
2939       property=GetImageArtifact(next_image,"psd:opacity-mask");
2940       if (property != (const char *) NULL)
2941         {
2942           mask=(Image *) GetImageRegistry(ImageRegistryType,property,
2943             exception);
2944           if (mask != (Image *) NULL)
2945             {
2946               if (compression == RLECompression)
2947                 {
2948                   compact_pixels=AcquireCompactPixels(mask,exception);
2949                   if (compact_pixels == (unsigned char *) NULL)
2950                     return(0);
2951                 }
2952               length=WritePSDChannel(psd_info,image_info,image,mask,
2953                 RedQuantum,compact_pixels,rows_offset,MagickTrue,compression,
2954                 exception);
2955               (void) WritePSDSize(psd_info,image,length,size_offset);
2956               count+=length;
2957               compact_pixels=(unsigned char *) RelinquishMagickMemory(
2958                 compact_pixels);
2959             }
2960         }
2961     }
2962   return(count);
2963 }
2964
2965 static size_t WritePascalString(Image *image,const char *value,size_t padding)
2966 {
2967   size_t
2968     count,
2969     length;
2970
2971   register ssize_t
2972     i;
2973
2974   /*
2975     Max length is 255.
2976   */
2977   count=0;
2978   length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
2979   if (length ==  0)
2980     count+=WriteBlobByte(image,0);
2981   else
2982     {
2983       count+=WriteBlobByte(image,(unsigned char) length);
2984       count+=WriteBlob(image,length,(const unsigned char *) value);
2985     }
2986   length++;
2987   if ((length % padding) == 0)
2988     return(count);
2989   for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
2990     count+=WriteBlobByte(image,0);
2991   return(count);
2992 }
2993
2994 static void WriteResolutionResourceBlock(Image *image)
2995 {
2996   double
2997     x_resolution,
2998     y_resolution;
2999
3000   unsigned short
3001     units;
3002
3003   if (image->units == PixelsPerCentimeterResolution)
3004     {
3005       x_resolution=2.54*65536.0*image->resolution.x+0.5;
3006       y_resolution=2.54*65536.0*image->resolution.y+0.5;
3007       units=2;
3008     }
3009   else
3010     {
3011       x_resolution=65536.0*image->resolution.x+0.5;
3012       y_resolution=65536.0*image->resolution.y+0.5;
3013       units=1;
3014     }
3015   (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3016   (void) WriteBlobMSBShort(image,0x03ED);
3017   (void) WriteBlobMSBShort(image,0);
3018   (void) WriteBlobMSBLong(image,16); /* resource size */
3019   (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
3020   (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
3021   (void) WriteBlobMSBShort(image,units); /* width unit */
3022   (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
3023   (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
3024   (void) WriteBlobMSBShort(image,units); /* height unit */
3025 }
3026
3027 static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
3028   const signed short channel)
3029 {
3030   size_t
3031     count;
3032
3033   count=(size_t) WriteBlobShort(image,channel);
3034   count+=SetPSDSize(psd_info,image,0);
3035   return(count);
3036 }
3037
3038 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
3039 {
3040   register const unsigned char
3041     *p;
3042
3043   size_t
3044     length;
3045
3046   unsigned char
3047     *datum;
3048
3049   unsigned int
3050     count,
3051     long_sans;
3052
3053   unsigned short
3054     id,
3055     short_sans;
3056
3057   length=GetStringInfoLength(bim_profile);
3058   if (length < 16)
3059     return;
3060   datum=GetStringInfoDatum(bim_profile);
3061   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3062   {
3063     register unsigned char
3064       *q;
3065
3066     q=(unsigned char *) p;
3067     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3068       break;
3069     p=PushLongPixel(MSBEndian,p,&long_sans);
3070     p=PushShortPixel(MSBEndian,p,&id);
3071     p=PushShortPixel(MSBEndian,p,&short_sans);
3072     p=PushLongPixel(MSBEndian,p,&count);
3073     if (id == 0x0000040f)
3074       {
3075         ssize_t
3076           quantum;
3077
3078         quantum=PSDQuantum(count)+12;
3079         if ((quantum >= 12) && (quantum < (ssize_t) length))
3080           {
3081             if ((q+quantum < (datum+length-16)))
3082               (void) memmove(q,q+quantum,length-quantum-(q-datum));
3083             SetStringInfoLength(bim_profile,length-quantum);
3084           }
3085         break;
3086       }
3087     p+=count;
3088     if ((count & 0x01) != 0)
3089       p++;
3090   }
3091 }
3092
3093 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
3094 {
3095   register const unsigned char
3096     *p;
3097
3098   size_t
3099     length;
3100
3101   unsigned char
3102     *datum;
3103
3104   unsigned int
3105     count,
3106     long_sans;
3107
3108   unsigned short
3109     id,
3110     short_sans;
3111
3112   length=GetStringInfoLength(bim_profile);
3113   if (length < 16)
3114     return;
3115   datum=GetStringInfoDatum(bim_profile);
3116   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3117   {
3118     register unsigned char
3119       *q;
3120
3121     ssize_t
3122       cnt;
3123
3124     q=(unsigned char *) p;
3125     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3126       return;
3127     p=PushLongPixel(MSBEndian,p,&long_sans);
3128     p=PushShortPixel(MSBEndian,p,&id);
3129     p=PushShortPixel(MSBEndian,p,&short_sans);
3130     p=PushLongPixel(MSBEndian,p,&count);
3131     cnt=PSDQuantum(count);
3132     if (cnt < 0)
3133       return;
3134     if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)) &&
3135         ((ssize_t) length-(cnt+12)-(q-datum)) > 0)
3136       {
3137         (void) memmove(q,q+cnt+12,length-(cnt+12)-(q-datum));
3138         SetStringInfoLength(bim_profile,length-(cnt+12));
3139         break;
3140       }
3141     p+=count;
3142     if ((count & 0x01) != 0)
3143       p++;
3144   }
3145 }
3146
3147 static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
3148   Image *image,ExceptionInfo *exception)
3149 {
3150 #define PSDKeySize 5
3151 #define PSDAllowedLength 36
3152
3153   char
3154     key[PSDKeySize];
3155
3156   /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
3157   const char
3158     allowed[PSDAllowedLength][PSDKeySize] = {
3159       "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
3160       "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
3161       "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
3162       "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
3163     },
3164     *option;
3165
3166   const StringInfo
3167     *info;
3168
3169   MagickBooleanType
3170     found;
3171
3172   register size_t
3173     i;
3174
3175   size_t
3176     remaining_length,
3177     length;
3178
3179   StringInfo
3180     *profile;
3181
3182   unsigned char
3183     *p;
3184
3185   unsigned int
3186     size;
3187
3188   info=GetImageProfile(image,"psd:additional-info");
3189   if (info == (const StringInfo *) NULL)
3190     return((const StringInfo *) NULL);
3191   option=GetImageOption(image_info,"psd:additional-info");
3192   if (LocaleCompare(option,"all") == 0)
3193     return(info);
3194   if (LocaleCompare(option,"selective") != 0)
3195     {
3196       profile=RemoveImageProfile(image,"psd:additional-info");
3197       return(DestroyStringInfo(profile));
3198     }
3199   length=GetStringInfoLength(info);
3200   p=GetStringInfoDatum(info);
3201   remaining_length=length;
3202   length=0;
3203   while (remaining_length >= 12)
3204   {
3205     /* skip over signature */
3206     p+=4;
3207     key[0]=(*p++);
3208     key[1]=(*p++);
3209     key[2]=(*p++);
3210     key[3]=(*p++);
3211     key[4]='\0';
3212     size=(unsigned int) (*p++) << 24;
3213     size|=(unsigned int) (*p++) << 16;
3214     size|=(unsigned int) (*p++) << 8;
3215     size|=(unsigned int) (*p++);
3216     size=size & 0xffffffff;
3217     remaining_length-=12;
3218     if ((size_t) size > remaining_length)
3219       return((const StringInfo *) NULL);
3220     found=MagickFalse;
3221     for (i=0; i < PSDAllowedLength; i++)
3222     {
3223       if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3224         continue;
3225
3226       found=MagickTrue;
3227       break;
3228     }
3229     remaining_length-=(size_t) size;
3230     if (found == MagickFalse)
3231       {
3232         if (remaining_length > 0)
3233           p=(unsigned char *) memmove(p-12,p+size,remaining_length);
3234         continue;
3235       }
3236     length+=(size_t) size+12;
3237     p+=size;
3238   }
3239   profile=RemoveImageProfile(image,"psd:additional-info");
3240   if (length == 0)
3241     return(DestroyStringInfo(profile));
3242   SetStringInfoLength(profile,(const size_t) length);
3243   SetImageProfile(image,"psd:additional-info",info,exception);
3244   return(profile);
3245 }
3246
3247 static MagickBooleanType WritePSDLayersInternal(Image *image,
3248   const ImageInfo *image_info,const PSDInfo *psd_info,size_t *layers_size,
3249   ExceptionInfo *exception)
3250 {
3251   char
3252     layer_name[MagickPathExtent];
3253
3254   const char
3255     *property;
3256
3257   const StringInfo
3258     *info;
3259
3260   Image
3261     *base_image,
3262     *next_image;
3263
3264   MagickBooleanType
3265     status;
3266
3267   MagickOffsetType
3268     *layer_size_offsets,
3269     size_offset;
3270
3271   register ssize_t
3272     i;
3273
3274   size_t
3275     layer_count,
3276     layer_index,
3277     length,
3278     name_length,
3279     rounded_size,
3280     size;
3281
3282   status=MagickTrue;
3283   base_image=GetNextImageInList(image);
3284   if (base_image == (Image *) NULL)
3285     base_image=image;
3286   size=0;
3287   size_offset=TellBlob(image);
3288   SetPSDSize(psd_info,image,0);
3289   layer_count=0;
3290   for (next_image=base_image; next_image != NULL; )
3291   {
3292     layer_count++;
3293     next_image=GetNextImageInList(next_image);
3294   }
3295   if (image->alpha_trait != UndefinedPixelTrait)
3296     size+=WriteBlobShort(image,-(unsigned short) layer_count);
3297   else
3298     size+=WriteBlobShort(image,(unsigned short) layer_count);
3299   layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3300     (size_t) layer_count,sizeof(MagickOffsetType));
3301   if (layer_size_offsets == (MagickOffsetType *) NULL)
3302     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3303   layer_index=0;
3304   for (next_image=base_image; next_image != NULL; )
3305   {
3306     Image
3307       *mask;
3308
3309     unsigned char
3310       default_color;
3311
3312     unsigned short
3313       channels,
3314       total_channels;
3315
3316     mask=(Image *) NULL;
3317     property=GetImageArtifact(next_image,"psd:opacity-mask");
3318     default_color=0;
3319     if (property != (const char *) NULL)
3320       {
3321         mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3322         default_color=strlen(property) == 9 ? 255 : 0;
3323       }
3324     size+=WriteBlobSignedLong(image,(signed int) next_image->page.y);
3325     size+=WriteBlobSignedLong(image,(signed int) next_image->page.x);
3326     size+=WriteBlobSignedLong(image,(signed int) (next_image->page.y+
3327       next_image->rows));
3328     size+=WriteBlobSignedLong(image,(signed int) (next_image->page.x+
3329       next_image->columns));
3330     channels=1U;
3331     if ((next_image->storage_class != PseudoClass) &&
3332         (IsImageGray(next_image) == MagickFalse))
3333       channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
3334     total_channels=channels;
3335     if (next_image->alpha_trait != UndefinedPixelTrait)
3336       total_channels++;
3337     if (mask != (Image *) NULL)
3338       total_channels++;
3339     size+=WriteBlobShort(image,total_channels);
3340     layer_size_offsets[layer_index++]=TellBlob(image);
3341     for (i=0; i < (ssize_t) channels; i++)
3342       size+=WriteChannelSize(psd_info,image,(signed short) i);
3343     if (next_image->alpha_trait != UndefinedPixelTrait)
3344       size+=WriteChannelSize(psd_info,image,-1);
3345     if (mask != (Image *) NULL)
3346       size+=WriteChannelSize(psd_info,image,-2);
3347     size+=WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :"8BIM");
3348     size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(image));
3349     property=GetImageArtifact(next_image,"psd:layer.opacity");
3350     if (property != (const char *) NULL)
3351       {
3352         Quantum
3353           opacity;
3354
3355         opacity=(Quantum) StringToInteger(property);
3356         size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
3357         (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3358       }
3359     else
3360       size+=WriteBlobByte(image,255);
3361     size+=WriteBlobByte(image,0);
3362     size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
3363       1 << 0x02 : 1); /* layer properties - visible, etc. */
3364     size+=WriteBlobByte(image,0);
3365     info=GetAdditionalInformation(image_info,next_image,exception);
3366     property=(const char *) GetImageProperty(next_image,"label",exception);
3367     if (property == (const char *) NULL)
3368       {
3369         (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3370           (double) layer_index);
3371         property=layer_name;
3372       }
3373     name_length=strlen(property)+1;
3374     if ((name_length % 4) != 0)
3375       name_length+=(4-(name_length % 4));
3376     if (info != (const StringInfo *) NULL)
3377       name_length+=GetStringInfoLength(info);
3378     name_length+=8;
3379     if (mask != (Image *) NULL)
3380       name_length+=20;
3381     size+=WriteBlobLong(image,(unsigned int) name_length);
3382     if (mask == (Image *) NULL)
3383       size+=WriteBlobLong(image,0);
3384     else
3385       {
3386         if (mask->compose != NoCompositeOp)
3387           (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3388             default_color),MagickTrue,exception);
3389         mask->page.y+=image->page.y;
3390         mask->page.x+=image->page.x;
3391         size+=WriteBlobLong(image,20);
3392         size+=WriteBlobSignedLong(image,mask->page.y);
3393         size+=WriteBlobSignedLong(image,mask->page.x);
3394         size+=WriteBlobSignedLong(image,(const signed int) mask->rows+
3395           mask->page.y);
3396         size+=WriteBlobSignedLong(image,(const signed int) mask->columns+
3397           mask->page.x);
3398         size+=WriteBlobByte(image,default_color);
3399         size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
3400         size+=WriteBlobMSBShort(image,0);
3401       }
3402     size+=WriteBlobLong(image,0);
3403     size+=WritePascalString(image,property,4);
3404     if (info != (const StringInfo *) NULL)
3405       size+=WriteBlob(image,GetStringInfoLength(info),
3406         GetStringInfoDatum(info));
3407     next_image=GetNextImageInList(next_image);
3408   }
3409   /*
3410     Now the image data!
3411   */
3412   next_image=base_image;
3413   layer_index=0;
3414   while (next_image != NULL)
3415   {
3416     length=WritePSDChannels(psd_info,image_info,image,next_image,
3417       layer_size_offsets[layer_index++],MagickTrue,exception);
3418     if (length == 0)
3419       {
3420         status=MagickFalse;
3421         break;
3422       }
3423     size+=length;
3424     next_image=GetNextImageInList(next_image);
3425   }
3426   /*
3427     Write the total size
3428   */
3429   if (layers_size != (size_t*) NULL)
3430     *layers_size=size;
3431   if ((size/2) != ((size+1)/2))
3432     rounded_size=size+1;
3433   else
3434     rounded_size=size;
3435   (void) WritePSDSize(psd_info,image,rounded_size,size_offset);
3436   layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3437     layer_size_offsets);
3438   /*
3439     Remove the opacity mask from the registry
3440   */
3441   next_image=base_image;
3442   while (next_image != (Image *) NULL)
3443   {
3444     property=GetImageArtifact(next_image,"psd:opacity-mask");
3445     if (property != (const char *) NULL)
3446       DeleteImageRegistry(property);
3447     next_image=GetNextImageInList(next_image);
3448   }
3449
3450   return(status);
3451 }
3452
3453 ModuleExport MagickBooleanType WritePSDLayers(Image * image,
3454   const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
3455 {
3456   PolicyDomain
3457     domain;
3458
3459   PolicyRights
3460     rights;
3461
3462   domain=CoderPolicyDomain;
3463   rights=WritePolicyRights;
3464   if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
3465     return(MagickTrue);
3466   return WritePSDLayersInternal(image,image_info,psd_info,(size_t*) NULL,
3467     exception);
3468 }
3469
3470 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3471   Image *image,ExceptionInfo *exception)
3472 {
3473   const StringInfo
3474     *icc_profile;
3475
3476   MagickBooleanType
3477     status;
3478
3479   PSDInfo
3480     psd_info;
3481
3482   register ssize_t
3483     i;
3484
3485   size_t
3486     length,
3487     num_channels,
3488     packet_size;
3489
3490   StringInfo
3491     *bim_profile;
3492
3493   /*
3494     Open image file.
3495   */
3496   assert(image_info != (const ImageInfo *) NULL);
3497   assert(image_info->signature == MagickCoreSignature);
3498   assert(image != (Image *) NULL);
3499   assert(image->signature == MagickCoreSignature);
3500   if (image->debug != MagickFalse)
3501     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3502   assert(exception != (ExceptionInfo *) NULL);
3503   assert(exception->signature == MagickCoreSignature);
3504   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3505   if (status == MagickFalse)
3506     return(status);
3507   packet_size=(size_t) (image->depth > 8 ? 6 : 3);
3508   if (image->alpha_trait != UndefinedPixelTrait)
3509     packet_size+=image->depth > 8 ? 2 : 1;
3510   psd_info.version=1;
3511   if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3512       (image->columns > 30000) || (image->rows > 30000))
3513     psd_info.version=2;
3514   (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3515   (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
3516   for (i=1; i <= 6; i++)
3517     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
3518   /* When the image has a color profile it won't be converted to gray scale */
3519   if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
3520       (SetImageGray(image,exception) != MagickFalse))
3521     num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3522   else
3523     if ((image_info->type != TrueColorType) && (image_info->type !=
3524          TrueColorAlphaType) && (image->storage_class == PseudoClass))
3525       num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3526     else
3527       {
3528         if (image->storage_class == PseudoClass)
3529           (void) SetImageStorageClass(image,DirectClass,exception);
3530         if (image->colorspace != CMYKColorspace)
3531           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3532         else
3533           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3534       }
3535   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3536   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3537   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3538   if (IsImageGray(image) != MagickFalse)
3539     {
3540       MagickBooleanType
3541         monochrome;
3542
3543       /*
3544         Write depth & mode.
3545       */
3546       monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3547         MagickTrue : MagickFalse;
3548       (void) WriteBlobMSBShort(image,(unsigned short)
3549         (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3550       (void) WriteBlobMSBShort(image,(unsigned short)
3551         (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3552     }
3553   else
3554     {
3555       (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3556         PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3557
3558       if (((image_info->colorspace != UndefinedColorspace) ||
3559            (image->colorspace != CMYKColorspace)) &&
3560           (image_info->colorspace != CMYKColorspace))
3561         {
3562           (void) TransformImageColorspace(image,sRGBColorspace,exception);
3563           (void) WriteBlobMSBShort(image,(unsigned short)
3564             (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3565         }
3566       else
3567         {
3568           if (image->colorspace != CMYKColorspace)
3569             (void) TransformImageColorspace(image,CMYKColorspace,exception);
3570           (void) WriteBlobMSBShort(image,CMYKMode);
3571         }
3572     }
3573   if ((IsImageGray(image) != MagickFalse) ||
3574       (image->storage_class == DirectClass) || (image->colors > 256))
3575     (void) WriteBlobMSBLong(image,0);
3576   else
3577     {
3578       /*
3579         Write PSD raster colormap.
3580       */
3581       (void) WriteBlobMSBLong(image,768);
3582       for (i=0; i < (ssize_t) image->colors; i++)
3583         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
3584       for ( ; i < 256; i++)
3585         (void) WriteBlobByte(image,0);
3586       for (i=0; i < (ssize_t) image->colors; i++)
3587         (void) WriteBlobByte(image,ScaleQuantumToChar(
3588           image->colormap[i].green));
3589       for ( ; i < 256; i++)
3590         (void) WriteBlobByte(image,0);
3591       for (i=0; i < (ssize_t) image->colors; i++)
3592         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
3593       for ( ; i < 256; i++)
3594         (void) WriteBlobByte(image,0);
3595     }
3596   /*
3597     Image resource block.
3598   */
3599   length=28; /* 0x03EB */
3600   bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
3601   icc_profile=GetImageProfile(image,"icc");
3602   if (bim_profile != (StringInfo *) NULL)
3603     {
3604       bim_profile=CloneStringInfo(bim_profile);
3605       if (icc_profile != (StringInfo *) NULL)
3606         RemoveICCProfileFromResourceBlock(bim_profile);
3607       RemoveResolutionFromResourceBlock(bim_profile);
3608       length+=PSDQuantum(GetStringInfoLength(bim_profile));
3609     }
3610   if (icc_profile != (const StringInfo *) NULL)
3611     length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
3612   (void) WriteBlobMSBLong(image,(unsigned int) length);
3613   WriteResolutionResourceBlock(image);
3614   if (bim_profile != (StringInfo *) NULL)
3615     {
3616       (void) WriteBlob(image,GetStringInfoLength(bim_profile),
3617         GetStringInfoDatum(bim_profile));
3618       bim_profile=DestroyStringInfo(bim_profile);
3619     }
3620   if (icc_profile != (StringInfo *) NULL)
3621     {
3622       (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3623       (void) WriteBlobMSBShort(image,0x0000040F);
3624       (void) WriteBlobMSBShort(image,0);
3625       (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
3626         icc_profile));
3627       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
3628         GetStringInfoDatum(icc_profile));
3629       if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
3630           PSDQuantum(GetStringInfoLength(icc_profile)))
3631         (void) WriteBlobByte(image,0);
3632     }
3633   if (status != MagickFalse)
3634     {
3635       MagickOffsetType
3636         size_offset;
3637
3638       size_t
3639         size;
3640
3641       size_offset=TellBlob(image);
3642       SetPSDSize(&psd_info,image,0);
3643       status=WritePSDLayersInternal(image,image_info,&psd_info,&size,
3644         exception);
3645       size_offset+=WritePSDSize(&psd_info,image,size+
3646         (psd_info.version == 1 ? 8 : 12),size_offset);
3647     }
3648   (void) WriteBlobMSBLong(image,0);  /* user mask data */
3649   /*
3650     Write composite image.
3651   */
3652   if (status != MagickFalse)
3653     {
3654       CompressionType
3655         compression;
3656
3657       compression=image->compression;
3658       if (image->compression == ZipCompression)
3659         image->compression=RLECompression;
3660       if (image_info->compression != UndefinedCompression)
3661         image->compression=image_info->compression;
3662       if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
3663           exception) == 0)
3664         status=MagickFalse;
3665       image->compression=compression;
3666     }
3667   (void) CloseBlob(image);
3668   return(status);
3669 }