]> 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,ExceptionInfo *exception)
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=BlobToStringInfo((const void *) NULL,length);
428   SetStringInfoDatum(profile,blocks);
429   (void) SetImageProfile(image,"8bim",profile,exception);
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->resolution.x=(double) resolution;
454         (void) FormatLocaleString(value,MaxTextExtent,"%g",image->resolution.x);
455         (void) SetImageProperty(image,"tiff:XResolution",value,exception);
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->resolution.y=(double) resolution;
461         (void) FormatLocaleString(value,MaxTextExtent,"%g",image->resolution.y);
462         (void) SetImageProperty(image,"tiff:YResolution",value,exception);
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 == (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               SetPixelInfoPixel(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                     SetPixelInfoPixel(image,image->colormap+(ssize_t)
671                       GetPixelIndex(image,q),q);
672                     q+=GetPixelChannels(image);
673                     x++;
674                   }
675                 }
676             }
677           break;
678         }
679         case 1:
680         {
681           if (image->storage_class == PseudoClass)
682             SetPixelAlpha(image,pixel,q);
683           else
684             SetPixelGreen(image,pixel,q);
685           break;
686         }
687         case 2:
688         {
689           if (image->storage_class == PseudoClass)
690             SetPixelAlpha(image,pixel,q);
691           else
692             SetPixelBlue(image,pixel,q);
693           break;
694         }
695         case 3:
696         {
697           if (image->colorspace == CMYKColorspace)
698             SetPixelBlack(image,pixel,q);
699           else
700             SetPixelAlpha(image,pixel,q);
701           break;
702         }
703         case 4:
704         {
705           if ((IsRGBColorspace(image->colorspace) == MagickTrue) && (channels > 3))
706             break;
707           SetPixelAlpha(image,pixel,q);
708           break;
709         }
710         default:
711           break;
712       }
713       q+=GetPixelChannels(image);
714     }
715     if (SyncAuthenticPixels(image,exception) == MagickFalse)
716       break;
717   }
718   image->colorspace=colorspace;
719   if (image->compression == RLECompression)
720     compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
721   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
722   return(MagickTrue);
723 }
724
725 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
726 {
727   char
728     message[MaxTextExtent],
729     type[4];
730
731   Image
732     *image;
733
734   LayerInfo
735     *layer_info;
736
737   MagickBooleanType
738     status;
739
740   MagickOffsetType
741     offset,
742     *offsets;
743
744   MagickSizeType
745     combinedlength,
746     length,
747     size;
748
749   PSDInfo
750     psd_info;
751
752   register Quantum
753     *q;
754
755   register ssize_t
756     i,
757     x;
758
759   size_t
760     mask_size,
761     skip_first_alpha = 0;
762
763   ssize_t
764     count,
765     j,
766     number_layers,
767     y;
768
769   unsigned char
770     *data;
771
772   unsigned short
773     compression;
774
775   /*
776     Open image file.
777   */
778   assert(image_info != (const ImageInfo *) NULL);
779   assert(image_info->signature == MagickSignature);
780   if (image_info->debug != MagickFalse)
781     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
782       image_info->filename);
783   assert(exception != (ExceptionInfo *) NULL);
784   assert(exception->signature == MagickSignature);
785   image=AcquireImage(image_info,exception);
786   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
787   if (status == MagickFalse)
788     {
789       image=DestroyImageList(image);
790       return((Image *) NULL);
791     }
792   /*
793     Read image header.
794   */
795   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
796   psd_info.version=ReadBlobMSBShort(image);
797   if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
798       ((psd_info.version != 1) && (psd_info.version != 2)))
799     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
800   count=ReadBlob(image,6,psd_info.reserved);
801   psd_info.channels=ReadBlobMSBShort(image);
802   if (psd_info.channels > MaxPSDChannels)
803     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
804   psd_info.rows=ReadBlobMSBLong(image);
805   psd_info.columns=ReadBlobMSBLong(image);
806   if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
807       (psd_info.columns > 30000)))
808     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
809   psd_info.depth=ReadBlobMSBShort(image);
810   if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
811     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
812   psd_info.mode=ReadBlobMSBShort(image);
813   if (image->debug != MagickFalse)
814     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
815       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
816       (double) psd_info.columns,(double) psd_info.rows,(double)
817       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
818       psd_info.mode));
819   /*
820     Initialize image.
821   */
822   image->depth=psd_info.depth;
823   image->columns=psd_info.columns;
824   image->rows=psd_info.rows;
825   if (SetImageBackgroundColor(image,exception) == MagickFalse)
826     {
827       image=DestroyImageList(image);
828       return((Image *) NULL);
829     }
830   image->matte=psd_info.channels >= 4 ? MagickTrue : MagickFalse;
831   if (psd_info.mode == LabMode)
832     image->colorspace=LabColorspace;
833   if (psd_info.mode == CMYKMode)
834     {
835       image->colorspace=CMYKColorspace;
836       image->matte=psd_info.channels >= 5 ? MagickTrue : MagickFalse;
837     }
838   if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
839       (psd_info.mode == DuotoneMode))
840     {
841       if (AcquireImageColormap(image,256,exception) == MagickFalse)
842         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
843       image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
844       if (image->debug != MagickFalse)
845         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
846           "  Image colormap allocated");
847       image->colorspace=GRAYColorspace;
848     }
849   if (image->debug != MagickFalse)
850     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
851       image->matte ? "  image has matte" : "  image has no matte");
852   /*
853     Read PSD raster colormap only present for indexed and duotone images.
854   */
855   length=ReadBlobMSBLong(image);
856   if (length != 0)
857     {
858       if (image->debug != MagickFalse)
859         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
860           "  reading colormap");
861       if (psd_info.mode == DuotoneMode)
862         {
863           /*
864             Duotone image data;  the format of this data is undocumented.
865           */
866           data=(unsigned char *) AcquireQuantumMemory((size_t) length,
867             sizeof(*data));
868           if (data == (unsigned char *) NULL)
869             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
870           count=ReadBlob(image,(size_t) length,data);
871           data=(unsigned char *) RelinquishMagickMemory(data);
872         }
873       else
874         {
875           /*
876             Read PSD raster colormap.
877           */
878           if (AcquireImageColormap(image,(size_t) (length/3),exception) == MagickFalse)
879             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
880           for (i=0; i < (ssize_t) image->colors; i++)
881             image->colormap[i].red=ScaleCharToQuantum((unsigned char)
882               ReadBlobByte(image));
883           for (i=0; i < (ssize_t) image->colors; i++)
884             image->colormap[i].green=ScaleCharToQuantum((unsigned char)
885               ReadBlobByte(image));
886           for (i=0; i < (ssize_t) image->colors; i++)
887             image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
888               ReadBlobByte(image));
889           image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
890         }
891     }
892   length=ReadBlobMSBLong(image);
893   if (length != 0)
894     {
895       unsigned char
896         *blocks;
897
898       /*
899         Image resources block.
900       */
901       if (image->debug != MagickFalse)
902         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
903           "  reading image resource blocks - %.20g bytes",(double)
904           ((MagickOffsetType) length));
905       blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
906         sizeof(*blocks));
907       if (blocks == (unsigned char *) NULL)
908         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
909       count=ReadBlob(image,(size_t) length,blocks);
910       if ((count != (ssize_t) length) ||
911           (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
912         {
913           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
914           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
915         }
916       (void) ParseImageResourceBlocks(image,blocks,(size_t) length,
917         exception);
918       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
919     }
920   /*
921     Layer and mask block.
922   */
923   layer_info=(LayerInfo *) NULL;
924   number_layers=1;
925   length=GetPSDSize(&psd_info,image);
926   if (length == 8)
927     {
928       length=ReadBlobMSBLong(image);
929       length=ReadBlobMSBLong(image);
930     }
931   if ((image_info->number_scenes == 1) && (image_info->scene == 0))
932     {
933       if (DiscardBlobBytes(image,length) == MagickFalse)
934         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
935           image->filename);
936       length=0;
937     }
938   if (length == 0)
939     {
940       if (image->debug != MagickFalse)
941         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
942           "  image has no layers");
943     }
944   else
945     {
946       offset=TellBlob(image);
947       size=GetPSDSize(&psd_info,image);
948       if (size == 0)
949         {
950           size_t
951             quantum;
952
953           unsigned long
954             tag;
955
956           /*
957             Skip layers & masks.
958           */
959           quantum=psd_info.version == 1 ? 4UL : 8UL;
960           tag=ReadBlobMSBLong(image);
961           (void) tag;
962           count=ReadBlob(image,4,(unsigned char *) type);
963           if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
964             {
965               if (DiscardBlobBytes(image,length-quantum-8) == MagickFalse)
966                 ThrowFileException(exception,CorruptImageError,
967                   "UnexpectedEndOfFile",image->filename);
968             }
969           else
970             {
971               count=ReadBlob(image,4,(unsigned char *) type);
972               if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
973                 size=GetPSDSize(&psd_info,image);
974               else
975                 if (DiscardBlobBytes(image,length-quantum-12) == MagickFalse)
976                   ThrowFileException(exception,CorruptImageError,
977                     "UnexpectedEndOfFile",image->filename);
978             }
979         }
980       if (size != 0)
981         {
982           MagickOffsetType
983             layer_offset;
984
985           layer_offset=offset+length;
986           number_layers=(short) ReadBlobMSBShort(image);
987           if (image->debug != MagickFalse)
988             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
989               "  image contains %.20g layers",(double) number_layers);
990           if (number_layers < 0)
991             {
992               /*
993                 Weird hack in PSD format to ignore first alpha channel.
994               */
995               skip_first_alpha=1;
996               (void) skip_first_alpha;
997               number_layers=MagickAbsoluteValue(number_layers);
998               if (image->debug != MagickFalse)
999                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1000                   "  negative layer count corrected for");
1001             }
1002           layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1003             sizeof(*layer_info));
1004           if (layer_info == (LayerInfo *) NULL)
1005             {
1006               if (image->debug != MagickFalse)
1007                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1008                   "  allocation of LayerInfo failed");
1009               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1010             }
1011           (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1012             sizeof(*layer_info));
1013           for (i=0; i < number_layers; i++)
1014           {
1015             int
1016               x,
1017               y;
1018
1019             if (image->debug != MagickFalse)
1020               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1021                 "  reading layer #%.20g",(double) i+1);
1022             layer_info[i].page.y=(int) ReadBlobMSBLong(image);
1023             layer_info[i].page.x=(int) ReadBlobMSBLong(image);
1024             y=(int) ReadBlobMSBLong(image);
1025             x=(int) ReadBlobMSBLong(image);
1026             layer_info[i].page.width=(ssize_t) (x-layer_info[i].page.x);
1027             layer_info[i].page.height=(ssize_t) (y-layer_info[i].page.y);
1028             layer_info[i].channels=ReadBlobMSBShort(image);
1029             if (layer_info[i].channels > MaxPSDChannels)
1030               ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1031             if (image->debug != MagickFalse)
1032               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1033                 "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1034                 (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1035                 (double) layer_info[i].page.height,(double)
1036                 layer_info[i].page.width,(double) layer_info[i].channels);
1037             for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1038             {
1039               layer_info[i].channel_info[j].type=(short)
1040                 ReadBlobMSBShort(image);
1041               layer_info[i].channel_info[j].size=(size_t)
1042                 GetPSDSize(&psd_info,image);
1043               if (image->debug != MagickFalse)
1044                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1045                   "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1046                   (double) layer_info[i].channel_info[j].type,
1047                   (double) layer_info[i].channel_info[j].size);
1048             }
1049             count=ReadBlob(image,4,(unsigned char *) type);
1050             if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1051               {
1052                 if (image->debug != MagickFalse)
1053                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1054                     "  layer type was %.4s instead of 8BIM", type);
1055                  ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1056               }
1057             count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1058             layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1059               ReadBlobByte(image));
1060             layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1061             layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1062             layer_info[i].visible=!(layer_info[i].flags & 0x02);
1063             if (image->debug != MagickFalse)
1064               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1065                 "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1066                 layer_info[i].blendkey,(double) layer_info[i].opacity,
1067                 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1068                 layer_info[i].visible ? "true" : "false");
1069             (void) ReadBlobByte(image);  /* filler */
1070             combinedlength=0;
1071             size=ReadBlobMSBLong(image);
1072             if (size != 0)
1073               {
1074                 if (image->debug != MagickFalse)
1075                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1076                     "    layer contains additional info");
1077                 length=ReadBlobMSBLong(image);
1078                 if (length != 0)
1079                   {
1080                     /*
1081                       Layer mask info.
1082                     */
1083                     layer_info[i].mask.y=(int) ReadBlobMSBLong(image);
1084                     layer_info[i].mask.x=(int) ReadBlobMSBLong(image);
1085                     layer_info[i].mask.height=(size_t)
1086                       (ReadBlobMSBLong(image)-layer_info[i].mask.y);
1087                     layer_info[i].mask.width=(size_t)
1088                       (ReadBlobMSBLong(image)-layer_info[i].mask.x);
1089                     if (image->debug != MagickFalse)
1090                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1091                         "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1092                         (double) layer_info[i].mask.x,(double) layer_info[i].mask.y,
1093                         (double) layer_info[i].mask.width,(double)
1094                         layer_info[i].mask.height,(double)
1095                         ((MagickOffsetType) length-16));
1096                     /*
1097                       Skip over the rest of the layer mask information.
1098                     */
1099                     if (DiscardBlobBytes(image,length-16) == MagickFalse)
1100                       ThrowFileException(exception,CorruptImageError,
1101                         "UnexpectedEndOfFile",image->filename);
1102                   }
1103                 combinedlength+=length+4;  /* +4 for length */
1104                 length=ReadBlobMSBLong(image);
1105                 if (length != 0)
1106                   {
1107                     /*
1108                       Layer blending ranges info.
1109                     */
1110                     if (image->debug != MagickFalse)
1111                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1112                         "      layer blending ranges: length=%.20g",(double)
1113                         ((MagickOffsetType) length));
1114                     /*
1115                       We read it, but don't use it...
1116                     */
1117                     for (j=0; j < (ssize_t) (length); j+=8)
1118                     {
1119                       size_t blend_source=ReadBlobMSBLong(image);
1120                       size_t blend_dest=ReadBlobMSBLong(image);
1121                       if (image->debug != MagickFalse)
1122                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1123                           "        source(%x), dest(%x)",(unsigned int)
1124                           blend_source,(unsigned int) blend_dest);
1125                     }
1126                   }
1127                 combinedlength+=length+4;
1128                 /*
1129                   Layer name.
1130                 */
1131                 length=(size_t) ReadBlobByte(image);
1132                 for (j=0; j < (ssize_t) length; j++)
1133                   layer_info[i].name[j]=(unsigned char) ReadBlobByte(image);
1134                 layer_info[i].name[j]='\0';
1135                 if (image->debug != MagickFalse)
1136                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1137                     "      layer name: %s",layer_info[i].name);
1138                 combinedlength+=length+1;
1139
1140 #if     0  /* still in development */
1141           /*
1142             Adjustment layers and other stuff...
1143           */
1144           {
1145             char  alsig[4], alkey[4];
1146
1147             count=ReadBlob(image,4,alsig);
1148             if ((count == 0) || (LocaleNCompare(alsig,"8BIM",4) != 0)) {
1149               if (debug != MagickFalse)
1150               {
1151                 if (image->debug != MagickFalse)
1152                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  adjustment layer type was %.4s instead of 8BIM", alsig);
1153               }
1154               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1155             }
1156             count=ReadBlob(image,4,alkey);
1157             length=ReadBlobMSBLong(image);
1158               if (debug != MagickFalse)
1159               {
1160                 if (image->debug != MagickFalse)
1161                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1162                             "      adjustment layer key: %.4s, data length=%.20g",
1163                             alkey, (double) length);
1164               }
1165
1166               if ( length ) {
1167               for (j=0; j < (ssize_t) (length); j++)
1168                 (void) ReadBlobByte(image);
1169               }
1170
1171           }
1172           combinedlength += 12 + length;  /* sig, key, length + the actual length*/
1173 #endif
1174
1175                /*
1176                   Skip the rest of the variable data until we support it.
1177                 */
1178                 if (image->debug != MagickFalse)
1179                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1180                     "      unsupported data: length=%.20g",(double)
1181                     ((MagickOffsetType) (size-combinedlength)));
1182                 if (DiscardBlobBytes(image,size-combinedlength) == MagickFalse)
1183                   ThrowFileException(exception,CorruptImageError,
1184                     "UnexpectedEndOfFile",image->filename);
1185               }
1186             /*
1187               Allocate layered image.
1188             */
1189             layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1190               layer_info[i].page.height == ~0U ? 1 : layer_info[i].page.height,
1191               MagickFalse,exception);
1192             if (layer_info[i].image == (Image *) NULL)
1193               {
1194                 for (j=0; j < i; j++)
1195                   layer_info[j].image=DestroyImage(layer_info[j].image);
1196                 if (image->debug != MagickFalse)
1197                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1198                     "  allocation of image for layer %.20g failed",(double) i);
1199                 ThrowReaderException(ResourceLimitError,
1200                   "MemoryAllocationFailed");
1201               }
1202             if (image->debug != MagickFalse)
1203               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1204                 "    setting up new layer image");
1205             if (image_info->ping != MagickFalse)
1206               (void) SetImageBackgroundColor(layer_info[i].image,exception);
1207             layer_info[i].image->compose=
1208               PSDBlendModeToCompositeOperator(layer_info[i].blendkey);
1209             if (layer_info[i].visible == MagickFalse)
1210               layer_info[i].image->compose=NoCompositeOp;
1211             if (psd_info.mode == CMYKMode)
1212               layer_info[i].image->colorspace=CMYKColorspace;
1213             if ((psd_info.mode == BitmapMode) ||
1214                 (psd_info.mode == GrayscaleMode) ||
1215                 (psd_info.mode == DuotoneMode))
1216               layer_info[i].image->colorspace=GRAYColorspace;
1217             for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1218               if (layer_info[i].channel_info[j].type == -1)
1219                 layer_info[i].image->matte=MagickTrue;
1220             /*
1221               Set up some hidden attributes for folks that need them.
1222             */
1223             (void) FormatLocaleString(message,MaxTextExtent,"%.20gld",
1224               (double) layer_info[i].page.x);
1225             (void) SetImageArtifact(layer_info[i].image,"psd:layer.x",message);
1226             (void) FormatLocaleString(message,MaxTextExtent,"%.20g",
1227               (double) layer_info[i].page.y);
1228             (void) SetImageArtifact(layer_info[i].image,"psd:layer.y",message);
1229             (void) FormatLocaleString(message,MaxTextExtent,"%.20g",
1230               (double) layer_info[i].opacity);
1231             (void) SetImageArtifact(layer_info[i].image,"psd:layer.opacity",
1232               message);
1233             (void) SetImageProperty(layer_info[i].image,"label",(char *)
1234               layer_info[i].name,exception);
1235           }
1236         if (image->debug != MagickFalse)
1237           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1238             "  reading image data for layers");
1239         /*
1240           Read pixel data for each layer.
1241         */
1242         for (i=0; i < number_layers; i++)
1243         {
1244           if (image->debug != MagickFalse)
1245             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1246               "  reading data for layer %.20g",(double) i);
1247             for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1248             {
1249               if (image->debug != MagickFalse)
1250                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1251                   "    reading data for channel %.20g",(double) j);
1252 #if     1
1253               if (layer_info[i].channel_info[j].size <= (2*layer_info[i].image->rows))
1254                 {
1255                   ssize_t
1256                     k;
1257
1258                   if (image->debug != MagickFalse)
1259                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1260                       "      layer data is empty");
1261                   /*
1262                     A layer without data.
1263                   */
1264                   for (k=0; k < (ssize_t) layer_info[i].channel_info[j].size; k++)
1265                     (void) ReadBlobByte(layer_info[i].image);
1266                   continue;
1267                 }
1268 #endif
1269               offsets=(MagickOffsetType *) NULL;
1270               layer_info[i].image->compression=NoCompression;
1271               compression=ReadBlobMSBShort(layer_info[i].image);
1272               if ((layer_info[i].page.height != 0) &&
1273                   (layer_info[i].page.width != 0))
1274                 {
1275                   if (compression == 1)
1276                     {
1277                       /*
1278                         Read RLE compressed data.
1279                       */
1280                       layer_info[i].image->compression=RLECompression;
1281                       if (image->debug != MagickFalse)
1282                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1283                           "      layer data is RLE compressed");
1284                       offsets=(MagickOffsetType *) AcquireQuantumMemory(
1285                         layer_info[i].image->rows,sizeof(*offsets));
1286                       if (offsets == (MagickOffsetType *) NULL)
1287                         ThrowReaderException(ResourceLimitError,
1288                           "MemoryAllocationFailed");
1289                       for (y=0; y < (ssize_t) layer_info[i].image->rows; y++)
1290                         offsets[y]=GetPSDOffset(&psd_info,layer_info[i].image);
1291                     }
1292                   status=ReadPSDLayer(layer_info[i].image,
1293                     layer_info[i].channels,layer_info[i].channel_info[j].type,
1294                     offsets,exception);
1295                   if (compression == 1)
1296                     offsets=(MagickOffsetType *) RelinquishMagickMemory(
1297                       offsets);
1298                   if (status == MagickFalse)
1299                     break;
1300                 }
1301               }
1302             if (layer_info[i].opacity != OpaqueAlpha)
1303               {
1304                 /*
1305                   Correct for opacity level.
1306                 */
1307                 for (y=0; y < (ssize_t) layer_info[i].image->rows; y++)
1308                 {
1309                   q=GetAuthenticPixels(layer_info[i].image,0,y,
1310                     layer_info[i].image->columns,1,exception);
1311                   if (q == (Quantum *) NULL)
1312                     break;
1313                   for (x=0; x < (ssize_t) layer_info[i].image->columns; x++)
1314                   {
1315                     SetPixelAlpha(layer_info[i].image,(Quantum)
1316                       (QuantumScale*(GetPixelAlpha(layer_info[i].image,q))*
1317                       layer_info[i].opacity),q);
1318                     q+=GetPixelChannels(layer_info[i].image);
1319                   }
1320                   if (SyncAuthenticPixels(layer_info[i].image,exception) == MagickFalse)
1321                     break;
1322                 }
1323               }
1324             if (layer_info[i].image->colorspace == CMYKColorspace)
1325               (void) NegateImage(layer_info[i].image,MagickFalse,exception);
1326             status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1327               number_layers);
1328             if (status == MagickFalse)
1329               break;
1330           }
1331         /* added by palf -> invisible group layer make layer of this group
1332            invisible I consider that all layer with width and height null are
1333            layer for group layer */
1334        {
1335          short inside_layer = 0;
1336          short layer_visible = 0;
1337          for (i=number_layers-1; i >=0; i--)
1338          {
1339            if ((layer_info[i].page.width == 0) ||
1340                (layer_info[i].page.height == 0))
1341              {
1342                if (inside_layer == 0)
1343                  {
1344                    inside_layer=1;
1345                    layer_visible=(short int) layer_info[i].visible;
1346                  }
1347                else
1348                  {
1349                    inside_layer = 0;
1350                  }
1351              }
1352            else
1353              if ((inside_layer == 1) && (layer_visible == 0))
1354                {
1355                  layer_info[i].visible=(unsigned char) layer_visible;
1356                  layer_info[i].image->compose=NoCompositeOp;
1357                }
1358          }
1359        }
1360        /* added by palf -> suppression of empty layer */
1361        /* I consider that all layer with width and height null are layer for group layer */
1362        for (i=0; i < number_layers; i++)
1363        {
1364          if ((layer_info[i].page.width == 0) ||
1365              (layer_info[i].page.height == 0))
1366            {
1367              if (layer_info[i].image != (Image *) NULL)
1368                layer_info[i].image=DestroyImage(layer_info[i].image);
1369              for (j=i; j < number_layers - 1; j++)
1370                layer_info[j] = layer_info[j+1];
1371              number_layers--;
1372              i--;
1373            }
1374         }
1375         mask_size = ReadBlobMSBLong(image);  /* global mask size: currently ignored */
1376         (void) mask_size;
1377         if (number_layers > 0)
1378           {
1379             if (image->debug != MagickFalse)
1380               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1381                 "  putting layers into image list");
1382             for (i=0; i < number_layers; i++)
1383             {
1384               if (i > 0)
1385                 layer_info[i].image->previous=layer_info[i-1].image;
1386               if (i < (number_layers-1))
1387                 layer_info[i].image->next=layer_info[i+1].image;
1388               layer_info[i].image->page=layer_info[i].page;
1389             }
1390             image->next=layer_info[0].image;
1391             layer_info[0].image->previous=image;
1392             layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1393           }
1394         layer_offset-=TellBlob(image);
1395         offset=SeekBlob(image,layer_offset,SEEK_CUR);
1396       }
1397     }
1398   /*
1399     Read the precombined layer, present for PSD < 4 compatibility
1400   */
1401   if (image->debug != MagickFalse)
1402     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1403       "  reading the precombined layer");
1404   offsets=(MagickOffsetType *) NULL;
1405   image->compression=NoCompression;
1406   compression=ReadBlobMSBShort(image);
1407   if (compression == 1)
1408     {
1409       /*
1410         Read Packbit encoded pixel data as separate planes.
1411       */
1412       image->compression=RLECompression;
1413       offsets=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
1414         psd_info.channels*sizeof(*offsets));
1415       if (offsets == (MagickOffsetType *) NULL)
1416         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1417       for (i=0; i < (ssize_t) (image->rows*psd_info.channels); i++)
1418         offsets[i]=GetPSDOffset(&psd_info,image);
1419     }
1420   for (i=0; i < (ssize_t) psd_info.channels; i++)
1421   {
1422     status=ReadPSDLayer(image,psd_info.channels,i,offsets+i*image->rows,
1423       exception);
1424     if (status == MagickFalse)
1425       break;
1426     status=SetImageProgress(image,LoadImagesTag,i,psd_info.channels);
1427     if (status == MagickFalse)
1428       break;
1429   }
1430   if (compression == 1)
1431     offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1432   if (image->colorspace == CMYKColorspace)
1433     (void) NegateImage(image,MagickFalse,exception);
1434   (void) CloseBlob(image);
1435   return(GetFirstImageInList(image));
1436 }
1437 \f
1438 /*
1439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 %                                                                             %
1441 %                                                                             %
1442 %                                                                             %
1443 %   R e g i s t e r P S D I m a g e                                           %
1444 %                                                                             %
1445 %                                                                             %
1446 %                                                                             %
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 %
1449 %  RegisterPSDImage() adds properties for the PSD image format to
1450 %  the list of supported formats.  The properties include the image format
1451 %  tag, a method to read and/or write the format, whether the format
1452 %  supports the saving of more than one frame to the same file or blob,
1453 %  whether the format supports native in-memory I/O, and a brief
1454 %  description of the format.
1455 %
1456 %  The format of the RegisterPSDImage method is:
1457 %
1458 %      size_t RegisterPSDImage(void)
1459 %
1460 */
1461 ModuleExport size_t RegisterPSDImage(void)
1462 {
1463   MagickInfo
1464     *entry;
1465
1466   entry=SetMagickInfo("PSB");
1467   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1468   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1469   entry->magick=(IsImageFormatHandler *) IsPSD;
1470   entry->seekable_stream=MagickTrue;
1471   entry->description=ConstantString("Adobe Large Document Format");
1472   entry->module=ConstantString("PSD");
1473   (void) RegisterMagickInfo(entry);
1474   entry=SetMagickInfo("PSD");
1475   entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1476   entry->encoder=(EncodeImageHandler *) WritePSDImage;
1477   entry->magick=(IsImageFormatHandler *) IsPSD;
1478   entry->seekable_stream=MagickTrue;
1479   entry->description=ConstantString("Adobe Photoshop bitmap");
1480   entry->module=ConstantString("PSD");
1481   (void) RegisterMagickInfo(entry);
1482   return(MagickImageCoderSignature);
1483 }
1484 \f
1485 /*
1486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487 %                                                                             %
1488 %                                                                             %
1489 %                                                                             %
1490 %   U n r e g i s t e r P S D I m a g e                                       %
1491 %                                                                             %
1492 %                                                                             %
1493 %                                                                             %
1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495 %
1496 %  UnregisterPSDImage() removes format registrations made by the
1497 %  PSD module from the list of supported formats.
1498 %
1499 %  The format of the UnregisterPSDImage method is:
1500 %
1501 %      UnregisterPSDImage(void)
1502 %
1503 */
1504 ModuleExport void UnregisterPSDImage(void)
1505 {
1506   (void) UnregisterMagickInfo("PSB");
1507   (void) UnregisterMagickInfo("PSD");
1508 }
1509 \f
1510 /*
1511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 %                                                                             %
1513 %                                                                             %
1514 %                                                                             %
1515 %   W r i t e P S D I m a g e                                                 %
1516 %                                                                             %
1517 %                                                                             %
1518 %                                                                             %
1519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1520 %
1521 %  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
1522 %
1523 %  The format of the WritePSDImage method is:
1524 %
1525 %      MagickBooleanType WritePSDImage(const ImageInfo *image_info,
1526 %        Image *image,ExceptionInfo *exception)
1527 %
1528 %  A description of each parameter follows.
1529 %
1530 %    o image_info: the image info.
1531 %
1532 %    o image:  The image.
1533 %
1534 %    o exception: return any errors or warnings in this structure.
1535 %
1536 */
1537
1538 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
1539   const size_t offset)
1540 {
1541   if (psd_info->version == 1)
1542     return(WriteBlobMSBShort(image,(unsigned short) offset));
1543   return(WriteBlobMSBLong(image,(unsigned short) offset));
1544 }
1545
1546 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
1547   const MagickSizeType size)
1548 {
1549   if (psd_info->version == 1)
1550     return(WriteBlobMSBLong(image,(unsigned int) size));
1551   return(WriteBlobMSBLongLong(image,size));
1552 }
1553
1554 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
1555   const unsigned char *pixels,unsigned char *compact_pixels,
1556   ExceptionInfo *exception)
1557 {
1558   int
1559     count;
1560
1561   register ssize_t
1562     i,
1563     j;
1564
1565   register unsigned char
1566     *q;
1567
1568   unsigned char
1569     *packbits;
1570
1571   /*
1572     Compress pixels with Packbits encoding.
1573   */
1574   assert(image != (Image *) NULL);
1575   assert(image->signature == MagickSignature);
1576   if (image->debug != MagickFalse)
1577     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1578   assert(pixels != (unsigned char *) NULL);
1579   packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
1580   if (packbits == (unsigned char *) NULL)
1581     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1582       image->filename);
1583   q=compact_pixels;
1584   for (i=(ssize_t) length; i != 0; )
1585   {
1586     switch (i)
1587     {
1588       case 1:
1589       {
1590         i--;
1591         *q++=(unsigned char) 0;
1592         *q++=(*pixels);
1593         break;
1594       }
1595       case 2:
1596       {
1597         i-=2;
1598         *q++=(unsigned char) 1;
1599         *q++=(*pixels);
1600         *q++=pixels[1];
1601         break;
1602       }
1603       case 3:
1604       {
1605         i-=3;
1606         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1607           {
1608             *q++=(unsigned char) ((256-3)+1);
1609             *q++=(*pixels);
1610             break;
1611           }
1612         *q++=(unsigned char) 2;
1613         *q++=(*pixels);
1614         *q++=pixels[1];
1615         *q++=pixels[2];
1616         break;
1617       }
1618       default:
1619       {
1620         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1621           {
1622             /*
1623               Packed run.
1624             */
1625             count=3;
1626             while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
1627             {
1628               count++;
1629               if (count >= 127)
1630                 break;
1631             }
1632             i-=count;
1633             *q++=(unsigned char) ((256-count)+1);
1634             *q++=(*pixels);
1635             pixels+=count;
1636             break;
1637           }
1638         /*
1639           Literal run.
1640         */
1641         count=0;
1642         while ((*(pixels+count) != *(pixels+count+1)) ||
1643                (*(pixels+count+1) != *(pixels+count+2)))
1644         {
1645           packbits[count+1]=pixels[count];
1646           count++;
1647           if (((ssize_t) count >= (i-3)) || (count >= 127))
1648             break;
1649         }
1650         i-=count;
1651         *packbits=(unsigned char) (count-1);
1652         for (j=0; j <= (ssize_t) count; j++)
1653           *q++=packbits[j];
1654         pixels+=count;
1655         break;
1656       }
1657     }
1658   }
1659   *q++=(unsigned char) 128;  /* EOD marker */
1660   packbits=(unsigned char *) RelinquishMagickMemory(packbits);
1661   return((size_t) (q-compact_pixels));
1662 }
1663
1664 static void WritePackbitsLength(const PSDInfo *psd_info,
1665   const ImageInfo *image_info,Image *image,Image *next_image,
1666   unsigned char *compact_pixels,const QuantumType quantum_type,
1667   ExceptionInfo *exception)
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,exception);
1694     if (p == (const Quantum *) NULL)
1695       break;
1696     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
1697       quantum_type,pixels,exception);
1698     length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
1699       exception);
1700     (void) SetPSDOffset(psd_info,image,length);
1701   }
1702   quantum_info=DestroyQuantumInfo(quantum_info);
1703 }
1704
1705 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
1706   Image *image,Image *next_image,unsigned char *compact_pixels,
1707   const QuantumType quantum_type,const MagickBooleanType compression_flag,
1708   ExceptionInfo *exception)
1709 {
1710   int
1711     y;
1712
1713   MagickBooleanType
1714     monochrome;
1715
1716   QuantumInfo
1717     *quantum_info;
1718
1719   register const Quantum
1720     *p;
1721
1722   register ssize_t
1723     i;
1724
1725   size_t
1726     length,
1727     packet_size;
1728
1729   unsigned char
1730     *pixels;
1731
1732   (void) psd_info;
1733   if ((compression_flag != MagickFalse) &&
1734       (next_image->compression != RLECompression))
1735     (void) WriteBlobMSBShort(image,0);
1736   if (next_image->depth > 8)
1737     next_image->depth=16;
1738   monochrome=IsImageMonochrome(image,exception) && (image->depth == 1) ?
1739     MagickTrue : MagickFalse;
1740   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
1741   (void) packet_size;
1742   quantum_info=AcquireQuantumInfo(image_info,image);
1743   pixels=GetQuantumPixels(quantum_info);
1744   for (y=0; y < (ssize_t) next_image->rows; y++)
1745   {
1746     p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
1747     if (p == (const Quantum *) NULL)
1748       break;
1749     length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
1750       quantum_type,pixels,exception);
1751     if (monochrome != MagickFalse)
1752       for (i=0; i < (ssize_t) length; i++)
1753         pixels[i]=(~pixels[i]);
1754     if (next_image->compression != RLECompression)
1755       (void) WriteBlob(image,length,pixels);
1756     else
1757       {
1758         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
1759           exception);
1760         (void) WriteBlob(image,length,compact_pixels);
1761       }
1762   }
1763   quantum_info=DestroyQuantumInfo(quantum_info);
1764 }
1765
1766 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
1767   const ImageInfo *image_info,Image *image,Image *next_image,
1768   const MagickBooleanType separate,ExceptionInfo *exception)
1769 {
1770   int
1771     i;
1772
1773   size_t
1774     channels,
1775     packet_size;
1776
1777   unsigned char
1778     *compact_pixels;
1779
1780   /*
1781     Write uncompressed pixels as separate planes.
1782   */
1783   channels=1;
1784   packet_size=next_image->depth > 8UL ? 2UL : 1UL;
1785   compact_pixels=(unsigned char *) NULL;
1786   if (next_image->compression == RLECompression)
1787     {
1788       compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
1789         next_image->columns,packet_size*sizeof(*compact_pixels));
1790       if (compact_pixels == (unsigned char *) NULL)
1791         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1792     }
1793   i=0;
1794   if (IsImageGray(next_image,exception) != MagickFalse)
1795     {
1796       if (next_image->compression == RLECompression)
1797         {
1798           /*
1799             Packbits compression.
1800           */
1801           (void) WriteBlobMSBShort(image,1);
1802           WritePackbitsLength(psd_info,image_info,image,next_image,
1803             compact_pixels,GrayQuantum,exception);
1804           if (next_image->matte != MagickFalse)
1805             WritePackbitsLength(psd_info,image_info,image,next_image,
1806               compact_pixels,AlphaQuantum,exception);
1807         }
1808       WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1809         GrayQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1810         MagickFalse,exception);
1811       if (next_image->matte != MagickFalse)
1812         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1813           AlphaQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1814           MagickFalse,exception);
1815       (void) SetImageProgress(image,SaveImagesTag,0,1);
1816     }
1817   else
1818     if (next_image->storage_class == PseudoClass)
1819       {
1820         if (next_image->compression == RLECompression)
1821           {
1822             /*
1823               Packbits compression.
1824             */
1825             (void) WriteBlobMSBShort(image,1);
1826             WritePackbitsLength(psd_info,image_info,image,next_image,
1827               compact_pixels,IndexQuantum,exception);
1828             if (next_image->matte != MagickFalse)
1829               WritePackbitsLength(psd_info,image_info,image,next_image,
1830                 compact_pixels,AlphaQuantum,exception);
1831           }
1832         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1833           IndexQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1834           MagickFalse,exception);
1835         if (next_image->matte != MagickFalse)
1836           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1837             AlphaQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1838             MagickFalse,exception);
1839         (void) SetImageProgress(image,SaveImagesTag,0,1);
1840       }
1841     else
1842       {
1843         if (next_image->colorspace == CMYKColorspace)
1844           (void) NegateImage(next_image,MagickFalse,exception);
1845         if (next_image->compression == RLECompression)
1846           {
1847             /*
1848               Packbits compression.
1849             */
1850             (void) WriteBlobMSBShort(image,1);
1851             WritePackbitsLength(psd_info,image_info,image,next_image,
1852               compact_pixels,RedQuantum,exception);
1853             WritePackbitsLength(psd_info,image_info,image,next_image,
1854               compact_pixels,GreenQuantum,exception);
1855             WritePackbitsLength(psd_info,image_info,image,next_image,
1856               compact_pixels,BlueQuantum,exception);
1857             if (next_image->colorspace == CMYKColorspace)
1858               WritePackbitsLength(psd_info,image_info,image,next_image,
1859                 compact_pixels,BlackQuantum,exception);
1860             if (next_image->matte != MagickFalse)
1861               WritePackbitsLength(psd_info,image_info,image,next_image,
1862                 compact_pixels,AlphaQuantum,exception);
1863           }
1864         (void) SetImageProgress(image,SaveImagesTag,0,6);
1865         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1866           RedQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1867           MagickFalse,exception);
1868         (void) SetImageProgress(image,SaveImagesTag,1,6);
1869         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1870           GreenQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1871           MagickFalse,exception);
1872         (void) SetImageProgress(image,SaveImagesTag,2,6);
1873         WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1874           BlueQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1875           MagickFalse,exception);
1876         (void) SetImageProgress(image,SaveImagesTag,3,6);
1877         if (next_image->colorspace == CMYKColorspace)
1878           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1879             BlackQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1880             MagickFalse,exception);
1881         (void) SetImageProgress(image,SaveImagesTag,4,6);
1882         if (next_image->matte != MagickFalse)
1883           WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
1884             AlphaQuantum,(i++ == 0) || (separate != MagickFalse) ? MagickTrue :
1885             MagickFalse,exception);
1886         (void) SetImageProgress(image,SaveImagesTag,5,6);
1887         if (next_image->colorspace == CMYKColorspace)
1888           (void) NegateImage(next_image,MagickFalse,exception);
1889       }
1890   if (next_image->compression == RLECompression)
1891     compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1892   return(MagickTrue);
1893 }
1894
1895 static void WritePascalString(Image* inImage,const char *inString,int inPad)
1896 {
1897   size_t
1898     length;
1899
1900   register ssize_t
1901     i;
1902
1903   /*
1904     Max length is 255.
1905   */
1906   length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
1907   if (length ==  0)
1908     (void) WriteBlobByte(inImage,0);
1909   else
1910     {
1911       (void) WriteBlobByte(inImage,(unsigned char) length);
1912       (void) WriteBlob(inImage, length, (const unsigned char *) inString);
1913     }
1914   length++;
1915   if ((length % inPad) == 0)
1916     return;
1917   for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
1918     (void) WriteBlobByte(inImage,0);
1919 }
1920
1921 static void WriteResolutionResourceBlock(Image *image)
1922 {
1923   double
1924     x_resolution,
1925     y_resolution;
1926
1927   unsigned short
1928     units;
1929
1930   x_resolution=65536.0*image->resolution.x+0.5;
1931   y_resolution=65536.0*image->resolution.y+0.5;
1932   units=1;
1933   if (image->units == PixelsPerCentimeterResolution)
1934     {
1935       x_resolution=2.54*65536.0*image->resolution.x*0.5;
1936       y_resolution=2.54*65536.0*image->resolution.y+0.5;
1937       units=2;
1938     }
1939   (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
1940   (void) WriteBlobMSBShort(image,0x03ED);
1941   (void) WriteBlobMSBShort(image,0);
1942   (void) WriteBlobMSBLong(image,16); /* resource size */
1943   (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
1944   (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
1945   (void) WriteBlobMSBShort(image,units); /* width unit */
1946   (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
1947   (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
1948   (void) WriteBlobMSBShort(image,units); /* height unit */
1949 }
1950
1951 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
1952 {
1953   register const unsigned char
1954     *p;
1955
1956   size_t
1957     length;
1958
1959   unsigned char
1960     *datum;
1961
1962   unsigned int
1963     count,
1964     long_sans;
1965
1966   unsigned short
1967     id,
1968     short_sans;
1969
1970   length=GetStringInfoLength(bim_profile);
1971   if (length < 16)
1972     return;
1973   datum=GetStringInfoDatum(bim_profile);
1974   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
1975   {
1976     register unsigned char
1977       *q;
1978
1979     q=(unsigned char *) p;
1980     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
1981       break;
1982     p=PushLongPixel(MSBEndian,p,&long_sans);
1983     p=PushShortPixel(MSBEndian,p,&id);
1984     p=PushShortPixel(MSBEndian,p,&short_sans);
1985     p=PushLongPixel(MSBEndian,p,&count);
1986     if (id == 0x0000040f)
1987       {
1988         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
1989           (PSDQuantum(count)+12)-(q-datum));
1990         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
1991         break;
1992       }
1993     p+=count;
1994     if ((count & 0x01) != 0)
1995       p++;
1996   }
1997 }
1998
1999 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2000 {
2001   register const unsigned char
2002     *p;
2003
2004   size_t
2005     length;
2006
2007   unsigned char
2008     *datum;
2009
2010   unsigned int
2011     count,
2012     long_sans;
2013
2014   unsigned short
2015     id,
2016     short_sans;
2017
2018   length=GetStringInfoLength(bim_profile);
2019   if (length < 16)
2020     return;
2021   datum=GetStringInfoDatum(bim_profile);
2022   for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2023   {
2024     register unsigned char
2025       *q;
2026
2027     q=(unsigned char *) p;
2028     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2029       break;
2030     p=PushLongPixel(MSBEndian,p,&long_sans);
2031     p=PushShortPixel(MSBEndian,p,&id);
2032     p=PushShortPixel(MSBEndian,p,&short_sans);
2033     p=PushLongPixel(MSBEndian,p,&count);
2034     if ((id == 0x000003ed) && (PSDQuantum(count) < (ssize_t) (length-12)))
2035       {
2036         (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
2037           (PSDQuantum(count)+12)-(q-datum));
2038         SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
2039         break;
2040       }
2041     p+=count;
2042     if ((count & 0x01) != 0)
2043       p++;
2044   }
2045 }
2046
2047 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2048   ExceptionInfo *exception)
2049 {
2050   const char
2051     *property;
2052
2053   const StringInfo
2054     *icc_profile;
2055
2056   Image
2057     *base_image,
2058     *next_image;
2059
2060   MagickBooleanType
2061     status;
2062
2063   PSDInfo
2064     psd_info;
2065
2066   register ssize_t
2067     i;
2068
2069   size_t
2070     channel_size,
2071     channelLength,
2072     layer_count,
2073     layer_info_size,
2074     length,
2075     num_channels,
2076     packet_size,
2077     rounded_layer_info_size;
2078
2079   StringInfo
2080     *bim_profile;
2081
2082   unsigned char
2083     layer_name[4];
2084
2085   /*
2086     Open image file.
2087   */
2088   assert(image_info != (const ImageInfo *) NULL);
2089   assert(image_info->signature == MagickSignature);
2090   assert(image != (Image *) NULL);
2091   assert(image->signature == MagickSignature);
2092   if (image->debug != MagickFalse)
2093     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2094   assert(exception != (ExceptionInfo *) NULL);
2095   assert(exception->signature == MagickSignature);
2096   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2097   if (status == MagickFalse)
2098     return(status);
2099   packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2100   if (image->matte != MagickFalse)
2101     packet_size+=image->depth > 8 ? 2 : 1;
2102   psd_info.version=1;
2103   if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2104       (image->columns > 30000) || (image->rows > 30000))
2105     psd_info.version=2;
2106   (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2107   (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
2108   for (i=1; i <= 6; i++)
2109     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
2110   if (IsImageGray(image,exception) != MagickFalse)
2111     num_channels=(image->matte != MagickFalse ? 2UL : 1UL);
2112   else
2113     if (image->storage_class == PseudoClass)
2114       num_channels=(image->matte != MagickFalse ? 2UL : 1UL);
2115     else
2116       {
2117         if (image->colorspace != CMYKColorspace)
2118           num_channels=(image->matte != MagickFalse ? 4UL : 3UL);
2119         else
2120           num_channels=(image->matte != MagickFalse ? 5UL : 4UL);
2121       }
2122   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2123   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2124   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2125   if (IsImageGray(image,exception) != MagickFalse)
2126     {
2127       MagickBooleanType
2128         monochrome;
2129
2130       /*
2131         Write depth & mode.
2132       */
2133       monochrome=IsImageMonochrome(image,exception) && (image->depth == 1) ?
2134         MagickTrue : MagickFalse;
2135       (void) WriteBlobMSBShort(image,(unsigned short)
2136         (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2137       (void) WriteBlobMSBShort(image,(unsigned short)
2138         (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
2139     }
2140   else
2141     {
2142       (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2143         PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2144       if (((image_info->colorspace != UndefinedColorspace) ||
2145            (image->colorspace != CMYKColorspace)) &&
2146           (image_info->colorspace != CMYKColorspace))
2147         {
2148           if (IsRGBColorspace(image->colorspace) == MagickFalse)
2149             (void) TransformImageColorspace(image,RGBColorspace,exception);
2150           (void) WriteBlobMSBShort(image,(unsigned short)
2151             (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2152         }
2153       else
2154         {
2155           if (image->colorspace != CMYKColorspace)
2156             (void) TransformImageColorspace(image,CMYKColorspace,exception);
2157           (void) WriteBlobMSBShort(image,CMYKMode);
2158         }
2159     }
2160   if ((IsImageGray(image,exception) != MagickFalse) ||
2161       (image->storage_class == DirectClass) || (image->colors > 256))
2162     (void) WriteBlobMSBLong(image,0);
2163   else
2164     {
2165       /*
2166         Write PSD raster colormap.
2167       */
2168       (void) WriteBlobMSBLong(image,768);
2169       for (i=0; i < (ssize_t) image->colors; i++)
2170         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2171       for ( ; i < 256; i++)
2172         (void) WriteBlobByte(image,0);
2173       for (i=0; i < (ssize_t) image->colors; i++)
2174         (void) WriteBlobByte(image,ScaleQuantumToChar(
2175           image->colormap[i].green));
2176       for ( ; i < 256; i++)
2177         (void) WriteBlobByte(image,0);
2178       for (i=0; i < (ssize_t) image->colors; i++)
2179         (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2180       for ( ; i < 256; i++)
2181         (void) WriteBlobByte(image,0);
2182     }
2183   /*
2184     Image resource block.
2185   */
2186   length=28; /* 0x03EB */
2187   bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2188   icc_profile=GetImageProfile(image,"icc");
2189   if (bim_profile != (StringInfo *) NULL)
2190     {
2191       bim_profile=CloneStringInfo(bim_profile);
2192       if (icc_profile != (StringInfo *) NULL)
2193         RemoveICCProfileFromResourceBlock(bim_profile);
2194       RemoveResolutionFromResourceBlock(bim_profile);
2195       length+=PSDQuantum(GetStringInfoLength(bim_profile));
2196     }
2197   if (icc_profile != (const StringInfo *) NULL)
2198     length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2199   (void) WriteBlobMSBLong(image,(unsigned int) length);
2200   WriteResolutionResourceBlock(image);
2201   if (bim_profile != (StringInfo *) NULL)
2202     {
2203       (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2204         GetStringInfoDatum(bim_profile));
2205       bim_profile=DestroyStringInfo(bim_profile);
2206     }
2207   if (icc_profile != (StringInfo *) NULL)
2208     {
2209       (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2210       (void) WriteBlobMSBShort(image,0x0000040F);
2211       (void) WriteBlobMSBShort(image,0);
2212       (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2213         icc_profile));
2214       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2215         GetStringInfoDatum(icc_profile));
2216       if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2217           PSDQuantum(GetStringInfoLength(icc_profile)))
2218         (void) WriteBlobByte(image,0);
2219     }
2220   layer_count=0;
2221   layer_info_size=2;
2222   base_image=GetNextImageInList(image);
2223   if ((image->matte != MagickFalse) && (base_image == (Image *) NULL))
2224     base_image=image;
2225   next_image=base_image;
2226   while ( next_image != NULL )
2227   {
2228     packet_size=next_image->depth > 8 ? 2UL : 1UL;
2229     if (IsImageGray(next_image,exception) != MagickFalse)
2230       num_channels=next_image->matte != MagickFalse ? 2UL : 1UL;
2231     else
2232       if (next_image->storage_class == PseudoClass)
2233         num_channels=next_image->matte != MagickFalse ? 2UL : 1UL;
2234       else
2235         if (next_image->colorspace != CMYKColorspace)
2236           num_channels=next_image->matte != MagickFalse ? 4UL : 3UL;
2237         else
2238           num_channels=next_image->matte != MagickFalse ? 5UL : 4UL;
2239     channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
2240     layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
2241       16)+4*1+4+num_channels*channelLength);
2242     property=(const char *) GetImageProperty(next_image,"label",exception);
2243     if (property == (const char *) NULL)
2244       layer_info_size+=16;
2245     else
2246       {
2247         size_t
2248           length;
2249
2250         length=strlen(property);
2251         layer_info_size+=8+length+(4-(length % 4));
2252       }
2253     layer_count++;
2254     next_image=GetNextImageInList(next_image);
2255   }
2256   if (layer_count == 0)
2257     (void) SetPSDSize(&psd_info,image,0);
2258   else
2259     {
2260       CompressionType
2261         compression;
2262
2263       (void) SetPSDSize(&psd_info,image,layer_info_size+
2264         (psd_info.version == 1 ? 8 : 16));
2265       if ((layer_info_size/2) != ((layer_info_size+1)/2))
2266         rounded_layer_info_size=layer_info_size+1;
2267       else
2268         rounded_layer_info_size=layer_info_size;
2269       (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2270       (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2271       layer_count=1;
2272       compression=base_image->compression;
2273       next_image=base_image;
2274       while (next_image != NULL)
2275       {
2276         next_image->compression=NoCompression;
2277         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2278         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
2279         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y+
2280           next_image->rows);
2281         (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x+
2282           next_image->columns);
2283         packet_size=next_image->depth > 8 ? 2UL : 1UL;
2284         channel_size=(unsigned int) ((packet_size*next_image->rows*
2285           next_image->columns)+2);
2286         if ((IsImageGray(next_image,exception) != MagickFalse) ||
2287             (next_image->storage_class == PseudoClass))
2288           {
2289              (void) WriteBlobMSBShort(image,(unsigned short)
2290                (next_image->matte != MagickFalse ? 2 : 1));
2291              (void) WriteBlobMSBShort(image,0);
2292              (void) SetPSDSize(&psd_info,image,channel_size);
2293              if (next_image->matte != MagickFalse)
2294                {
2295                  (void) WriteBlobMSBShort(image,(unsigned short) -1);
2296                  (void) SetPSDSize(&psd_info,image,channel_size);
2297                }
2298            }
2299           else
2300             if (next_image->colorspace != CMYKColorspace)
2301               {
2302                 (void) WriteBlobMSBShort(image,(unsigned short)
2303                   (next_image->matte != MagickFalse ? 4 : 3));
2304                (void) WriteBlobMSBShort(image,0);
2305                (void) SetPSDSize(&psd_info,image,channel_size);
2306                (void) WriteBlobMSBShort(image,1);
2307                (void) SetPSDSize(&psd_info,image,channel_size);
2308                (void) WriteBlobMSBShort(image,2);
2309                (void) SetPSDSize(&psd_info,image,channel_size);
2310                if (next_image->matte!= MagickFalse )
2311                  {
2312                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2313                    (void) SetPSDSize(&psd_info,image,channel_size);
2314                  }
2315              }
2316            else
2317              {
2318                (void) WriteBlobMSBShort(image,(unsigned short)
2319                  (next_image->matte ? 5 : 4));
2320                (void) WriteBlobMSBShort(image,0);
2321                (void) SetPSDSize(&psd_info,image,channel_size);
2322                (void) WriteBlobMSBShort(image,1);
2323                (void) SetPSDSize(&psd_info,image,channel_size);
2324                (void) WriteBlobMSBShort(image,2);
2325                (void) SetPSDSize(&psd_info,image,channel_size);
2326                (void) WriteBlobMSBShort(image,3);
2327                (void) SetPSDSize(&psd_info,image,channel_size);
2328                if (next_image->matte)
2329                  {
2330                    (void) WriteBlobMSBShort(image,(unsigned short) -1);
2331                    (void) SetPSDSize(&psd_info,image,channel_size);
2332                  }
2333              }
2334         (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2335         (void) WriteBlob(image,4,(const unsigned char *)
2336           CompositeOperatorToPSDBlendMode(next_image->compose));
2337         (void) WriteBlobByte(image,255); /* layer opacity */
2338         (void) WriteBlobByte(image,0);
2339         (void) WriteBlobByte(image,1); /* layer propertys - visible, etc. */
2340         (void) WriteBlobByte(image,0);
2341         property=(const char *) GetImageProperty(next_image,"label",exception);
2342         if (property == (const char *) NULL)
2343           {
2344             (void) WriteBlobMSBLong(image,16);
2345             (void) WriteBlobMSBLong(image,0);
2346             (void) WriteBlobMSBLong(image,0);
2347             (void) FormatLocaleString((char *) layer_name,MaxTextExtent,
2348               "L%06ld",(long) layer_count++);
2349             WritePascalString( image, (char*)layer_name, 4 );
2350           }
2351         else
2352           {
2353             size_t
2354               length;
2355
2356             length=strlen(property);
2357             (void) WriteBlobMSBLong(image,(unsigned int) (length+(4-
2358               (length % 4))+8));
2359             (void) WriteBlobMSBLong(image,0);
2360             (void) WriteBlobMSBLong(image,0);
2361             WritePascalString(image,property,4);
2362           }
2363         next_image=GetNextImageInList(next_image);
2364       }
2365       /*
2366         Now the image data!
2367       */
2368       next_image=base_image;
2369       while (next_image != NULL)
2370       {
2371         status=WriteImageChannels(&psd_info,image_info,image,next_image,
2372           MagickTrue,exception);
2373         next_image=GetNextImageInList(next_image);
2374       }
2375       (void) WriteBlobMSBLong(image,0);  /* user mask data */
2376       base_image->compression=compression;
2377     }
2378   /*
2379     Write composite image.
2380   */
2381   status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
2382     exception);
2383   (void) CloseBlob(image);
2384   return(status);
2385 }