]> granicus.if.org Git - imagemagick/blob - coders/psd.c
Replaced calls to SetImageMonochrome and SetImageGray with IsImageMonochrome and...
[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)
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,
1586   ExceptionInfo *exception)
1587 {
1588   Image
1589     *image;
1590
1591   MagickBooleanType
1592     has_merged_image,
1593     skip_layers,
1594     status;
1595
1596   MagickOffsetType
1597     offset;
1598
1599   MagickSizeType
1600     length;
1601
1602   PSDInfo
1603     psd_info;
1604
1605   register ssize_t
1606     i;
1607
1608   ssize_t
1609     count;
1610
1611   unsigned char
1612     *data;
1613
1614   /*
1615     Open image file.
1616   */
1617   assert(image_info != (const ImageInfo *) NULL);
1618   assert(image_info->signature == MagickSignature);
1619   if (image_info->debug != MagickFalse)
1620     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1621       image_info->filename);
1622   assert(exception != (ExceptionInfo *) NULL);
1623   assert(exception->signature == MagickSignature);
1624
1625   image=AcquireImage(image_info,exception);
1626   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1627   if (status == MagickFalse)
1628     {
1629       image=DestroyImageList(image);
1630       return((Image *) NULL);
1631     }
1632   /*
1633     Read image header.
1634   */
1635   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1636   psd_info.version=ReadBlobMSBShort(image);
1637   if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1638       ((psd_info.version != 1) && (psd_info.version != 2)))
1639     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1640   count=ReadBlob(image,6,psd_info.reserved);
1641   psd_info.channels=ReadBlobMSBShort(image);
1642   if (psd_info.channels > MaxPSDChannels)
1643     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1644   psd_info.rows=ReadBlobMSBLong(image);
1645   psd_info.columns=ReadBlobMSBLong(image);
1646   if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1647       (psd_info.columns > 30000)))
1648     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1649   psd_info.depth=ReadBlobMSBShort(image);
1650   if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1651     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1652   psd_info.mode=ReadBlobMSBShort(image);
1653   if (image->debug != MagickFalse)
1654     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1655       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1656       (double) psd_info.columns,(double) psd_info.rows,(double)
1657       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1658       psd_info.mode));
1659   /*
1660     Initialize image.
1661   */
1662   image->depth=psd_info.depth;
1663   image->columns=psd_info.columns;
1664   image->rows=psd_info.rows;
1665   status=SetImageExtent(image,image->columns,image->rows,exception);
1666   if (status == MagickFalse)
1667     return(DestroyImageList(image));
1668   if (SetImageBackgroundColor(image,exception) == MagickFalse)
1669     {
1670       image=DestroyImageList(image);
1671       return((Image *) NULL);
1672     }
1673   if (psd_info.mode == LabMode)
1674     SetImageColorspace(image,LabColorspace,exception);
1675   if (psd_info.mode == CMYKMode)
1676     {
1677       SetImageColorspace(image,CMYKColorspace,exception);
1678       image->alpha_trait=psd_info.channels > 4 ? BlendPixelTrait :
1679         UndefinedPixelTrait;
1680     }
1681   else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
1682       (psd_info.mode == DuotoneMode))
1683     {
1684       status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1685         exception);
1686       if (status == MagickFalse)
1687         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1688       if (image->debug != MagickFalse)
1689         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1690           "  Image colormap allocated");
1691       SetImageColorspace(image,GRAYColorspace,exception);
1692       image->alpha_trait=psd_info.channels > 1 ? BlendPixelTrait :
1693         UndefinedPixelTrait;
1694     }
1695   else
1696     image->alpha_trait=psd_info.channels > 3 ? BlendPixelTrait :
1697       UndefinedPixelTrait;
1698   /*
1699     Read PSD raster colormap only present for indexed and duotone images.
1700   */
1701   length=ReadBlobMSBLong(image);
1702   if (length != 0)
1703     {
1704       if (image->debug != MagickFalse)
1705         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1706           "  reading colormap");
1707       if (psd_info.mode == DuotoneMode)
1708         {
1709           /*
1710             Duotone image data;  the format of this data is undocumented.
1711           */
1712           data=(unsigned char *) AcquireQuantumMemory((size_t) length,
1713             sizeof(*data));
1714           if (data == (unsigned char *) NULL)
1715             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1716           count=ReadBlob(image,(size_t) length,data);
1717           data=(unsigned char *) RelinquishMagickMemory(data);
1718         }
1719       else
1720         {
1721           size_t
1722             number_colors;
1723
1724           /*
1725             Read PSD raster colormap.
1726           */
1727           number_colors=length/3;
1728           if (number_colors > 65536)
1729             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1730           if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
1731             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1732           for (i=0; i < (ssize_t) image->colors; i++)
1733             image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1734               ReadBlobByte(image));
1735           for (i=0; i < (ssize_t) image->colors; i++)
1736             image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1737               ReadBlobByte(image));
1738           for (i=0; i < (ssize_t) image->colors; i++)
1739             image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1740               ReadBlobByte(image));
1741           image->alpha_trait=UndefinedPixelTrait;
1742         }
1743     }
1744   has_merged_image=MagickTrue;
1745   length=ReadBlobMSBLong(image);
1746   if (length != 0)
1747     {
1748       unsigned char
1749         *blocks;
1750
1751       /*
1752         Image resources block.
1753       */
1754       if (image->debug != MagickFalse)
1755         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1756           "  reading image resource blocks - %.20g bytes",(double)
1757           ((MagickOffsetType) length));
1758       blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
1759         sizeof(*blocks));
1760       if (blocks == (unsigned char *) NULL)
1761         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1762       count=ReadBlob(image,(size_t) length,blocks);
1763       if ((count != (ssize_t) length) ||
1764           (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
1765         {
1766           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1767           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1768         }
1769       ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
1770         exception);
1771       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1772     }
1773   /*
1774     Layer and mask block.
1775   */
1776   length=GetPSDSize(&psd_info,image);
1777   if (length == 8)
1778     {
1779       length=ReadBlobMSBLong(image);
1780       length=ReadBlobMSBLong(image);
1781     }
1782   offset=TellBlob(image);
1783   skip_layers=MagickFalse;
1784   if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
1785       (has_merged_image != MagickFalse))
1786     {
1787       if (image->debug != MagickFalse)
1788         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1789           "  read composite only");
1790       skip_layers=MagickTrue;
1791     }
1792   if (length == 0)
1793     {
1794       if (image->debug != MagickFalse)
1795         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1796           "  image has no layers");
1797     }
1798   else
1799     {
1800       if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
1801           MagickTrue)
1802         {
1803           (void) CloseBlob(image);
1804           image=DestroyImageList(image);
1805           return((Image *) NULL);
1806         }
1807
1808       /*
1809          Skip the rest of the layer and mask information.
1810       */
1811       SeekBlob(image,offset+length,SEEK_SET);
1812     }
1813   /*
1814     If we are only "pinging" the image, then we're done - so return.
1815   */
1816   if (image_info->ping != MagickFalse)
1817     {
1818       (void) CloseBlob(image);
1819       return(GetFirstImageInList(image));
1820     }
1821   /*
1822     Read the precombined layer, present for PSD < 4 compatibility.
1823   */
1824   if (image->debug != MagickFalse)
1825     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1826       "  reading the precombined layer");
1827   if (has_merged_image != MagickFalse || GetImageListLength(image) == 1)
1828     has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image,&psd_info,
1829       exception);
1830   if (has_merged_image == MagickFalse && GetImageListLength(image) == 1 &&
1831     length != 0)
1832     {
1833       SeekBlob(image,offset,SEEK_SET);
1834       if (ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception) !=
1835           MagickTrue)
1836         {
1837           (void) CloseBlob(image);
1838           return((Image *) NULL);
1839         }
1840     }
1841   if (has_merged_image == MagickFalse && GetImageListLength(image) > 1)
1842     {
1843       Image
1844         *merged;
1845
1846       SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
1847       image->background_color.alpha=TransparentAlpha;
1848       merged=MergeImageLayers(image,FlattenLayer,exception);
1849       ReplaceImageInList(&image,merged);
1850     }
1851   (void) CloseBlob(image);
1852   return(GetFirstImageInList(image));
1853 }
1854 \f
1855 /*
1856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857 %                                                                             %
1858 %                                                                             %
1859 %                                                                             %
1860 %   R e g i s t e r P S D I m a g e                                           %
1861 %                                                                             %
1862 %                                                                             %
1863 %                                                                             %
1864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865 %
1866 %  RegisterPSDImage() adds properties for the PSD image format to
1867 %  the list of supported formats.  The properties include the image format
1868 %  tag, a method to read and/or write the format, whether the format
1869 %  supports the saving of more than one frame to the same file or blob,
1870 %  whether the format supports native in-memory I/O, and a brief
1871 %  description of the format.
1872 %
1873 %  The format of the RegisterPSDImage method is:
1874 %
1875 %      size_t RegisterPSDImage(void)
1876 %
1877 */
1878 ModuleExport size_t RegisterPSDImage(void)
1879 {
1880   MagickInfo
1881     *entry;
1882
1883   entry=SetMagickInfo("PSB");
1884   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1885   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1886   entry->magick=(IsImageFormatHandler *) IsPSD;
1887   entry->flags|=CoderSeekableStreamFlag;
1888   entry->description=ConstantString("Adobe Large Document Format");
1889   entry->module=ConstantString("PSD");
1890   (void) RegisterMagickInfo(entry);
1891   entry=SetMagickInfo("PSD");
1892   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1893   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1894   entry->magick=(IsImageFormatHandler *) IsPSD;
1895   entry->flags|=CoderSeekableStreamFlag;
1896   entry->description=ConstantString("Adobe Photoshop bitmap");
1897   entry->module=ConstantString("PSD");
1898   (void) RegisterMagickInfo(entry);
1899   return(MagickImageCoderSignature);
1900 }
1901 \f
1902 /*
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 %                                                                             %
1905 %                                                                             %
1906 %                                                                             %
1907 %   U n r e g i s t e r P S D I m a g e                                       %
1908 %                                                                             %
1909 %                                                                             %
1910 %                                                                             %
1911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912 %
1913 %  UnregisterPSDImage() removes format registrations made by the
1914 %  PSD module from the list of supported formats.
1915 %
1916 %  The format of the UnregisterPSDImage method is:
1917 %
1918 %      UnregisterPSDImage(void)
1919 %
1920 */
1921 ModuleExport void UnregisterPSDImage(void)
1922 {
1923   (void) UnregisterMagickInfo("PSB");
1924   (void) UnregisterMagickInfo("PSD");
1925 }
1926 \f
1927 /*
1928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1929 %                                                                             %
1930 %                                                                             %
1931 %                                                                             %
1932 %   W r i t e P S D I m a g e                                                 %
1933 %                                                                             %
1934 %                                                                             %
1935 %                                                                             %
1936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937 %
1938 %  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
1939 %
1940 %  The format of the WritePSDImage method is:
1941 %
1942 %      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
1943 %        ExceptionInfo *exception)
1944 %
1945 %  A description of each parameter follows.
1946 %
1947 %    o image_info: the image info.
1948 %
1949 %    o image:  The image.
1950 %
1951 %    o exception: return any errors or warnings in this structure.
1952 %
1953 */
1954
1955 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
1956   const size_t offset)
1957 {
1958   if (psd_info->version == 1)
1959     return(WriteBlobMSBShort(image,(unsigned short) offset));
1960   return(WriteBlobMSBLong(image,(unsigned short) offset));
1961 }
1962
1963 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
1964   const MagickSizeType size)
1965 {
1966   if (psd_info->version == 1)
1967     return(WriteBlobMSBLong(image,(unsigned int) size));
1968   return(WriteBlobMSBLongLong(image,size));
1969 }
1970
1971 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
1972   const unsigned char *pixels,unsigned char *compact_pixels,
1973   ExceptionInfo *exception)
1974 {
1975   int
1976     count;
1977
1978   register ssize_t
1979     i,
1980     j;
1981
1982   register unsigned char
1983     *q;
1984
1985   unsigned char
1986     *packbits;
1987
1988   /*
1989     Compress pixels with Packbits encoding.
1990   */
1991   assert(image != (Image *) NULL);
1992   assert(image->signature == MagickSignature);
1993   if (image->debug != MagickFalse)
1994     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1995   assert(pixels != (unsigned char *) NULL);
1996   packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
1997   if (packbits == (unsigned char *) NULL)
1998     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1999       image->filename);
2000   q=compact_pixels;
2001   for (i=(ssize_t) length; i != 0; )
2002   {
2003     switch (i)
2004     {
2005       case 1:
2006       {
2007         i--;
2008         *q++=(unsigned char) 0;
2009         *q++=(*pixels);
2010         break;
2011       }
2012       case 2:
2013       {
2014         i-=2;
2015         *q++=(unsigned char) 1;
2016         *q++=(*pixels);
2017         *q++=pixels[1];
2018         break;
2019       }
2020       case 3:
2021       {
2022         i-=3;
2023         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2024           {
2025             *q++=(unsigned char) ((256-3)+1);
2026             *q++=(*pixels);
2027             break;
2028           }
2029         *q++=(unsigned char) 2;
2030         *q++=(*pixels);
2031         *q++=pixels[1];
2032         *q++=pixels[2];
2033         break;
2034       }
2035       default:
2036       {
2037         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2038           {
2039             /*
2040               Packed run.
2041             */
2042             count=3;
2043             while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2044             {
2045               count++;
2046               if (count >= 127)
2047                 break;
2048             }
2049             i-=count;
2050             *q++=(unsigned char) ((256-count)+1);
2051             *q++=(*pixels);
2052             pixels+=count;
2053             break;
2054           }
2055         /*
2056           Literal run.
2057         */
2058         count=0;
2059         while ((*(pixels+count) != *(pixels+count+1)) ||
2060                (*(pixels+count+1) != *(pixels+count+2)))
2061         {
2062           packbits[count+1]=pixels[count];
2063           count++;
2064           if (((ssize_t) count >= (i-3)) || (count >= 127))
2065             break;
2066         }
2067         i-=count;
2068         *packbits=(unsigned char) (count-1);
2069         for (j=0; j <= (ssize_t) count; j++)
2070           *q++=packbits[j];
2071         pixels+=count;
2072         break;
2073       }
2074     }
2075   }
2076   *q++=(unsigned char) 128;  /* EOD marker */
2077   packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2078   return((size_t) (q-compact_pixels));
2079 }
2080
2081 static void WritePackbitsLength(const PSDInfo *psd_info,
2082   const ImageInfo *image_info,Image *image,Image *next_image,
2083   unsigned char *compact_pixels,const QuantumType quantum_type,
2084   ExceptionInfo *exception)
2085 {
2086   QuantumInfo
2087     *quantum_info;
2088
2089   register const Quantum
2090     *p;
2091
2092   size_t
2093     length,
2094     packet_size;
2095
2096   ssize_t
2097     y;
2098
2099   unsigned char
2100     *pixels;
2101
2102   if (next_image->depth > 8)
2103     next_image->depth=16;
2104   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2105   (void) packet_size;
2106   quantum_info=AcquireQuantumInfo(image_info,image);
2107   pixels=GetQuantumPixels(quantum_info);
2108   for (y=0; y < (ssize_t) next_image->rows; y++)
2109   {
2110     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2111     if (p == (const Quantum *) NULL)
2112       break;
2113     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2114       quantum_type,pixels,exception);
2115     length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2116       exception);
2117     (void) SetPSDOffset(psd_info,image,length);
2118   }
2119   quantum_info=DestroyQuantumInfo(quantum_info);
2120 }
2121
2122 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
2123   Image *image,Image *next_image,unsigned char *compact_pixels,
2124   const QuantumType quantum_type,const MagickBooleanType compression_flag,
2125   ExceptionInfo *exception)
2126 {
2127   int
2128     y;
2129
2130   MagickBooleanType
2131     monochrome;
2132
2133   QuantumInfo
2134     *quantum_info;
2135
2136   register const Quantum
2137     *p;
2138
2139   register ssize_t
2140     i;
2141
2142   size_t
2143     length,
2144     packet_size;
2145
2146   unsigned char
2147     *pixels;
2148
2149   (void) psd_info;
2150   if ((compression_flag != MagickFalse) &&
2151       (next_image->compression != RLECompression))
2152     (void) WriteBlobMSBShort(image,0);
2153   if (next_image->depth > 8)
2154     next_image->depth=16;
2155   monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2156     MagickTrue : MagickFalse;
2157   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2158   (void) packet_size;
2159   quantum_info=AcquireQuantumInfo(image_info,image);
2160   pixels=GetQuantumPixels(quantum_info);
2161   for (y=0; y < (ssize_t) next_image->rows; y++)
2162   {
2163     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2164     if (p == (const Quantum *) NULL)
2165       break;
2166     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2167       quantum_type,pixels,exception);
2168     if (monochrome != MagickFalse)
2169       for (i=0; i < (ssize_t) length; i++)
2170         pixels[i]=(~pixels[i]);
2171     if (next_image->compression != RLECompression)
2172       (void) WriteBlob(image,length,pixels);
2173     else
2174       {
2175         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2176           exception);
2177         (void) WriteBlob(image,length,compact_pixels);
2178       }
2179   }
2180   quantum_info=DestroyQuantumInfo(quantum_info);
2181 }
2182
2183 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
2184   const ImageInfo *image_info,Image *image,Image *next_image,
2185   const MagickBooleanType separate,ExceptionInfo *exception)
2186 {
2187   size_t
2188     channels,
2189     packet_size;
2190
2191   unsigned char
2192     *compact_pixels;
2193
2194   /*
2195     Write uncompressed pixels as separate planes.
2196   */
2197   channels=1;
2198   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2199   compact_pixels=(unsigned char *) NULL;
2200   if (next_image->compression == RLECompression)
2201     {
2202       compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
2203         next_image->columns,packet_size*sizeof(*compact_pixels));
2204       if (compact_pixels == (unsigned char *) NULL)
2205         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2206     }
2207   if (IsImageGray(next_image) != MagickFalse)
2208     {
2209       if (next_image->compression == RLECompression)
2210         {
2211           /*
2212             Packbits compression.
2213           */
2214           (void) WriteBlobMSBShort(image,1);
2215           WritePackbitsLength(psd_info,image_info,image,next_image,
2216             compact_pixels,GrayQuantum,exception);
2217           if (next_image->alpha_trait != UndefinedPixelTrait)
2218             WritePackbitsLength(psd_info,image_info,image,next_image,
2219               compact_pixels,AlphaQuantum,exception);
2220         }
2221       WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2222         GrayQuantum,MagickTrue,exception);
2223       if (next_image->alpha_trait != UndefinedPixelTrait)
2224         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2225           AlphaQuantum,separate,exception);
2226       (void) SetImageProgress(image,SaveImagesTag,0,1);
2227     }
2228   else
2229     if (next_image->storage_class == PseudoClass)
2230       {
2231         if (next_image->compression == RLECompression)
2232           {
2233             /*
2234               Packbits compression.
2235             */
2236             (void) WriteBlobMSBShort(image,1);
2237             WritePackbitsLength(psd_info,image_info,image,next_image,
2238               compact_pixels,IndexQuantum,exception);
2239             if (next_image->alpha_trait != UndefinedPixelTrait)
2240               WritePackbitsLength(psd_info,image_info,image,next_image,
2241                 compact_pixels,AlphaQuantum,exception);
2242           }
2243         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2244           IndexQuantum,MagickTrue,exception);
2245         if (next_image->alpha_trait != UndefinedPixelTrait)
2246           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2247             AlphaQuantum,separate,exception);
2248         (void) SetImageProgress(image,SaveImagesTag,0,1);
2249       }
2250     else
2251       {
2252         if (next_image->colorspace == CMYKColorspace)
2253           (void) NegateCMYK(next_image,exception);
2254         if (next_image->compression == RLECompression)
2255           {
2256             /*
2257               Packbits compression.
2258             */
2259             (void) WriteBlobMSBShort(image,1);
2260             WritePackbitsLength(psd_info,image_info,image,next_image,
2261               compact_pixels,RedQuantum,exception);
2262             WritePackbitsLength(psd_info,image_info,image,next_image,
2263               compact_pixels,GreenQuantum,exception);
2264             WritePackbitsLength(psd_info,image_info,image,next_image,
2265               compact_pixels,BlueQuantum,exception);
2266             if (next_image->colorspace == CMYKColorspace)
2267               WritePackbitsLength(psd_info,image_info,image,next_image,
2268                 compact_pixels,BlackQuantum,exception);
2269             if (next_image->alpha_trait != UndefinedPixelTrait)
2270               WritePackbitsLength(psd_info,image_info,image,next_image,
2271                 compact_pixels,AlphaQuantum,exception);
2272           }
2273         (void) SetImageProgress(image,SaveImagesTag,0,6);
2274         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2275           RedQuantum,MagickTrue,exception);
2276         (void) SetImageProgress(image,SaveImagesTag,1,6);
2277         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2278           GreenQuantum,separate,exception);
2279         (void) SetImageProgress(image,SaveImagesTag,2,6);
2280         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2281           BlueQuantum,separate,exception);
2282         (void) SetImageProgress(image,SaveImagesTag,3,6);
2283         if (next_image->colorspace == CMYKColorspace)
2284           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2285             BlackQuantum,separate,exception);
2286         (void) SetImageProgress(image,SaveImagesTag,4,6);
2287         if (next_image->alpha_trait != UndefinedPixelTrait)
2288           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2289             AlphaQuantum,separate,exception);
2290         (void) SetImageProgress(image,SaveImagesTag,5,6);
2291         if (next_image->colorspace == CMYKColorspace)
2292           (void) NegateCMYK(next_image,exception);
2293       }
2294   if (next_image->compression == RLECompression)
2295     compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2296   return(MagickTrue);
2297 }
2298
2299 static void WritePascalString(Image* inImage,const char *inString,int inPad)
2300 {
2301   size_t
2302     length;
2303
2304   register ssize_t
2305     i;
2306
2307   /*
2308     Max length is 255.
2309   */
2310   length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
2311   if (length ==  0)
2312     (void) WriteBlobByte(inImage,0);
2313   else
2314     {
2315       (void) WriteBlobByte(inImage,(unsigned char) length);
2316       (void) WriteBlob(inImage, length, (const unsigned char *) inString);
2317     }
2318   length++;
2319   if ((length % inPad) == 0)
2320     return;
2321   for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
2322     (void) WriteBlobByte(inImage,0);
2323 }
2324
2325 static void WriteResolutionResourceBlock(Image *image)
2326 {
2327   double
2328     x_resolution,
2329     y_resolution;
2330
2331   unsigned short
2332     units;
2333
2334   if (image->units == PixelsPerCentimeterResolution)
2335     {
2336       x_resolution=2.54*65536.0*image->resolution.x+0.5;
2337       y_resolution=2.54*65536.0*image->resolution.y+0.5;
2338       units=2;
2339     }
2340   else
2341     {
2342       x_resolution=65536.0*image->resolution.x+0.5;
2343       y_resolution=65536.0*image->resolution.y+0.5;
2344       units=1;
2345     }
2346   (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2347   (void) WriteBlobMSBShort(image,0x03ED);
2348   (void) WriteBlobMSBShort(image,0);
2349   (void) WriteBlobMSBLong(image,16); /* resource size */
2350   (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2351   (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2352   (void) WriteBlobMSBShort(image,units); /* width unit */
2353   (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2354   (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2355   (void) WriteBlobMSBShort(image,units); /* height unit */
2356 }
2357
2358 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2359 {
2360   register const unsigned char
2361     *p;
2362
2363   size_t
2364     length;
2365
2366   unsigned char
2367     *datum;
2368
2369   unsigned int
2370     count,
2371     long_sans;
2372
2373   unsigned short
2374     id,
2375     short_sans;
2376
2377   length=GetStringInfoLength(bim_profile);
2378   if (length < 16)
2379     return;
2380   datum=GetStringInfoDatum(bim_profile);
2381   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2382   {
2383     register unsigned char
2384       *q;
2385
2386     q=(unsigned char *) p;
2387     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2388       break;
2389     p=PushLongPixel(MSBEndian,p,&long_sans);
2390     p=PushShortPixel(MSBEndian,p,&id);
2391     p=PushShortPixel(MSBEndian,p,&short_sans);
2392     p=PushLongPixel(MSBEndian,p,&count);
2393     if (id == 0x0000040f)
2394       {
2395         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2396           (PSDQuantum(count)+12)-(q-datum));
2397         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2398         break;
2399       }
2400     p+=count;
2401     if ((count & 0x01) != 0)
2402       p++;
2403   }
2404 }
2405
2406 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2407 {
2408   register const unsigned char
2409     *p;
2410
2411   size_t
2412     length;
2413
2414   unsigned char
2415     *datum;
2416
2417   unsigned int
2418     count,
2419     long_sans;
2420
2421   unsigned short
2422     id,
2423     short_sans;
2424
2425   length=GetStringInfoLength(bim_profile);
2426   if (length < 16)
2427     return;
2428   datum=GetStringInfoDatum(bim_profile);
2429   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2430   {
2431     register unsigned char
2432       *q;
2433
2434     q=(unsigned char *) p;
2435     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2436       break;
2437     p=PushLongPixel(MSBEndian,p,&long_sans);
2438     p=PushShortPixel(MSBEndian,p,&id);
2439     p=PushShortPixel(MSBEndian,p,&short_sans);
2440     p=PushLongPixel(MSBEndian,p,&count);
2441     if ((id == 0x000003ed) && (PSDQuantum(count) < (ssize_t) (length-12)))
2442       {
2443         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2444           (PSDQuantum(count)+12)-(q-datum));
2445         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2446         break;
2447       }
2448     p+=count;
2449     if ((count & 0x01) != 0)
2450       p++;
2451   }
2452 }
2453
2454 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2455   ExceptionInfo *exception)
2456 {
2457   const char
2458     *property;
2459
2460   const StringInfo
2461     *icc_profile;
2462
2463   Image
2464     *base_image,
2465     *next_image;
2466
2467   MagickBooleanType
2468     status;
2469
2470   PSDInfo
2471     psd_info;
2472
2473   register ssize_t
2474     i;
2475
2476   size_t
2477     channel_size,
2478     channelLength,
2479     layer_count,
2480     layer_info_size,
2481     length,
2482     num_channels,
2483     packet_size,
2484     rounded_layer_info_size;
2485
2486   StringInfo
2487     *bim_profile;
2488
2489   /*
2490     Open image file.
2491   */
2492   assert(image_info != (const ImageInfo *) NULL);
2493   assert(image_info->signature == MagickSignature);
2494   assert(image != (Image *) NULL);
2495   assert(image->signature == MagickSignature);
2496   if (image->debug != MagickFalse)
2497     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2498   assert(exception != (ExceptionInfo *) NULL);
2499   assert(exception->signature == MagickSignature);
2500   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2501   if (status == MagickFalse)
2502     return(status);
2503   packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2504   if (image->alpha_trait != UndefinedPixelTrait)
2505     packet_size+=image->depth > 8 ? 2 : 1;
2506   psd_info.version=1;
2507   if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2508       (image->columns > 30000) || (image->rows > 30000))
2509     psd_info.version=2;
2510   (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2511   (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
2512   for (i=1; i <= 6; i++)
2513     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
2514   if (IsImageGray(image) != MagickFalse)
2515     num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2516   else
2517     if (image->storage_class == PseudoClass)
2518       num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2519     else
2520       {
2521         if (image->colorspace != CMYKColorspace)
2522           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
2523         else
2524           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
2525       }
2526   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2527   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2528   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2529   if (IsImageGray(image) != MagickFalse)
2530     {
2531       MagickBooleanType
2532         monochrome;
2533
2534       /*
2535         Write depth & mode.
2536       */
2537       monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2538         MagickTrue : MagickFalse;
2539       (void) WriteBlobMSBShort(image,(unsigned short)
2540         (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2541       (void) WriteBlobMSBShort(image,(unsigned short)
2542         (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
2543     }
2544   else
2545     {
2546       (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2547         PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2548
2549       if (((image_info->colorspace != UndefinedColorspace) ||
2550            (image->colorspace != CMYKColorspace)) &&
2551           (image_info->colorspace != CMYKColorspace))
2552         {
2553           (void) TransformImageColorspace(image,sRGBColorspace,exception);
2554           (void) WriteBlobMSBShort(image,(unsigned short)
2555             (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2556         }
2557       else
2558         {
2559           if (image->colorspace != CMYKColorspace)
2560             (void) TransformImageColorspace(image,CMYKColorspace,exception);
2561           (void) WriteBlobMSBShort(image,CMYKMode);
2562         }
2563     }
2564   if ((IsImageGray(image) != MagickFalse) ||
2565       (image->storage_class == DirectClass) || (image->colors > 256))
2566     (void) WriteBlobMSBLong(image,0);
2567   else
2568     {
2569       /*
2570         Write PSD raster colormap.
2571       */
2572       (void) WriteBlobMSBLong(image,768);
2573       for (i=0; i < (ssize_t) image->colors; i++)
2574         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
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(
2579           image->colormap[i].green));
2580       for ( ; i < 256; i++)
2581         (void) WriteBlobByte(image,0);
2582       for (i=0; i < (ssize_t) image->colors; i++)
2583         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2584       for ( ; i < 256; i++)
2585         (void) WriteBlobByte(image,0);
2586     }
2587   /*
2588     Image resource block.
2589   */
2590   length=28; /* 0x03EB */
2591   bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2592   icc_profile=GetImageProfile(image,"icc");
2593   if (bim_profile != (StringInfo *) NULL)
2594     {
2595       bim_profile=CloneStringInfo(bim_profile);
2596       if (icc_profile != (StringInfo *) NULL)
2597         RemoveICCProfileFromResourceBlock(bim_profile);
2598       RemoveResolutionFromResourceBlock(bim_profile);
2599       length+=PSDQuantum(GetStringInfoLength(bim_profile));
2600     }
2601   if (icc_profile != (const StringInfo *) NULL)
2602     length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2603   (void) WriteBlobMSBLong(image,(unsigned int) length);
2604   WriteResolutionResourceBlock(image);
2605   if (bim_profile != (StringInfo *) NULL)
2606     {
2607       (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2608         GetStringInfoDatum(bim_profile));
2609       bim_profile=DestroyStringInfo(bim_profile);
2610     }
2611   if (icc_profile != (StringInfo *) NULL)
2612     {
2613       (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2614       (void) WriteBlobMSBShort(image,0x0000040F);
2615       (void) WriteBlobMSBShort(image,0);
2616       (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2617         icc_profile));
2618       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2619         GetStringInfoDatum(icc_profile));
2620       if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2621           PSDQuantum(GetStringInfoLength(icc_profile)))
2622         (void) WriteBlobByte(image,0);
2623     }
2624   layer_count=0;
2625   layer_info_size=2;
2626   base_image=GetNextImageInList(image);
2627   if ((image->alpha_trait != UndefinedPixelTrait) && (base_image == (Image *) NULL))
2628     base_image=image;
2629   next_image=base_image;
2630   while ( next_image != NULL )
2631   {
2632     packet_size=next_image->depth > 8 ? 2UL : 1UL;
2633     if (IsImageGray(next_image) != MagickFalse)
2634       num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2635     else
2636       if (next_image->storage_class == PseudoClass)
2637         num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2638       else
2639         if (next_image->colorspace != CMYKColorspace)
2640           num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
2641         else
2642           num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
2643     channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
2644     layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
2645       16)+4*1+4+num_channels*channelLength);
2646     property=(const char *) GetImageProperty(next_image,"label",exception);
2647     if (property == (const char *) NULL)
2648       layer_info_size+=16;
2649     else
2650       {
2651         size_t
2652           length;
2653
2654         length=strlen(property);
2655         layer_info_size+=8+length+(4-(length % 4));
2656       }
2657     layer_count++;
2658     next_image=GetNextImageInList(next_image);
2659   }
2660   if (layer_count == 0)
2661     (void) SetPSDSize(&psd_info,image,0);
2662   else
2663     {
2664       CompressionType
2665         compression;
2666
2667       (void) SetPSDSize(&psd_info,image,layer_info_size+
2668         (psd_info.version == 1 ? 8 : 16));
2669       if ((layer_info_size/2) != ((layer_info_size+1)/2))
2670         rounded_layer_info_size=layer_info_size+1;
2671       else
2672         rounded_layer_info_size=layer_info_size;
2673       (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2674       if (image->alpha_trait != UndefinedPixelTrait)
2675         (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
2676       else
2677         (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2678       layer_count=1;
2679       compression=base_image->compression;
2680       for (next_image=base_image; next_image != NULL; )
2681       {
2682         next_image->compression=NoCompression;
2683         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2684         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
2685         (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
2686           next_image->rows));
2687         (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
2688           next_image->columns));
2689         packet_size=next_image->depth > 8 ? 2UL : 1UL;
2690         channel_size=(unsigned int) ((packet_size*next_image->rows*
2691           next_image->columns)+2);
2692         if ((IsImageGray(next_image) != MagickFalse) ||
2693             (next_image->storage_class == PseudoClass))
2694           {
2695              (void) WriteBlobMSBShort(image,(unsigned short)
2696                (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
2697              (void) WriteBlobMSBShort(image,0);
2698              (void) SetPSDSize(&psd_info,image,channel_size);
2699              if (next_image->alpha_trait != UndefinedPixelTrait)
2700                {
2701                  (void) WriteBlobMSBShort(image,(unsigned short) -1);
2702                  (void) SetPSDSize(&psd_info,image,channel_size);
2703                }
2704            }
2705           else
2706             if (next_image->colorspace != CMYKColorspace)
2707               {
2708                 (void) WriteBlobMSBShort(image,(unsigned short)
2709                   (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
2710                (void) WriteBlobMSBShort(image,0);
2711                (void) SetPSDSize(&psd_info,image,channel_size);
2712                (void) WriteBlobMSBShort(image,1);
2713                (void) SetPSDSize(&psd_info,image,channel_size);
2714                (void) WriteBlobMSBShort(image,2);
2715                (void) SetPSDSize(&psd_info,image,channel_size);
2716                if (next_image->alpha_trait != UndefinedPixelTrait)
2717                  {
2718                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2719                    (void) SetPSDSize(&psd_info,image,channel_size);
2720                  }
2721              }
2722            else
2723              {
2724                (void) WriteBlobMSBShort(image,(unsigned short)
2725                  (next_image->alpha_trait ? 5 : 4));
2726                (void) WriteBlobMSBShort(image,0);
2727                (void) SetPSDSize(&psd_info,image,channel_size);
2728                (void) WriteBlobMSBShort(image,1);
2729                (void) SetPSDSize(&psd_info,image,channel_size);
2730                (void) WriteBlobMSBShort(image,2);
2731                (void) SetPSDSize(&psd_info,image,channel_size);
2732                (void) WriteBlobMSBShort(image,3);
2733                (void) SetPSDSize(&psd_info,image,channel_size);
2734                if (next_image->alpha_trait)
2735                  {
2736                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2737                    (void) SetPSDSize(&psd_info,image,channel_size);
2738                  }
2739              }
2740         (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2741         (void) WriteBlob(image,4,(const unsigned char *)
2742           CompositeOperatorToPSDBlendMode(next_image->compose));
2743         (void) WriteBlobByte(image,255); /* layer opacity */
2744         (void) WriteBlobByte(image,0);
2745         (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
2746           1 << 0x02 : 1); /* layer properties - visible, etc. */
2747         (void) WriteBlobByte(image,0);
2748         property=(const char *) GetImageProperty(next_image,"label",exception);
2749         if (property == (const char *) NULL)
2750           {
2751             char
2752               layer_name[MaxTextExtent];
2753
2754             (void) WriteBlobMSBLong(image,16);
2755             (void) WriteBlobMSBLong(image,0);
2756             (void) WriteBlobMSBLong(image,0);
2757             (void) FormatLocaleString(layer_name,MaxTextExtent,"L%04ld",(long)
2758               layer_count++);
2759             WritePascalString(image,layer_name,4);
2760           }
2761         else
2762           {
2763             size_t
2764               length;
2765
2766             length=strlen(property);
2767             (void) WriteBlobMSBLong(image,(unsigned int) (length+(4-
2768               (length % 4))+8));
2769             (void) WriteBlobMSBLong(image,0);
2770             (void) WriteBlobMSBLong(image,0);
2771             WritePascalString(image,property,4);
2772           }
2773         next_image=GetNextImageInList(next_image);
2774       }
2775       /*
2776         Now the image data!
2777       */
2778       next_image=base_image;
2779       while (next_image != NULL)
2780       {
2781         status=WriteImageChannels(&psd_info,image_info,image,next_image,
2782           MagickTrue,exception);
2783         next_image=GetNextImageInList(next_image);
2784       }
2785       (void) WriteBlobMSBLong(image,0);  /* user mask data */
2786       base_image->compression=compression;
2787     }
2788   /*
2789     Write composite image.
2790   */
2791   status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
2792     exception);
2793   (void) CloseBlob(image);
2794   return(status);
2795 }