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