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