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