size;
} ChannelInfo;
-typedef struct _LayerInfo
+typedef struct _MaskInfo
{
+ Image
+ *image;
+
RectangleInfo
- page,
- mask;
+ page;
- unsigned short
- channels;
+ unsigned char
+ background,
+ flags;
+} MaskInfo;
+typedef struct _LayerInfo
+{
ChannelInfo
channel_info[MaxPSDChannels];
char
blendkey[4];
+ Image
+ *image;
+
+ MaskInfo
+ mask;
+
Quantum
opacity;
- unsigned char
- clipping,
- visible,
- flags;
+ RectangleInfo
+ page;
size_t
offset_x,
offset_y;
unsigned char
- name[256];
+ clipping,
+ flags,
+ name[256],
+ visible;
- Image
- *image;
+ unsigned short
+ channels;
} LayerInfo;
-
-typedef struct _PSDInfo
+\ftypedef struct _PSDInfo
{
char
signature[4];
depth,
mode;
} PSDInfo;
-\f
+
+
/*
Forward declarations.
*/
{
if (layer_info[i].image != (Image *) NULL)
layer_info[i].image=DestroyImage(layer_info[i].image);
+ if (layer_info[i].mask.image != (Image *) NULL)
+ layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
}
return (LayerInfo *) RelinquishMagickMemory(layer_info);
SetPixelAlpha(image,pixel,q);
break;
}
+ case -2:
case 0:
{
SetPixelRed(image,pixel,q);
- if (channels == 1)
+ if (channels == 1 || type == -2)
SetPixelGray(image,pixel,q);
if (image->storage_class == PseudoClass)
{
#endif
static MagickStatusType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
- const LayerInfo* layer_info,const size_t channel,
+ LayerInfo* layer_info,const size_t channel,
const PSDCompressionType compression,ExceptionInfo *exception)
{
+ Image
+ *channel_image,
+ *mask;
+
MagickOffsetType
offset;
MagickStatusType
status;
+ channel_image=image;
+ mask=(Image *) NULL;
if (layer_info->channel_info[channel].type < -1)
{
- /* ignore user supplied layer mask */
- SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
- return(MagickTrue);
+ /*
+ Ignore mask that is not a user supplied layer mask, if the mask is
+ disabled or if the flags have unsupported values.
+ */
+ if (layer_info->channel_info[channel].type != -2 ||
+ (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02))
+ {
+ SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
+ return(MagickTrue);
+ }
+ mask=CloneImage(image,layer_info->mask.page.width,
+ layer_info->mask.page.height,MagickFalse,exception);
+ SetImageType(mask,GrayscaleType,exception);
+ channel_image=mask;
}
- offset=TellBlob(image);
+ offset=TellBlob(channel_image);
status=MagickTrue;
switch(compression)
{
case Raw:
- return(ReadPSDChannelRaw(image,psd_info->channels,
+ return(ReadPSDChannelRaw(channel_image,psd_info->channels,
layer_info->channel_info[channel].type,exception));
case RLE:
{
MagickOffsetType
*offsets;
- offsets=ReadPSDRLEOffsets(image,psd_info,image->rows);
+ offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
if (offsets == (MagickOffsetType *) NULL)
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
- status=ReadPSDChannelRLE(image,psd_info,
- layer_info->channel_info[channel].type,offsets,exception);
+ status=ReadPSDChannelRLE(channel_image,psd_info,
+ layer_info->channel_info[channel].type,offsets,exception);
offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
}
break;
case ZipWithPrediction:
case ZipWithoutPrediction:
#ifdef MAGICKCORE_ZLIB_DELEGATE
- status=ReadPSDChannelZip(image,layer_info->channels,
+ status=ReadPSDChannelZip(channel_image,layer_info->channels,
layer_info->channel_info[channel].type,compression,
layer_info->channel_info[channel].size-2,exception);
#else
if (status == MagickFalse)
SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
+ if (mask != (Image *) NULL)
+ {
+ if (status != MagickFalse)
+ {
+ PixelInfo
+ color;
+
+ layer_info->mask.image=CloneImage(image,image->columns,image->rows,
+ MagickTrue,exception);
+ layer_info->mask.image->alpha_trait=UndefinedPixelTrait;
+ GetPixelInfo(layer_info->mask.image,&color);
+ color.red=layer_info->mask.background == 0 ? 0 : QuantumRange;
+ SetImageColor(layer_info->mask.image,&color,exception);
+ (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp,
+ MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y,
+ exception);
+ }
+ DestroyImage(mask);
+ }
return(status);
}
/*
Set up some hidden attributes for folks that need them.
*/
- (void) FormatLocaleString(message,MagickPathExtent,"%.20gld",
+ (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
(double) layer_info->page.x);
(void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
(void) FormatLocaleString(message,MagickPathExtent,"%.20g",
if (status != MagickFalse)
status=CorrectPSDOpacity(layer_info,exception);
- if (status != MagickFalse && layer_info->image->colorspace == CMYKColorspace)
- (void) NegateCMYK(layer_info->image,exception);
+ if (status != MagickFalse)
+ {
+ if (layer_info->image->colorspace == CMYKColorspace)
+ NegateCMYK(layer_info->image,exception);
+ if (layer_info->mask.image != (Image *) NULL)
+ {
+ CompositeImage(layer_info->image,layer_info->mask.image,
+ CopyAlphaCompositeOp,MagickTrue,0,0,exception);
+ layer_info->mask.image=DestroyImage(layer_info->mask.image);
+ }
+ }
return(status);
}
/*
Layer mask info.
*/
- layer_info[i].mask.y=(int) ReadBlobMSBLong(image);
- layer_info[i].mask.x=(int) ReadBlobMSBLong(image);
- layer_info[i].mask.height=(size_t)
- (ReadBlobMSBLong(image)-layer_info[i].mask.y);
- layer_info[i].mask.width=(size_t)
- (ReadBlobMSBLong(image)-layer_info[i].mask.x);
+ layer_info[i].mask.page.y=(int) ReadBlobMSBLong(image);
+ layer_info[i].mask.page.x=(int) ReadBlobMSBLong(image);
+ layer_info[i].mask.page.height=(size_t)
+ (ReadBlobMSBLong(image)-layer_info[i].mask.page.y);
+ layer_info[i].mask.page.width=(size_t)
+ (ReadBlobMSBLong(image)-layer_info[i].mask.page.x);
+ layer_info[i].mask.background=(unsigned char) ReadBlobByte(
+ image);
+ layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
+ if (!(layer_info[i].mask.flags & 0x01))
+ {
+ layer_info[i].mask.page.y=layer_info[i].mask.page.y-
+ layer_info[i].page.y;
+ layer_info[i].mask.page.x=layer_info[i].mask.page.x-
+ layer_info[i].page.x;
+ }
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
- (double) layer_info[i].mask.x,(double)
- layer_info[i].mask.y,(double) layer_info[i].mask.width,
- (double) layer_info[i].mask.height,(double)
- ((MagickOffsetType) length)-16);
+ (double) layer_info[i].mask.page.x,(double)
+ layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
+ (double) layer_info[i].mask.page.height,(double)
+ ((MagickOffsetType) length)-18);
/*
Skip over the rest of the layer mask information.
*/
- if (DiscardBlobBytes(image,(MagickSizeType) (length-16)) == MagickFalse)
+ if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
{
layer_info=DestroyLayerInfo(layer_info,number_layers);
ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
*/
length=(size_t) ReadBlobByte(image);
combined_length+=length+1;
- for (j=0; j < (ssize_t) length; j++)
- layer_info[i].name[j]=(unsigned char) ReadBlobByte(image);
- layer_info[i].name[j]='\0';
+ if (length > 0)
+ (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
+ layer_info[i].name[length]='\0';
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" layer name: %s",layer_info[i].name);
MagickBooleanType
has_merged_image,
- skip_layers,
- status;
+ skip_layers;
MagickOffsetType
offset;
MagickSizeType
length;
+ MagickStatusType
+ status;
+
PSDInfo
psd_info;