]> granicus.if.org Git - imagemagick/blob - coders/psd.c
Reverted typecast due to issues in 64-bit build.
[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) ReadBlobLong(image));
487   return((MagickSizeType) ReadBlobLongLong(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 inline void ReversePSDString(Image *image,char *p,size_t length)
662 {
663   char
664     *q;
665
666   if (image->endian == MSBEndian)
667     return;
668
669   q=p+length;
670   for(--q; p < q; ++p, --q)
671   {
672     *p = *p ^ *q,
673     *q = *p ^ *q,
674     *p = *p ^ *q;
675   }
676 }
677
678 static MagickStatusType ReadPSDChannelPixels(Image *image,
679   const size_t channels,const size_t row,const ssize_t type,
680   const unsigned char *pixels,ExceptionInfo *exception)
681 {
682   Quantum
683     pixel;
684
685   register const unsigned char
686     *p;
687
688   register Quantum
689     *q;
690
691   register ssize_t
692     x;
693
694   size_t
695     packet_size;
696
697   unsigned short
698     nibble;
699
700   p=pixels;
701   q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
702   if (q == (Quantum *) NULL)
703     return MagickFalse;
704   packet_size=GetPSDPacketSize(image);
705   for (x=0; x < (ssize_t) image->columns; x++)
706   {
707     if (packet_size == 1)
708       pixel=ScaleCharToQuantum(*p++);
709     else
710       {
711         p=PushShortPixel(MSBEndian,p,&nibble);
712         pixel=ScaleShortToQuantum(nibble);
713       }
714     switch (type)
715     {
716       case -1:
717       {
718         SetPixelAlpha(image,pixel,q);
719         break;
720       }
721       case -2:
722       case 0:
723       {
724         SetPixelRed(image,pixel,q);
725         if (channels == 1 || type == -2)
726           SetPixelGray(image,pixel,q);
727         if (image->storage_class == PseudoClass)
728           {
729             if (packet_size == 1)
730               SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
731             else
732               SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
733             SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
734               ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
735             if (image->depth == 1)
736               {
737                 ssize_t
738                   bit,
739                   number_bits;
740   
741                 number_bits=image->columns-x;
742                 if (number_bits > 8)
743                   number_bits=8;
744                 for (bit=0; bit < number_bits; bit++)
745                 {
746                   SetPixelIndex(image,(((unsigned char) pixel) &
747                     (0x01 << (7-bit))) != 0 ? 0 : 255,q);
748                   SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
749                     GetPixelIndex(image,q),q);
750                   q+=GetPixelChannels(image);
751                   x++;
752                 }
753                 x--;
754                 continue;
755               }
756           }
757         break;
758       }
759       case 1:
760       {
761         if (image->storage_class == PseudoClass)
762           SetPixelAlpha(image,pixel,q);
763         else
764           SetPixelGreen(image,pixel,q);
765         break;
766       }
767       case 2:
768       {
769         if (image->storage_class == PseudoClass)
770           SetPixelAlpha(image,pixel,q);
771         else
772           SetPixelBlue(image,pixel,q);
773         break;
774       }
775       case 3:
776       {
777         if (image->colorspace == CMYKColorspace)
778           SetPixelBlack(image,pixel,q);
779         else
780           if (image->alpha_trait != UndefinedPixelTrait)
781             SetPixelAlpha(image,pixel,q);
782         break;
783       }
784       case 4:
785       {
786         if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
787             (channels > 3))
788           break;
789         if (image->alpha_trait != UndefinedPixelTrait)
790           SetPixelAlpha(image,pixel,q);
791         break;
792       }
793       default:
794         break;
795     }
796     q+=GetPixelChannels(image);
797   }
798   return(SyncAuthenticPixels(image,exception));
799 }
800
801 static MagickStatusType ReadPSDChannelRaw(Image *image,const size_t channels,
802   const ssize_t type,ExceptionInfo *exception)
803 {
804   MagickStatusType
805     status;
806
807   size_t
808     count,
809     row_size;
810
811   ssize_t
812     y;
813
814   unsigned char
815     *pixels;
816
817   if (image->debug != MagickFalse)
818     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
819        "      layer data is RAW");
820
821   row_size=GetPSDRowSize(image);
822   pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
823   if (pixels == (unsigned char *) NULL)
824     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
825       image->filename);
826
827   status=MagickTrue;
828   for (y=0; y < (ssize_t) image->rows; y++)
829   {
830     status=MagickFalse;
831
832     count=ReadBlob(image,row_size,pixels);
833     if (count != row_size)
834       break;
835
836     status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
837     if (status == MagickFalse)
838       break;
839   }
840
841   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
842   return(status);
843 }
844
845 static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
846   const PSDInfo *psd_info,const size_t size)
847 {
848   MagickOffsetType
849     *offsets;
850
851   ssize_t
852     y;
853
854   offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets));
855   if(offsets != (MagickOffsetType *) NULL)
856     {
857       for (y=0; y < (ssize_t) size; y++)
858       {
859         if (psd_info->version == 1)
860           offsets[y]=(MagickOffsetType) ReadBlobShort(image);
861         else
862           offsets[y]=(MagickOffsetType) ReadBlobLong(image);
863       }
864     }
865   return offsets;
866 }
867
868 static MagickStatusType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
869   const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
870 {
871   MagickStatusType
872     status;
873
874   size_t
875     length,
876     row_size;
877
878   ssize_t
879     count,
880     y;
881
882   unsigned char
883     *compact_pixels,
884     *pixels;
885
886   if (image->debug != MagickFalse)
887     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
888        "      layer data is RLE compressed");
889
890   row_size=GetPSDRowSize(image);
891   pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
892   if (pixels == (unsigned char *) NULL)
893     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
894       image->filename);
895
896   length=0;
897   for (y=0; y < (ssize_t) image->rows; y++)
898     if ((MagickOffsetType) length < offsets[y])
899       length=(size_t) offsets[y];
900
901   if (length > row_size + 256) // arbitrary number
902     {
903       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
904       ThrowBinaryException(ResourceLimitError,"InvalidLength",
905         image->filename);
906     }
907
908   compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
909   if (compact_pixels == (unsigned char *) NULL)
910     {
911       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
912       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
913         image->filename);
914     }
915
916   (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
917
918   status=MagickTrue;
919   for (y=0; y < (ssize_t) image->rows; y++)
920   {
921     status=MagickFalse;
922
923     count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
924     if (count != (ssize_t) offsets[y])
925       break;
926
927     count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
928       (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
929     if (count != (ssize_t) row_size)
930       break;
931
932     status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
933       exception);
934     if (status == MagickFalse)
935       break;
936   }
937
938   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
939   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
940   return(status);
941 }
942
943 #ifdef MAGICKCORE_ZLIB_DELEGATE
944 static MagickStatusType ReadPSDChannelZip(Image *image,const size_t channels,
945   const ssize_t type,const PSDCompressionType compression,
946   const size_t compact_size,ExceptionInfo *exception)
947 {
948   MagickStatusType
949     status;
950
951   register unsigned char
952     *p;
953
954   size_t
955     count,
956     length,
957     packet_size,
958     row_size;
959
960   ssize_t
961     y;
962
963   unsigned char
964     *compact_pixels,
965     *pixels;
966
967   z_stream
968     stream;
969
970   if (image->debug != MagickFalse)
971     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
972        "      layer data is ZIP compressed");
973
974   compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
975     sizeof(*compact_pixels));
976   if (compact_pixels == (unsigned char *) NULL)
977     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
978       image->filename);
979
980   packet_size=GetPSDPacketSize(image);
981   row_size=image->columns*packet_size;
982   count=image->rows*row_size;
983
984   pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
985   if (pixels == (unsigned char *) NULL)
986     {
987       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
988       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
989         image->filename);
990     }
991
992   ResetMagickMemory(&stream, 0, sizeof(z_stream));
993   stream.data_type=Z_BINARY;
994   (void) ReadBlob(image,compact_size,compact_pixels);
995
996   stream.next_in=(Bytef *)compact_pixels;
997   stream.avail_in=(unsigned int) compact_size;
998   stream.next_out=(Bytef *)pixels;
999   stream.avail_out=(unsigned int) count;
1000
1001   if(inflateInit(&stream) == Z_OK)
1002     {
1003       int
1004         ret;
1005
1006       while (stream.avail_out > 0)
1007       {
1008         ret=inflate(&stream, Z_SYNC_FLUSH);
1009         if (ret != Z_OK && ret != Z_STREAM_END)
1010         {
1011           compact_pixels=(unsigned char *) RelinquishMagickMemory(
1012             compact_pixels);
1013           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1014           return(MagickFalse);
1015         }
1016       }
1017     }
1018
1019   if (compression == ZipWithPrediction)
1020   {
1021      p=pixels;
1022      while(count > 0)
1023      {
1024        length=image->columns;
1025        while(--length)
1026        {
1027          if (packet_size == 2)
1028            {
1029              p[2]+=p[0]+((p[1]+p[3]) >> 8);
1030              p[3]+=p[1];
1031            }
1032          else
1033           *(p+1)+=*p;
1034          p+=packet_size;
1035        }
1036        p+=packet_size;
1037        count-=row_size;
1038      }
1039   }
1040
1041   status=MagickTrue;
1042   p=pixels;
1043   for (y=0; y < (ssize_t) image->rows; y++)
1044   {
1045     status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1046     if (status == MagickFalse)
1047       break;
1048
1049     p+=row_size;
1050   }
1051
1052   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1053   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1054   return(status);
1055 }
1056 #endif
1057
1058 static MagickStatusType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
1059   LayerInfo* layer_info,const size_t channel,
1060   const PSDCompressionType compression,ExceptionInfo *exception)
1061 {
1062   Image
1063     *channel_image,
1064     *mask;
1065
1066   MagickOffsetType
1067     offset;
1068
1069   MagickStatusType
1070     status;
1071
1072   channel_image=image;
1073   mask=(Image *) NULL;
1074   if (layer_info->channel_info[channel].type < -1)
1075   {
1076     /*
1077       Ignore mask that is not a user supplied layer mask, if the mask is
1078       disabled or if the flags have unsupported values.
1079     */
1080     if (layer_info->channel_info[channel].type != -2 ||
1081         (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02))
1082     {
1083       SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1084       return(MagickTrue);
1085     }
1086     mask=CloneImage(image,layer_info->mask.page.width,
1087       layer_info->mask.page.height,MagickFalse,exception);
1088     SetImageType(mask,GrayscaleType,exception);
1089     channel_image=mask;
1090   }
1091
1092   offset=TellBlob(channel_image);
1093   status=MagickTrue;
1094   switch(compression)
1095   {
1096     case Raw:
1097       return(ReadPSDChannelRaw(channel_image,psd_info->channels,
1098         layer_info->channel_info[channel].type,exception));
1099     case RLE:
1100       {
1101         MagickOffsetType
1102           *offsets;
1103
1104         offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
1105         if (offsets == (MagickOffsetType *) NULL)
1106           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1107             image->filename);
1108         status=ReadPSDChannelRLE(channel_image,psd_info,
1109           layer_info->channel_info[channel].type,offsets,exception);
1110         offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1111       }
1112       break;
1113     case ZipWithPrediction:
1114     case ZipWithoutPrediction:
1115 #ifdef MAGICKCORE_ZLIB_DELEGATE
1116       status=ReadPSDChannelZip(channel_image,layer_info->channels,
1117         layer_info->channel_info[channel].type,compression,
1118         layer_info->channel_info[channel].size-2,exception);
1119 #else
1120       SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1121       (void) ThrowMagickException(exception,GetMagickModule(),
1122           MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1123             "'%s' (ZLIB)",image->filename);
1124 #endif
1125       break;
1126     default:
1127       SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1128       (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1129         "CompressionNotSupported","'%.20g'",(double) compression);
1130       break;
1131   }
1132
1133   if (status == MagickFalse)
1134     SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1135   if (mask != (Image *) NULL)
1136   {
1137     if (status != MagickFalse)
1138       {
1139         PixelInfo
1140           color;
1141
1142         layer_info->mask.image=CloneImage(image,image->columns,image->rows,
1143           MagickTrue,exception);
1144         layer_info->mask.image->alpha_trait=UndefinedPixelTrait;
1145         GetPixelInfo(layer_info->mask.image,&color);
1146         color.red=layer_info->mask.background == 0 ? 0 : QuantumRange;
1147         SetImageColor(layer_info->mask.image,&color,exception);
1148         (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp,
1149           MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y,
1150           exception);
1151       }
1152     DestroyImage(mask);
1153   }
1154
1155   return(status);
1156 }
1157
1158 static MagickStatusType ReadPSDLayer(Image *image,const PSDInfo *psd_info,
1159   LayerInfo* layer_info,ExceptionInfo *exception)
1160 {
1161   char
1162     message[MagickPathExtent];
1163
1164   MagickStatusType
1165     status;
1166
1167   PSDCompressionType
1168     compression;
1169
1170   ssize_t
1171     j;
1172
1173   if (image->debug != MagickFalse)
1174     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1175       "    setting up new layer image");
1176   (void) SetImageBackgroundColor(layer_info->image,exception);
1177   layer_info->image->compose=PSDBlendModeToCompositeOperator(
1178     layer_info->blendkey);
1179   if (layer_info->visible == MagickFalse)
1180     layer_info->image->compose=NoCompositeOp;
1181   if (psd_info->mode == CMYKMode)
1182     SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1183   if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) ||
1184       (psd_info->mode == DuotoneMode))
1185     SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1186   /*
1187     Set up some hidden attributes for folks that need them.
1188   */
1189   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1190     (double) layer_info->page.x);
1191   (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1192   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1193     (double) layer_info->page.y);
1194   (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1195   (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1196     layer_info->opacity);
1197   (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1198   (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1199     exception);
1200
1201   status=MagickTrue;
1202   for (j=0; j < (ssize_t) layer_info->channels; j++)
1203   {
1204     if (image->debug != MagickFalse)
1205       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1206         "    reading data for channel %.20g",(double) j);
1207
1208     compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1209     layer_info->image->compression=ConvertPSDCompression(compression);
1210     if (layer_info->channel_info[j].type == -1)
1211       layer_info->image->alpha_trait=BlendPixelTrait;
1212
1213     status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j,
1214       compression,exception);
1215
1216     if (status == MagickFalse)
1217       break;
1218   }
1219
1220   if (status != MagickFalse)
1221     status=CorrectPSDOpacity(layer_info,exception);
1222
1223   if (status != MagickFalse)
1224     {
1225       if (layer_info->image->colorspace == CMYKColorspace)
1226         NegateCMYK(layer_info->image,exception);
1227       if (layer_info->mask.image != (Image *) NULL)
1228         {
1229           CompositeImage(layer_info->image,layer_info->mask.image,
1230             CopyAlphaCompositeOp,MagickTrue,0,0,exception);
1231           layer_info->mask.image=DestroyImage(layer_info->mask.image);
1232         }
1233     }
1234
1235   return(status);
1236 }
1237
1238 ModuleExport MagickStatusType ReadPSDLayers(Image *image,
1239   const ImageInfo *image_info,const PSDInfo *psd_info,
1240   const MagickBooleanType skip_layers,ExceptionInfo *exception)
1241 {
1242   char
1243     type[4];
1244
1245   LayerInfo
1246     *layer_info;
1247
1248   MagickSizeType
1249     size;
1250
1251   MagickStatusType
1252     status;
1253
1254   register ssize_t
1255     i;
1256
1257   ssize_t
1258     count,
1259     j,
1260     number_layers;
1261
1262   size=GetPSDSize(psd_info,image);
1263   if (size == 0)
1264     {
1265       /*
1266         Skip layers & masks.
1267       */
1268       (void) ReadBlobLong(image);
1269       count=ReadBlob(image,4,(unsigned char *) type);
1270       ReversePSDString(image,type,4);
1271       status=MagickFalse;
1272       if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1273         return(MagickTrue);
1274       else
1275         {
1276           count=ReadBlob(image,4,(unsigned char *) type);
1277           ReversePSDString(image,type,4);
1278           if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1279             size=GetPSDSize(psd_info,image);
1280           else
1281             return(MagickTrue);
1282         }
1283     }
1284   status=MagickTrue;
1285   if (size != 0)
1286     {
1287       layer_info=(LayerInfo *) NULL;
1288       number_layers=(short) ReadBlobShort(image);
1289
1290       if (number_layers < 0)
1291         {
1292           /*
1293             The first alpha channel in the merged result contains the
1294             transparency data for the merged result.
1295           */
1296           number_layers=MagickAbsoluteValue(number_layers);
1297           if (image->debug != MagickFalse)
1298             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1299               "  negative layer count corrected for");
1300           image->alpha_trait=BlendPixelTrait;
1301         }
1302
1303       /*
1304         We only need to know if the image has an alpha channel
1305       */
1306       if (skip_layers != MagickFalse)
1307         return(MagickTrue);
1308
1309       if (image->debug != MagickFalse)
1310         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1311           "  image contains %.20g layers",(double) number_layers);
1312
1313       if (number_layers == 0)
1314         ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1315           image->filename);
1316
1317       layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1318         sizeof(*layer_info));
1319       if (layer_info == (LayerInfo *) NULL)
1320         {
1321           if (image->debug != MagickFalse)
1322             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1323               "  allocation of LayerInfo failed");
1324           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1325             image->filename);
1326         }
1327       (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1328         sizeof(*layer_info));
1329
1330       for (i=0; i < number_layers; i++)
1331       {
1332         ssize_t
1333           x,
1334           y;
1335
1336         if (image->debug != MagickFalse)
1337           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1338             "  reading layer #%.20g",(double) i+1);
1339         layer_info[i].page.y=(int) ReadBlobLong(image);
1340         layer_info[i].page.x=(int) ReadBlobLong(image);
1341         y=(int) ReadBlobLong(image);
1342         x=(int) ReadBlobLong(image);
1343         layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1344         layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
1345         layer_info[i].channels=ReadBlobShort(image);
1346         if (layer_info[i].channels > MaxPSDChannels)
1347           {
1348             layer_info=DestroyLayerInfo(layer_info,number_layers);
1349             ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1350               image->filename);
1351           }
1352         if (image->debug != MagickFalse)
1353           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1354             "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1355             (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1356             (double) layer_info[i].page.height,(double)
1357             layer_info[i].page.width,(double) layer_info[i].channels);
1358         for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1359         {
1360           layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1361           layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1362             image);
1363           if (image->debug != MagickFalse)
1364             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1365               "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1366               (double) layer_info[i].channel_info[j].type,
1367               (double) layer_info[i].channel_info[j].size);
1368         }
1369         count=ReadBlob(image,4,(unsigned char *) type);
1370         ReversePSDString(image,type,4);
1371         if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1372           {
1373             if (image->debug != MagickFalse)
1374               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1375                 "  layer type was %.4s instead of 8BIM", type);
1376             layer_info=DestroyLayerInfo(layer_info,number_layers);
1377             ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1378               image->filename);
1379           }
1380         count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1381         ReversePSDString(image,layer_info[i].blendkey,4);
1382         layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1383           ReadBlobByte(image));
1384         layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1385         layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1386         layer_info[i].visible=!(layer_info[i].flags & 0x02);
1387         if (image->debug != MagickFalse)
1388           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1389             "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1390             layer_info[i].blendkey,(double) layer_info[i].opacity,
1391             layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1392             layer_info[i].visible ? "true" : "false");
1393         (void) ReadBlobByte(image);  /* filler */
1394
1395         size=ReadBlobLong(image);
1396         if (size != 0)
1397           {
1398             MagickSizeType
1399               combined_length,
1400               length;
1401
1402             if (image->debug != MagickFalse)
1403               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1404                 "    layer contains additional info");
1405             length=ReadBlobLong(image);
1406             combined_length=length+4;
1407             if (length != 0)
1408               {
1409                 /*
1410                   Layer mask info.
1411                 */
1412                 layer_info[i].mask.page.y=(int) ReadBlobLong(image);
1413                 layer_info[i].mask.page.x=(int) ReadBlobLong(image);
1414                 layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
1415                   layer_info[i].mask.page.y);
1416                 layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
1417                   layer_info[i].mask.page.x);
1418                 layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1419                   image);
1420                 layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1421                 if (!(layer_info[i].mask.flags & 0x01))
1422                   {
1423                     layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1424                       layer_info[i].page.y;
1425                     layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1426                       layer_info[i].page.x;
1427                   }
1428                 if (image->debug != MagickFalse)
1429                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1430                     "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1431                     (double) layer_info[i].mask.page.x,(double) 
1432                     layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1433                     (double) layer_info[i].mask.page.height,(double)
1434                     ((MagickOffsetType) length)-18);
1435                 /*
1436                   Skip over the rest of the layer mask information.
1437                 */
1438                 if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1439                   {
1440                     layer_info=DestroyLayerInfo(layer_info,number_layers);
1441                     ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1442                       image->filename);
1443                   }
1444               }
1445             length=ReadBlobLong(image);
1446             combined_length+=length+4;
1447             if (length != 0)
1448               {
1449                 /*
1450                   Layer blending ranges info.
1451                 */
1452                 if (image->debug != MagickFalse)
1453                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1454                     "      layer blending ranges: length=%.20g",(double)
1455                     ((MagickOffsetType) length));
1456                 /*
1457                   We read it, but don't use it...
1458                 */
1459                 for (j=0; j < (ssize_t) (length); j+=8)
1460                 {
1461                   size_t blend_source=ReadBlobLong(image);
1462                   size_t blend_dest=ReadBlobLong(image);
1463                   if (image->debug != MagickFalse)
1464                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1465                       "        source(%x), dest(%x)",(unsigned int)
1466                       blend_source,(unsigned int) blend_dest);
1467                 }
1468               }
1469             /*
1470               Layer name.
1471             */
1472             length=(size_t) ReadBlobByte(image);
1473             combined_length+=length+1;
1474             if (length > 0)
1475               (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1476             layer_info[i].name[length]='\0';
1477             if (image->debug != MagickFalse)
1478               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1479                 "      layer name: %s",layer_info[i].name);
1480             /*
1481                Skip the rest of the variable data until we support it.
1482              */
1483              if (image->debug != MagickFalse)
1484                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1485                  "      unsupported data: length=%.20g",(double)
1486                  ((MagickOffsetType) (size-combined_length)));
1487              if (DiscardBlobBytes(image,(MagickSizeType) (size-combined_length)) == MagickFalse)
1488                {
1489                  layer_info=DestroyLayerInfo(layer_info,number_layers);
1490                  ThrowBinaryException(CorruptImageError,
1491                    "UnexpectedEndOfFile",image->filename);
1492                }
1493           }
1494       }
1495
1496       for (i=0; i < number_layers; i++)
1497       {
1498         if ((layer_info[i].page.width == 0) ||
1499               (layer_info[i].page.height == 0))
1500           {
1501             if (image->debug != MagickFalse)
1502               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1503                 "      layer data is empty");
1504             continue;
1505           }
1506
1507         /*
1508           Allocate layered image.
1509         */
1510         layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1511           layer_info[i].page.height,MagickFalse,exception);
1512         if (layer_info[i].image == (Image *) NULL)
1513           {
1514             layer_info=DestroyLayerInfo(layer_info,number_layers);
1515             if (image->debug != MagickFalse)
1516               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1517                 "  allocation of image for layer %.20g failed",(double) i);
1518             ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1519               image->filename);
1520           }
1521       }
1522
1523       if (image_info->ping == MagickFalse)
1524         {
1525           for (i=0; i < number_layers; i++)
1526           {
1527             if (layer_info[i].image == (Image *) NULL)
1528               {
1529                 for (j=0; j < layer_info[i].channels; j++)
1530                 {
1531                   if (DiscardBlobBytes(image,(MagickSizeType)
1532                       layer_info[i].channel_info[j].size) == MagickFalse)
1533                     {
1534                       layer_info=DestroyLayerInfo(layer_info,number_layers);
1535                       ThrowBinaryException(CorruptImageError,
1536                         "UnexpectedEndOfFile",image->filename);
1537                     }
1538                 }
1539                 continue;
1540               }
1541
1542             if (image->debug != MagickFalse)
1543               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1544                 "  reading data for layer %.20g",(double) i);
1545
1546             status=ReadPSDLayer(image,psd_info,&layer_info[i],exception);
1547             if (status == MagickFalse)
1548               break;
1549
1550             status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1551               number_layers);
1552             if (status == MagickFalse)
1553               break;
1554           }
1555         }
1556
1557       if (status != MagickFalse)
1558       {
1559         for (i=0; i < number_layers; i++)
1560         {
1561           if (layer_info[i].image == (Image *) NULL)
1562           {
1563             for (j=i; j < number_layers - 1; j++)
1564               layer_info[j] = layer_info[j+1];
1565             number_layers--;
1566             i--;
1567           }
1568         }
1569
1570         if (number_layers > 0)
1571           {
1572             for (i=0; i < number_layers; i++)
1573             {
1574               if (i > 0)
1575                 layer_info[i].image->previous=layer_info[i-1].image;
1576               if (i < (number_layers-1))
1577                 layer_info[i].image->next=layer_info[i+1].image;
1578               layer_info[i].image->page=layer_info[i].page;
1579             }
1580             image->next=layer_info[0].image;
1581             layer_info[0].image->previous=image;
1582           }
1583       }
1584       layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1585     }
1586
1587   return(status);
1588 }
1589
1590 static MagickStatusType ReadPSDMergedImage(Image* image,
1591   const PSDInfo* psd_info,ExceptionInfo *exception)
1592 {
1593   MagickOffsetType
1594     *offsets;
1595
1596   MagickStatusType
1597     status;
1598
1599   PSDCompressionType
1600     compression;
1601
1602   register ssize_t
1603     i;
1604
1605   compression=(PSDCompressionType) ReadBlobMSBShort(image);
1606   image->compression=ConvertPSDCompression(compression);
1607
1608   if (compression != Raw && compression != RLE)
1609     {
1610       (void) ThrowMagickException(exception,GetMagickModule(),
1611         TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1612       return(MagickFalse);
1613     }
1614
1615   offsets=(MagickOffsetType *) NULL;
1616   if (compression == RLE)
1617   {
1618     offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
1619     if (offsets == (MagickOffsetType *) NULL)
1620       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1621         image->filename);
1622   }
1623
1624   status=MagickTrue;
1625   for (i=0; i < (ssize_t) psd_info->channels; i++)
1626   {
1627     if (compression == RLE)
1628       status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
1629         exception);
1630     else
1631       status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1632
1633     if (status == MagickFalse)
1634       break;
1635     status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1636     if (status == MagickFalse)
1637       break;
1638   }
1639
1640   if (image->colorspace == CMYKColorspace)
1641     (void) NegateCMYK(image,exception);
1642
1643   if (offsets != (MagickOffsetType *) NULL)
1644     offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1645
1646   return(status);
1647 }
1648
1649 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1650 {
1651   Image
1652     *image;
1653
1654   MagickBooleanType
1655     has_merged_image,
1656     skip_layers;
1657
1658   MagickOffsetType
1659     offset;
1660
1661   MagickSizeType
1662     length;
1663
1664   MagickStatusType
1665     status;
1666
1667   PSDInfo
1668     psd_info;
1669
1670   register ssize_t
1671     i;
1672
1673   ssize_t
1674     count;
1675
1676   unsigned char
1677     *data;
1678
1679   /*
1680     Open image file.
1681   */
1682   assert(image_info != (const ImageInfo *) NULL);
1683   assert(image_info->signature == MagickCoreSignature);
1684   if (image_info->debug != MagickFalse)
1685     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1686       image_info->filename);
1687   assert(exception != (ExceptionInfo *) NULL);
1688   assert(exception->signature == MagickCoreSignature);
1689
1690   image=AcquireImage(image_info,exception);
1691   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1692   if (status == MagickFalse)
1693     {
1694       image=DestroyImageList(image);
1695       return((Image *) NULL);
1696     }
1697   /*
1698     Read image header.
1699   */
1700   image->endian=MSBEndian;
1701   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1702   psd_info.version=ReadBlobMSBShort(image);
1703   if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1704       ((psd_info.version != 1) && (psd_info.version != 2)))
1705     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1706   (void) ReadBlob(image,6,psd_info.reserved);
1707   psd_info.channels=ReadBlobMSBShort(image);
1708   if (psd_info.channels > MaxPSDChannels)
1709     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1710   psd_info.rows=ReadBlobMSBLong(image);
1711   psd_info.columns=ReadBlobMSBLong(image);
1712   if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1713       (psd_info.columns > 30000)))
1714     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1715   psd_info.depth=ReadBlobMSBShort(image);
1716   if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1717     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1718   psd_info.mode=ReadBlobMSBShort(image);
1719   if (image->debug != MagickFalse)
1720     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1721       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1722       (double) psd_info.columns,(double) psd_info.rows,(double)
1723       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1724       psd_info.mode));
1725   /*
1726     Initialize image.
1727   */
1728   image->depth=psd_info.depth;
1729   image->columns=psd_info.columns;
1730   image->rows=psd_info.rows;
1731   status=SetImageExtent(image,image->columns,image->rows,exception);
1732   if (status == MagickFalse)
1733     return(DestroyImageList(image));
1734   if (SetImageBackgroundColor(image,exception) == MagickFalse)
1735     {
1736       image=DestroyImageList(image);
1737       return((Image *) NULL);
1738     }
1739   if (psd_info.mode == LabMode)
1740     SetImageColorspace(image,LabColorspace,exception);
1741   if (psd_info.mode == CMYKMode)
1742     {
1743       SetImageColorspace(image,CMYKColorspace,exception);
1744       image->alpha_trait=psd_info.channels > 4 ? BlendPixelTrait :
1745         UndefinedPixelTrait;
1746     }
1747   else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
1748       (psd_info.mode == DuotoneMode))
1749     {
1750       status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1751         exception);
1752       if (status == MagickFalse)
1753         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1754       if (image->debug != MagickFalse)
1755         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1756           "  Image colormap allocated");
1757       SetImageColorspace(image,GRAYColorspace,exception);
1758       image->alpha_trait=psd_info.channels > 1 ? BlendPixelTrait :
1759         UndefinedPixelTrait;
1760     }
1761   else
1762     image->alpha_trait=psd_info.channels > 3 ? BlendPixelTrait :
1763       UndefinedPixelTrait;
1764   /*
1765     Read PSD raster colormap only present for indexed and duotone images.
1766   */
1767   length=ReadBlobMSBLong(image);
1768   if (length != 0)
1769     {
1770       if (image->debug != MagickFalse)
1771         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1772           "  reading colormap");
1773       if (psd_info.mode == DuotoneMode)
1774         {
1775           /*
1776             Duotone image data;  the format of this data is undocumented.
1777           */
1778           data=(unsigned char *) AcquireQuantumMemory((size_t) length,
1779             sizeof(*data));
1780           if (data == (unsigned char *) NULL)
1781             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1782           (void) ReadBlob(image,(size_t) length,data);
1783           data=(unsigned char *) RelinquishMagickMemory(data);
1784         }
1785       else
1786         {
1787           size_t
1788             number_colors;
1789
1790           /*
1791             Read PSD raster colormap.
1792           */
1793           number_colors=length/3;
1794           if (number_colors > 65536)
1795             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1796           if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
1797             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1798           for (i=0; i < (ssize_t) image->colors; i++)
1799             image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1800               ReadBlobByte(image));
1801           for (i=0; i < (ssize_t) image->colors; i++)
1802             image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1803               ReadBlobByte(image));
1804           for (i=0; i < (ssize_t) image->colors; i++)
1805             image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1806               ReadBlobByte(image));
1807           image->alpha_trait=UndefinedPixelTrait;
1808         }
1809     }
1810   has_merged_image=MagickTrue;
1811   length=ReadBlobMSBLong(image);
1812   if (length != 0)
1813     {
1814       unsigned char
1815         *blocks;
1816
1817       /*
1818         Image resources block.
1819       */
1820       if (image->debug != MagickFalse)
1821         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1822           "  reading image resource blocks - %.20g bytes",(double)
1823           ((MagickOffsetType) length));
1824       blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
1825         sizeof(*blocks));
1826       if (blocks == (unsigned char *) NULL)
1827         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1828       count=ReadBlob(image,(size_t) length,blocks);
1829       if ((count != (ssize_t) length) ||
1830           (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
1831         {
1832           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1833           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1834         }
1835       ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
1836         exception);
1837       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
1838     }
1839   /*
1840     Layer and mask block.
1841   */
1842   length=GetPSDSize(&psd_info,image);
1843   if (length == 8)
1844     {
1845       length=ReadBlobMSBLong(image);
1846       length=ReadBlobMSBLong(image);
1847     }
1848   offset=TellBlob(image);
1849   skip_layers=MagickFalse;
1850   if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
1851       (has_merged_image != MagickFalse))
1852     {
1853       if (image->debug != MagickFalse)
1854         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1855           "  read composite only");
1856       skip_layers=MagickTrue;
1857     }
1858   if (length == 0)
1859     {
1860       if (image->debug != MagickFalse)
1861         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1862           "  image has no layers");
1863     }
1864   else
1865     {
1866       if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
1867           MagickTrue)
1868         {
1869           (void) CloseBlob(image);
1870           image=DestroyImageList(image);
1871           return((Image *) NULL);
1872         }
1873
1874       /*
1875          Skip the rest of the layer and mask information.
1876       */
1877       SeekBlob(image,offset+length,SEEK_SET);
1878     }
1879   /*
1880     If we are only "pinging" the image, then we're done - so return.
1881   */
1882   if (image_info->ping != MagickFalse)
1883     {
1884       (void) CloseBlob(image);
1885       return(GetFirstImageInList(image));
1886     }
1887   /*
1888     Read the precombined layer, present for PSD < 4 compatibility.
1889   */
1890   if (image->debug != MagickFalse)
1891     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1892       "  reading the precombined layer");
1893   if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
1894     has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image,&psd_info,
1895       exception);
1896   if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
1897       (length != 0))
1898     {
1899       SeekBlob(image,offset,SEEK_SET);
1900       status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
1901       if (status != MagickTrue)
1902         {
1903           (void) CloseBlob(image);
1904           return((Image *) NULL);
1905         }
1906     }
1907   if ((has_merged_image == MagickFalse) && (GetImageListLength(image) > 1))
1908     {
1909       Image
1910         *merged;
1911
1912       SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
1913       image->background_color.alpha=TransparentAlpha;
1914       image->background_color.alpha_trait=BlendPixelTrait;
1915       merged=MergeImageLayers(image,FlattenLayer,exception);
1916       ReplaceImageInList(&image,merged);
1917     }
1918   (void) CloseBlob(image);
1919   return(GetFirstImageInList(image));
1920 }
1921 \f
1922 /*
1923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1924 %                                                                             %
1925 %                                                                             %
1926 %                                                                             %
1927 %   R e g i s t e r P S D I m a g e                                           %
1928 %                                                                             %
1929 %                                                                             %
1930 %                                                                             %
1931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1932 %
1933 %  RegisterPSDImage() adds properties for the PSD image format to
1934 %  the list of supported formats.  The properties include the image format
1935 %  tag, a method to read and/or write the format, whether the format
1936 %  supports the saving of more than one frame to the same file or blob,
1937 %  whether the format supports native in-memory I/O, and a brief
1938 %  description of the format.
1939 %
1940 %  The format of the RegisterPSDImage method is:
1941 %
1942 %      size_t RegisterPSDImage(void)
1943 %
1944 */
1945 ModuleExport size_t RegisterPSDImage(void)
1946 {
1947   MagickInfo
1948     *entry;
1949
1950   entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
1951   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1952   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1953   entry->magick=(IsImageFormatHandler *) IsPSD;
1954   entry->flags|=CoderSeekableStreamFlag;
1955   (void) RegisterMagickInfo(entry);
1956   entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
1957   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1958   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1959   entry->magick=(IsImageFormatHandler *) IsPSD;
1960   entry->flags|=CoderSeekableStreamFlag;
1961   (void) RegisterMagickInfo(entry);
1962   return(MagickImageCoderSignature);
1963 }
1964 \f
1965 /*
1966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967 %                                                                             %
1968 %                                                                             %
1969 %                                                                             %
1970 %   U n r e g i s t e r P S D I m a g e                                       %
1971 %                                                                             %
1972 %                                                                             %
1973 %                                                                             %
1974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 %
1976 %  UnregisterPSDImage() removes format registrations made by the
1977 %  PSD module from the list of supported formats.
1978 %
1979 %  The format of the UnregisterPSDImage method is:
1980 %
1981 %      UnregisterPSDImage(void)
1982 %
1983 */
1984 ModuleExport void UnregisterPSDImage(void)
1985 {
1986   (void) UnregisterMagickInfo("PSB");
1987   (void) UnregisterMagickInfo("PSD");
1988 }
1989 \f
1990 /*
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992 %                                                                             %
1993 %                                                                             %
1994 %                                                                             %
1995 %   W r i t e P S D I m a g e                                                 %
1996 %                                                                             %
1997 %                                                                             %
1998 %                                                                             %
1999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000 %
2001 %  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2002 %
2003 %  The format of the WritePSDImage method is:
2004 %
2005 %      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2006 %        ExceptionInfo *exception)
2007 %
2008 %  A description of each parameter follows.
2009 %
2010 %    o image_info: the image info.
2011 %
2012 %    o image:  The image.
2013 %
2014 %    o exception: return any errors or warnings in this structure.
2015 %
2016 */
2017
2018 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2019   const size_t offset)
2020 {
2021   if (psd_info->version == 1)
2022     return(WriteBlobMSBShort(image,(unsigned short) offset));
2023   return(WriteBlobMSBLong(image,(unsigned short) offset));
2024 }
2025
2026 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2027   const MagickSizeType size)
2028 {
2029   if (psd_info->version == 1)
2030     return(WriteBlobMSBLong(image,(unsigned int) size));
2031   return(WriteBlobMSBLongLong(image,size));
2032 }
2033
2034 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2035   const unsigned char *pixels,unsigned char *compact_pixels,
2036   ExceptionInfo *exception)
2037 {
2038   int
2039     count;
2040
2041   register ssize_t
2042     i,
2043     j;
2044
2045   register unsigned char
2046     *q;
2047
2048   unsigned char
2049     *packbits;
2050
2051   /*
2052     Compress pixels with Packbits encoding.
2053   */
2054   assert(image != (Image *) NULL);
2055   assert(image->signature == MagickCoreSignature);
2056   if (image->debug != MagickFalse)
2057     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2058   assert(pixels != (unsigned char *) NULL);
2059   packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2060   if (packbits == (unsigned char *) NULL)
2061     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2062       image->filename);
2063   q=compact_pixels;
2064   for (i=(ssize_t) length; i != 0; )
2065   {
2066     switch (i)
2067     {
2068       case 1:
2069       {
2070         i--;
2071         *q++=(unsigned char) 0;
2072         *q++=(*pixels);
2073         break;
2074       }
2075       case 2:
2076       {
2077         i-=2;
2078         *q++=(unsigned char) 1;
2079         *q++=(*pixels);
2080         *q++=pixels[1];
2081         break;
2082       }
2083       case 3:
2084       {
2085         i-=3;
2086         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2087           {
2088             *q++=(unsigned char) ((256-3)+1);
2089             *q++=(*pixels);
2090             break;
2091           }
2092         *q++=(unsigned char) 2;
2093         *q++=(*pixels);
2094         *q++=pixels[1];
2095         *q++=pixels[2];
2096         break;
2097       }
2098       default:
2099       {
2100         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2101           {
2102             /*
2103               Packed run.
2104             */
2105             count=3;
2106             while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2107             {
2108               count++;
2109               if (count >= 127)
2110                 break;
2111             }
2112             i-=count;
2113             *q++=(unsigned char) ((256-count)+1);
2114             *q++=(*pixels);
2115             pixels+=count;
2116             break;
2117           }
2118         /*
2119           Literal run.
2120         */
2121         count=0;
2122         while ((*(pixels+count) != *(pixels+count+1)) ||
2123                (*(pixels+count+1) != *(pixels+count+2)))
2124         {
2125           packbits[count+1]=pixels[count];
2126           count++;
2127           if (((ssize_t) count >= (i-3)) || (count >= 127))
2128             break;
2129         }
2130         i-=count;
2131         *packbits=(unsigned char) (count-1);
2132         for (j=0; j <= (ssize_t) count; j++)
2133           *q++=packbits[j];
2134         pixels+=count;
2135         break;
2136       }
2137     }
2138   }
2139   *q++=(unsigned char) 128;  /* EOD marker */
2140   packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2141   return((size_t) (q-compact_pixels));
2142 }
2143
2144 static void WritePackbitsLength(const PSDInfo *psd_info,
2145   const ImageInfo *image_info,Image *image,Image *next_image,
2146   unsigned char *compact_pixels,const QuantumType quantum_type,
2147   ExceptionInfo *exception)
2148 {
2149   QuantumInfo
2150     *quantum_info;
2151
2152   register const Quantum
2153     *p;
2154
2155   size_t
2156     length,
2157     packet_size;
2158
2159   ssize_t
2160     y;
2161
2162   unsigned char
2163     *pixels;
2164
2165   if (next_image->depth > 8)
2166     next_image->depth=16;
2167   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2168   (void) packet_size;
2169   quantum_info=AcquireQuantumInfo(image_info,image);
2170   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2171   for (y=0; y < (ssize_t) next_image->rows; y++)
2172   {
2173     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2174     if (p == (const Quantum *) NULL)
2175       break;
2176     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2177       quantum_type,pixels,exception);
2178     length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2179       exception);
2180     (void) SetPSDOffset(psd_info,image,length);
2181   }
2182   quantum_info=DestroyQuantumInfo(quantum_info);
2183 }
2184
2185 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
2186   Image *image,Image *next_image,unsigned char *compact_pixels,
2187   const QuantumType quantum_type,const MagickBooleanType compression_flag,
2188   ExceptionInfo *exception)
2189 {
2190   int
2191     y;
2192
2193   MagickBooleanType
2194     monochrome;
2195
2196   QuantumInfo
2197     *quantum_info;
2198
2199   register const Quantum
2200     *p;
2201
2202   register ssize_t
2203     i;
2204
2205   size_t
2206     length,
2207     packet_size;
2208
2209   unsigned char
2210     *pixels;
2211
2212   (void) psd_info;
2213   if ((compression_flag != MagickFalse) &&
2214       (next_image->compression != RLECompression))
2215     (void) WriteBlobMSBShort(image,0);
2216   if (next_image->depth > 8)
2217     next_image->depth=16;
2218   monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2219     MagickTrue : MagickFalse;
2220   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2221   (void) packet_size;
2222   quantum_info=AcquireQuantumInfo(image_info,image);
2223   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2224   for (y=0; y < (ssize_t) next_image->rows; y++)
2225   {
2226     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
2227     if (p == (const Quantum *) NULL)
2228       break;
2229     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2230       quantum_type,pixels,exception);
2231     if (monochrome != MagickFalse)
2232       for (i=0; i < (ssize_t) length; i++)
2233         pixels[i]=(~pixels[i]);
2234     if (next_image->compression != RLECompression)
2235       (void) WriteBlob(image,length,pixels);
2236     else
2237       {
2238         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2239           exception);
2240         (void) WriteBlob(image,length,compact_pixels);
2241       }
2242   }
2243   quantum_info=DestroyQuantumInfo(quantum_info);
2244 }
2245
2246 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
2247   const ImageInfo *image_info,Image *image,Image *next_image,
2248   const MagickBooleanType separate,ExceptionInfo *exception)
2249 {
2250   size_t
2251     channels,
2252     packet_size;
2253
2254   unsigned char
2255     *compact_pixels;
2256
2257   /*
2258     Write uncompressed pixels as separate planes.
2259   */
2260   channels=1;
2261   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2262   compact_pixels=(unsigned char *) NULL;
2263   if (next_image->compression == RLECompression)
2264     {
2265       compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
2266         next_image->columns,packet_size*sizeof(*compact_pixels));
2267       if (compact_pixels == (unsigned char *) NULL)
2268         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2269     }
2270   if (IsImageGray(next_image) != MagickFalse)
2271     {
2272       if (next_image->compression == RLECompression)
2273         {
2274           /*
2275             Packbits compression.
2276           */
2277           (void) WriteBlobMSBShort(image,1);
2278           WritePackbitsLength(psd_info,image_info,image,next_image,
2279             compact_pixels,GrayQuantum,exception);
2280           if (next_image->alpha_trait != UndefinedPixelTrait)
2281             WritePackbitsLength(psd_info,image_info,image,next_image,
2282               compact_pixels,AlphaQuantum,exception);
2283         }
2284       WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2285         GrayQuantum,MagickTrue,exception);
2286       if (next_image->alpha_trait != UndefinedPixelTrait)
2287         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2288           AlphaQuantum,separate,exception);
2289       (void) SetImageProgress(image,SaveImagesTag,0,1);
2290     }
2291   else
2292     if (next_image->storage_class == PseudoClass)
2293       {
2294         if (next_image->compression == RLECompression)
2295           {
2296             /*
2297               Packbits compression.
2298             */
2299             (void) WriteBlobMSBShort(image,1);
2300             WritePackbitsLength(psd_info,image_info,image,next_image,
2301               compact_pixels,IndexQuantum,exception);
2302             if (next_image->alpha_trait != UndefinedPixelTrait)
2303               WritePackbitsLength(psd_info,image_info,image,next_image,
2304                 compact_pixels,AlphaQuantum,exception);
2305           }
2306         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2307           IndexQuantum,MagickTrue,exception);
2308         if (next_image->alpha_trait != UndefinedPixelTrait)
2309           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2310             AlphaQuantum,separate,exception);
2311         (void) SetImageProgress(image,SaveImagesTag,0,1);
2312       }
2313     else
2314       {
2315         if (next_image->colorspace == CMYKColorspace)
2316           (void) NegateCMYK(next_image,exception);
2317         if (next_image->compression == RLECompression)
2318           {
2319             /*
2320               Packbits compression.
2321             */
2322             (void) WriteBlobMSBShort(image,1);
2323             WritePackbitsLength(psd_info,image_info,image,next_image,
2324               compact_pixels,RedQuantum,exception);
2325             WritePackbitsLength(psd_info,image_info,image,next_image,
2326               compact_pixels,GreenQuantum,exception);
2327             WritePackbitsLength(psd_info,image_info,image,next_image,
2328               compact_pixels,BlueQuantum,exception);
2329             if (next_image->colorspace == CMYKColorspace)
2330               WritePackbitsLength(psd_info,image_info,image,next_image,
2331                 compact_pixels,BlackQuantum,exception);
2332             if (next_image->alpha_trait != UndefinedPixelTrait)
2333               WritePackbitsLength(psd_info,image_info,image,next_image,
2334                 compact_pixels,AlphaQuantum,exception);
2335           }
2336         (void) SetImageProgress(image,SaveImagesTag,0,6);
2337         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2338           RedQuantum,MagickTrue,exception);
2339         (void) SetImageProgress(image,SaveImagesTag,1,6);
2340         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2341           GreenQuantum,separate,exception);
2342         (void) SetImageProgress(image,SaveImagesTag,2,6);
2343         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2344           BlueQuantum,separate,exception);
2345         (void) SetImageProgress(image,SaveImagesTag,3,6);
2346         if (next_image->colorspace == CMYKColorspace)
2347           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2348             BlackQuantum,separate,exception);
2349         (void) SetImageProgress(image,SaveImagesTag,4,6);
2350         if (next_image->alpha_trait != UndefinedPixelTrait)
2351           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2352             AlphaQuantum,separate,exception);
2353         (void) SetImageProgress(image,SaveImagesTag,5,6);
2354         if (next_image->colorspace == CMYKColorspace)
2355           (void) NegateCMYK(next_image,exception);
2356       }
2357   if (next_image->compression == RLECompression)
2358     compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
2359   return(MagickTrue);
2360 }
2361
2362 static void WritePascalString(Image* inImage,const char *inString,int inPad)
2363 {
2364   size_t
2365     length;
2366
2367   register ssize_t
2368     i;
2369
2370   /*
2371     Max length is 255.
2372   */
2373   length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
2374   if (length ==  0)
2375     (void) WriteBlobByte(inImage,0);
2376   else
2377     {
2378       (void) WriteBlobByte(inImage,(unsigned char) length);
2379       (void) WriteBlob(inImage, length, (const unsigned char *) inString);
2380     }
2381   length++;
2382   if ((length % inPad) == 0)
2383     return;
2384   for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
2385     (void) WriteBlobByte(inImage,0);
2386 }
2387
2388 static void WriteResolutionResourceBlock(Image *image)
2389 {
2390   double
2391     x_resolution,
2392     y_resolution;
2393
2394   unsigned short
2395     units;
2396
2397   if (image->units == PixelsPerCentimeterResolution)
2398     {
2399       x_resolution=2.54*65536.0*image->resolution.x+0.5;
2400       y_resolution=2.54*65536.0*image->resolution.y+0.5;
2401       units=2;
2402     }
2403   else
2404     {
2405       x_resolution=65536.0*image->resolution.x+0.5;
2406       y_resolution=65536.0*image->resolution.y+0.5;
2407       units=1;
2408     }
2409   (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2410   (void) WriteBlobMSBShort(image,0x03ED);
2411   (void) WriteBlobMSBShort(image,0);
2412   (void) WriteBlobMSBLong(image,16); /* resource size */
2413   (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
2414   (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
2415   (void) WriteBlobMSBShort(image,units); /* width unit */
2416   (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
2417   (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
2418   (void) WriteBlobMSBShort(image,units); /* height unit */
2419 }
2420
2421 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2422 {
2423   register const unsigned char
2424     *p;
2425
2426   size_t
2427     length;
2428
2429   unsigned char
2430     *datum;
2431
2432   unsigned int
2433     count,
2434     long_sans;
2435
2436   unsigned short
2437     id,
2438     short_sans;
2439
2440   length=GetStringInfoLength(bim_profile);
2441   if (length < 16)
2442     return;
2443   datum=GetStringInfoDatum(bim_profile);
2444   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2445   {
2446     register unsigned char
2447       *q;
2448
2449     q=(unsigned char *) p;
2450     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2451       break;
2452     p=PushLongPixel(MSBEndian,p,&long_sans);
2453     p=PushShortPixel(MSBEndian,p,&id);
2454     p=PushShortPixel(MSBEndian,p,&short_sans);
2455     p=PushLongPixel(MSBEndian,p,&count);
2456     if (id == 0x0000040f)
2457       {
2458         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2459           (PSDQuantum(count)+12)-(q-datum));
2460         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2461         break;
2462       }
2463     p+=count;
2464     if ((count & 0x01) != 0)
2465       p++;
2466   }
2467 }
2468
2469 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2470 {
2471   register const unsigned char
2472     *p;
2473
2474   size_t
2475     length;
2476
2477   unsigned char
2478     *datum;
2479
2480   unsigned int
2481     count,
2482     long_sans;
2483
2484   unsigned short
2485     id,
2486     short_sans;
2487
2488   length=GetStringInfoLength(bim_profile);
2489   if (length < 16)
2490     return;
2491   datum=GetStringInfoDatum(bim_profile);
2492   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2493   {
2494     register unsigned char
2495       *q;
2496
2497     q=(unsigned char *) p;
2498     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2499       break;
2500     p=PushLongPixel(MSBEndian,p,&long_sans);
2501     p=PushShortPixel(MSBEndian,p,&id);
2502     p=PushShortPixel(MSBEndian,p,&short_sans);
2503     p=PushLongPixel(MSBEndian,p,&count);
2504     if ((id == 0x000003ed) && (PSDQuantum(count) < (ssize_t) (length-12)))
2505       {
2506         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2507           (PSDQuantum(count)+12)-(q-datum));
2508         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2509         break;
2510       }
2511     p+=count;
2512     if ((count & 0x01) != 0)
2513       p++;
2514   }
2515 }
2516
2517 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2518   ExceptionInfo *exception)
2519 {
2520   const char
2521     *property;
2522
2523   const StringInfo
2524     *icc_profile;
2525
2526   Image
2527     *base_image,
2528     *next_image;
2529
2530   MagickBooleanType
2531     status;
2532
2533   PSDInfo
2534     psd_info;
2535
2536   register ssize_t
2537     i;
2538
2539   size_t
2540     channel_size,
2541     channelLength,
2542     layer_count,
2543     layer_info_size,
2544     length,
2545     num_channels,
2546     packet_size,
2547     rounded_layer_info_size;
2548
2549   StringInfo
2550     *bim_profile;
2551
2552   /*
2553     Open image file.
2554   */
2555   assert(image_info != (const ImageInfo *) NULL);
2556   assert(image_info->signature == MagickCoreSignature);
2557   assert(image != (Image *) NULL);
2558   assert(image->signature == MagickCoreSignature);
2559   if (image->debug != MagickFalse)
2560     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2561   assert(exception != (ExceptionInfo *) NULL);
2562   assert(exception->signature == MagickCoreSignature);
2563   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2564   if (status == MagickFalse)
2565     return(status);
2566   packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2567   if (image->alpha_trait != UndefinedPixelTrait)
2568     packet_size+=image->depth > 8 ? 2 : 1;
2569   psd_info.version=1;
2570   if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2571       (image->columns > 30000) || (image->rows > 30000))
2572     psd_info.version=2;
2573   (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2574   (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
2575   for (i=1; i <= 6; i++)
2576     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
2577   if (SetImageGray(image,exception) != MagickFalse)
2578     num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2579   else
2580     if ((image_info->type != TrueColorType) && (image_info->type !=
2581          TrueColorAlphaType) && (image->storage_class == PseudoClass))
2582       num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
2583     else
2584       {
2585         if (image->storage_class == PseudoClass)
2586           (void) SetImageStorageClass(image,DirectClass,exception);
2587         if (image->colorspace != CMYKColorspace)
2588           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
2589         else
2590           num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
2591       }
2592   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2593   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2594   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2595   if (IsImageGray(image) != MagickFalse)
2596     {
2597       MagickBooleanType
2598         monochrome;
2599
2600       /*
2601         Write depth & mode.
2602       */
2603       monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2604         MagickTrue : MagickFalse;
2605       (void) WriteBlobMSBShort(image,(unsigned short)
2606         (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2607       (void) WriteBlobMSBShort(image,(unsigned short)
2608         (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
2609     }
2610   else
2611     {
2612       (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2613         PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2614
2615       if (((image_info->colorspace != UndefinedColorspace) ||
2616            (image->colorspace != CMYKColorspace)) &&
2617           (image_info->colorspace != CMYKColorspace))
2618         {
2619           (void) TransformImageColorspace(image,sRGBColorspace,exception);
2620           (void) WriteBlobMSBShort(image,(unsigned short)
2621             (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2622         }
2623       else
2624         {
2625           if (image->colorspace != CMYKColorspace)
2626             (void) TransformImageColorspace(image,CMYKColorspace,exception);
2627           (void) WriteBlobMSBShort(image,CMYKMode);
2628         }
2629     }
2630   if ((IsImageGray(image) != MagickFalse) ||
2631       (image->storage_class == DirectClass) || (image->colors > 256))
2632     (void) WriteBlobMSBLong(image,0);
2633   else
2634     {
2635       /*
2636         Write PSD raster colormap.
2637       */
2638       (void) WriteBlobMSBLong(image,768);
2639       for (i=0; i < (ssize_t) image->colors; i++)
2640         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2641       for ( ; i < 256; i++)
2642         (void) WriteBlobByte(image,0);
2643       for (i=0; i < (ssize_t) image->colors; i++)
2644         (void) WriteBlobByte(image,ScaleQuantumToChar(
2645           image->colormap[i].green));
2646       for ( ; i < 256; i++)
2647         (void) WriteBlobByte(image,0);
2648       for (i=0; i < (ssize_t) image->colors; i++)
2649         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2650       for ( ; i < 256; i++)
2651         (void) WriteBlobByte(image,0);
2652     }
2653   /*
2654     Image resource block.
2655   */
2656   length=28; /* 0x03EB */
2657   bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2658   icc_profile=GetImageProfile(image,"icc");
2659   if (bim_profile != (StringInfo *) NULL)
2660     {
2661       bim_profile=CloneStringInfo(bim_profile);
2662       if (icc_profile != (StringInfo *) NULL)
2663         RemoveICCProfileFromResourceBlock(bim_profile);
2664       RemoveResolutionFromResourceBlock(bim_profile);
2665       length+=PSDQuantum(GetStringInfoLength(bim_profile));
2666     }
2667   if (icc_profile != (const StringInfo *) NULL)
2668     length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2669   (void) WriteBlobMSBLong(image,(unsigned int) length);
2670   WriteResolutionResourceBlock(image);
2671   if (bim_profile != (StringInfo *) NULL)
2672     {
2673       (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2674         GetStringInfoDatum(bim_profile));
2675       bim_profile=DestroyStringInfo(bim_profile);
2676     }
2677   if (icc_profile != (StringInfo *) NULL)
2678     {
2679       (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2680       (void) WriteBlobMSBShort(image,0x0000040F);
2681       (void) WriteBlobMSBShort(image,0);
2682       (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2683         icc_profile));
2684       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2685         GetStringInfoDatum(icc_profile));
2686       if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2687           PSDQuantum(GetStringInfoLength(icc_profile)))
2688         (void) WriteBlobByte(image,0);
2689     }
2690   layer_count=0;
2691   layer_info_size=2;
2692   base_image=GetNextImageInList(image);
2693   if ((image->alpha_trait != UndefinedPixelTrait) && (base_image == (Image *) NULL))
2694     base_image=image;
2695   next_image=base_image;
2696   while ( next_image != NULL )
2697   {
2698     packet_size=next_image->depth > 8 ? 2UL : 1UL;
2699     if (IsImageGray(next_image) != MagickFalse)
2700       num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2701     else
2702       if (next_image->storage_class == PseudoClass)
2703         num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
2704       else
2705         if (next_image->colorspace != CMYKColorspace)
2706           num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
2707         else
2708           num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
2709     channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
2710     layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
2711       16)+4*1+4+num_channels*channelLength);
2712     property=(const char *) GetImageProperty(next_image,"label",exception);
2713     if (property == (const char *) NULL)
2714       layer_info_size+=16;
2715     else
2716       {
2717         size_t
2718           layer_length;
2719
2720         layer_length=strlen(property);
2721         layer_info_size+=8+layer_length+(4-(layer_length % 4));
2722       }
2723     layer_count++;
2724     next_image=GetNextImageInList(next_image);
2725   }
2726   if (layer_count == 0)
2727     (void) SetPSDSize(&psd_info,image,0);
2728   else
2729     {
2730       CompressionType
2731         compression;
2732
2733       (void) SetPSDSize(&psd_info,image,layer_info_size+
2734         (psd_info.version == 1 ? 8 : 16));
2735       if ((layer_info_size/2) != ((layer_info_size+1)/2))
2736         rounded_layer_info_size=layer_info_size+1;
2737       else
2738         rounded_layer_info_size=layer_info_size;
2739       (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2740       if (image->alpha_trait != UndefinedPixelTrait)
2741         (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
2742       else
2743         (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2744       layer_count=1;
2745       compression=base_image->compression;
2746       for (next_image=base_image; next_image != NULL; )
2747       {
2748         next_image->compression=NoCompression;
2749         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2750         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
2751         (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
2752           next_image->rows));
2753         (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
2754           next_image->columns));
2755         packet_size=next_image->depth > 8 ? 2UL : 1UL;
2756         channel_size=(unsigned int) ((packet_size*next_image->rows*
2757           next_image->columns)+2);
2758         if ((IsImageGray(next_image) != MagickFalse) ||
2759             (next_image->storage_class == PseudoClass))
2760           {
2761              (void) WriteBlobMSBShort(image,(unsigned short)
2762                (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
2763              (void) WriteBlobMSBShort(image,0);
2764              (void) SetPSDSize(&psd_info,image,channel_size);
2765              if (next_image->alpha_trait != UndefinedPixelTrait)
2766                {
2767                  (void) WriteBlobMSBShort(image,(unsigned short) -1);
2768                  (void) SetPSDSize(&psd_info,image,channel_size);
2769                }
2770            }
2771           else
2772             if (next_image->colorspace != CMYKColorspace)
2773               {
2774                 (void) WriteBlobMSBShort(image,(unsigned short)
2775                   (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
2776                (void) WriteBlobMSBShort(image,0);
2777                (void) SetPSDSize(&psd_info,image,channel_size);
2778                (void) WriteBlobMSBShort(image,1);
2779                (void) SetPSDSize(&psd_info,image,channel_size);
2780                (void) WriteBlobMSBShort(image,2);
2781                (void) SetPSDSize(&psd_info,image,channel_size);
2782                if (next_image->alpha_trait != UndefinedPixelTrait)
2783                  {
2784                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2785                    (void) SetPSDSize(&psd_info,image,channel_size);
2786                  }
2787              }
2788            else
2789              {
2790                (void) WriteBlobMSBShort(image,(unsigned short)
2791                  (next_image->alpha_trait ? 5 : 4));
2792                (void) WriteBlobMSBShort(image,0);
2793                (void) SetPSDSize(&psd_info,image,channel_size);
2794                (void) WriteBlobMSBShort(image,1);
2795                (void) SetPSDSize(&psd_info,image,channel_size);
2796                (void) WriteBlobMSBShort(image,2);
2797                (void) SetPSDSize(&psd_info,image,channel_size);
2798                (void) WriteBlobMSBShort(image,3);
2799                (void) SetPSDSize(&psd_info,image,channel_size);
2800                if (next_image->alpha_trait)
2801                  {
2802                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2803                    (void) SetPSDSize(&psd_info,image,channel_size);
2804                  }
2805              }
2806         (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2807         (void) WriteBlob(image,4,(const unsigned char *)
2808           CompositeOperatorToPSDBlendMode(next_image->compose));
2809         (void) WriteBlobByte(image,255); /* layer opacity */
2810         (void) WriteBlobByte(image,0);
2811         (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
2812           1 << 0x02 : 1); /* layer properties - visible, etc. */
2813         (void) WriteBlobByte(image,0);
2814         property=(const char *) GetImageProperty(next_image,"label",exception);
2815         if (property == (const char *) NULL)
2816           {
2817             char
2818               layer_name[MagickPathExtent];
2819
2820             (void) WriteBlobMSBLong(image,16);
2821             (void) WriteBlobMSBLong(image,0);
2822             (void) WriteBlobMSBLong(image,0);
2823             (void) FormatLocaleString(layer_name,MagickPathExtent,"L%04ld",(long)
2824               layer_count++);
2825             WritePascalString(image,layer_name,4);
2826           }
2827         else
2828           {
2829             size_t
2830               label_length;
2831
2832             label_length=strlen(property);
2833             (void) WriteBlobMSBLong(image,(unsigned int) (label_length+(4-
2834               (label_length % 4))+8));
2835             (void) WriteBlobMSBLong(image,0);
2836             (void) WriteBlobMSBLong(image,0);
2837             WritePascalString(image,property,4);
2838           }
2839         next_image=GetNextImageInList(next_image);
2840       }
2841       /*
2842         Now the image data!
2843       */
2844       next_image=base_image;
2845       while (next_image != NULL)
2846       {
2847         status=WriteImageChannels(&psd_info,image_info,image,next_image,
2848           MagickTrue,exception);
2849         next_image=GetNextImageInList(next_image);
2850       }
2851       (void) WriteBlobMSBLong(image,0);  /* user mask data */
2852       base_image->compression=compression;
2853     }
2854   /*
2855     Write composite image.
2856   */
2857   if (status != MagickFalse)
2858     status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
2859       exception);
2860   (void) CloseBlob(image);
2861   return(status);
2862 }