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