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