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