2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Adobe Photoshop Image Format %
21 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
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. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/colorspace.h"
49 #include "magick/constitute.h"
50 #include "magick/enhance.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/image.h"
54 #include "magick/image-private.h"
55 #include "magick/list.h"
56 #include "magick/log.h"
57 #include "magick/magick.h"
58 #include "magick/memory_.h"
59 #include "magick/module.h"
60 #include "magick/monitor-private.h"
61 #include "magick/profile.h"
62 #include "magick/property.h"
63 #include "magick/quantum-private.h"
64 #include "magick/static.h"
65 #include "magick/string_.h"
70 #define MaxPSDChannels 56
71 #define PSDQuantum(x) (((long) (x)+1) & -2)
74 Enumerated declaractions.
89 Typedef declaractions.
91 typedef struct _ChannelInfo
100 typedef struct _LayerInfo
110 channel_info[MaxPSDChannels];
134 typedef struct _PSDInfo
156 Forward declarations.
158 static MagickBooleanType
159 WritePSDImage(const ImageInfo *,Image *);
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % IsPSD()() returns MagickTrue if the image format type, identified by the
173 % magick string, is PSD.
175 % The format of the IsPSD method is:
177 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
179 % A description of each parameter follows:
181 % o magick: compare image format pattern against these bytes.
183 % o length: Specifies the length of the magick string.
186 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
190 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 % R e a d P S D I m a g e %
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 % ReadPSDImage() reads an Adobe Photoshop image file and returns it. It
207 % allocates the memory necessary for the new Image structure and returns a
208 % pointer to the new image.
210 % The format of the ReadPSDImage method is:
212 % Image *ReadPSDImage(image_info)
214 % A description of each parameter follows:
216 % o image_info: the image info.
218 % o exception: return any errors or warnings in this structure.
222 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator operator)
229 case OverCompositeOp: blend_mode = "norm"; break;
230 case MultiplyCompositeOp: blend_mode = "mul "; break;
231 case DissolveCompositeOp: blend_mode = "diss"; break;
232 case DifferenceCompositeOp: blend_mode = "diff"; break;
233 case DarkenCompositeOp: blend_mode = "dark"; break;
234 case LightenCompositeOp: blend_mode = "lite"; break;
235 case HueCompositeOp: blend_mode = "hue "; break;
236 case SaturateCompositeOp: blend_mode = "sat "; break;
237 case ColorizeCompositeOp: blend_mode = "colr"; break;
238 case LuminizeCompositeOp: blend_mode = "lum "; break;
239 case ScreenCompositeOp: blend_mode = "scrn"; break;
240 case OverlayCompositeOp: blend_mode = "over"; break;
247 static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
248 const unsigned char *compact_pixels,const long depth,
249 const size_t number_pixels,unsigned char *pixels)
264 packets=(ssize_t) number_compact_pixels;
265 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
267 length=(*compact_pixels++);
274 pixel=(*compact_pixels++);
276 for (j=0; j < (long) length; j++)
282 *pixels++=(pixel >> 7) & 0x01 ? 0 : 255;
283 *pixels++=(pixel >> 6) & 0x01 ? 0 : 255;
284 *pixels++=(pixel >> 5) & 0x01 ? 0 : 255;
285 *pixels++=(pixel >> 4) & 0x01 ? 0 : 255;
286 *pixels++=(pixel >> 3) & 0x01 ? 0 : 255;
287 *pixels++=(pixel >> 2) & 0x01 ? 0 : 255;
288 *pixels++=(pixel >> 1) & 0x01 ? 0 : 255;
289 *pixels++=(pixel >> 0) & 0x01 ? 0 : 255;
295 *pixels++=(pixel >> 4) & 0xff;
296 *pixels++=(pixel & 0x0f) & 0xff;
302 *pixels++=(pixel >> 6) & 0x03;
303 *pixels++=(pixel >> 4) & 0x03;
304 *pixels++=(pixel >> 2) & 0x03;
305 *pixels++=(pixel & 0x03) & 0x03;
320 for (j=0; j < (long) length; j++)
326 *pixels++=(*compact_pixels >> 7) & 0x01 ? 0 : 255;
327 *pixels++=(*compact_pixels >> 6) & 0x01 ? 0 : 255;
328 *pixels++=(*compact_pixels >> 5) & 0x01 ? 0 : 255;
329 *pixels++=(*compact_pixels >> 4) & 0x01 ? 0 : 255;
330 *pixels++=(*compact_pixels >> 3) & 0x01 ? 0 : 255;
331 *pixels++=(*compact_pixels >> 2) & 0x01 ? 0 : 255;
332 *pixels++=(*compact_pixels >> 1) & 0x01 ? 0 : 255;
333 *pixels++=(*compact_pixels >> 0) & 0x01 ? 0 : 255;
339 *pixels++=(*compact_pixels >> 4) & 0xff;
340 *pixels++=(*compact_pixels & 0x0f) & 0xff;
346 *pixels++=(*compact_pixels >> 6) & 0x03;
347 *pixels++=(*compact_pixels >> 4) & 0x03;
348 *pixels++=(*compact_pixels >> 2) & 0x03;
349 *pixels++=(*compact_pixels & 0x03) & 0x03;
355 *pixels++=(*compact_pixels);
366 static inline MagickOffsetType GetPSDOffset(PSDInfo *psd_info,Image *image)
368 if (psd_info->version == 1)
369 return((MagickOffsetType) ReadBlobMSBShort(image));
370 return((MagickOffsetType) ReadBlobMSBLong(image));
373 static inline MagickSizeType GetPSDSize(PSDInfo *psd_info,Image *image)
375 if (psd_info->version == 1)
376 return((MagickSizeType) ReadBlobMSBLong(image));
377 return((MagickSizeType) ReadBlobMSBLongLong(image));
380 static inline long MagickAbsoluteValue(const long x)
387 static const char *ModeToString(PSDImageType type)
391 case BitmapMode: return "Bitmap";
392 case GrayscaleMode: return "Grayscale";
393 case IndexedMode: return "Indexed";
394 case RGBMode: return "RGB";
395 case CMYKMode: return "CMYK";
396 case MultichannelMode: return "Multichannel";
397 case DuotoneMode: return "Duotone";
398 case LabMode: return "L*A*B";
399 default: return "unknown";
403 static MagickBooleanType ParseImageResourceBlocks(Image *image,
404 const unsigned char *blocks,size_t length)
422 profile=AcquireStringInfo(length);
423 SetStringInfoDatum(profile,blocks);
424 (void) SetImageProfile(image,"8bim",profile);
425 profile=DestroyStringInfo(profile);
426 for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); )
428 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
430 p=PushLongPixel(LSBEndian,p,&long_sans);
431 p=PushShortPixel(LSBEndian,p,&id);
432 p=PushShortPixel(LSBEndian,p,&short_sans);
433 p=PushLongPixel(LSBEndian,p,&count);
444 p=PushShortPixel(LSBEndian,p,&resolution);
445 image->x_resolution=(double) resolution;
446 p=PushShortPixel(LSBEndian,p,&short_sans);
447 p=PushShortPixel(LSBEndian,p,&short_sans);
448 p=PushShortPixel(LSBEndian,p,&short_sans);
449 p=PushShortPixel(LSBEndian,p,&resolution);
450 image->y_resolution=(double) resolution;
451 p=PushShortPixel(LSBEndian,p,&short_sans);
452 p=PushShortPixel(LSBEndian,p,&short_sans);
453 p=PushShortPixel(LSBEndian,p,&short_sans);
462 if ((count & 0x01) != 0)
468 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
470 if (mode == (const char *) NULL)
471 return(OverCompositeOp);
472 if (LocaleNCompare(mode,"norm",4) == 0)
473 return(OverCompositeOp);
474 if (LocaleNCompare(mode,"mul ",4) == 0)
475 return(MultiplyCompositeOp);
476 if (LocaleNCompare(mode,"diss",4) == 0)
477 return(DissolveCompositeOp);
478 if (LocaleNCompare(mode,"diff",4) == 0)
479 return(DifferenceCompositeOp);
480 if (LocaleNCompare(mode,"dark",4) == 0)
481 return(DarkenCompositeOp);
482 if (LocaleNCompare(mode,"lite",4) == 0)
483 return(LightenCompositeOp);
484 if (LocaleNCompare(mode,"hue ",4) == 0)
485 return(HueCompositeOp);
486 if (LocaleNCompare(mode,"sat ",4) == 0)
487 return(SaturateCompositeOp);
488 if (LocaleNCompare(mode,"colr",4) == 0)
489 return(ColorizeCompositeOp);
490 if (LocaleNCompare(mode,"lum ",4) == 0)
491 return(LuminizeCompositeOp);
492 if (LocaleNCompare(mode,"scrn",4) == 0)
493 return(ScreenCompositeOp);
494 if (LocaleNCompare(mode,"over",4) == 0)
495 return(OverlayCompositeOp);
496 if (LocaleNCompare(mode,"hLit",4) == 0)
497 return(OverCompositeOp);
498 if (LocaleNCompare(mode,"sLit",4) == 0)
499 return(OverCompositeOp);
500 if (LocaleNCompare(mode,"smud",4) == 0)
501 return(OverCompositeOp);
502 if (LocaleNCompare(mode,"div ",4) == 0)
503 return(OverCompositeOp);
504 if (LocaleNCompare(mode,"idiv",4) == 0)
505 return(OverCompositeOp);
506 return(OverCompositeOp);
509 static MagickBooleanType ReadPSDLayer(Image *image,
510 const unsigned long channels,const unsigned long type,
511 const MagickOffsetType *offsets,ExceptionInfo *exception)
528 register const unsigned char
545 if (image->storage_class == PseudoClass)
547 if (image->colors > 256)
550 if (image->depth > 8)
554 if (image->depth > 8)
556 pixels=(unsigned char *) AcquireQuantumMemory(image->columns+256,packet_size*
558 if (pixels == (unsigned char *) NULL)
559 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
561 (void) ResetMagickMemory(pixels,0,image->columns*packet_size*sizeof(*pixels));
562 compact_pixels=(unsigned char *) NULL;
563 if (image->compression == RLECompression)
569 for (y=0; y < (long) image->rows; y++)
570 if ((MagickOffsetType) length < offsets[y])
572 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,
574 if (compact_pixels == (unsigned char *) NULL)
575 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
577 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
579 for (y=0; y < (long) image->rows; y++)
581 if (image->compression != RLECompression)
582 count=ReadBlob(image,packet_size*image->columns,pixels);
585 count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
586 if (count != (ssize_t) offsets[y])
588 count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
589 image->depth,packet_size*image->columns,pixels);
591 if (count < (ssize_t) (packet_size*image->columns))
593 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
594 if (q == (PixelPacket *) NULL)
596 indexes=GetAuthenticIndexQueue(image);
598 for (x=0; x < (long) image->columns; x++)
600 if (packet_size == 1)
601 pixel=ScaleCharToQuantum(*p++);
604 p=PushShortPixel(MSBEndian,p,&nibble);
605 pixel=ScaleShortToQuantum(nibble);
611 q->opacity=(Quantum) (QuantumRange-pixel);
622 if (image->storage_class == PseudoClass)
624 if (packet_size == 1)
625 indexes[x]=(IndexPacket) ScaleQuantumToChar(pixel);
627 indexes[x]=(IndexPacket) ScaleQuantumToShort(pixel);
628 *q=image->colormap[(long) indexes[x]];
629 q->red=image->colormap[(long) indexes[x]].red;
630 q->green=image->colormap[(long) indexes[x]].green;
631 q->blue=image->colormap[(long) indexes[x]].blue;
637 if (image->storage_class == PseudoClass)
638 q->opacity=(Quantum) (QuantumRange-pixel);
650 if (image->colorspace == CMYKColorspace)
651 indexes[x]=(IndexPacket) pixel;
653 q->opacity=(Quantum) (QuantumRange-pixel);
658 q->opacity=(Quantum) (QuantumRange-pixel);
666 if (SyncAuthenticPixels(image,exception) == MagickFalse)
669 if (image->compression == RLECompression)
670 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
671 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
675 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
678 message[MaxTextExtent],
728 skip_first_alpha = 0;
733 assert(image_info != (const ImageInfo *) NULL);
734 assert(image_info->signature == MagickSignature);
735 if (image_info->debug != MagickFalse)
736 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
737 image_info->filename);
738 assert(exception != (ExceptionInfo *) NULL);
739 assert(exception->signature == MagickSignature);
740 image=AcquireImage(image_info);
741 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
742 if (status == MagickFalse)
744 image=DestroyImageList(image);
745 return((Image *) NULL);
750 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
751 psd_info.version=ReadBlobMSBShort(image);
752 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
753 ((psd_info.version != 1) && (psd_info.version != 2)))
754 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
755 count=ReadBlob(image,6,psd_info.reserved);
756 psd_info.channels=ReadBlobMSBShort(image);
757 if (psd_info.channels > MaxPSDChannels)
758 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
759 psd_info.rows=ReadBlobMSBLong(image);
760 psd_info.columns=ReadBlobMSBLong(image);
761 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
762 (psd_info.columns > 30000)))
763 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
764 psd_info.depth=ReadBlobMSBShort(image);
765 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
766 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
767 psd_info.mode=ReadBlobMSBShort(image);
768 if (image->debug != MagickFalse)
769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
770 " Image is %ld x %ld with channels=%d, depth=%d, mode=%s",
771 psd_info.columns,psd_info.rows,psd_info.channels,psd_info.depth,
772 ModeToString((PSDImageType) psd_info.mode));
776 image->depth=psd_info.depth;
777 image->columns=psd_info.columns;
778 image->rows=psd_info.rows;
779 if (SetImageBackgroundColor(image) == MagickFalse)
781 InheritException(exception,&image->exception);
782 image=DestroyImageList(image);
783 return((Image *) NULL);
785 image->matte=psd_info.channels >= 4 ? MagickTrue : MagickFalse;
786 if (psd_info.mode == LabMode)
787 image->colorspace=LabColorspace;
788 if (psd_info.mode == CMYKMode)
790 image->colorspace=CMYKColorspace;
791 image->matte=psd_info.channels >= 5 ? MagickTrue : MagickFalse;
793 if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
794 (psd_info.mode == DuotoneMode))
796 if (AcquireImageColormap(image,256) == MagickFalse)
797 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
798 image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
799 if (image->debug != MagickFalse)
800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
801 " ImageColorMap allocated");
802 image->colorspace=GRAYColorspace;
804 if (image->debug != MagickFalse)
805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
806 image->matte ? " image has matte" : " image has no matte");
808 Read PSD raster colormap only present for indexed and duotone images.
810 length=ReadBlobMSBLong(image);
813 if (image->debug != MagickFalse)
814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
815 " reading colormap");
816 if (psd_info.mode == DuotoneMode)
819 Duotone image data; the format of this data is undocumented.
821 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
823 if (data == (unsigned char *) NULL)
824 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
825 count=ReadBlob(image,(size_t) length,data);
826 data=(unsigned char *) RelinquishMagickMemory(data);
831 Read PSD raster colormap.
833 if (AcquireImageColormap(image,(unsigned long) (length/3)) == MagickFalse)
834 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
835 for (i=0; i < (long) image->colors; i++)
836 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
837 ReadBlobByte(image));
838 for (i=0; i < (long) image->colors; i++)
839 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
840 ReadBlobByte(image));
841 for (i=0; i < (long) image->colors; i++)
842 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
843 ReadBlobByte(image));
844 image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
847 length=ReadBlobMSBLong(image);
854 Image resources block.
856 if (image->debug != MagickFalse)
857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
858 " reading image resource blocks - %ld bytes",(long) length);
859 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
861 if (blocks == (unsigned char *) NULL)
862 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
863 count=ReadBlob(image,(size_t) length,blocks);
864 if ((count != (ssize_t) length) ||
865 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
867 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
868 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
870 (void) ParseImageResourceBlocks(image,blocks,(size_t) length);
871 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
874 If we are only "pinging" the image, then we're done - so return.
876 if (image_info->ping != MagickFalse)
878 (void) CloseBlob(image);
879 return(GetFirstImageInList(image));
882 Layer and mask block.
884 layer_info=(LayerInfo *) NULL;
886 length=GetPSDSize(&psd_info,image);
889 length=ReadBlobMSBLong(image);
890 length=ReadBlobMSBLong(image);
892 if ((image_info->number_scenes == 1) && (image_info->scene == 0))
893 for ( ; length != 0; length--)
894 if (ReadBlobByte(image) == EOF)
896 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
902 if (image->debug != MagickFalse)
903 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
904 " image has no layers");
908 offset=TellBlob(image);
909 size=GetPSDSize(&psd_info,image);
918 quantum=psd_info.version == 1 ? 4UL : 8UL;
919 for (j=0; j < (long) (length-quantum); j++)
920 (void) ReadBlobByte(image);
927 layer_offset=offset+length;
928 number_layers=(short) ReadBlobMSBShort(image);
929 if (image->debug != MagickFalse)
930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
931 " image contains %ld layers", number_layers);
932 if (number_layers < 0)
935 Weird hack in PSD format to ignore first alpha channel.
938 number_layers=MagickAbsoluteValue(number_layers);
939 if (image->debug != MagickFalse)
940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
941 " negative layer count corrected for");
943 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
944 sizeof(*layer_info));
945 if (layer_info == (LayerInfo *) NULL)
947 if (image->debug != MagickFalse)
948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
949 " allocation of LayerInfo failed");
950 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
952 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
953 sizeof(*layer_info));
954 for (i=0; i < number_layers; i++)
956 if (image->debug != MagickFalse)
957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
958 " reading layer #%ld",i+1);
959 layer_info[i].page.y=(long) ReadBlobMSBLong(image);
960 layer_info[i].page.x=(long) ReadBlobMSBLong(image);
961 layer_info[i].page.height=(unsigned long)
962 ReadBlobMSBLong(image)-layer_info[i].page.y;
963 layer_info[i].page.width=(unsigned long)
964 ReadBlobMSBLong(image)-layer_info[i].page.x;
965 layer_info[i].channels=ReadBlobMSBShort(image);
966 if (layer_info[i].channels > MaxPSDChannels)
967 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
968 if (image->debug != MagickFalse)
969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
970 " offset(%ld,%ld), size(%ld,%ld), channels=%d",
971 layer_info[i].page.x, layer_info[i].page.y,
972 layer_info[i].page.height,layer_info[i].page.width,
973 layer_info[i].channels);
974 for (j=0; j < (long) layer_info[i].channels; j++)
976 layer_info[i].channel_info[j].type=(short)
977 ReadBlobMSBShort(image);
978 layer_info[i].channel_info[j].size=(unsigned long)
979 GetPSDSize(&psd_info,image);
980 if (image->debug != MagickFalse)
981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
982 " channel[%ld]: type=%d, size=%ld",j,
983 layer_info[i].channel_info[j].type,
984 (long) layer_info[i].channel_info[j].size);
986 count=ReadBlob(image,4,(unsigned char *) type);
987 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
989 if (image->debug != MagickFalse)
990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991 " layer type was %.4s instead of 8BIM", type);
992 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
994 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
995 layer_info[i].opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(
996 (unsigned char) ReadBlobByte(image)));
997 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
998 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
999 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1000 if (image->debug != MagickFalse)
1001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1002 " blend=%.4s, opacity=%lu, clipping=%s, flags=%d, visible=%s",
1003 layer_info[i].blendkey,(unsigned long) layer_info[i].opacity,
1004 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1005 layer_info[i].visible ? "true" : "false");
1006 (void) ReadBlobByte(image); /* filler */
1008 size=ReadBlobMSBLong(image);
1011 if (image->debug != MagickFalse)
1012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1013 " layer contains additional info");
1014 length=ReadBlobMSBLong(image);
1020 layer_info[i].mask.y=(long) ReadBlobMSBLong(image);
1021 layer_info[i].mask.x=(long) ReadBlobMSBLong(image);
1022 layer_info[i].mask.height=(unsigned long)
1023 (ReadBlobMSBLong(image)-layer_info[i].mask.y);
1024 layer_info[i].mask.width=(unsigned long)
1025 (ReadBlobMSBLong(image)-layer_info[i].mask.x);
1026 if (image->debug != MagickFalse)
1027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1028 " layer mask: offset(%ld,%ld), size(%ld,%ld), length=%ld",
1029 layer_info[i].mask.x,layer_info[i].mask.y,
1030 layer_info[i].mask.width, layer_info[i].mask.height,
1033 Skip over the rest of the layer mask information.
1035 for (j=0; j < (long) (length-16); j++)
1036 (void) ReadBlobByte(image);
1038 combinedlength+=length+4; /* +4 for length */
1039 length=ReadBlobMSBLong(image);
1043 Layer blending ranges info.
1045 if (image->debug != MagickFalse)
1046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1047 " layer blending ranges: length=%ld",(long) length);
1049 We read it, but don't use it...
1051 for (j=0; j < (long) (length); j+=8)
1053 size_t blend_source=ReadBlobMSBLong(image);
1054 size_t blend_dest=ReadBlobMSBLong(image);
1055 if (image->debug != MagickFalse)
1056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1057 " source(%x), dest(%x)",(unsigned int)
1058 blend_source,(unsigned int) blend_dest);
1061 combinedlength+=length+4;
1065 length=(size_t) ReadBlobByte(image);
1066 for (j=0; j < (long) length; j++)
1067 layer_info[i].name[j]=(unsigned char) ReadBlobByte(image);
1068 layer_info[i].name[j]='\0';
1069 if (image->debug != MagickFalse)
1070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1071 " layer name: %s",layer_info[i].name);
1072 combinedlength+=length+1;
1074 #if 0 /* still in development */
1076 Adjustment layers and other stuff...
1082 count=ReadBlob(image,4,alsig);
1083 if ((count == 0) || (LocaleNCompare(alsig,"8BIM",4) != 0)) {
1084 if (debug != MagickFalse)
1086 if (image->debug != MagickFalse)
1087 (void) LogMagickEvent(CoderEvent,GetMagickModule()," adjustment layer type was %.4s instead of 8BIM", alsig);
1089 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1091 count=ReadBlob(image,4,alkey);
1092 length=ReadBlobMSBLong(image);
1093 if (debug != MagickFalse)
1095 if (image->debug != MagickFalse)
1096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1097 " adjustment layer key: %.4s, data length=%ld",
1102 for (j=0; j < (long) (length); j++)
1103 (void) ReadBlobByte(image);
1107 combinedlength += 12 + length; /* sig, key, length + the actual length*/
1111 Skip the rest of the variable data until we support it.
1113 if (image->debug != MagickFalse)
1114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1115 " unsupported data: length=%ld",(long)
1116 (size-combinedlength));
1117 for (j=0; j < (long) (size-combinedlength); j++)
1118 (void) ReadBlobByte(image);
1121 Allocate layered image.
1123 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1124 layer_info[i].page.height,MagickFalse,&image->exception);
1125 if (layer_info[i].image == (Image *) NULL)
1127 for (j=0; j < i; j++)
1128 layer_info[j].image=DestroyImage(layer_info[j].image);
1129 if (image->debug != MagickFalse)
1130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1131 " allocation of image for layer %ld failed", i);
1132 ThrowReaderException(ResourceLimitError,
1133 "MemoryAllocationFailed");
1135 if (image->debug != MagickFalse)
1136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1137 " setting up new layer image");
1138 (void) SetImageBackgroundColor(layer_info[i].image);
1139 layer_info[i].image->compose=
1140 PSDBlendModeToCompositeOperator(layer_info[i].blendkey);
1141 if (layer_info[i].visible == MagickFalse)
1142 layer_info[i].image->compose=NoCompositeOp;
1143 if (psd_info.mode == CMYKMode)
1144 layer_info[i].image->colorspace=CMYKColorspace;
1145 if ((psd_info.mode == BitmapMode) ||
1146 (psd_info.mode == GrayscaleMode) ||
1147 (psd_info.mode == DuotoneMode))
1148 layer_info[i].image->colorspace=GRAYColorspace;
1149 for (j=0; j < (long) layer_info[i].channels; j++)
1150 if (layer_info[i].channel_info[j].type == -1)
1151 layer_info[i].image->matte=MagickTrue;
1153 Set up some hidden attributes for folks that need them.
1155 (void) FormatMagickString(message,MaxTextExtent,"%ld",
1156 layer_info[i].page.x);
1157 (void) SetImageArtifact(layer_info[i].image,"psd:layer.x",message);
1158 (void) FormatMagickString(message,MaxTextExtent,"%ld",
1159 layer_info[i].page.y);
1160 (void) SetImageArtifact(layer_info[i].image,"psd:layer.y",message);
1161 (void) FormatMagickString(message,MaxTextExtent,"%lu",
1162 (unsigned long) layer_info[i].opacity);
1163 (void) SetImageArtifact(layer_info[i].image,"psd:layer.opacity",
1165 (void) SetImageProperty(layer_info[i].image,"label",(char *)
1166 layer_info[i].name);
1168 if (image->debug != MagickFalse)
1169 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1170 " reading image data for layers");
1172 Read pixel data for each layer.
1174 for (i=0; i < number_layers; i++)
1176 if (image->debug != MagickFalse)
1177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1178 " reading data for layer %ld",i);
1179 for (j=0; j < (long) layer_info[i].channels; j++)
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1183 " reading data for channel %ld", j);
1185 if (layer_info[i].channel_info[j].size <= (2*layer_info[i].image->rows))
1190 if (image->debug != MagickFalse)
1191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1192 " layer data is empty");
1194 A layer without data.
1196 for (k=0; k < (long) layer_info[i].channel_info[j].size; k++)
1197 (void) ReadBlobByte(layer_info[i].image);
1201 offsets=(MagickOffsetType *) NULL;
1202 layer_info[i].image->compression=NoCompression;
1203 compression=ReadBlobMSBShort(layer_info[i].image);
1204 if ((layer_info[i].page.height != 0) &&
1205 (layer_info[i].page.width != 0))
1207 if (compression == 1)
1210 Read RLE compressed data.
1212 layer_info[i].image->compression=RLECompression;
1213 if (image->debug != MagickFalse)
1214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1215 " layer data is RLE compressed");
1216 offsets=(MagickOffsetType *) AcquireQuantumMemory(
1217 layer_info[i].image->rows,sizeof(*offsets));
1218 if (offsets == (MagickOffsetType *) NULL)
1219 ThrowReaderException(ResourceLimitError,
1220 "MemoryAllocationFailed");
1221 for (y=0; y < (long) layer_info[i].image->rows; y++)
1222 offsets[y]=GetPSDOffset(&psd_info,layer_info[i].image);
1224 status=ReadPSDLayer(layer_info[i].image,
1225 layer_info[i].channels,(unsigned long)
1226 layer_info[i].channel_info[j].type,offsets,exception);
1227 if (compression == 1)
1228 offsets=(MagickOffsetType *) RelinquishMagickMemory(
1230 if (status == MagickFalse)
1234 if (layer_info[i].opacity != OpaqueOpacity)
1237 Correct for opacity level.
1239 for (y=0; y < (long) layer_info[i].image->rows; y++)
1241 q=GetAuthenticPixels(layer_info[i].image,0,y,
1242 layer_info[i].image->columns,1,exception);
1243 if (q == (PixelPacket *) NULL)
1245 indexes=GetAuthenticIndexQueue(layer_info[i].image);
1246 for (x=0; x < (long) layer_info[i].image->columns; x++)
1248 q->opacity=(Quantum) (QuantumRange-(Quantum) (QuantumScale*
1249 ((QuantumRange-q->opacity)*(QuantumRange-
1250 layer_info[i].opacity))));
1253 if (SyncAuthenticPixels(layer_info[i].image,exception) == MagickFalse)
1257 if (layer_info[i].image->colorspace == CMYKColorspace)
1258 (void) NegateImage(layer_info[i].image,MagickFalse);
1259 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1261 if (status == MagickFalse)
1264 /* added by palf -> invisible group layer make layer of this group
1265 invisible I consider that all layer with width and height null are
1266 layer for group layer */
1268 short inside_layer = 0;
1269 short layer_visible = 0;
1270 for (i=number_layers-1; i >=0; i--)
1272 if ((layer_info[i].page.width == 0) ||
1273 (layer_info[i].page.height == 0))
1275 if (inside_layer == 0)
1278 layer_visible=(short int) layer_info[i].visible;
1286 if ((inside_layer == 1) && (layer_visible == 0))
1288 layer_info[i].visible=(unsigned char) layer_visible;
1289 layer_info[i].image->compose=NoCompositeOp;
1293 /* added by palf -> suppression of empty layer */
1294 /* I consider that all layer with width and height null are layer for group layer */
1295 for (i=0; i < number_layers; i++)
1297 if ((layer_info[i].page.width == 0) ||
1298 (layer_info[i].page.height == 0))
1300 if (layer_info[i].image != (Image *) NULL)
1301 layer_info[i].image=DestroyImage(layer_info[i].image);
1302 for (j=i; j < number_layers - 1; j++)
1303 layer_info[j] = layer_info[j+1];
1308 mask_size = ReadBlobMSBLong(image); /* global mask size: currently ignored */
1309 if (number_layers > 0)
1311 if (image->debug != MagickFalse)
1312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1313 " putting layers into image list");
1314 for (i=0; i < number_layers; i++)
1317 layer_info[i].image->previous=layer_info[i-1].image;
1318 if (i < (number_layers-1))
1319 layer_info[i].image->next=layer_info[i+1].image;
1320 layer_info[i].image->page=layer_info[i].page;
1322 image->next=layer_info[0].image;
1323 layer_info[0].image->previous=image;
1324 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1326 layer_offset-=TellBlob(image);
1327 offset=SeekBlob(image,layer_offset,SEEK_CUR);
1331 Read the precombined layer, present for PSD < 4 compatibility
1333 if (image->debug != MagickFalse)
1334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1335 " reading the precombined layer");
1336 offsets=(MagickOffsetType *) NULL;
1337 image->compression=NoCompression;
1338 compression=ReadBlobMSBShort(image);
1339 if (compression == 1)
1342 Read Packbit encoded pixel data as separate planes.
1344 image->compression=RLECompression;
1345 offsets=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
1346 psd_info.channels*sizeof(*offsets));
1347 if (offsets == (MagickOffsetType *) NULL)
1348 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1349 for (i=0; i < (long) (image->rows*psd_info.channels); i++)
1350 offsets[i]=GetPSDOffset(&psd_info,image);
1352 for (i=0; i < (long) psd_info.channels; i++)
1354 status=ReadPSDLayer(image,psd_info.channels,(unsigned long) i,offsets+i*
1355 image->rows,exception);
1356 if (status == MagickFalse)
1358 status=SetImageProgress(image,LoadImagesTag,i,psd_info.channels);
1359 if (status == MagickFalse)
1362 if (compression == 1)
1363 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1364 if (image->colorspace == CMYKColorspace)
1365 (void) NegateImage(image,MagickFalse);
1366 (void) CloseBlob(image);
1367 return(GetFirstImageInList(image));
1371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 % R e g i s t e r P S D I m a g e %
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % RegisterPSDImage() adds properties for the PSD image format to
1382 % the list of supported formats. The properties include the image format
1383 % tag, a method to read and/or write the format, whether the format
1384 % supports the saving of more than one frame to the same file or blob,
1385 % whether the format supports native in-memory I/O, and a brief
1386 % description of the format.
1388 % The format of the RegisterPSDImage method is:
1390 % unsigned long RegisterPSDImage(void)
1393 ModuleExport unsigned long RegisterPSDImage(void)
1398 entry=SetMagickInfo("PSB");
1399 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1400 entry->encoder=(EncodeImageHandler *) WritePSDImage;
1401 entry->magick=(IsImageFormatHandler *) IsPSD;
1402 entry->description=ConstantString("Adobe Large Document Format");
1403 entry->module=ConstantString("PSD");
1404 (void) RegisterMagickInfo(entry);
1405 entry=SetMagickInfo("PSD");
1406 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1407 entry->encoder=(EncodeImageHandler *) WritePSDImage;
1408 entry->magick=(IsImageFormatHandler *) IsPSD;
1409 entry->description=ConstantString("Adobe Photoshop bitmap");
1410 entry->module=ConstantString("PSD");
1411 (void) RegisterMagickInfo(entry);
1412 return(MagickImageCoderSignature);
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 % U n r e g i s t e r P S D I m a g e %
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % UnregisterPSDImage() removes format registrations made by the
1427 % PSD module from the list of supported formats.
1429 % The format of the UnregisterPSDImage method is:
1431 % UnregisterPSDImage(void)
1434 ModuleExport void UnregisterPSDImage(void)
1436 (void) UnregisterMagickInfo("PSB");
1437 (void) UnregisterMagickInfo("PSD");
1441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445 % W r i t e P S D I m a g e %
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
1453 % The format of the WritePSDImage method is:
1455 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image)
1457 % A description of each parameter follows.
1459 % o image_info: the image info.
1461 % o image: The image.
1466 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
1467 const size_t offset)
1469 if (psd_info->version == 1)
1470 return(WriteBlobMSBShort(image,(unsigned short) offset));
1471 return(WriteBlobMSBLong(image,(unsigned short) offset));
1474 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
1475 const MagickSizeType size)
1477 if (psd_info->version == 1)
1478 return(WriteBlobMSBLong(image,(unsigned int) size));
1479 return(WriteBlobMSBLongLong(image,size));
1482 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
1483 const unsigned char *pixels,unsigned char *compact_pixels)
1492 register unsigned char
1499 Compress pixels with Packbits encoding.
1501 assert(image != (Image *) NULL);
1502 assert(image->signature == MagickSignature);
1503 if (image->debug != MagickFalse)
1504 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1505 assert(pixels != (unsigned char *) NULL);
1506 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
1507 if (packbits == (unsigned char *) NULL)
1508 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1511 for (i=(long) length; i != 0; )
1518 *q++=(unsigned char) 0;
1525 *q++=(unsigned char) 1;
1533 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1535 *q++=(unsigned char) ((256-3)+1);
1539 *q++=(unsigned char) 2;
1547 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1553 while (((long) count < i) && (*pixels == *(pixels+count)))
1560 *q++=(unsigned char) ((256-count)+1);
1569 while ((*(pixels+count) != *(pixels+count+1)) ||
1570 (*(pixels+count+1) != *(pixels+count+2)))
1572 packbits[count+1]=pixels[count];
1574 if (((long) count >= (i-3)) || (count >= 127))
1578 *packbits=(unsigned char) (count-1);
1579 for (j=0; j <= (long) count; j++)
1586 *q++=(unsigned char) 128; /* EOD marker */
1587 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
1588 return((size_t) (q-compact_pixels));
1591 static void WritePackbitsLength(const PSDInfo *psd_info,
1592 const ImageInfo *image_info,Image *image,Image *tmp_image,
1593 unsigned char *pixels,unsigned char *compact_pixels,
1594 const QuantumType quantum_type)
1602 register const PixelPacket
1609 if (tmp_image->depth > 8)
1610 tmp_image->depth=16;
1611 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1612 quantum_info=AcquireQuantumInfo(image_info,image);
1613 for (y=0; y < (long) tmp_image->rows; y++)
1615 p=GetVirtualPixels(tmp_image,0,y,tmp_image->columns,1,&image->exception);
1616 if (p == (const PixelPacket *) NULL)
1618 length=ExportQuantumPixels(tmp_image,(CacheView *) NULL,quantum_info,
1619 quantum_type,pixels,&image->exception);
1620 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels);
1621 (void) SetPSDOffset(psd_info,image,length);
1623 quantum_info=DestroyQuantumInfo(quantum_info);
1626 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
1627 Image *image,Image *tmp_image,unsigned char *pixels,
1628 unsigned char *compact_pixels,const QuantumType quantum_type,
1629 const MagickBooleanType compression_flag)
1640 register const PixelPacket
1651 if ((compression_flag != MagickFalse) &&
1652 (tmp_image->compression != RLECompression))
1653 (void) WriteBlobMSBShort(image,0);
1654 if (tmp_image->depth > 8)
1655 tmp_image->depth=16;
1656 monochrome=IsMonochromeImage(image,&image->exception);
1657 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1658 quantum_info=AcquireQuantumInfo(image_info,image);
1659 for (y=0; y < (long) tmp_image->rows; y++)
1661 p=GetVirtualPixels(tmp_image,0,y,tmp_image->columns,1,&image->exception);
1662 if (p == (const PixelPacket *) NULL)
1664 length=ExportQuantumPixels(tmp_image,(CacheView *) NULL,quantum_info,
1665 quantum_type,pixels,&image->exception);
1666 if (monochrome != MagickFalse)
1667 for (i=0; i < (long) length; i++)
1668 pixels[i]=(~pixels[i]);
1669 if (tmp_image->compression != RLECompression)
1670 (void) WriteBlob(image,length,pixels);
1673 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels);
1674 (void) WriteBlob(image,length,compact_pixels);
1677 quantum_info=DestroyQuantumInfo(quantum_info);
1680 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
1681 const ImageInfo *image_info,Image *image,Image *tmp_image,
1682 const MagickBooleanType separate)
1696 Write uncompressed pixels as separate planes.
1699 if ((tmp_image->storage_class == PseudoClass) &&
1700 (tmp_image->matte == MagickFalse))
1702 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1703 pixels=(unsigned char *) AcquireQuantumMemory(channels*tmp_image->columns,
1704 packet_size*sizeof(*pixels));
1705 compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
1706 tmp_image->columns,packet_size*sizeof(*pixels));
1707 if ((pixels == (unsigned char *) NULL) ||
1708 (compact_pixels == (unsigned char *) NULL))
1710 if (pixels != (unsigned char *) NULL)
1711 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1712 if (compact_pixels != (unsigned char *) NULL)
1713 compact_pixels=(unsigned char *)
1714 RelinquishMagickMemory(compact_pixels);
1715 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1718 if (IsGrayImage(tmp_image,&tmp_image->exception) != MagickFalse)
1720 tmp_image->compression=RLECompression;
1721 if (tmp_image->compression == RLECompression)
1724 Packbits compression.
1726 (void) WriteBlobMSBShort(image,1);
1727 if (tmp_image->matte != MagickFalse)
1728 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1729 compact_pixels,AlphaQuantum);
1730 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1731 compact_pixels,GrayQuantum);
1733 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1734 compact_pixels,GrayQuantum,(i++ == 0) || (separate != MagickFalse) ?
1735 MagickTrue : MagickFalse);
1738 if (tmp_image->storage_class == PseudoClass)
1740 if (tmp_image->compression == RLECompression)
1743 Packbits compression.
1745 (void) WriteBlobMSBShort(image,1);
1746 if (tmp_image->matte == MagickFalse)
1747 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1748 compact_pixels,IndexQuantum);
1750 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1751 compact_pixels,IndexAlphaQuantum);
1753 if (tmp_image->matte == MagickFalse)
1754 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1755 compact_pixels,IndexQuantum,(i++ == 0) ||
1756 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1758 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1759 compact_pixels,IndexAlphaQuantum,(i++ == 0) ||
1760 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1761 (void) SetImageProgress(image,SaveImagesTag,0,1);
1765 if (tmp_image->colorspace == CMYKColorspace)
1767 tmp_image->compression=NoCompression;
1768 (void) NegateImage(tmp_image,MagickFalse);
1770 if (tmp_image->compression == RLECompression)
1773 Packbits compression.
1775 (void) WriteBlobMSBShort(image,1);
1776 if (tmp_image->matte != MagickFalse)
1777 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1778 compact_pixels,AlphaQuantum);
1779 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1780 compact_pixels,RedQuantum);
1781 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1782 compact_pixels,GreenQuantum);
1783 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1784 compact_pixels,BlueQuantum);
1785 if (tmp_image->colorspace == CMYKColorspace)
1786 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1787 compact_pixels,BlackQuantum);
1789 (void) SetImageProgress(image,SaveImagesTag,0,6);
1790 if (tmp_image->matte != MagickFalse)
1791 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1792 compact_pixels,AlphaQuantum,(i++ == 0) ||
1793 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1794 (void) SetImageProgress(image,SaveImagesTag,1,6);
1795 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1796 compact_pixels,RedQuantum,(i++ == 0) || (separate != MagickFalse) ?
1797 MagickTrue : MagickFalse);
1798 (void) SetImageProgress(image,SaveImagesTag,2,6);
1799 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1800 compact_pixels,GreenQuantum,(i++ == 0) || (separate != MagickFalse) ?
1801 MagickTrue : MagickFalse);
1802 (void) SetImageProgress(image,SaveImagesTag,3,6);
1803 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1804 compact_pixels,BlueQuantum,(i++ == 0) || (separate != MagickFalse) ?
1805 MagickTrue : MagickFalse);
1806 (void) SetImageProgress(image,SaveImagesTag,4,6);
1807 if (tmp_image->colorspace == CMYKColorspace)
1809 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1810 compact_pixels,BlackQuantum,(i++ == 0) ||
1811 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1812 (void) NegateImage(tmp_image,MagickFalse);
1814 (void) SetImageProgress(image,SaveImagesTag,5,6);
1816 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1820 static void WritePascalString(Image* inImage,const char *inString,int inPad)
1826 /* max length is 255 */
1828 strLength = (strlen(inString) > 255UL ) ? 255UL : strlen(inString);
1830 if ( strLength != 0 )
1832 (void) WriteBlobByte(inImage,(unsigned char) strLength);
1833 (void) WriteBlob(inImage, strLength, (const unsigned char *) inString);
1836 (void) WriteBlobByte(inImage, 0);
1840 if ( (strLength % inPad) == 0 )
1842 for (i=0; i < (long) (inPad-(strLength % inPad)); i++)
1843 (void) WriteBlobByte(inImage,0);
1846 static void WriteResolutionResourceBlock(Image *image)
1855 x_resolution=65536.0*image->x_resolution+0.5;
1856 y_resolution=65536.0*image->y_resolution+0.5;
1858 if (image->units == PixelsPerCentimeterResolution)
1860 x_resolution=2.54*65536.0*image->x_resolution*0.5;
1861 y_resolution=2.54*65536.0*image->y_resolution+0.5;
1864 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
1865 (void) WriteBlobMSBShort(image,0x03ED);
1866 (void) WriteBlobMSBShort(image,0);
1867 (void) WriteBlobMSBLong(image,16); /* resource size */
1868 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
1869 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
1870 (void) WriteBlobMSBShort(image,units); /* width unit */
1871 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
1872 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
1873 (void) WriteBlobMSBShort(image,units); /* height unit */
1876 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image)
1886 invert_layer_count = MagickFalse,
1908 rounded_layer_info_size;
1911 * tmp_image = (Image *) NULL,
1912 * base_image = GetNextImageInList(image);
1917 assert(image_info != (const ImageInfo *) NULL);
1918 assert(image_info->signature == MagickSignature);
1919 assert(image != (Image *) NULL);
1920 assert(image->signature == MagickSignature);
1921 if (image->debug != MagickFalse)
1922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1923 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1924 if (status == MagickFalse)
1926 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
1927 if (image->matte != MagickFalse)
1928 packet_size+=image->depth > 8 ? 2 : 1;
1930 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
1931 (image->columns > 30000) || (image->rows > 30000))
1933 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
1934 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
1935 for (i=1; i <= 6; i++)
1936 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
1937 if (IsGrayImage(image,&image->exception) != MagickFalse)
1940 if (image->storage_class == PseudoClass)
1941 num_channels=(image->matte ? 2UL : 1UL);
1944 if (image->colorspace != CMYKColorspace)
1945 num_channels=(image->matte ? 4UL : 3UL);
1947 num_channels=(image->matte ? 5UL : 4UL);
1949 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
1950 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
1951 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
1952 if (IsGrayImage(image,&image->exception) != MagickFalse)
1960 monochrome=IsMonochromeImage(image,&image->exception);
1961 (void) WriteBlobMSBShort(image,monochrome != MagickFalse ? 1 :
1962 image->depth > 8 ? 16 : 8);
1963 (void) WriteBlobMSBShort(image,monochrome != MagickFalse ?
1964 BitmapMode : GrayscaleMode);
1968 (void) WriteBlobMSBShort(image,(unsigned short)
1969 (image->storage_class == PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
1970 if (((image->colorspace != UndefinedColorspace) ||
1971 (image->colorspace != CMYKColorspace)) &&
1972 (image->colorspace != CMYKColorspace))
1974 if (image->colorspace != RGBColorspace)
1975 (void) TransformImageColorspace(image,RGBColorspace);
1976 (void) WriteBlobMSBShort(image,(unsigned short)
1977 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
1981 if (image->colorspace != RGBColorspace)
1982 (void) TransformImageColorspace(image,CMYKColorspace);
1983 (void) WriteBlobMSBShort(image,CMYKMode);
1986 if ((IsGrayImage(image,&image->exception) != MagickFalse) ||
1987 (image->storage_class == DirectClass) || (image->colors > 256))
1988 (void) WriteBlobMSBLong(image,0);
1992 Write PSD raster colormap.
1994 (void) WriteBlobMSBLong(image,768);
1995 for (i=0; i < (long) image->colors; i++)
1996 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
1997 for ( ; i < 256; i++)
1998 (void) WriteBlobByte(image,0);
1999 for (i=0; i < (long) image->colors; i++)
2000 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green));
2001 for ( ; i < 256; i++)
2002 (void) WriteBlobByte(image,0);
2003 for (i=0; i < (long) image->colors; i++)
2004 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2005 for ( ; i < 256; i++)
2006 (void) WriteBlobByte(image,0);
2009 Image resource block.
2011 length=28; /* 0x03EB */
2012 bim_profile=GetImageProfile(image,"8bim");
2013 if (bim_profile != (StringInfo *) NULL)
2014 length+=GetStringInfoLength(bim_profile);
2015 icc_profile=GetImageProfile(image,"icc");
2016 if (icc_profile != (StringInfo *) NULL)
2017 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2018 (void) WriteBlobMSBLong(image,length);
2019 WriteResolutionResourceBlock(image);
2020 if (bim_profile != (StringInfo *) NULL)
2021 (void) WriteBlob(image,GetStringInfoLength(bim_profile),GetStringInfoDatum(
2023 if (icc_profile != (StringInfo *) NULL)
2025 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2026 (void) WriteBlobMSBShort(image,0x040F);
2027 (void) WriteBlobMSBShort(image,0);
2028 (void) WriteBlobMSBLong(image,GetStringInfoLength(icc_profile));
2029 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2030 GetStringInfoDatum(icc_profile));
2031 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2032 PSDQuantum(GetStringInfoLength(icc_profile)))
2033 (void) WriteBlobByte(image,0);
2038 layer_info_size = 2;
2039 tmp_image = base_image;
2040 while ( tmp_image != NULL ) {
2041 packet_size=tmp_image->depth > 8 ? 2UL : 1UL;
2043 if (IsGrayImage(image,&image->exception) != MagickFalse)
2046 if (tmp_image->storage_class == PseudoClass)
2047 num_channels = (tmp_image->matte != MagickFalse ? 2UL : 1UL);
2049 if (tmp_image->colorspace != CMYKColorspace)
2050 num_channels = (tmp_image->matte != MagickFalse ? 4UL : 3UL);
2052 num_channels = (tmp_image->matte != MagickFalse ? 5UL : 4UL);
2054 channelLength=(unsigned long) (tmp_image->columns * tmp_image->rows *
2056 layer_info_size += (unsigned long) (4*4 + 2 + num_channels * 6 +
2057 (psd_info.version == 1 ? 8 : 16) + 4 * 1 + 4 + num_channels *
2059 theAttr=(const char *) GetImageProperty(tmp_image,"label");
2061 layer_info_size += 16;
2064 size_t length=strlen(theAttr);
2065 layer_info_size += 8+length+(4-(length % 4))+1;
2068 tmp_image = GetNextImageInList(tmp_image);
2071 /* if the image has a matte, then we need to use layers */
2072 if ( layer_count == 0 && image->matte == MagickTrue )
2074 invert_layer_count = MagickTrue;
2076 goto compute_layer_info; /* yes, goto's suck, but it keeps the code cleaner! */
2079 if ( layer_count == 0 )
2080 (void) SetPSDSize(&psd_info,image,0);
2083 (void) SetPSDSize(&psd_info,image,layer_info_size+
2084 (psd_info.version == 1 ? 8 : 16));
2085 if ( layer_info_size/2 != (layer_info_size+1)/2 ) /* odd */
2086 rounded_layer_info_size = layer_info_size + 1;
2088 rounded_layer_info_size = layer_info_size;
2089 (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2091 if ( invert_layer_count )
2092 layer_count *= -1; /* if we have a matte, then use negative count! */
2093 (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2096 tmp_image = base_image;
2097 tmp_image->compression=NoCompression;
2098 while ( tmp_image != NULL ) {
2099 (void) WriteBlobMSBLong(image,0);
2100 (void) WriteBlobMSBLong(image,0);
2101 (void) WriteBlobMSBLong(image,(unsigned int) tmp_image->rows);
2102 (void) WriteBlobMSBLong(image,(unsigned int) tmp_image->columns);
2104 packet_size=tmp_image->depth > 8 ? 2UL : 1UL;
2105 channel_size=(unsigned int) ((packet_size*tmp_image->rows*
2106 tmp_image->columns)+2);
2107 if (tmp_image->storage_class == PseudoClass) {
2108 (void) WriteBlobMSBShort(image,(unsigned short)
2109 (tmp_image->matte ? 2 : 1));
2110 if (tmp_image->matte) {
2111 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2112 (void) SetPSDSize(&psd_info,image,channel_size);
2114 (void) WriteBlobMSBShort(image, 0);
2115 (void) SetPSDSize(&psd_info,image,channel_size);
2117 if (tmp_image->colorspace != CMYKColorspace)
2119 (void) WriteBlobMSBShort(image,(unsigned short)
2120 (tmp_image->matte ? 4 : 3));
2121 if (tmp_image->matte) {
2122 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2123 (void) SetPSDSize(&psd_info,image,channel_size);
2125 (void) WriteBlobMSBShort(image, 0);
2126 (void) SetPSDSize(&psd_info,image,channel_size);
2127 (void) WriteBlobMSBShort(image, 1);
2128 (void) SetPSDSize(&psd_info,image,channel_size);
2129 (void) WriteBlobMSBShort(image, 2);
2130 (void) SetPSDSize(&psd_info,image,channel_size);
2134 (void) WriteBlobMSBShort(image,(unsigned short)
2135 (tmp_image->matte ? 5 : 4));
2136 if (tmp_image->matte) {
2137 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2138 (void) SetPSDSize(&psd_info,image,channel_size);
2140 (void) WriteBlobMSBShort(image, 0);
2141 (void) SetPSDSize(&psd_info,image,channel_size);
2142 (void) WriteBlobMSBShort(image, 1);
2143 (void) SetPSDSize(&psd_info,image,channel_size);
2144 (void) WriteBlobMSBShort(image, 2);
2145 (void) SetPSDSize(&psd_info,image,channel_size);
2146 (void) WriteBlobMSBShort(image, 3);
2147 (void) SetPSDSize(&psd_info,image,channel_size);
2150 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2151 (void) WriteBlob(image,4,(const unsigned char *)
2152 CompositeOperatorToPSDBlendMode(tmp_image->compose));
2153 (void) WriteBlobByte(image, 255); /* BOGUS: layer opacity */
2154 (void) WriteBlobByte(image, 0);
2155 (void) WriteBlobByte(image, 1); /* BOGUS: layer attributes - visible, etc. */
2156 (void) WriteBlobByte(image, 0);
2159 theAttr=(const char *) GetImageProperty(tmp_image,"label");
2161 (void) WriteBlobMSBLong(image, 16);
2162 (void) WriteBlobMSBLong(image, 0);
2163 (void) WriteBlobMSBLong(image, 0);
2164 (void) FormatMagickString((char *) layer_name,MaxTextExtent,"L%06ld",
2166 WritePascalString( image, (char*)layer_name, 4 );
2168 size_t length=strlen(theAttr);
2169 (void) WriteBlobMSBLong(image,(unsigned int) (length+(4-(length % 4))+
2171 (void) WriteBlobMSBLong(image,0);
2172 (void) WriteBlobMSBLong(image,0);
2173 WritePascalString( image, theAttr, 4 );
2175 tmp_image = GetNextImageInList(tmp_image);
2178 /* now the image data! */
2179 tmp_image = base_image;
2180 while ( tmp_image != NULL ) {
2181 status=WriteImageChannels(&psd_info,image_info,image,tmp_image,MagickTrue);
2183 /* add in the pad! */
2184 if ( rounded_layer_info_size != layer_info_size )
2185 (void) WriteBlobByte(image,'\0');
2187 tmp_image = GetNextImageInList(tmp_image);
2190 /* user mask data */
2191 (void) WriteBlobMSBLong(image, 0);
2195 /* now the background image data! */
2196 status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse);
2198 (void) CloseBlob(image);