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