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