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