From: dirk Date: Mon, 25 May 2015 07:56:17 +0000 (+0000) Subject: Added support for reading a user supplied layer mask in PSD files. X-Git-Tag: 7.0.1-0~997 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a41d97fa7de942f144af6cfcceba24c523775c54;p=imagemagick Added support for reading a user supplied layer mask in PSD files. --- diff --git a/coders/psd.c b/coders/psd.c index 54dd96771..1ce127853 100644 --- a/coders/psd.c +++ b/coders/psd.c @@ -117,41 +117,53 @@ typedef struct _ChannelInfo 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 + typedef struct _PSDInfo { char signature[4]; @@ -171,7 +183,8 @@ typedef struct _PSDInfo depth, mode; } PSDInfo; - + + /* Forward declarations. */ @@ -464,6 +477,8 @@ static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info, { 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); @@ -706,10 +721,11 @@ static MagickStatusType ReadPSDChannelPixels(Image *image, 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) { @@ -1043,47 +1059,64 @@ static MagickStatusType ReadPSDChannelZip(Image *image,const size_t channels, #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 @@ -1102,6 +1135,25 @@ static MagickStatusType ReadPSDChannel(Image *image,const PSDInfo *psd_info, 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); } @@ -1137,7 +1189,7 @@ static MagickStatusType ReadPSDLayer(Image *image,const PSDInfo *psd_info, /* 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", @@ -1171,8 +1223,17 @@ static MagickStatusType ReadPSDLayer(Image *image,const PSDInfo *psd_info, 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); } @@ -1355,23 +1416,33 @@ static MagickStatusType ReadPSDLayers(Image *image,const ImageInfo *image_info, /* 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", @@ -1407,9 +1478,9 @@ static MagickStatusType ReadPSDLayers(Image *image,const ImageInfo *image_info, */ 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); @@ -1589,8 +1660,7 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception) MagickBooleanType has_merged_image, - skip_layers, - status; + skip_layers; MagickOffsetType offset; @@ -1598,6 +1668,9 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception) MagickSizeType length; + MagickStatusType + status; + PSDInfo psd_info;