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/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"
71 #define MaxPSDChannels 56
72 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
75 Enumerated declaractions.
90 Typedef declaractions.
92 typedef struct _ChannelInfo
101 typedef struct _LayerInfo
111 channel_info[MaxPSDChannels];
135 typedef struct _PSDInfo
157 Forward declarations.
159 static MagickBooleanType
160 WritePSDImage(const ImageInfo *,Image *);
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % IsPSD()() returns MagickTrue if the image format type, identified by the
174 % magick string, is PSD.
176 % The format of the IsPSD method is:
178 % MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
180 % A description of each parameter follows:
182 % o magick: compare image format pattern against these bytes.
184 % o length: Specifies the length of the magick string.
187 static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
191 if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
201 % R e a d P S D I m a g e %
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
211 % The format of the ReadPSDImage method is:
213 % Image *ReadPSDImage(image_info)
215 % A description of each parameter follows:
217 % o image_info: the image info.
219 % o exception: return any errors or warnings in this structure.
223 static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
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;
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)
265 packets=(ssize_t) number_compact_pixels;
266 for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
268 length=(*compact_pixels++);
275 pixel=(*compact_pixels++);
277 for (j=0; j < (ssize_t) length; j++)
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;
296 *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
297 *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
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);
312 *pixels++=(unsigned char) pixel;
321 for (j=0; j < (ssize_t) length; j++)
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;
340 *pixels++=(*compact_pixels >> 4) & 0xff;
341 *pixels++=(*compact_pixels & 0x0f) & 0xff;
347 *pixels++=(*compact_pixels >> 6) & 0x03;
348 *pixels++=(*compact_pixels >> 4) & 0x03;
349 *pixels++=(*compact_pixels >> 2) & 0x03;
350 *pixels++=(*compact_pixels & 0x03) & 0x03;
356 *pixels++=(*compact_pixels);
367 static inline MagickOffsetType GetPSDOffset(PSDInfo *psd_info,Image *image)
369 if (psd_info->version == 1)
370 return((MagickOffsetType) ReadBlobMSBShort(image));
371 return((MagickOffsetType) ReadBlobMSBLong(image));
374 static inline MagickSizeType GetPSDSize(PSDInfo *psd_info,Image *image)
376 if (psd_info->version == 1)
377 return((MagickSizeType) ReadBlobMSBLong(image));
378 return((MagickSizeType) ReadBlobMSBLongLong(image));
381 static inline ssize_t MagickAbsoluteValue(const ssize_t x)
388 static const char *ModeToString(PSDImageType type)
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";
404 static MagickBooleanType ParseImageResourceBlocks(Image *image,
405 const unsigned char *blocks,size_t length)
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)); )
429 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
431 p=PushLongPixel(MSBEndian,p,&ssize_t_sans);
432 p=PushShortPixel(MSBEndian,p,&id);
433 p=PushShortPixel(MSBEndian,p,&short_sans);
434 p=PushLongPixel(MSBEndian,p,&count);
440 value[MaxTextExtent];
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);
470 if ((count & 0x01) != 0)
476 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
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);
517 static MagickBooleanType ReadPSDLayer(Image *image,const size_t channels,
518 const ssize_t type,const MagickOffsetType *offsets,ExceptionInfo *exception)
535 register const unsigned char
552 if (image->storage_class == PseudoClass)
554 if (image->colors > 256)
557 if (image->depth > 8)
561 if (image->depth > 8)
563 pixels=(unsigned char *) AcquireQuantumMemory(image->columns+256,packet_size*
565 if (pixels == (unsigned char *) NULL)
566 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
568 (void) ResetMagickMemory(pixels,0,image->columns*packet_size*sizeof(*pixels));
569 compact_pixels=(unsigned char *) NULL;
570 if (image->compression == RLECompression)
576 for (y=0; y < (ssize_t) image->rows; y++)
577 if ((MagickOffsetType) length < offsets[y])
578 length=(size_t) offsets[y];
579 compact_pixels=(unsigned char *) AcquireQuantumMemory(length,
581 if (compact_pixels == (unsigned char *) NULL)
582 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
584 (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
586 for (y=0; y < (ssize_t) image->rows; y++)
588 if (image->compression != RLECompression)
589 count=ReadBlob(image,packet_size*image->columns,pixels);
592 count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
593 if (count != (ssize_t) offsets[y])
595 count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
596 (ssize_t) image->depth,packet_size*image->columns,pixels);
598 if (count < (ssize_t) (packet_size*image->columns))
600 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
601 if (q == (PixelPacket *) NULL)
603 indexes=GetAuthenticIndexQueue(image);
605 for (x=0; x < (ssize_t) image->columns; x++)
607 if (packet_size == 1)
608 pixel=ScaleCharToQuantum(*p++);
611 p=PushShortPixel(MSBEndian,p,&nibble);
612 pixel=ScaleShortToQuantum(nibble);
618 q->opacity=(Quantum) (QuantumRange-pixel);
629 if (image->storage_class == PseudoClass)
631 if (packet_size == 1)
632 indexes[x]=(IndexPacket) ScaleQuantumToChar(pixel);
634 indexes[x]=(IndexPacket) ScaleQuantumToShort(pixel);
635 *q=image->colormap[(ssize_t) indexes[x]];
636 q->red=image->colormap[(ssize_t) indexes[x]].red;
637 q->green=image->colormap[(ssize_t) indexes[x]].green;
638 q->blue=image->colormap[(ssize_t) indexes[x]].blue;
644 if (image->storage_class == PseudoClass)
645 q->opacity=(Quantum) (QuantumRange-pixel);
657 if (image->colorspace == CMYKColorspace)
658 indexes[x]=(IndexPacket) pixel;
660 q->opacity=(Quantum) (QuantumRange-pixel);
665 q->opacity=(Quantum) (QuantumRange-pixel);
673 if (SyncAuthenticPixels(image,exception) == MagickFalse)
676 if (image->compression == RLECompression)
677 compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
678 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
682 static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
685 message[MaxTextExtent],
735 skip_first_alpha = 0;
740 assert(image_info != (const ImageInfo *) NULL);
741 assert(image_info->signature == MagickSignature);
742 if (image_info->debug != MagickFalse)
743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
744 image_info->filename);
745 assert(exception != (ExceptionInfo *) NULL);
746 assert(exception->signature == MagickSignature);
747 image=AcquireImage(image_info);
748 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
749 if (status == MagickFalse)
751 image=DestroyImageList(image);
752 return((Image *) NULL);
757 count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
758 psd_info.version=ReadBlobMSBShort(image);
759 if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
760 ((psd_info.version != 1) && (psd_info.version != 2)))
761 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
762 count=ReadBlob(image,6,psd_info.reserved);
763 psd_info.channels=ReadBlobMSBShort(image);
764 if (psd_info.channels > MaxPSDChannels)
765 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
766 psd_info.rows=ReadBlobMSBLong(image);
767 psd_info.columns=ReadBlobMSBLong(image);
768 if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
769 (psd_info.columns > 30000)))
770 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
771 psd_info.depth=ReadBlobMSBShort(image);
772 if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
773 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
774 psd_info.mode=ReadBlobMSBShort(image);
775 if (image->debug != MagickFalse)
776 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
777 " Image is %lu x %lu with channels=%lu, depth=%lu, mode=%s",
778 (unsigned long) psd_info.columns,(unsigned long) psd_info.rows,
779 (unsigned long) psd_info.channels,(unsigned long) psd_info.depth,
780 ModeToString((PSDImageType) psd_info.mode));
784 image->depth=psd_info.depth;
785 image->columns=psd_info.columns;
786 image->rows=psd_info.rows;
787 if (SetImageBackgroundColor(image) == MagickFalse)
789 InheritException(exception,&image->exception);
790 image=DestroyImageList(image);
791 return((Image *) NULL);
793 image->matte=psd_info.channels >= 4 ? MagickTrue : MagickFalse;
794 if (psd_info.mode == LabMode)
795 image->colorspace=LabColorspace;
796 if (psd_info.mode == CMYKMode)
798 image->colorspace=CMYKColorspace;
799 image->matte=psd_info.channels >= 5 ? MagickTrue : MagickFalse;
801 if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
802 (psd_info.mode == DuotoneMode))
804 if (AcquireImageColormap(image,256) == MagickFalse)
805 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
806 image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
807 if (image->debug != MagickFalse)
808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
809 " ImageColorMap allocated");
810 image->colorspace=GRAYColorspace;
812 if (image->debug != MagickFalse)
813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
814 image->matte ? " image has matte" : " image has no matte");
816 Read PSD raster colormap only present for indexed and duotone images.
818 length=ReadBlobMSBLong(image);
821 if (image->debug != MagickFalse)
822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
823 " reading colormap");
824 if (psd_info.mode == DuotoneMode)
827 Duotone image data; the format of this data is undocumented.
829 data=(unsigned char *) AcquireQuantumMemory((size_t) length,
831 if (data == (unsigned char *) NULL)
832 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
833 count=ReadBlob(image,(size_t) length,data);
834 data=(unsigned char *) RelinquishMagickMemory(data);
839 Read PSD raster colormap.
841 if (AcquireImageColormap(image,(size_t) (length/3)) == MagickFalse)
842 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
843 for (i=0; i < (ssize_t) image->colors; i++)
844 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
845 ReadBlobByte(image));
846 for (i=0; i < (ssize_t) image->colors; i++)
847 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
848 ReadBlobByte(image));
849 for (i=0; i < (ssize_t) image->colors; i++)
850 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
851 ReadBlobByte(image));
852 image->matte=psd_info.channels >= 2 ? MagickTrue : MagickFalse;
855 length=ReadBlobMSBLong(image);
862 Image resources block.
864 if (image->debug != MagickFalse)
865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
866 " reading image resource blocks - %lu bytes",(unsigned long) length);
867 blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
869 if (blocks == (unsigned char *) NULL)
870 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
871 count=ReadBlob(image,(size_t) length,blocks);
872 if ((count != (ssize_t) length) ||
873 (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
875 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
876 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
878 (void) ParseImageResourceBlocks(image,blocks,(size_t) length);
879 blocks=(unsigned char *) RelinquishMagickMemory(blocks);
882 If we are only "pinging" the image, then we're done - so return.
884 if (image_info->ping != MagickFalse)
886 (void) CloseBlob(image);
887 return(GetFirstImageInList(image));
890 Layer and mask block.
892 layer_info=(LayerInfo *) NULL;
894 length=GetPSDSize(&psd_info,image);
897 length=ReadBlobMSBLong(image);
898 length=ReadBlobMSBLong(image);
900 if ((image_info->number_scenes == 1) && (image_info->scene == 0))
901 for ( ; length != 0; length--)
902 if (ReadBlobByte(image) == EOF)
904 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
910 if (image->debug != MagickFalse)
911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
912 " image has no layers");
916 offset=TellBlob(image);
917 size=GetPSDSize(&psd_info,image);
926 quantum=psd_info.version == 1 ? 4UL : 8UL;
927 for (j=0; j < (ssize_t) (length-quantum); j++)
928 (void) ReadBlobByte(image);
935 layer_offset=offset+length;
936 number_layers=(short) ReadBlobMSBShort(image);
937 if (image->debug != MagickFalse)
938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
939 " image contains %ld layers",(long) number_layers);
940 if (number_layers < 0)
943 Weird hack in PSD format to ignore first alpha channel.
946 number_layers=MagickAbsoluteValue(number_layers);
947 if (image->debug != MagickFalse)
948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
949 " negative layer count corrected for");
951 layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
952 sizeof(*layer_info));
953 if (layer_info == (LayerInfo *) NULL)
955 if (image->debug != MagickFalse)
956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
957 " allocation of LayerInfo failed");
958 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
960 (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
961 sizeof(*layer_info));
962 for (i=0; i < number_layers; i++)
964 if (image->debug != MagickFalse)
965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
966 " reading layer #%ld",(long) i+1);
967 layer_info[i].page.y=(ssize_t) ReadBlobMSBLong(image);
968 layer_info[i].page.x=(ssize_t) ReadBlobMSBLong(image);
969 layer_info[i].page.height=(size_t)
970 (ReadBlobMSBLong(image)-layer_info[i].page.y);
971 layer_info[i].page.width=(size_t)
972 (ReadBlobMSBLong(image)-layer_info[i].page.x);
973 if (layer_info[i].page.height > 300000)
974 layer_info[i].page.height+=4294967295UL;
975 if (layer_info[i].page.width > 300000)
976 layer_info[i].page.width+=4294967295UL;
977 layer_info[i].channels=ReadBlobMSBShort(image);
978 if (layer_info[i].channels > MaxPSDChannels)
979 ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
980 if (image->debug != MagickFalse)
981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
982 " offset(%ld,%ld), size(%ld,%ld), channels=%ld",
983 (long) layer_info[i].page.x,(long) layer_info[i].page.y,
984 (long) layer_info[i].page.height,(long)
985 layer_info[i].page.width,(long) layer_info[i].channels);
986 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
988 layer_info[i].channel_info[j].type=(short)
989 ReadBlobMSBShort(image);
990 layer_info[i].channel_info[j].size=(size_t)
991 GetPSDSize(&psd_info,image);
992 if (image->debug != MagickFalse)
993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
994 " channel[%ld]: type=%ld, size=%ld",(long) j,
995 (long) layer_info[i].channel_info[j].type,
996 (long) layer_info[i].channel_info[j].size);
998 count=ReadBlob(image,4,(unsigned char *) type);
999 if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1001 if (image->debug != MagickFalse)
1002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1003 " layer type was %.4s instead of 8BIM", type);
1004 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1006 count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
1007 layer_info[i].opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(
1008 (unsigned char) ReadBlobByte(image)));
1009 layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1010 layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1011 layer_info[i].visible=!(layer_info[i].flags & 0x02);
1012 if (image->debug != MagickFalse)
1013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1014 " blend=%.4s, opacity=%lu, clipping=%s, flags=%d, visible=%s",
1015 layer_info[i].blendkey,(long) layer_info[i].opacity,
1016 layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1017 layer_info[i].visible ? "true" : "false");
1018 (void) ReadBlobByte(image); /* filler */
1020 size=ReadBlobMSBLong(image);
1023 if (image->debug != MagickFalse)
1024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1025 " layer contains additional info");
1026 length=ReadBlobMSBLong(image);
1032 layer_info[i].mask.y=(ssize_t) ReadBlobMSBLong(image);
1033 layer_info[i].mask.x=(ssize_t) ReadBlobMSBLong(image);
1034 layer_info[i].mask.height=(size_t)
1035 (ReadBlobMSBLong(image)-layer_info[i].mask.y);
1036 layer_info[i].mask.width=(size_t)
1037 (ReadBlobMSBLong(image)-layer_info[i].mask.x);
1038 if (layer_info[i].mask.height > 300000)
1039 layer_info[i].mask.height+=4294967295UL;
1040 if (layer_info[i].mask.width > 300000)
1041 layer_info[i].mask.width+=4294967295UL;
1042 if (image->debug != MagickFalse)
1043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1044 " layer mask: offset(%ld,%ld), size(%ld,%ld), length=%ld",
1045 (long) layer_info[i].mask.x,(long) layer_info[i].mask.y,
1046 (long) layer_info[i].mask.width,(long)
1047 layer_info[i].mask.height,(long) length-16);
1049 Skip over the rest of the layer mask information.
1051 for (j=0; j < (ssize_t) (length-16); j++)
1052 (void) ReadBlobByte(image);
1054 combinedlength+=length+4; /* +4 for length */
1055 length=ReadBlobMSBLong(image);
1059 Layer blending ranges info.
1061 if (image->debug != MagickFalse)
1062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1063 " layer blending ranges: length=%ld",(long)
1066 We read it, but don't use it...
1068 for (j=0; j < (ssize_t) (length); j+=8)
1070 size_t blend_source=ReadBlobMSBLong(image);
1071 size_t blend_dest=ReadBlobMSBLong(image);
1072 if (image->debug != MagickFalse)
1073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1074 " source(%x), dest(%x)",(unsigned int)
1075 blend_source,(unsigned int) blend_dest);
1078 combinedlength+=length+4;
1082 length=(size_t) ReadBlobByte(image);
1083 for (j=0; j < (ssize_t) length; j++)
1084 layer_info[i].name[j]=(unsigned char) ReadBlobByte(image);
1085 layer_info[i].name[j]='\0';
1086 if (image->debug != MagickFalse)
1087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1088 " layer name: %s",layer_info[i].name);
1089 combinedlength+=length+1;
1091 #if 0 /* still in development */
1093 Adjustment layers and other stuff...
1099 count=ReadBlob(image,4,alsig);
1100 if ((count == 0) || (LocaleNCompare(alsig,"8BIM",4) != 0)) {
1101 if (debug != MagickFalse)
1103 if (image->debug != MagickFalse)
1104 (void) LogMagickEvent(CoderEvent,GetMagickModule()," adjustment layer type was %.4s instead of 8BIM", alsig);
1106 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1108 count=ReadBlob(image,4,alkey);
1109 length=ReadBlobMSBLong(image);
1110 if (debug != MagickFalse)
1112 if (image->debug != MagickFalse)
1113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1114 " adjustment layer key: %.4s, data length=%ld",
1119 for (j=0; j < (ssize_t) (length); j++)
1120 (void) ReadBlobByte(image);
1124 combinedlength += 12 + length; /* sig, key, length + the actual length*/
1128 Skip the rest of the variable data until we support it.
1130 if (image->debug != MagickFalse)
1131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1132 " unsupported data: length=%ld",(long)
1133 (size-combinedlength));
1134 for (j=0; j < (ssize_t) (size-combinedlength); j++)
1135 (void) ReadBlobByte(image);
1138 Allocate layered image.
1140 layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1141 layer_info[i].page.height,MagickFalse,&image->exception);
1142 if (layer_info[i].image == (Image *) NULL)
1144 for (j=0; j < i; j++)
1145 layer_info[j].image=DestroyImage(layer_info[j].image);
1146 if (image->debug != MagickFalse)
1147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1148 " allocation of image for layer %ld failed",(long) i);
1149 ThrowReaderException(ResourceLimitError,
1150 "MemoryAllocationFailed");
1152 if (image->debug != MagickFalse)
1153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1154 " setting up new layer image");
1155 (void) SetImageBackgroundColor(layer_info[i].image);
1156 layer_info[i].image->compose=
1157 PSDBlendModeToCompositeOperator(layer_info[i].blendkey);
1158 if (layer_info[i].visible == MagickFalse)
1159 layer_info[i].image->compose=NoCompositeOp;
1160 if (psd_info.mode == CMYKMode)
1161 layer_info[i].image->colorspace=CMYKColorspace;
1162 if ((psd_info.mode == BitmapMode) ||
1163 (psd_info.mode == GrayscaleMode) ||
1164 (psd_info.mode == DuotoneMode))
1165 layer_info[i].image->colorspace=GRAYColorspace;
1166 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1167 if (layer_info[i].channel_info[j].type == -1)
1168 layer_info[i].image->matte=MagickTrue;
1170 Set up some hidden attributes for folks that need them.
1172 (void) FormatMagickString(message,MaxTextExtent,"%ld",
1173 (long) layer_info[i].page.x);
1174 (void) SetImageArtifact(layer_info[i].image,"psd:layer.x",message);
1175 (void) FormatMagickString(message,MaxTextExtent,"%ld",
1176 (long) layer_info[i].page.y);
1177 (void) SetImageArtifact(layer_info[i].image,"psd:layer.y",message);
1178 (void) FormatMagickString(message,MaxTextExtent,"%lu",
1179 (unsigned long) layer_info[i].opacity);
1180 (void) SetImageArtifact(layer_info[i].image,"psd:layer.opacity",
1182 (void) SetImageProperty(layer_info[i].image,"label",(char *)
1183 layer_info[i].name);
1185 if (image->debug != MagickFalse)
1186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1187 " reading image data for layers");
1189 Read pixel data for each layer.
1191 for (i=0; i < number_layers; i++)
1193 if (image->debug != MagickFalse)
1194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1195 " reading data for layer %ld",(long) i);
1196 for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1198 if (image->debug != MagickFalse)
1199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1200 " reading data for channel %ld",(long) j);
1202 if (layer_info[i].channel_info[j].size <= (2*layer_info[i].image->rows))
1207 if (image->debug != MagickFalse)
1208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1209 " layer data is empty");
1211 A layer without data.
1213 for (k=0; k < (ssize_t) layer_info[i].channel_info[j].size; k++)
1214 (void) ReadBlobByte(layer_info[i].image);
1218 offsets=(MagickOffsetType *) NULL;
1219 layer_info[i].image->compression=NoCompression;
1220 compression=ReadBlobMSBShort(layer_info[i].image);
1221 if ((layer_info[i].page.height != 0) &&
1222 (layer_info[i].page.width != 0))
1224 if (compression == 1)
1227 Read RLE compressed data.
1229 layer_info[i].image->compression=RLECompression;
1230 if (image->debug != MagickFalse)
1231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1232 " layer data is RLE compressed");
1233 offsets=(MagickOffsetType *) AcquireQuantumMemory(
1234 layer_info[i].image->rows,sizeof(*offsets));
1235 if (offsets == (MagickOffsetType *) NULL)
1236 ThrowReaderException(ResourceLimitError,
1237 "MemoryAllocationFailed");
1238 for (y=0; y < (ssize_t) layer_info[i].image->rows; y++)
1239 offsets[y]=GetPSDOffset(&psd_info,layer_info[i].image);
1241 status=ReadPSDLayer(layer_info[i].image,
1242 layer_info[i].channels,layer_info[i].channel_info[j].type,
1244 if (compression == 1)
1245 offsets=(MagickOffsetType *) RelinquishMagickMemory(
1247 if (status == MagickFalse)
1251 if (layer_info[i].opacity != OpaqueOpacity)
1254 Correct for opacity level.
1256 for (y=0; y < (ssize_t) layer_info[i].image->rows; y++)
1258 q=GetAuthenticPixels(layer_info[i].image,0,y,
1259 layer_info[i].image->columns,1,exception);
1260 if (q == (PixelPacket *) NULL)
1262 indexes=GetAuthenticIndexQueue(layer_info[i].image);
1263 for (x=0; x < (ssize_t) layer_info[i].image->columns; x++)
1265 q->opacity=(Quantum) (QuantumRange-(Quantum) (QuantumScale*
1266 ((QuantumRange-q->opacity)*(QuantumRange-
1267 layer_info[i].opacity))));
1270 if (SyncAuthenticPixels(layer_info[i].image,exception) == MagickFalse)
1274 if (layer_info[i].image->colorspace == CMYKColorspace)
1275 (void) NegateImage(layer_info[i].image,MagickFalse);
1276 status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
1278 if (status == MagickFalse)
1281 /* added by palf -> invisible group layer make layer of this group
1282 invisible I consider that all layer with width and height null are
1283 layer for group layer */
1285 short inside_layer = 0;
1286 short layer_visible = 0;
1287 for (i=number_layers-1; i >=0; i--)
1289 if ((layer_info[i].page.width == 0) ||
1290 (layer_info[i].page.height == 0))
1292 if (inside_layer == 0)
1295 layer_visible=(short int) layer_info[i].visible;
1303 if ((inside_layer == 1) && (layer_visible == 0))
1305 layer_info[i].visible=(unsigned char) layer_visible;
1306 layer_info[i].image->compose=NoCompositeOp;
1310 /* added by palf -> suppression of empty layer */
1311 /* I consider that all layer with width and height null are layer for group layer */
1312 for (i=0; i < number_layers; i++)
1314 if ((layer_info[i].page.width == 0) ||
1315 (layer_info[i].page.height == 0))
1317 if (layer_info[i].image != (Image *) NULL)
1318 layer_info[i].image=DestroyImage(layer_info[i].image);
1319 for (j=i; j < number_layers - 1; j++)
1320 layer_info[j] = layer_info[j+1];
1325 mask_size = ReadBlobMSBLong(image); /* global mask size: currently ignored */
1326 if (number_layers > 0)
1328 if (image->debug != MagickFalse)
1329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1330 " putting layers into image list");
1331 for (i=0; i < number_layers; i++)
1334 layer_info[i].image->previous=layer_info[i-1].image;
1335 if (i < (number_layers-1))
1336 layer_info[i].image->next=layer_info[i+1].image;
1337 layer_info[i].image->page=layer_info[i].page;
1339 image->next=layer_info[0].image;
1340 layer_info[0].image->previous=image;
1341 layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1343 layer_offset-=TellBlob(image);
1344 offset=SeekBlob(image,layer_offset,SEEK_CUR);
1348 Read the precombined layer, present for PSD < 4 compatibility
1350 if (image->debug != MagickFalse)
1351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1352 " reading the precombined layer");
1353 offsets=(MagickOffsetType *) NULL;
1354 image->compression=NoCompression;
1355 compression=ReadBlobMSBShort(image);
1356 if (compression == 1)
1359 Read Packbit encoded pixel data as separate planes.
1361 image->compression=RLECompression;
1362 offsets=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
1363 psd_info.channels*sizeof(*offsets));
1364 if (offsets == (MagickOffsetType *) NULL)
1365 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1366 for (i=0; i < (ssize_t) (image->rows*psd_info.channels); i++)
1367 offsets[i]=GetPSDOffset(&psd_info,image);
1369 for (i=0; i < (ssize_t) psd_info.channels; i++)
1371 status=ReadPSDLayer(image,psd_info.channels,i,offsets+i*image->rows,
1373 if (status == MagickFalse)
1375 status=SetImageProgress(image,LoadImagesTag,i,psd_info.channels);
1376 if (status == MagickFalse)
1379 if (compression == 1)
1380 offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1381 if (image->colorspace == CMYKColorspace)
1382 (void) NegateImage(image,MagickFalse);
1383 (void) CloseBlob(image);
1384 return(GetFirstImageInList(image));
1388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 % R e g i s t e r P S D I m a g e %
1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 % RegisterPSDImage() adds properties for the PSD image format to
1399 % the list of supported formats. The properties include the image format
1400 % tag, a method to read and/or write the format, whether the format
1401 % supports the saving of more than one frame to the same file or blob,
1402 % whether the format supports native in-memory I/O, and a brief
1403 % description of the format.
1405 % The format of the RegisterPSDImage method is:
1407 % size_t RegisterPSDImage(void)
1410 ModuleExport size_t RegisterPSDImage(void)
1415 entry=SetMagickInfo("PSB");
1416 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1417 entry->encoder=(EncodeImageHandler *) WritePSDImage;
1418 entry->magick=(IsImageFormatHandler *) IsPSD;
1419 entry->description=ConstantString("Adobe Large Document Format");
1420 entry->module=ConstantString("PSD");
1421 (void) RegisterMagickInfo(entry);
1422 entry=SetMagickInfo("PSD");
1423 entry->decoder=(DecodeImageHandler *) ReadPSDImage;
1424 entry->encoder=(EncodeImageHandler *) WritePSDImage;
1425 entry->magick=(IsImageFormatHandler *) IsPSD;
1426 entry->description=ConstantString("Adobe Photoshop bitmap");
1427 entry->module=ConstantString("PSD");
1428 (void) RegisterMagickInfo(entry);
1429 return(MagickImageCoderSignature);
1433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437 % U n r e g i s t e r P S D I m a g e %
1441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443 % UnregisterPSDImage() removes format registrations made by the
1444 % PSD module from the list of supported formats.
1446 % The format of the UnregisterPSDImage method is:
1448 % UnregisterPSDImage(void)
1451 ModuleExport void UnregisterPSDImage(void)
1453 (void) UnregisterMagickInfo("PSB");
1454 (void) UnregisterMagickInfo("PSD");
1458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462 % W r i t e P S D I m a g e %
1466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468 % WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
1470 % The format of the WritePSDImage method is:
1472 % MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image)
1474 % A description of each parameter follows.
1476 % o image_info: the image info.
1478 % o image: The image.
1483 static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
1484 const size_t offset)
1486 if (psd_info->version == 1)
1487 return(WriteBlobMSBShort(image,(unsigned short) offset));
1488 return(WriteBlobMSBLong(image,(unsigned short) offset));
1491 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
1492 const MagickSizeType size)
1494 if (psd_info->version == 1)
1495 return(WriteBlobMSBLong(image,(unsigned int) size));
1496 return(WriteBlobMSBLongLong(image,size));
1499 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
1500 const unsigned char *pixels,unsigned char *compact_pixels)
1509 register unsigned char
1516 Compress pixels with Packbits encoding.
1518 assert(image != (Image *) NULL);
1519 assert(image->signature == MagickSignature);
1520 if (image->debug != MagickFalse)
1521 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1522 assert(pixels != (unsigned char *) NULL);
1523 packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
1524 if (packbits == (unsigned char *) NULL)
1525 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1528 for (i=(ssize_t) length; i != 0; )
1535 *q++=(unsigned char) 0;
1542 *q++=(unsigned char) 1;
1550 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1552 *q++=(unsigned char) ((256-3)+1);
1556 *q++=(unsigned char) 2;
1564 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
1570 while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
1577 *q++=(unsigned char) ((256-count)+1);
1586 while ((*(pixels+count) != *(pixels+count+1)) ||
1587 (*(pixels+count+1) != *(pixels+count+2)))
1589 packbits[count+1]=pixels[count];
1591 if (((ssize_t) count >= (i-3)) || (count >= 127))
1595 *packbits=(unsigned char) (count-1);
1596 for (j=0; j <= (ssize_t) count; j++)
1603 *q++=(unsigned char) 128; /* EOD marker */
1604 packbits=(unsigned char *) RelinquishMagickMemory(packbits);
1605 return((size_t) (q-compact_pixels));
1608 static void WritePackbitsLength(const PSDInfo *psd_info,
1609 const ImageInfo *image_info,Image *image,Image *tmp_image,
1610 unsigned char *pixels,unsigned char *compact_pixels,
1611 const QuantumType quantum_type)
1619 register const PixelPacket
1626 if (tmp_image->depth > 8)
1627 tmp_image->depth=16;
1628 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1629 quantum_info=AcquireQuantumInfo(image_info,image);
1630 for (y=0; y < (ssize_t) tmp_image->rows; y++)
1632 p=GetVirtualPixels(tmp_image,0,y,tmp_image->columns,1,&image->exception);
1633 if (p == (const PixelPacket *) NULL)
1635 length=ExportQuantumPixels(tmp_image,(CacheView *) NULL,quantum_info,
1636 quantum_type,pixels,&image->exception);
1637 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels);
1638 (void) SetPSDOffset(psd_info,image,length);
1640 quantum_info=DestroyQuantumInfo(quantum_info);
1643 static void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
1644 Image *image,Image *tmp_image,unsigned char *pixels,
1645 unsigned char *compact_pixels,const QuantumType quantum_type,
1646 const MagickBooleanType compression_flag)
1657 register const PixelPacket
1668 if ((compression_flag != MagickFalse) &&
1669 (tmp_image->compression != RLECompression))
1670 (void) WriteBlobMSBShort(image,0);
1671 if (tmp_image->depth > 8)
1672 tmp_image->depth=16;
1673 monochrome=IsMonochromeImage(image,&image->exception);
1674 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1675 quantum_info=AcquireQuantumInfo(image_info,image);
1676 for (y=0; y < (ssize_t) tmp_image->rows; y++)
1678 p=GetVirtualPixels(tmp_image,0,y,tmp_image->columns,1,&image->exception);
1679 if (p == (const PixelPacket *) NULL)
1681 length=ExportQuantumPixels(tmp_image,(CacheView *) NULL,quantum_info,
1682 quantum_type,pixels,&image->exception);
1683 if (monochrome != MagickFalse)
1684 for (i=0; i < (ssize_t) length; i++)
1685 pixels[i]=(~pixels[i]);
1686 if (tmp_image->compression != RLECompression)
1687 (void) WriteBlob(image,length,pixels);
1690 length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels);
1691 (void) WriteBlob(image,length,compact_pixels);
1694 quantum_info=DestroyQuantumInfo(quantum_info);
1697 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
1698 const ImageInfo *image_info,Image *image,Image *tmp_image,
1699 const MagickBooleanType separate)
1713 Write uncompressed pixels as separate planes.
1716 packet_size=tmp_image->depth > 8UL ? 2UL : 1UL;
1717 pixels=(unsigned char *) AcquireQuantumMemory(channels*tmp_image->columns,
1718 packet_size*sizeof(*pixels));
1719 compact_pixels=(unsigned char *) AcquireQuantumMemory(2*channels*
1720 tmp_image->columns,packet_size*sizeof(*pixels));
1721 if ((pixels == (unsigned char *) NULL) ||
1722 (compact_pixels == (unsigned char *) NULL))
1724 if (pixels != (unsigned char *) NULL)
1725 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1726 if (compact_pixels != (unsigned char *) NULL)
1727 compact_pixels=(unsigned char *)
1728 RelinquishMagickMemory(compact_pixels);
1729 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1732 if (IsGrayImage(tmp_image,&tmp_image->exception) != MagickFalse)
1734 if (tmp_image->compression == RLECompression)
1737 Packbits compression.
1739 (void) WriteBlobMSBShort(image,1);
1740 if (tmp_image->matte != MagickFalse)
1741 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1742 compact_pixels,AlphaQuantum);
1743 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1744 compact_pixels,GrayQuantum);
1746 if (tmp_image->matte != MagickFalse)
1747 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1748 compact_pixels,AlphaQuantum,(i++ == 0) ||
1749 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1750 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1751 compact_pixels,GrayQuantum,(i++ == 0) ||
1752 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1753 (void) SetImageProgress(image,SaveImagesTag,0,1);
1756 if (tmp_image->storage_class == PseudoClass)
1758 if (tmp_image->compression == RLECompression)
1761 Packbits compression.
1763 (void) WriteBlobMSBShort(image,1);
1764 if (tmp_image->matte != MagickFalse)
1765 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1766 compact_pixels,AlphaQuantum);
1767 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1768 compact_pixels,IndexQuantum);
1770 if (tmp_image->matte != MagickFalse)
1771 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1772 compact_pixels,AlphaQuantum,(i++ == 0) ||
1773 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1774 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1775 compact_pixels,IndexQuantum,(i++ == 0) ||
1776 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1777 (void) SetImageProgress(image,SaveImagesTag,0,1);
1781 if (tmp_image->colorspace == CMYKColorspace)
1782 (void) NegateImage(tmp_image,MagickFalse);
1783 if (tmp_image->compression == RLECompression)
1786 Packbits compression.
1788 (void) WriteBlobMSBShort(image,1);
1789 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1790 compact_pixels,RedQuantum);
1791 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1792 compact_pixels,GreenQuantum);
1793 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1794 compact_pixels,BlueQuantum);
1795 if (tmp_image->colorspace == CMYKColorspace)
1796 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1797 compact_pixels,BlackQuantum);
1798 if (tmp_image->matte != MagickFalse)
1799 WritePackbitsLength(psd_info,image_info,image,tmp_image,pixels,
1800 compact_pixels,AlphaQuantum);
1802 (void) SetImageProgress(image,SaveImagesTag,0,6);
1803 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1804 compact_pixels,RedQuantum,(i++ == 0) || (separate != MagickFalse) ?
1805 MagickTrue : MagickFalse);
1806 (void) SetImageProgress(image,SaveImagesTag,1,6);
1807 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1808 compact_pixels,GreenQuantum,(i++ == 0) || (separate != MagickFalse) ?
1809 MagickTrue : MagickFalse);
1810 (void) SetImageProgress(image,SaveImagesTag,2,6);
1811 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1812 compact_pixels,BlueQuantum,(i++ == 0) || (separate != MagickFalse) ?
1813 MagickTrue : MagickFalse);
1814 (void) SetImageProgress(image,SaveImagesTag,3,6);
1815 if (tmp_image->colorspace == CMYKColorspace)
1817 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1818 compact_pixels,BlackQuantum,(i++ == 0) ||
1819 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1820 (void) NegateImage(tmp_image,MagickFalse);
1822 (void) SetImageProgress(image,SaveImagesTag,4,6);
1823 if (tmp_image->matte != MagickFalse)
1824 WriteOneChannel(psd_info,image_info,image,tmp_image,pixels,
1825 compact_pixels,AlphaQuantum,(i++ == 0) ||
1826 (separate != MagickFalse) ? MagickTrue : MagickFalse);
1827 (void) SetImageProgress(image,SaveImagesTag,5,6);
1829 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1833 static void WritePascalString(Image* inImage,const char *inString,int inPad)
1839 /* max length is 255 */
1841 strLength = (strlen(inString) > 255UL ) ? 255UL : strlen(inString);
1843 if ( strLength != 0 )
1845 (void) WriteBlobByte(inImage,(unsigned char) strLength);
1846 (void) WriteBlob(inImage, strLength, (const unsigned char *) inString);
1849 (void) WriteBlobByte(inImage, 0);
1853 if ( (strLength % inPad) == 0 )
1855 for (i=0; i < (ssize_t) (inPad-(strLength % inPad)); i++)
1856 (void) WriteBlobByte(inImage,0);
1859 static void WriteResolutionResourceBlock(Image *image)
1868 x_resolution=65536.0*image->x_resolution+0.5;
1869 y_resolution=65536.0*image->y_resolution+0.5;
1871 if (image->units == PixelsPerCentimeterResolution)
1873 x_resolution=2.54*65536.0*image->x_resolution*0.5;
1874 y_resolution=2.54*65536.0*image->y_resolution+0.5;
1877 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
1878 (void) WriteBlobMSBShort(image,0x03ED);
1879 (void) WriteBlobMSBShort(image,0);
1880 (void) WriteBlobMSBLong(image,16); /* resource size */
1881 (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
1882 (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
1883 (void) WriteBlobMSBShort(image,units); /* width unit */
1884 (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
1885 (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
1886 (void) WriteBlobMSBShort(image,units); /* height unit */
1889 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
1891 register const unsigned char
1908 length=GetStringInfoLength(bim_profile);
1911 datum=GetStringInfoDatum(bim_profile);
1912 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
1914 register unsigned char
1917 q=(unsigned char *) p;
1918 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
1920 p=PushLongPixel(MSBEndian,p,&ssize_t_sans);
1921 p=PushShortPixel(MSBEndian,p,&id);
1922 p=PushShortPixel(MSBEndian,p,&short_sans);
1923 p=PushLongPixel(MSBEndian,p,&count);
1924 if (id == 0x0000040f)
1926 (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
1927 (PSDQuantum(count)+12)-(q-datum));
1928 SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
1932 if ((count & 0x01) != 0)
1937 static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
1939 register const unsigned char
1956 length=GetStringInfoLength(bim_profile);
1959 datum=GetStringInfoDatum(bim_profile);
1960 for (p=datum; (p >= datum) && (p < (datum+length-16)); )
1962 register unsigned char
1965 q=(unsigned char *) p;
1966 if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
1968 p=PushLongPixel(MSBEndian,p,&ssize_t_sans);
1969 p=PushShortPixel(MSBEndian,p,&id);
1970 p=PushShortPixel(MSBEndian,p,&short_sans);
1971 p=PushLongPixel(MSBEndian,p,&count);
1972 if (id == 0x000003ed)
1974 (void) CopyMagickMemory(q,q+PSDQuantum(count)+12,length-
1975 (PSDQuantum(count)+12)-(q-datum));
1976 SetStringInfoLength(bim_profile,length-(PSDQuantum(count)+12));
1980 if ((count & 0x01) != 0)
1985 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image)
2018 rounded_layer_info_size;
2021 *tmp_image = (Image *) NULL,
2022 *base_image = GetNextImageInList(image);
2027 assert(image_info != (const ImageInfo *) NULL);
2028 assert(image_info->signature == MagickSignature);
2029 assert(image != (Image *) NULL);
2030 assert(image->signature == MagickSignature);
2031 if (image->debug != MagickFalse)
2032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2033 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2034 if (status == MagickFalse)
2036 packet_size=(size_t) (image->depth > 8 ? 6 : 3);
2037 if (image->matte != MagickFalse)
2038 packet_size+=image->depth > 8 ? 2 : 1;
2040 if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2041 (image->columns > 30000) || (image->rows > 30000))
2043 (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2044 (void) WriteBlobMSBShort(image,psd_info.version); /* version */
2045 for (i=1; i <= 6; i++)
2046 (void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
2047 if (IsGrayImage(image,&image->exception) != MagickFalse)
2048 num_channels=(image->matte != MagickFalse ? 2UL : 1UL);
2050 if (image->storage_class == PseudoClass)
2051 num_channels=(image->matte != MagickFalse ? 2UL : 1UL);
2054 if (image->colorspace != CMYKColorspace)
2055 num_channels=(image->matte != MagickFalse ? 4UL : 3UL);
2057 num_channels=(image->matte != MagickFalse ? 5UL : 4UL);
2059 (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
2060 (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
2061 (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2062 if (IsGrayImage(image,&image->exception) != MagickFalse)
2070 monochrome=IsMonochromeImage(image,&image->exception);
2071 (void) WriteBlobMSBShort(image,(unsigned short)
2072 (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
2073 (void) WriteBlobMSBShort(image,monochrome != MagickFalse ?
2074 BitmapMode : GrayscaleMode);
2078 (void) WriteBlobMSBShort(image,(unsigned short)
2079 (image->storage_class == PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
2080 if (((image->colorspace != UndefinedColorspace) ||
2081 (image->colorspace != CMYKColorspace)) &&
2082 (image->colorspace != CMYKColorspace))
2084 if (image->colorspace != RGBColorspace)
2085 (void) TransformImageColorspace(image,RGBColorspace);
2086 (void) WriteBlobMSBShort(image,(unsigned short)
2087 (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
2091 if (image->colorspace != RGBColorspace)
2092 (void) TransformImageColorspace(image,CMYKColorspace);
2093 (void) WriteBlobMSBShort(image,CMYKMode);
2096 if ((IsGrayImage(image,&image->exception) != MagickFalse) ||
2097 (image->storage_class == DirectClass) || (image->colors > 256))
2098 (void) WriteBlobMSBLong(image,0);
2102 Write PSD raster colormap.
2104 (void) WriteBlobMSBLong(image,768);
2105 for (i=0; i < (ssize_t) image->colors; i++)
2106 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2107 for ( ; i < 256; i++)
2108 (void) WriteBlobByte(image,0);
2109 for (i=0; i < (ssize_t) image->colors; i++)
2110 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green));
2111 for ( ; i < 256; i++)
2112 (void) WriteBlobByte(image,0);
2113 for (i=0; i < (ssize_t) image->colors; i++)
2114 (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2115 for ( ; i < 256; i++)
2116 (void) WriteBlobByte(image,0);
2119 Image resource block.
2121 length=28; /* 0x03EB */
2122 bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2123 icc_profile=GetImageProfile(image,"icc");
2124 if (bim_profile != (StringInfo *) NULL)
2126 bim_profile=CloneStringInfo(bim_profile);
2127 if (icc_profile != (StringInfo *) NULL)
2128 RemoveICCProfileFromResourceBlock(bim_profile);
2129 RemoveResolutionFromResourceBlock(bim_profile);
2130 length+=PSDQuantum(GetStringInfoLength(bim_profile));
2132 if (icc_profile != (const StringInfo *) NULL)
2133 length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2134 (void) WriteBlobMSBLong(image,(unsigned int) length);
2135 WriteResolutionResourceBlock(image);
2136 if (bim_profile != (StringInfo *) NULL)
2138 (void) WriteBlob(image,GetStringInfoLength(bim_profile),
2139 GetStringInfoDatum(bim_profile));
2140 bim_profile=DestroyStringInfo(bim_profile);
2142 if (icc_profile != (StringInfo *) NULL)
2144 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2145 (void) WriteBlobMSBShort(image,0x0000040F);
2146 (void) WriteBlobMSBShort(image,0);
2147 (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2149 (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2150 GetStringInfoDatum(icc_profile));
2151 if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
2152 PSDQuantum(GetStringInfoLength(icc_profile)))
2153 (void) WriteBlobByte(image,0);
2157 layer_info_size = 2;
2158 tmp_image = base_image;
2159 while ( tmp_image != NULL ) {
2160 packet_size=tmp_image->depth > 8 ? 2UL : 1UL;
2162 if (IsGrayImage(image,&image->exception) != MagickFalse)
2163 num_channels=tmp_image->matte != MagickFalse ? 2UL : 1UL;
2165 if (tmp_image->storage_class == PseudoClass)
2166 num_channels=tmp_image->matte != MagickFalse ? 2UL : 1UL;
2168 if (tmp_image->colorspace != CMYKColorspace)
2169 num_channels=tmp_image->matte != MagickFalse ? 4UL : 3UL;
2171 num_channels=tmp_image->matte != MagickFalse ? 5UL : 4UL;
2173 channelLength=(size_t) (tmp_image->columns * tmp_image->rows *
2175 layer_info_size += (size_t) (4*4 + 2 + num_channels * 6 +
2176 (psd_info.version == 1 ? 8 : 16) + 4 * 1 + 4 + num_channels *
2178 theAttr=(const char *) GetImageProperty(tmp_image,"label");
2180 layer_info_size += 16;
2183 size_t length=strlen(theAttr);
2184 layer_info_size += 8+length+(4-(length % 4));
2187 tmp_image = GetNextImageInList(tmp_image);
2189 if (layer_count == 0)
2190 (void) SetPSDSize(&psd_info,image,0);
2193 (void) SetPSDSize(&psd_info,image,layer_info_size+
2194 (psd_info.version == 1 ? 8 : 16));
2195 if ( layer_info_size/2 != (layer_info_size+1)/2 ) /* odd */
2196 rounded_layer_info_size = layer_info_size + 1;
2198 rounded_layer_info_size = layer_info_size;
2199 (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
2200 (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
2202 tmp_image = base_image;
2203 while ( tmp_image != NULL ) {
2204 (void) WriteBlobMSBLong(image,0);
2205 (void) WriteBlobMSBLong(image,0);
2206 (void) WriteBlobMSBLong(image,(unsigned int) tmp_image->rows);
2207 (void) WriteBlobMSBLong(image,(unsigned int) tmp_image->columns);
2209 packet_size=tmp_image->depth > 8 ? 2UL : 1UL;
2210 channel_size=(unsigned int) ((packet_size*tmp_image->rows*
2211 tmp_image->columns)+2);
2212 if ((IsGrayImage(tmp_image,&image->exception) != MagickFalse) ||
2213 (tmp_image->storage_class == PseudoClass)) {
2214 (void) WriteBlobMSBShort(image,(unsigned short)
2215 (tmp_image->matte != MagickFalse ? 2 : 1));
2216 (void) WriteBlobMSBShort(image, 0);
2217 (void) SetPSDSize(&psd_info,image,channel_size);
2218 if (tmp_image->matte != MagickFalse) {
2219 (void) WriteBlobMSBShort(image,(unsigned short) 1);
2220 (void) SetPSDSize(&psd_info,image,channel_size);
2223 if (tmp_image->colorspace != CMYKColorspace)
2225 (void) WriteBlobMSBShort(image,(unsigned short)
2226 (tmp_image->matte != MagickFalse ? 4 : 3));
2227 (void) WriteBlobMSBShort(image, 0);
2228 (void) SetPSDSize(&psd_info,image,channel_size);
2229 (void) WriteBlobMSBShort(image, 1);
2230 (void) SetPSDSize(&psd_info,image,channel_size);
2231 (void) WriteBlobMSBShort(image, 2);
2232 (void) SetPSDSize(&psd_info,image,channel_size);
2233 if (tmp_image->matte!= MagickFalse ) {
2234 (void) WriteBlobMSBShort(image,(unsigned short) 3);
2235 (void) SetPSDSize(&psd_info,image,channel_size);
2240 (void) WriteBlobMSBShort(image,(unsigned short)
2241 (tmp_image->matte ? 5 : 4));
2242 (void) WriteBlobMSBShort(image, 0);
2243 (void) SetPSDSize(&psd_info,image,channel_size);
2244 (void) WriteBlobMSBShort(image, 1);
2245 (void) SetPSDSize(&psd_info,image,channel_size);
2246 (void) WriteBlobMSBShort(image, 2);
2247 (void) SetPSDSize(&psd_info,image,channel_size);
2248 (void) WriteBlobMSBShort(image, 3);
2249 (void) SetPSDSize(&psd_info,image,channel_size);
2250 if (tmp_image->matte) {
2251 (void) WriteBlobMSBShort(image,(unsigned short) 4);
2252 (void) SetPSDSize(&psd_info,image,channel_size);
2256 (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
2257 (void) WriteBlob(image,4,(const unsigned char *)
2258 CompositeOperatorToPSDBlendMode(tmp_image->compose));
2259 (void) WriteBlobByte(image, 255); /* BOGUS: layer opacity */
2260 (void) WriteBlobByte(image, 0);
2261 (void) WriteBlobByte(image, 1); /* BOGUS: layer attributes - visible, etc. */
2262 (void) WriteBlobByte(image, 0);
2265 theAttr=(const char *) GetImageProperty(tmp_image,"label");
2267 (void) WriteBlobMSBLong(image, 16);
2268 (void) WriteBlobMSBLong(image, 0);
2269 (void) WriteBlobMSBLong(image, 0);
2270 (void) FormatMagickString((char *) layer_name,MaxTextExtent,"L%06ld",
2271 (long) layer_count++);
2272 WritePascalString( image, (char*)layer_name, 4 );
2274 size_t length=strlen(theAttr);
2275 (void) WriteBlobMSBLong(image,(unsigned int) (length+(4-(length % 4))+
2277 (void) WriteBlobMSBLong(image,0);
2278 (void) WriteBlobMSBLong(image,0);
2279 WritePascalString( image, theAttr, 4 );
2281 tmp_image = GetNextImageInList(tmp_image);
2283 /* now the image data! */
2284 tmp_image = base_image;
2285 while ( tmp_image != NULL ) {
2286 status=WriteImageChannels(&psd_info,image_info,image,tmp_image,MagickTrue);
2287 /* add in the pad! */
2288 if ( rounded_layer_info_size != layer_info_size )
2289 (void) WriteBlobByte(image,'\0');
2291 tmp_image = GetNextImageInList(tmp_image);
2293 /* user mask data */
2294 (void) WriteBlobMSBLong(image,0);
2297 Write composite image.
2299 status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse);
2300 (void) CloseBlob(image);