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