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