% %
% %
% %
++ A t t a c h C u s t o m S t r e a m %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% AttachCustomStream() attaches a CustomStreamInfo to the BlobInfo structure.
+%
+% The format of the AttachCustomStream method is:
+%
+% void AttachCustomStream(BlobInfo *blob_info,
+% CustomStreamInfo *custom_stream)
+%
+% A description of each parameter follows:
+%
+% o blob_info: specifies a pointer to a BlobInfo structure.
+%
+% o custom_stream: the custom stream info.
+%
+*/
+MagickExport void AttachCustomStream(BlobInfo *blob_info,
+ CustomStreamInfo *custom_stream)
+{
+ assert(blob_info != (BlobInfo *) NULL);
+ assert(custom_stream != (CustomStreamInfo *) NULL);
+ assert(custom_stream->signature == MagickCoreSignature);
+ if (blob_info->debug != MagickFalse)
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+ blob_info->type=CustomStream;
+ blob_info->custom_stream=custom_stream;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+ B l o b T o F i l e %
% %
% %
% %
% %
% %
++ W r i t e B l o b L o n g L o n g %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in the
+% byte-order specified by the endian member of the image structure.
+%
+% The format of the WriteBlobLongLong method is:
+%
+% ssize_t WriteBlobLongLong(Image *image,const MagickSizeType value)
+%
+% A description of each parameter follows.
+%
+% o value: Specifies the value to write.
+%
+% o image: the image.
+%
+*/
+MagickExport ssize_t WriteBlobLongLong(Image *image,const MagickSizeType value)
+{
+ unsigned char
+ buffer[8];
+
+ assert(image != (Image *) NULL);
+ assert(image->signature == MagickCoreSignature);
+ if (image->endian == LSBEndian)
+ {
+ buffer[0]=(unsigned char) value;
+ buffer[1]=(unsigned char) (value >> 8);
+ buffer[2]=(unsigned char) (value >> 16);
+ buffer[3]=(unsigned char) (value >> 24);
+ buffer[4]=(unsigned char) (value >> 32);
+ buffer[5]=(unsigned char) (value >> 40);
+ buffer[6]=(unsigned char) (value >> 48);
+ buffer[7]=(unsigned char) (value >> 56);
+ return(WriteBlobStream(image,8,buffer));
+ }
+ buffer[0]=(unsigned char) (value >> 56);
+ buffer[1]=(unsigned char) (value >> 48);
+ buffer[2]=(unsigned char) (value >> 40);
+ buffer[3]=(unsigned char) (value >> 32);
+ buffer[4]=(unsigned char) (value >> 24);
+ buffer[5]=(unsigned char) (value >> 16);
+ buffer[6]=(unsigned char) (value >> 8);
+ buffer[7]=(unsigned char) value;
+ return(WriteBlobStream(image,8,buffer));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+ W r i t e B l o b S h o r t %
% %
% %
% %
% %
% %
++ W r i t e B l o b S i g n e d L o n g %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% WriteBlobSignedLong() writes a signed value as a 32-bit quantity in the
+% byte-order specified by the endian member of the image structure.
+%
+% The format of the WriteBlobSignedLong method is:
+%
+% ssize_t WriteBlobSignedLong(Image *image,const signed int value)
+%
+% A description of each parameter follows.
+%
+% o image: the image.
+%
+% o value: Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobSignedLong(Image *image,const signed int value)
+{
+ union
+ {
+ unsigned int
+ unsigned_value;
+
+ signed int
+ signed_value;
+ } quantum;
+
+ unsigned char
+ buffer[4];
+
+ assert(image != (Image *) NULL);
+ assert(image->signature == MagickCoreSignature);
+ quantum.signed_value=value;
+ if (image->endian == LSBEndian)
+ {
+ buffer[0]=(unsigned char) quantum.unsigned_value;
+ buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
+ buffer[2]=(unsigned char) (quantum.unsigned_value >> 16);
+ buffer[3]=(unsigned char) (quantum.unsigned_value >> 24);
+ return(WriteBlobStream(image,4,buffer));
+ }
+ buffer[0]=(unsigned char) (quantum.unsigned_value >> 24);
+ buffer[1]=(unsigned char) (quantum.unsigned_value >> 16);
+ buffer[2]=(unsigned char) (quantum.unsigned_value >> 8);
+ buffer[3]=(unsigned char) quantum.unsigned_value;
+ return(WriteBlobStream(image,4,buffer));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+ W r i t e B l o b L S B L o n g %
% %
% %
% %
% %
% %
-+ W r i t e B l o b M S B L o n g L o n g %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in
-% most-significant byte first order.
-%
-% The format of the WriteBlobMSBLongLong method is:
-%
-% ssize_t WriteBlobMSBLongLong(Image *image,const MagickSizeType value)
-%
-% A description of each parameter follows.
-%
-% o value: Specifies the value to write.
-%
-% o image: the image.
-%
-*/
-MagickExport ssize_t WriteBlobMSBLongLong(Image *image,
- const MagickSizeType value)
-{
- unsigned char
- buffer[8];
-
- assert(image != (Image *) NULL);
- assert(image->signature == MagickCoreSignature);
- buffer[0]=(unsigned char) (value >> 56);
- buffer[1]=(unsigned char) (value >> 48);
- buffer[2]=(unsigned char) (value >> 40);
- buffer[3]=(unsigned char) (value >> 32);
- buffer[4]=(unsigned char) (value >> 24);
- buffer[5]=(unsigned char) (value >> 16);
- buffer[6]=(unsigned char) (value >> 8);
- buffer[7]=(unsigned char) value;
- return(WriteBlobStream(image,8,buffer));
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-+ W r i t e B l o b M S B S i g n e d L o n g %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% WriteBlobMSBSignedLong() writes a signed value as a 32-bit quantity in
-% most-significant byte first order.
-%
-% The format of the WriteBlobMSBSignedLong method is:
-%
-% ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
-%
-% A description of each parameter follows.
-%
-% o image: the image.
-%
-% o value: Specifies the value to write.
-%
-*/
-MagickExport ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
-{
- union
- {
- unsigned int
- unsigned_value;
-
- signed int
- signed_value;
- } quantum;
-
- unsigned char
- buffer[4];
-
- assert(image != (Image *) NULL);
- assert(image->signature == MagickCoreSignature);
- quantum.signed_value=value;
- buffer[0]=(unsigned char) (quantum.unsigned_value >> 24);
- buffer[1]=(unsigned char) (quantum.unsigned_value >> 16);
- buffer[2]=(unsigned char) (quantum.unsigned_value >> 8);
- buffer[3]=(unsigned char) quantum.unsigned_value;
- return(WriteBlobStream(image,4,buffer));
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
+ W r i t e B l o b M S B S i g n e d S h o r t %
% %
% %
%
*/
-static const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
+static const char *CompositeOperatorToPSDBlendMode(Image *image)
{
- const char
- *blend_mode;
-
- switch (op)
+ switch (image->compose)
{
- case ColorBurnCompositeOp: blend_mode = "idiv"; break;
- case ColorDodgeCompositeOp: blend_mode = "div "; break;
- case ColorizeCompositeOp: blend_mode = "colr"; break;
- case DarkenCompositeOp: blend_mode = "dark"; break;
- case DifferenceCompositeOp: blend_mode = "diff"; break;
- case DissolveCompositeOp: blend_mode = "diss"; break;
- case ExclusionCompositeOp: blend_mode = "smud"; break;
- case HardLightCompositeOp: blend_mode = "hLit"; break;
- case HardMixCompositeOp: blend_mode = "hMix"; break;
- case HueCompositeOp: blend_mode = "hue "; break;
- case LightenCompositeOp: blend_mode = "lite"; break;
- case LinearBurnCompositeOp: blend_mode = "lbrn"; break;
- case LinearDodgeCompositeOp:blend_mode = "lddg"; break;
- case LinearLightCompositeOp:blend_mode = "lLit"; break;
- case LuminizeCompositeOp: blend_mode = "lum "; break;
- case MultiplyCompositeOp: blend_mode = "mul "; break;
- case OverCompositeOp: blend_mode = "norm"; break;
- case OverlayCompositeOp: blend_mode = "over"; break;
- case PinLightCompositeOp: blend_mode = "pLit"; break;
- case SaturateCompositeOp: blend_mode = "sat "; break;
- case ScreenCompositeOp: blend_mode = "scrn"; break;
- case SoftLightCompositeOp: blend_mode = "sLit"; break;
- case VividLightCompositeOp: blend_mode = "vLit"; break;
- default: blend_mode = "norm";
+ case ColorBurnCompositeOp:
+ return(image->endian == LSBEndian ? "vidi" : "idiv");
+ case ColorDodgeCompositeOp:
+ return(image->endian == LSBEndian ? " vid" : "div ");
+ case ColorizeCompositeOp:
+ return(image->endian == LSBEndian ? "rloc" : "colr");
+ case DarkenCompositeOp:
+ return(image->endian == LSBEndian ? "krad" : "dark");
+ case DifferenceCompositeOp:
+ return(image->endian == LSBEndian ? "ffid" : "diff");
+ case DissolveCompositeOp:
+ return(image->endian == LSBEndian ? "ssid" : "diss");
+ case ExclusionCompositeOp:
+ return(image->endian == LSBEndian ? "dums" : "smud");
+ case HardLightCompositeOp:
+ return(image->endian == LSBEndian ? "tiLh" : "hLit");
+ case HardMixCompositeOp:
+ return(image->endian == LSBEndian ? "xiMh" : "hMix");
+ case HueCompositeOp:
+ return(image->endian == LSBEndian ? " euh" : "hue ");
+ case LightenCompositeOp:
+ return(image->endian == LSBEndian ? "etil" : "lite");
+ case LinearBurnCompositeOp:
+ return(image->endian == LSBEndian ? "nrbl" : "lbrn");
+ case LinearDodgeCompositeOp:
+ return(image->endian == LSBEndian ? "gddl" : "lddg");
+ case LinearLightCompositeOp:
+ return(image->endian == LSBEndian ? "tiLl" : "lLit");
+ case LuminizeCompositeOp:
+ return(image->endian == LSBEndian ? " mul" : "lum ");
+ case MultiplyCompositeOp:
+ return(image->endian == LSBEndian ? " lum" : "mul ");
+ case OverlayCompositeOp:
+ return(image->endian == LSBEndian ? "revo" : "over");
+ case PinLightCompositeOp:
+ return(image->endian == LSBEndian ? "tiLp" : "pLit");
+ case SaturateCompositeOp:
+ return(image->endian == LSBEndian ? " tas" : "sat ");
+ case ScreenCompositeOp:
+ return(image->endian == LSBEndian ? "nrcs" : "scrn");
+ case SoftLightCompositeOp:
+ return(image->endian == LSBEndian ? "tiLs" : "sLit");
+ case VividLightCompositeOp:
+ return(image->endian == LSBEndian ? "tiLv" : "vLit");
+ case OverCompositeOp:
+ default:
+ return(image->endian == LSBEndian ? "mron" : "norm");
}
- return(blend_mode);
}
/*
}
ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
- const ImageInfo *image_info,const PSDInfo *psd_info,
- const MagickBooleanType skip_layers,ExceptionInfo *exception)
+ const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
{
PolicyDomain
domain;
domain=CoderPolicyDomain;
rights=ReadPolicyRights;
if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
- return(MagickFalse);
- return(ReadPSDLayersInternal(image,image_info,psd_info,skip_layers,
+ return(MagickTrue);
+ return(ReadPSDLayersInternal(image,image_info,psd_info,MagickFalse,
exception));
}
const MagickSizeType size)
{
if (psd_info->version == 1)
- return(WriteBlobMSBLong(image,(unsigned int) size));
- return(WriteBlobMSBLongLong(image,size));
+ return(WriteBlobLong(image,(unsigned int) size));
+ return(WriteBlobLongLong(image,size));
}
static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
current_offset=TellBlob(image);
SeekBlob(image,offset,SEEK_SET);
- if (psd_info->version == 1)
- result=WriteBlobMSBLong(image,(unsigned int) size);
- else
- result=WriteBlobMSBLongLong(image,size);
+ result=SetPSDSize(psd_info, image, size);
SeekBlob(image,current_offset,SEEK_SET);
return(result);
}
if (next_image->compression == RLECompression)
{
- length=WriteBlobMSBShort(image,RLE);
+ length=WriteBlobShort(image,RLE);
for (i=0; i < channels; i++)
for (y=0; y < (ssize_t) next_image->rows; y++)
length+=SetPSDOffset(psd_info,image,0);
}
#ifdef MAGICKCORE_ZLIB_DELEGATE
else if (next_image->compression == ZipCompression)
- length=WriteBlobMSBShort(image,ZipWithoutPrediction);
+ length=WriteBlobShort(image,ZipWithoutPrediction);
#endif
else
- length=WriteBlobMSBShort(image,Raw);
+ length=WriteBlobShort(image,Raw);
return(length);
}
size_t
count;
- count=WriteBlobMSBSignedShort(image,channel);
+ count=(size_t) WriteBlobShort(image,channel);
count+=SetPSDSize(psd_info,image,0);
return(count);
}
return(profile);
}
-static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
- Image *image,ExceptionInfo *exception)
+static MagickBooleanType WritePSDLayersInternal(Image *image,
+ const ImageInfo *image_info,const PSDInfo *psd_info,size_t *layers_size,
+ ExceptionInfo *exception)
{
char
layer_name[MagickPathExtent];
*property;
const StringInfo
- *icc_profile,
*info;
Image
*layer_size_offsets,
size_offset;
- PSDInfo
- psd_info;
-
register ssize_t
i;
layer_index,
length,
name_length,
- num_channels,
- packet_size,
rounded_size,
size;
+ status=MagickTrue;
+ base_image=GetNextImageInList(image);
+ if (base_image == (Image *) NULL)
+ base_image=image;
+ size=0;
+ size_offset=TellBlob(image);
+ SetPSDSize(psd_info,image,0);
+ layer_count=0;
+ for (next_image=base_image; next_image != NULL; )
+ {
+ layer_count++;
+ next_image=GetNextImageInList(next_image);
+ }
+ if (image->alpha_trait != UndefinedPixelTrait)
+ size+=WriteBlobShort(image,-(unsigned short) layer_count);
+ else
+ size+=WriteBlobShort(image,(unsigned short) layer_count);
+ layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
+ (size_t) layer_count,sizeof(MagickOffsetType));
+ if (layer_size_offsets == (MagickOffsetType *) NULL)
+ ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+ layer_index=0;
+ for (next_image=base_image; next_image != NULL; )
+ {
+ Image
+ *mask;
+
+ unsigned char
+ default_color;
+
+ unsigned short
+ channels,
+ total_channels;
+
+ mask=(Image *) NULL;
+ property=GetImageArtifact(next_image,"psd:opacity-mask");
+ default_color=0;
+ if (property != (const char *) NULL)
+ {
+ mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
+ default_color=strlen(property) == 9 ? 255 : 0;
+ }
+ size+=WriteBlobSignedLong(image,(signed int) next_image->page.y);
+ size+=WriteBlobSignedLong(image,(signed int) next_image->page.x);
+ size+=WriteBlobSignedLong(image,(signed int) (next_image->page.y+
+ next_image->rows));
+ size+=WriteBlobSignedLong(image,(signed int) (next_image->page.x+
+ next_image->columns));
+ channels=1U;
+ if ((next_image->storage_class != PseudoClass) &&
+ (IsImageGray(next_image) == MagickFalse))
+ channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
+ total_channels=channels;
+ if (next_image->alpha_trait != UndefinedPixelTrait)
+ total_channels++;
+ if (mask != (Image *) NULL)
+ total_channels++;
+ size+=WriteBlobShort(image,total_channels);
+ layer_size_offsets[layer_index++]=TellBlob(image);
+ for (i=0; i < (ssize_t) channels; i++)
+ size+=WriteChannelSize(psd_info,image,(signed short) i);
+ if (next_image->alpha_trait != UndefinedPixelTrait)
+ size+=WriteChannelSize(psd_info,image,-1);
+ if (mask != (Image *) NULL)
+ size+=WriteChannelSize(psd_info,image,-2);
+ size+=WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :"8BIM");
+ size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(image));
+ property=GetImageArtifact(next_image,"psd:layer.opacity");
+ if (property != (const char *) NULL)
+ {
+ Quantum
+ opacity;
+
+ opacity=(Quantum) StringToInteger(property);
+ size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
+ (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
+ }
+ else
+ size+=WriteBlobByte(image,255);
+ size+=WriteBlobByte(image,0);
+ size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
+ 1 << 0x02 : 1); /* layer properties - visible, etc. */
+ size+=WriteBlobByte(image,0);
+ info=GetAdditionalInformation(image_info,next_image,exception);
+ property=(const char *) GetImageProperty(next_image,"label",exception);
+ if (property == (const char *) NULL)
+ {
+ (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
+ (double) layer_index);
+ property=layer_name;
+ }
+ name_length=strlen(property)+1;
+ if ((name_length % 4) != 0)
+ name_length+=(4-(name_length % 4));
+ if (info != (const StringInfo *) NULL)
+ name_length+=GetStringInfoLength(info);
+ name_length+=8;
+ if (mask != (Image *) NULL)
+ name_length+=20;
+ size+=WriteBlobLong(image,(unsigned int) name_length);
+ if (mask == (Image *) NULL)
+ size+=WriteBlobLong(image,0);
+ else
+ {
+ if (mask->compose != NoCompositeOp)
+ (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
+ default_color),MagickTrue,exception);
+ mask->page.y+=image->page.y;
+ mask->page.x+=image->page.x;
+ size+=WriteBlobLong(image,20);
+ size+=WriteBlobSignedLong(image,mask->page.y);
+ size+=WriteBlobSignedLong(image,mask->page.x);
+ size+=WriteBlobSignedLong(image,(const signed int) mask->rows+
+ mask->page.y);
+ size+=WriteBlobSignedLong(image,(const signed int) mask->columns+
+ mask->page.x);
+ size+=WriteBlobByte(image,default_color);
+ size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
+ size+=WriteBlobMSBShort(image,0);
+ }
+ size+=WriteBlobLong(image,0);
+ size+=WritePascalString(image,property,4);
+ if (info != (const StringInfo *) NULL)
+ size+=WriteBlob(image,GetStringInfoLength(info),
+ GetStringInfoDatum(info));
+ next_image=GetNextImageInList(next_image);
+ }
+ /*
+ Now the image data!
+ */
+ next_image=base_image;
+ layer_index=0;
+ while (next_image != NULL)
+ {
+ length=WritePSDChannels(psd_info,image_info,image,next_image,
+ layer_size_offsets[layer_index++],MagickTrue,exception);
+ if (length == 0)
+ {
+ status=MagickFalse;
+ break;
+ }
+ size+=length;
+ next_image=GetNextImageInList(next_image);
+ }
+ /*
+ Write the total size
+ */
+ if (layers_size != (size_t*) NULL)
+ *layers_size=size;
+ if ((size/2) != ((size+1)/2))
+ rounded_size=size+1;
+ else
+ rounded_size=size;
+ (void) WritePSDSize(psd_info,image,rounded_size,size_offset);
+ layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
+ layer_size_offsets);
+ /*
+ Remove the opacity mask from the registry
+ */
+ next_image=base_image;
+ while (next_image != (Image *) NULL)
+ {
+ property=GetImageArtifact(next_image,"psd:opacity-mask");
+ if (property != (const char *) NULL)
+ DeleteImageRegistry(property);
+ next_image=GetNextImageInList(next_image);
+ }
+
+ return(status);
+}
+
+ModuleExport MagickBooleanType WritePSDLayers(Image * image,
+ const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
+{
+ PolicyDomain
+ domain;
+
+ PolicyRights
+ rights;
+
+ domain=CoderPolicyDomain;
+ rights=WritePolicyRights;
+ if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
+ return(MagickTrue);
+ return WritePSDLayersInternal(image,image_info,psd_info,(size_t*) NULL,
+ exception);
+}
+
+static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
+ Image *image,ExceptionInfo *exception)
+{
+ const StringInfo
+ *icc_profile;
+
+ Image
+ *base_image,
+ *next_image;
+
+ MagickBooleanType
+ status;
+
+ PSDInfo
+ psd_info;
+
+ register ssize_t
+ i;
+
+ size_t
+ length,
+ num_channels,
+ packet_size;
+
StringInfo
*bim_profile;
PSDQuantum(GetStringInfoLength(icc_profile)))
(void) WriteBlobByte(image,0);
}
- base_image=GetNextImageInList(image);
- if (base_image == (Image *) NULL)
- base_image=image;
- size=0;
- size_offset=TellBlob(image);
- SetPSDSize(&psd_info,image,0);
- SetPSDSize(&psd_info,image,0);
- layer_count=0;
- for (next_image=base_image; next_image != NULL; )
- {
- layer_count++;
- next_image=GetNextImageInList(next_image);
- }
- if (image->alpha_trait != UndefinedPixelTrait)
- size+=WriteBlobMSBShort(image,-(unsigned short) layer_count);
- else
- size+=WriteBlobMSBShort(image,(unsigned short) layer_count);
- layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
- (size_t) layer_count,sizeof(MagickOffsetType));
- if (layer_size_offsets == (MagickOffsetType *) NULL)
- ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
- layer_index=0;
- for (next_image=base_image; next_image != NULL; )
- {
- Image
- *mask;
-
- unsigned char
- default_color;
+ if (status != MagickFalse)
+ {
+ MagickOffsetType
+ size_offset;
- unsigned short
- channels,
- total_channels;
+ size_t
+ size;
- mask=(Image *) NULL;
- property=GetImageArtifact(next_image,"psd:opacity-mask");
- default_color=0;
- if (property != (const char *) NULL)
- {
- mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
- default_color=strlen(property) == 9 ? 255 : 0;
- }
- size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
- size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
- size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
- next_image->rows));
- size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
- next_image->columns));
- channels=1U;
- if ((next_image->storage_class != PseudoClass) &&
- (IsImageGray(next_image) == MagickFalse))
- channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
- total_channels=channels;
- if (next_image->alpha_trait != UndefinedPixelTrait)
- total_channels++;
- if (mask != (Image *) NULL)
- total_channels++;
- size+=WriteBlobMSBShort(image,total_channels);
- layer_size_offsets[layer_index++]=TellBlob(image);
- for (i=0; i < (ssize_t) channels; i++)
- size+=WriteChannelSize(&psd_info,image,(signed short) i);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- size+=WriteChannelSize(&psd_info,image,-1);
- if (mask != (Image *) NULL)
- size+=WriteChannelSize(&psd_info,image,-2);
- size+=WriteBlob(image,4,(const unsigned char *) "8BIM");
- size+=WriteBlob(image,4,(const unsigned char *)
- CompositeOperatorToPSDBlendMode(next_image->compose));
- property=GetImageArtifact(next_image,"psd:layer.opacity");
- if (property != (const char *) NULL)
- {
- Quantum
- opacity;
-
- opacity=(Quantum) StringToInteger(property);
- size+=WriteBlobByte(image,ScaleQuantumToChar(opacity));
- (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
- }
- else
- size+=WriteBlobByte(image,255);
- size+=WriteBlobByte(image,0);
- size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
- 1 << 0x02 : 1); /* layer properties - visible, etc. */
- size+=WriteBlobByte(image,0);
- info=GetAdditionalInformation(image_info,next_image,exception);
- property=(const char *) GetImageProperty(next_image,"label",exception);
- if (property == (const char *) NULL)
- {
- (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
- (double) layer_index);
- property=layer_name;
- }
- name_length=strlen(property)+1;
- if ((name_length % 4) != 0)
- name_length+=(4-(name_length % 4));
- if (info != (const StringInfo *) NULL)
- name_length+=GetStringInfoLength(info);
- name_length+=8;
- if (mask != (Image *) NULL)
- name_length+=20;
- size+=WriteBlobMSBLong(image,(unsigned int) name_length);
- if (mask == (Image *) NULL)
- size+=WriteBlobMSBLong(image,0);
- else
- {
- if (mask->compose != NoCompositeOp)
- (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
- default_color),MagickTrue,exception);
- mask->page.y+=image->page.y;
- mask->page.x+=image->page.x;
- size+=WriteBlobMSBLong(image,20);
- size+=WriteBlobMSBSignedLong(image,mask->page.y);
- size+=WriteBlobMSBSignedLong(image,mask->page.x);
- size+=WriteBlobMSBSignedLong(image,(const signed int) mask->rows+
- mask->page.y);
- size+=WriteBlobMSBSignedLong(image,(const signed int) mask->columns+
- mask->page.x);
- size+=WriteBlobByte(image,default_color);
- size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
- size+=WriteBlobMSBShort(image,0);
- }
- size+=WriteBlobMSBLong(image,0);
- size+=WritePascalString(image,property,4);
- if (info != (const StringInfo *) NULL)
- size+=WriteBlob(image,GetStringInfoLength(info),
- GetStringInfoDatum(info));
- next_image=GetNextImageInList(next_image);
- }
- /*
- Now the image data!
- */
- next_image=base_image;
- layer_index=0;
- while (next_image != NULL)
- {
- length=WritePSDChannels(&psd_info,image_info,image,next_image,
- layer_size_offsets[layer_index++],MagickTrue,exception);
- if (length == 0)
- {
- status=MagickFalse;
- break;
- }
- size+=length;
- next_image=GetNextImageInList(next_image);
- }
+ size_offset=TellBlob(image);
+ SetPSDSize(&psd_info,image,0);
+ status=WritePSDLayersInternal(image,image_info,&psd_info,&size,
+ exception);
+ size_offset+=WritePSDSize(&psd_info,image,size+
+ (psd_info.version == 1 ? 8 : 16),size_offset);
+ }
(void) WriteBlobMSBLong(image,0); /* user mask data */
- /*
- Write the total size
- */
- size_offset+=WritePSDSize(&psd_info,image,size+
- (psd_info.version == 1 ? 8 : 16),size_offset);
- if ((size/2) != ((size+1)/2))
- rounded_size=size+1;
- else
- rounded_size=size;
- (void) WritePSDSize(&psd_info,image,rounded_size,size_offset);
- layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
- layer_size_offsets);
- /*
- Remove the opacity mask from the registry
- */
- next_image=base_image;
- while (next_image != (Image *) NULL)
- {
- property=GetImageArtifact(next_image,"psd:opacity-mask");
- if (property != (const char *) NULL)
- DeleteImageRegistry(property);
- next_image=GetNextImageInList(next_image);
- }
/*
Write composite image.
*/
ReadGenericMethod
} TIFFMethodType;
+typedef struct _PhotoshopProfile
+{
+ StringInfo
+ *data;
+
+ MagickOffsetType
+ offset;
+
+ size_t
+ length,
+ extent,
+ quantum;
+} PhotoshopProfile;
+
#if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
typedef struct _ExifInfo
{
WriteGROUP4Image(const ImageInfo *,Image *,ExceptionInfo *),
WritePTIFImage(const ImageInfo *,Image *,ExceptionInfo *),
WriteTIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
+
+static MagickOffsetType TIFFSeekCustomStream(const MagickOffsetType offset,
+ const int whence,void *user_data)
+{
+ PhotoshopProfile
+ *profile;
+
+ profile=(PhotoshopProfile *) user_data;
+ switch (whence)
+ {
+ case SEEK_SET:
+ default:
+ {
+ if (offset < 0)
+ return(-1);
+ profile->offset=offset;
+ break;
+ }
+ case SEEK_CUR:
+ {
+ if ((profile->offset+offset) < 0)
+ return(-1);
+ profile->offset+=offset;
+ break;
+ }
+ case SEEK_END:
+ {
+ if (((MagickOffsetType) profile->length+offset) < 0)
+ return(-1);
+ profile->offset=profile->length+offset;
+ break;
+ }
+ }
+
+ return(profile->offset);
+}
+
+static MagickOffsetType TIFFTellCustomStream(void *user_data)
+{
+ PhotoshopProfile
+ *profile;
+
+ profile=(PhotoshopProfile *) user_data;
+ return(profile->offset);
+}
+
+static void InitPSDInfo(const Image *image, PSDInfo *info)
+{
+ info->version=1;
+ info->columns=image->columns;
+ info->rows=image->rows;
+ /* Setting the mode to a value that won't change the colorspace */
+ info->mode=10;
+ info->channels=1U;
+ if (image->storage_class == PseudoClass)
+ info->mode=2; // indexed mode
+ else
+ info->channels=(unsigned short) image->number_channels;
+}
#endif
\f
/*
return(method);
}
+static ssize_t TIFFReadCustomStream(unsigned char *data,const size_t count,
+ void *user_data)
+{
+ PhotoshopProfile
+ *profile;
+
+ size_t
+ total;
+
+ ssize_t
+ remaining;
+
+ if (count == 0)
+ return(0);
+ profile=(PhotoshopProfile *) user_data;
+ remaining=(MagickOffsetType) profile->length-profile->offset;
+ if (remaining <= 0)
+ return(-1);
+ total=MagickMin(count, (size_t) remaining);
+ (void) memcpy(data,profile->data->datum+profile->offset,total);
+ return(total);
+}
+
+static CustomStreamInfo *TIFFAcquireCustomStreamForReading(
+ PhotoshopProfile *profile,ExceptionInfo *exception)
+{
+ CustomStreamInfo
+ *custom_stream;
+
+ custom_stream=AcquireCustomStreamInfo(exception);
+ if (custom_stream == (CustomStreamInfo *) NULL)
+ return(custom_stream);
+ SetCustomStreamData(custom_stream,(void *) profile);
+ SetCustomStreamReader(custom_stream,TIFFReadCustomStream);
+ SetCustomStreamSeeker(custom_stream,TIFFSeekCustomStream);
+ SetCustomStreamTeller(custom_stream,TIFFTellCustomStream);
+ return(custom_stream);
+}
+
static void TIFFReadPhotoshopLayers(Image* image,const ImageInfo *image_info,
ExceptionInfo *exception)
{
*option;
const StringInfo
- *layer_info;
+ *profile;
+
+ CustomStreamInfo
+ *custom_stream;
Image
*layers;
+ PhotoshopProfile
+ photoshop_profile;
+
PSDInfo
info;
option=GetImageOption(image_info,"tiff:ignore-layers");
if (option != (const char * ) NULL)
return;
- layer_info=GetImageProfile(image,"tiff:37724");
- if (layer_info == (const StringInfo *) NULL)
+ profile=GetImageProfile(image,"tiff:37724");
+ if (profile == (const StringInfo *) NULL)
return;
- for (i=0; i < (ssize_t) layer_info->length-8; i++)
+ for (i=0; i < (ssize_t) profile->length-8; i++)
{
- if (LocaleNCompare((const char *) (layer_info->datum+i),
+ if (LocaleNCompare((const char *) (profile->datum+i),
image->endian == MSBEndian ? "8BIM" : "MIB8",4) != 0)
continue;
i+=4;
- if ((LocaleNCompare((const char *) (layer_info->datum+i),
+ if ((LocaleNCompare((const char *) (profile->datum+i),
image->endian == MSBEndian ? "Layr" : "ryaL",4) == 0) ||
- (LocaleNCompare((const char *) (layer_info->datum+i),
+ (LocaleNCompare((const char *) (profile->datum+i),
image->endian == MSBEndian ? "LMsk" : "ksML",4) == 0) ||
- (LocaleNCompare((const char *) (layer_info->datum+i),
+ (LocaleNCompare((const char *) (profile->datum+i),
image->endian == MSBEndian ? "Lr16" : "61rL",4) == 0) ||
- (LocaleNCompare((const char *) (layer_info->datum+i),
+ (LocaleNCompare((const char *) (profile->datum+i),
image->endian == MSBEndian ? "Lr32" : "23rL",4) == 0))
break;
}
i+=4;
- if (i >= (ssize_t) (layer_info->length-8))
+ if (i >= (ssize_t) (profile->length-8))
+ return;
+ photoshop_profile.data=(StringInfo *) profile;
+ photoshop_profile.length=profile->length;
+ custom_stream=TIFFAcquireCustomStreamForReading(&photoshop_profile,exception);
+ if (custom_stream == (CustomStreamInfo *) NULL)
return;
layers=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+ if (layers == (Image *) NULL)
+ {
+ custom_stream=DestroyCustomStreamInfo(custom_stream);
+ return;
+ }
(void) DeleteImageProfile(layers,"tiff:37724");
- AttachBlob(layers->blob,layer_info->datum,layer_info->length);
+ AttachCustomStream(layers->blob,custom_stream);
SeekBlob(layers,(MagickOffsetType) i,SEEK_SET);
- info.version=1;
- info.columns=layers->columns;
- info.rows=layers->rows;
- info.channels=(unsigned short) layers->number_channels;
- /* Setting the mode to a value that won't change the colorspace */
- info.mode=10;
- ReadPSDLayers(layers,image_info,&info,MagickFalse,exception);
- /* we need to set the datum in case a realloc happened */
- ((StringInfo *) layer_info)->datum=GetBlobStreamData(layers);
+ InitPSDInfo(layers,&info);
+ (void) ReadPSDLayers(layers,image_info,&info,exception);
DeleteImageFromList(&layers);
if (layers != (Image *) NULL)
{
layers=GetNextImageInList(layers);
}
}
+ custom_stream=DestroyCustomStreamInfo(custom_stream);
}
#if defined(__cplusplus) || defined(c_plusplus)
return(status);
}
+static ssize_t TIFFWriteCustomStream(unsigned char *data,const size_t count,
+ void *user_data)
+{
+ PhotoshopProfile
+ *profile;
+
+ if (count == 0)
+ return(0);
+ profile=(PhotoshopProfile *) user_data;
+ if ((profile->offset+(MagickOffsetType) count) >=
+ (MagickOffsetType) profile->extent)
+ {
+ profile->extent+=count+profile->quantum;
+ profile->quantum<<=1;
+ SetStringInfoLength(profile->data,profile->extent);
+ }
+ (void) memcpy(profile->data->datum+profile->offset,data,count);
+ profile->offset+=count;
+ return(count);
+}
+
+static CustomStreamInfo *TIFFAcquireCustomStreamForWriting(
+ PhotoshopProfile *profile,ExceptionInfo *exception)
+{
+ CustomStreamInfo
+ *custom_stream;
+
+ custom_stream=AcquireCustomStreamInfo(exception);
+ if (custom_stream == (CustomStreamInfo *) NULL)
+ return(custom_stream);
+ SetCustomStreamData(custom_stream,(void *) profile);
+ SetCustomStreamWriter(custom_stream,TIFFWriteCustomStream);
+ SetCustomStreamSeeker(custom_stream,TIFFSeekCustomStream);
+ SetCustomStreamTeller(custom_stream,TIFFTellCustomStream);
+ return(custom_stream);
+}
+
+static MagickBooleanType TIFFWritePhotoshopLayers(Image* image,
+ const ImageInfo *image_info,ExceptionInfo *exception)
+{
+ BlobInfo
+ *blob;
+
+ CustomStreamInfo
+ *custom_stream;
+
+ Image
+ *next;
+
+ ImageInfo
+ *clone_info;
+
+ MagickBooleanType
+ status;
+
+ PhotoshopProfile
+ profile;
+
+ PSDInfo
+ info;
+
+ size_t
+ length;
+
+ StringInfo
+ *layers;
+
+ next=image->next;
+ if (next == (Image *) NULL)
+ return(MagickTrue);
+ clone_info=CloneImageInfo(image_info);
+ if (clone_info == (ImageInfo *) NULL)
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
+ profile.offset=0;
+ profile.quantum=MagickMinBlobExtent;
+ layers=AcquireStringInfo(profile.quantum);
+ if (layers == (StringInfo *) NULL)
+ {
+ clone_info=DestroyImageInfo(clone_info);
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
+ }
+ profile.data=layers;
+ profile.extent=layers->length;
+ custom_stream=TIFFAcquireCustomStreamForWriting(&profile,exception);
+ if (custom_stream == (CustomStreamInfo *) NULL)
+ {
+ clone_info=DestroyImageInfo(clone_info);
+ layers=DestroyStringInfo(layers);
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
+ }
+ blob=CloneBlobInfo((BlobInfo *) NULL);
+ if (blob == (BlobInfo *) NULL)
+ {
+ clone_info=DestroyImageInfo(clone_info);
+ layers=DestroyStringInfo(layers);
+ custom_stream=DestroyCustomStreamInfo(custom_stream);
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
+ }
+ DestroyBlob(next);
+ next->blob=blob;
+ while (next != (Image *) NULL)
+ next=SyncNextImageInList(next);
+ next=image->next;
+ AttachCustomStream(next->blob,custom_stream);
+ InitPSDInfo(image,&info);
+ if (next->endian == UndefinedEndian)
+ next->endian=(HOST_FILLORDER == FILLORDER_LSB2MSB) ? LSBEndian : MSBEndian;
+ WriteBlobString(next,"Adobe Photoshop Document Data Block");
+ WriteBlobByte(next,0);
+ WriteBlobString(next,next->endian == LSBEndian ? "MIB8ryaL" : "8BIMLayr");
+ status=WritePSDLayers(next,clone_info,&info,exception);
+ if (status != MagickFalse)
+ {
+ SetStringInfoLength(layers,(size_t) profile.offset);
+ status=SetImageProfile(image,"tiff:37724",layers,exception);
+ }
+ while (next != (Image *) NULL)
+ {
+ CloseBlob(next);
+ next=next->next;
+ }
+ layers=DestroyStringInfo(layers);
+ clone_info=DestroyImageInfo(clone_info);
+ custom_stream=DestroyCustomStreamInfo(custom_stream);
+ return(status);
+}
+
static void TIFFSetProfiles(TIFF *tiff,Image *image)
{
const char
}
}
-static void TIFFSetProperties(TIFF *tiff,const ImageInfo *image_info,
+static void TIFFSetProperties(TIFF *tiff,const MagickBooleanType adjoin,
Image *image,ExceptionInfo *exception)
{
const char
page=(uint16) image->scene;
pages=(uint16) GetImageListLength(image);
- if ((image_info->adjoin != MagickFalse) && (pages > 1))
+ if ((adjoin != MagickFalse) && (pages > 1))
(void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
(void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
}
endian_type;
MagickBooleanType
+ adjoin,
debug,
status;
scene=0;
debug=IsEventLogging();
(void) debug;
+ adjoin=image_info->adjoin;
do
{
/*
chromaticity[1]=(float) image->chromaticity.white_point.y;
(void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
}
+ option=GetImageOption(image_info,"tiff:write-layers");
+ if (IsStringTrue(option) != MagickFalse)
+ {
+ (void) TIFFWritePhotoshopLayers(image,image_info,exception);
+ adjoin=MagickFalse;
+ }
if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
- (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
+ (adjoin != MagickFalse) && (GetImageListLength(image) > 1))
{
(void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
if (image->scene != 0)
}
if (image->orientation != UndefinedOrientation)
(void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
- (void) TIFFSetProfiles(tiff,image);
+ TIFFSetProfiles(tiff,image);
{
uint16
page,
page=(uint16) scene;
pages=(uint16) GetImageListLength(image);
if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
- (image_info->adjoin != MagickFalse) && (pages > 1))
+ (adjoin != MagickFalse) && (pages > 1))
(void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
(void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
}
- (void) TIFFSetProperties(tiff,image_info,image,exception);
+ (void) TIFFSetProperties(tiff,adjoin,image,exception);
DisableMSCWarning(4127)
if (0)
RestoreMSCWarning
GetImageListLength(image));
if (status == MagickFalse)
break;
- } while (image_info->adjoin != MagickFalse);
+ } while (adjoin != MagickFalse);
TIFFClose(tiff);
return(MagickTrue);
}