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