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