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