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