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