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