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