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