% December 2013 %
% %
% %
-% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
-% http://www.imagemagick.org/script/license.php %
+% https://www.imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
#include "MagickCore/option.h"
#include "MagickCore/pixel.h"
#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/policy.h"
#include "MagickCore/profile.h"
#include "MagickCore/property.h"
+#include "MagickCore/registry.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
#include "MagickCore/thread-private.h"
#ifdef MAGICKCORE_ZLIB_DELEGATE
#include <zlib.h>
*/
#define MaxPSDChannels 56
#define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
-#define PSDAdditionalInfo "psd:additional-info"
\f
/*
Enumerated declaractions.
}
}
-static MagickBooleanType CorrectPSDOpacity(LayerInfo *layer_info,
- ExceptionInfo *exception)
+static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
+ MagickBooleanType revert,ExceptionInfo *exception)
{
MagickBooleanType
status;
ssize_t
y;
- if (layer_info->opacity == OpaqueAlpha)
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " applying layer opacity %.20g", (double) opacity);
+ if (opacity == OpaqueAlpha)
return(MagickTrue);
-
- layer_info->image->alpha_trait=BlendPixelTrait;
+ image->alpha_trait=BlendPixelTrait;
status=MagickTrue;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(static,4) shared(status) \
- magick_threads(layer_info->image,layer_info->image,layer_info->image->rows,1)
+ magick_threads(image,image,image->rows,1)
#endif
- for (y=0; y < (ssize_t) layer_info->image->rows; y++)
+ for (y=0; y < (ssize_t) image->rows; y++)
{
register Quantum
*magick_restrict q;
if (status == MagickFalse)
continue;
- q=GetAuthenticPixels(layer_info->image,0,y,layer_info->image->columns,1,
- exception);
- if (q == (Quantum *)NULL)
+ q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+ if (q == (Quantum *) NULL)
{
status=MagickFalse;
continue;
}
- for (x=0; x < (ssize_t) layer_info->image->columns; x++)
+ for (x=0; x < (ssize_t) image->columns; x++)
{
- SetPixelAlpha(layer_info->image,(Quantum) (QuantumScale*(GetPixelAlpha(
- layer_info->image,q))*layer_info->opacity),q);
- q+=GetPixelChannels(layer_info->image);
+ if (revert == MagickFalse)
+ SetPixelAlpha(image,(Quantum) (QuantumScale*(GetPixelAlpha(image,q))*
+ opacity),q);
+ else if (opacity > 0)
+ SetPixelAlpha(image,(Quantum) (QuantumRange*(GetPixelAlpha(image,q)/
+ (MagickRealType) opacity)),q);
+ q+=GetPixelChannels(image);
}
- if (SyncAuthenticPixels(layer_info->image,exception) == MagickFalse)
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
status=MagickFalse;
}
return(status);
}
+static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
+ Quantum background,MagickBooleanType revert,ExceptionInfo *exception)
+{
+ Image
+ *complete_mask;
+
+ MagickBooleanType
+ status;
+
+ PixelInfo
+ color;
+
+ ssize_t
+ y;
+
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " applying opacity mask");
+ complete_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
+ exception);
+ complete_mask->alpha_trait=BlendPixelTrait;
+ GetPixelInfo(complete_mask,&color);
+ color.red=background;
+ SetImageColor(complete_mask,&color,exception);
+ status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
+ mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
+ if (status == MagickFalse)
+ {
+ complete_mask=DestroyImage(complete_mask);
+ return(status);
+ }
+ image->alpha_trait=BlendPixelTrait;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp parallel for schedule(static,4) shared(status) \
+ magick_threads(image,image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register Quantum
+ *magick_restrict q;
+
+ register Quantum
+ *p;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+ p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception);
+ if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL))
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ MagickRealType
+ alpha,
+ intensity;
+
+ alpha=GetPixelAlpha(image,q);
+ intensity=GetPixelIntensity(complete_mask,p);
+ if (revert == MagickFalse)
+ SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
+ else if (intensity > 0)
+ SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*QuantumRange),q);
+ q+=GetPixelChannels(image);
+ p+=GetPixelChannels(complete_mask);
+ }
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ status=MagickFalse;
+ }
+ complete_mask=DestroyImage(complete_mask);
+ return(status);
+}
+
+static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info,
+ ExceptionInfo *exception)
+{
+ char
+ *key;
+
+ RandomInfo
+ *random_info;
+
+ StringInfo
+ *key_info;
+
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " preserving opacity mask");
+ random_info=AcquireRandomInfo();
+ key_info=GetRandomKey(random_info,2+1);
+ key=(char *) GetStringInfoDatum(key_info);
+ key[8]=layer_info->mask.background;
+ key[9]='\0';
+ layer_info->mask.image->page.x+=layer_info->page.x;
+ layer_info->mask.image->page.y+=layer_info->page.y;
+ (void) SetImageRegistry(ImageRegistryType,(const char *) key,
+ layer_info->mask.image,exception);
+ (void) SetImageArtifact(layer_info->image,"psd:opacity-mask",
+ (const char *) key);
+ key_info=DestroyStringInfo(key_info);
+ random_info=DestroyRandomInfo(random_info);
+}
+
static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
const unsigned char *compact_pixels,const ssize_t depth,
const size_t number_pixels,unsigned char *pixels)
StringInfo
*profile;
+ unsigned char
+ name_length;
+
unsigned int
- count,
- long_sans;
+ count;
unsigned short
id,
SetStringInfoDatum(profile,blocks);
(void) SetImageProfile(image,"8bim",profile,exception);
profile=DestroyStringInfo(profile);
- for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); )
+ for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
{
if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
break;
- p=PushLongPixel(MSBEndian,p,&long_sans);
+ p+=4;
p=PushShortPixel(MSBEndian,p,&id);
- p=PushShortPixel(MSBEndian,p,&short_sans);
+ p=PushCharPixel(p,&name_length);
+ if ((name_length % 2) == 0)
+ name_length++;
+ p+=name_length;
+ if (p > (blocks+length-4))
+ return;
p=PushLongPixel(MSBEndian,p,&count);
- if ((p+count) > (blocks+length-16))
+ if ((p+count) > (blocks+length))
return;
switch (id)
{
/*
Resolution info.
*/
+ if (count < 16)
+ return;
p=PushShortPixel(MSBEndian,p,&resolution);
image->resolution.x=(double) resolution;
- (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.x);
+ (void) FormatLocaleString(value,MagickPathExtent,"%g",
+ image->resolution.x);
(void) SetImageProperty(image,"tiff:XResolution",value,exception);
p=PushShortPixel(MSBEndian,p,&short_sans);
p=PushShortPixel(MSBEndian,p,&short_sans);
p=PushShortPixel(MSBEndian,p,&short_sans);
p=PushShortPixel(MSBEndian,p,&resolution);
image->resolution.y=(double) resolution;
- (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.y);
+ (void) FormatLocaleString(value,MagickPathExtent,"%g",
+ image->resolution.y);
(void) SetImageProperty(image,"tiff:YResolution",value,exception);
p=PushShortPixel(MSBEndian,p,&short_sans);
p=PushShortPixel(MSBEndian,p,&short_sans);
}
case 0x0421:
{
- if (*(p+4) == 0)
+ if ((count > 3) && (*(p+4) == 0))
*has_merged_image=MagickFalse;
p+=count;
break;
{
if (image->storage_class == PseudoClass)
{
- if (packet_size == 1)
- SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
+ PixelInfo
+ *color;
+
+ if (type == 0)
+ {
+ if (packet_size == 1)
+ SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
+ else
+ SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
+ }
+ color=image->colormap+(ssize_t) ConstrainColormapIndex(image,
+ GetPixelIndex(image,q),exception);
+ if ((type == 0) && (channels > 1))
+ return;
else
- SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
- SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
- ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
+ color->alpha=(MagickRealType) pixel;
+ SetPixelViaPixelInfo(image,color,q);
return;
}
switch (type)
{
case -1:
{
- SetPixelAlpha(image, pixel,q);
+ SetPixelAlpha(image,pixel,q);
break;
}
case -2:
case 0:
{
SetPixelRed(image,pixel,q);
- if (channels == 1 || type == -2)
- SetPixelGray(image,pixel,q);
break;
}
case 1:
{
- if (image->storage_class == PseudoClass)
- SetPixelAlpha(image,pixel,q);
- else
- SetPixelGreen(image,pixel,q);
+ SetPixelGreen(image,pixel,q);
break;
}
case 2:
{
- if (image->storage_class == PseudoClass)
- SetPixelAlpha(image,pixel,q);
- else
- SetPixelBlue(image,pixel,q);
+ SetPixelBlue(image,pixel,q);
break;
}
case 3:
ssize_t
bit,
number_bits;
-
+
number_bits=image->columns-x;
if (number_bits > 8)
number_bits=8;
return(status);
}
-static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
+static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
const PSDInfo *psd_info,const size_t size)
{
MagickOffsetType
- *offsets;
+ *sizes;
ssize_t
y;
- offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets));
- if(offsets != (MagickOffsetType *) NULL)
+ sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes));
+ if(sizes != (MagickOffsetType *) NULL)
{
for (y=0; y < (ssize_t) size; y++)
{
if (psd_info->version == 1)
- offsets[y]=(MagickOffsetType) ReadBlobShort(image);
+ sizes[y]=(MagickOffsetType) ReadBlobShort(image);
else
- offsets[y]=(MagickOffsetType) ReadBlobLong(image);
+ sizes[y]=(MagickOffsetType) ReadBlobLong(image);
}
}
- return offsets;
+ return sizes;
}
static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
- const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
+ const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception)
{
MagickBooleanType
status;
length=0;
for (y=0; y < (ssize_t) image->rows; y++)
- if ((MagickOffsetType) length < offsets[y])
- length=(size_t) offsets[y];
+ if ((MagickOffsetType) length < sizes[y])
+ length=(size_t) sizes[y];
if (length > row_size + 256) // arbitrary number
{
pixels=(unsigned char *) RelinquishMagickMemory(pixels);
- ThrowBinaryException(ResourceLimitError,"InvalidLength",
- image->filename);
+ ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
}
compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
{
status=MagickFalse;
- count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
- if (count != (ssize_t) offsets[y])
+ count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
+ if (count != (ssize_t) sizes[y])
break;
- count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
+ count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
(ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
if (count != (ssize_t) row_size)
break;
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
+ if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
+ {
+ compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
+ ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
+ image->filename);
+ }
- ResetMagickMemory(&stream, 0, sizeof(z_stream));
+ ResetMagickMemory(&stream,0,sizeof(stream));
stream.data_type=Z_BINARY;
- (void) ReadBlob(image,compact_size,compact_pixels);
-
stream.next_in=(Bytef *)compact_pixels;
- stream.avail_in=(unsigned int) compact_size;
+ stream.avail_in=(uInt) compact_size;
stream.next_out=(Bytef *)pixels;
- stream.avail_out=(unsigned int) count;
+ stream.avail_out=(uInt) count;
- if(inflateInit(&stream) == Z_OK)
+ if (inflateInit(&stream) == Z_OK)
{
int
ret;
while (stream.avail_out > 0)
{
- ret=inflate(&stream, Z_SYNC_FLUSH);
- if (ret != Z_OK && ret != Z_STREAM_END)
- {
- compact_pixels=(unsigned char *) RelinquishMagickMemory(
- compact_pixels);
- pixels=(unsigned char *) RelinquishMagickMemory(pixels);
- return(MagickFalse);
- }
+ ret=inflate(&stream,Z_SYNC_FLUSH);
+ if ((ret != Z_OK) && (ret != Z_STREAM_END))
+ {
+ (void) inflateEnd(&stream);
+ compact_pixels=(unsigned char *) RelinquishMagickMemory(
+ compact_pixels);
+ pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+ return(MagickFalse);
+ }
}
+ (void) inflateEnd(&stream);
}
if (compression == ZipWithPrediction)
{
p=pixels;
- while(count > 0)
+ while (count > 0)
{
length=image->columns;
- while(--length)
+ while (--length)
{
if (packet_size == 2)
{
}
#endif
-static MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
- LayerInfo* layer_info,const size_t channel,
- const PSDCompressionType compression,ExceptionInfo *exception)
+static MagickBooleanType ReadPSDChannel(Image *image,
+ const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
+ const size_t channel,const PSDCompressionType compression,
+ ExceptionInfo *exception)
{
Image
*channel_image,
channel_image=image;
mask=(Image *) NULL;
if (layer_info->channel_info[channel].type < -1)
- {
- /*
- 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;
- }
+ {
+ const char
+ *option;
+ /*
+ Ignore mask that is not a user supplied layer mask, if the mask is
+ disabled or if the flags have unsupported values.
+ */
+ option=GetImageOption(image_info,"psd:preserve-opacity-mask");
+ if ((layer_info->channel_info[channel].type != -2) ||
+ (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
+ (IsStringTrue(option) == MagickFalse)))
+ {
+ 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);
+ if (mask != (Image *) NULL)
+ {
+ SetImageType(mask,GrayscaleType,exception);
+ channel_image=mask;
+ }
+ }
offset=TellBlob(image);
status=MagickTrue;
case RLE:
{
MagickOffsetType
- *offsets;
+ *sizes;
- offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
- if (offsets == (MagickOffsetType *) NULL)
+ sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
+ if (sizes == (MagickOffsetType *) NULL)
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
status=ReadPSDChannelRLE(channel_image,psd_info,
- layer_info->channel_info[channel].type,offsets,exception);
- offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
+ layer_info->channel_info[channel].type,sizes,exception);
+ sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
}
break;
case ZipWithPrediction:
ThrowBinaryException(CoderError,"UnableToDecompressImage",
image->filename);
}
- 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;
- color.green=color.red;
- color.blue=color.red;
- color.black=color.red;
- 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);
- }
-
+ layer_info->mask.image=mask;
return(status);
}
-static MagickBooleanType ReadPSDLayer(Image *image,const PSDInfo *psd_info,
- LayerInfo* layer_info,ExceptionInfo *exception)
+static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
+ const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
{
char
message[MagickPathExtent];
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" setting up new layer image");
- (void) SetImageBackgroundColor(layer_info->image,exception);
+ if (psd_info->mode != IndexedMode)
+ (void) SetImageBackgroundColor(layer_info->image,exception);
layer_info->image->compose=PSDBlendModeToCompositeOperator(
layer_info->blendkey);
if (layer_info->visible == MagickFalse)
layer_info->image->compose=NoCompositeOp;
if (psd_info->mode == CMYKMode)
SetImageColorspace(layer_info->image,CMYKColorspace,exception);
- if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) ||
- (psd_info->mode == DuotoneMode))
+ else if ((psd_info->mode == BitmapMode) || (psd_info->mode == DuotoneMode) ||
+ (psd_info->mode == GrayscaleMode))
SetImageColorspace(layer_info->image,GRAYColorspace,exception);
/*
Set up some hidden attributes for folks that need them.
if (layer_info->channel_info[j].type == -1)
layer_info->image->alpha_trait=BlendPixelTrait;
- status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j,
+ status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
compression,exception);
if (status == MagickFalse)
}
if (status != MagickFalse)
- status=CorrectPSDOpacity(layer_info,exception);
+ status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
+ MagickFalse,exception);
if ((status != MagickFalse) &&
(layer_info->image->colorspace == CMYKColorspace))
if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
{
- status=CompositeImage(layer_info->image,layer_info->mask.image,
- CopyAlphaCompositeOp,MagickTrue,layer_info->mask.page.x,
- layer_info->mask.page.y,exception);
+ const char
+ *option;
+
+ layer_info->mask.image->page.x=layer_info->mask.page.x;
+ layer_info->mask.image->page.y=layer_info->mask.page.y;
+ /* Do not composite the mask when it is disabled */
+ if ((layer_info->mask.flags & 0x02) == 0x02)
+ layer_info->mask.image->compose=NoCompositeOp;
+ else
+ status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
+ layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
+ exception);
+ option=GetImageOption(image_info,"psd:preserve-opacity-mask");
+ if (IsStringTrue(option) != MagickFalse)
+ PreservePSDOpacityMask(image,layer_info,exception);
layer_info->mask.image=DestroyImage(layer_info->mask.image);
}
return(status);
}
-ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
+static MagickBooleanType ReadPSDLayersInternal(Image *image,
const ImageInfo *image_info,const PSDInfo *psd_info,
const MagickBooleanType skip_layers,ExceptionInfo *exception)
{
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
- (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);
+ (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-18)) == MagickFalse)
{
layer_info=DestroyLayerInfo(layer_info,number_layers);
- ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
- image->filename);
+ ThrowBinaryException(CorruptImageError,
+ "UnexpectedEndOfFile",image->filename);
}
}
length=ReadBlobLong(image);
/*
Layer name.
*/
- length=(MagickSizeType) ReadBlobByte(image);
+ length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
combined_length+=length+1;
if (length > 0)
(void) ReadBlob(image,(size_t) length++,layer_info[i].name);
combined_length+=length;
/* Skip over the padding of the layer name */
if (DiscardBlobBytes(image,length) == MagickFalse)
- {
- layer_info=DestroyLayerInfo(layer_info,number_layers);
- ThrowBinaryException(CorruptImageError,
- "UnexpectedEndOfFile",image->filename);
- }
+ {
+ layer_info=DestroyLayerInfo(layer_info,number_layers);
+ ThrowBinaryException(CorruptImageError,
+ "UnexpectedEndOfFile",image->filename);
+ }
}
length=(MagickSizeType) size-combined_length;
if (length > 0)
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" layer data is empty");
+ if (layer_info[i].info != (StringInfo *) NULL)
+ layer_info[i].info=DestroyStringInfo(layer_info[i].info);
continue;
}
if (layer_info[i].info != (StringInfo *) NULL)
{
- (void) SetImageProfile(layer_info[i].image,PSDAdditionalInfo,
+ (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
layer_info[i].info,exception);
layer_info[i].info=DestroyStringInfo(layer_info[i].info);
}
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" reading data for layer %.20g",(double) i);
- status=ReadPSDLayer(image,psd_info,&layer_info[i],exception);
+ status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
+ exception);
if (status == MagickFalse)
break;
}
if (status != MagickFalse)
- {
- for (i=0; i < number_layers; i++)
{
- if (layer_info[i].image == (Image *) NULL)
+ for (i=0; i < number_layers; i++)
{
- for (j=i; j < number_layers - 1; j++)
- layer_info[j] = layer_info[j+1];
- number_layers--;
- i--;
+ if (layer_info[i].image == (Image *) NULL)
+ {
+ for (j=i; j < number_layers - 1; j++)
+ layer_info[j] = layer_info[j+1];
+ number_layers--;
+ i--;
+ }
}
- }
- if (number_layers > 0)
- {
- for (i=0; i < number_layers; i++)
+ if (number_layers > 0)
{
- if (i > 0)
- layer_info[i].image->previous=layer_info[i-1].image;
- if (i < (number_layers-1))
- layer_info[i].image->next=layer_info[i+1].image;
- layer_info[i].image->page=layer_info[i].page;
+ for (i=0; i < number_layers; i++)
+ {
+ if (i > 0)
+ layer_info[i].image->previous=layer_info[i-1].image;
+ if (i < (number_layers-1))
+ layer_info[i].image->next=layer_info[i+1].image;
+ layer_info[i].image->page=layer_info[i].page;
+ }
+ image->next=layer_info[0].image;
+ layer_info[0].image->previous=image;
}
- image->next=layer_info[0].image;
- layer_info[0].image->previous=image;
- }
- layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
- }
+ layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
+ }
else
layer_info=DestroyLayerInfo(layer_info,number_layers);
}
return(status);
}
+ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
+ const ImageInfo *image_info,const PSDInfo *psd_info,
+ const MagickBooleanType skip_layers,ExceptionInfo *exception)
+{
+ PolicyDomain
+ domain;
+
+ PolicyRights
+ rights;
+
+ domain=CoderPolicyDomain;
+ rights=ReadPolicyRights;
+ if (IsRightsAuthorized(domain,rights,"PSD") == MagickFalse)
+ return(MagickFalse);
+ return(ReadPSDLayersInternal(image,image_info,psd_info,skip_layers,
+ exception));
+}
+
static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
{
MagickOffsetType
- *offsets;
+ *sizes;
MagickBooleanType
status;
return(MagickFalse);
}
- offsets=(MagickOffsetType *) NULL;
+ sizes=(MagickOffsetType *) NULL;
if (compression == RLE)
- {
- offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
- if (offsets == (MagickOffsetType *) NULL)
- ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
- image->filename);
- }
+ {
+ sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
+ if (sizes == (MagickOffsetType *) NULL)
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
+ }
status=MagickTrue;
for (i=0; i < (ssize_t) psd_info->channels; i++)
{
if (compression == RLE)
- status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
+ status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
exception);
else
status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
if (status != MagickFalse)
status=CorrectPSDAlphaBlend(image_info,image,exception);
- if (offsets != (MagickOffsetType *) NULL)
- offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
+ sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
return(status);
}
SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
}
else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
- (psd_info.mode == DuotoneMode))
+ (psd_info.mode == DuotoneMode))
{
status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
exception);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" reading image resource blocks - %.20g bytes",(double)
((MagickOffsetType) length));
+ if (length > GetBlobSize(image))
+ ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
sizeof(*blocks));
if (blocks == (unsigned char *) NULL)
}
else
{
- if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
- MagickTrue)
+ if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,
+ exception) != MagickTrue)
{
(void) CloseBlob(image);
image=DestroyImageList(image);
(length != 0))
{
SeekBlob(image,offset,SEEK_SET);
- status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
+ status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
+ exception);
if (status != MagickTrue)
{
(void) CloseBlob(image);
entry->decoder=(DecodeImageHandler *) ReadPSDImage;
entry->encoder=(EncodeImageHandler *) WritePSDImage;
entry->magick=(IsImageFormatHandler *) IsPSD;
- entry->flags|=CoderSeekableStreamFlag;
+ entry->flags|=CoderDecoderSeekableStreamFlag;
+ entry->flags|=CoderEncoderSeekableStreamFlag;
(void) RegisterMagickInfo(entry);
entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
entry->decoder=(DecodeImageHandler *) ReadPSDImage;
entry->encoder=(EncodeImageHandler *) WritePSDImage;
entry->magick=(IsImageFormatHandler *) IsPSD;
- entry->flags|=CoderSeekableStreamFlag;
+ entry->flags|=CoderDecoderSeekableStreamFlag;
+ entry->flags|=CoderEncoderSeekableStreamFlag;
(void) RegisterMagickInfo(entry);
return(MagickImageCoderSignature);
}
return(WriteBlobMSBLong(image,(unsigned short) offset));
}
+static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
+ const MagickSizeType size,const MagickSizeType offset)
+{
+ MagickSizeType
+ current_offset;
+
+ ssize_t
+ result;
+
+ current_offset=TellBlob(image);
+ SeekBlob(image,offset,SEEK_SET);
+ if (psd_info->version == 1)
+ result=WriteBlobMSBShort(image,(unsigned short) size);
+ else
+ result=(WriteBlobMSBLong(image,(unsigned short) size));
+ SeekBlob(image,current_offset,SEEK_SET);
+ return(result);
+}
+
static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
const MagickSizeType size)
{
return(WriteBlobMSBLongLong(image,size));
}
+static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
+ const MagickSizeType size,const MagickSizeType offset)
+{
+ MagickSizeType
+ current_offset;
+
+ ssize_t
+ result;
+
+ 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);
+ SeekBlob(image,current_offset,SEEK_SET);
+ return(result);
+}
+
static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
const unsigned char *pixels,unsigned char *compact_pixels,
ExceptionInfo *exception)
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(pixels != (unsigned char *) NULL);
+ assert(compact_pixels != (unsigned char *) NULL);
packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
if (packbits == (unsigned char *) NULL)
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
return((size_t) (q-compact_pixels));
}
-static void WritePackbitsLength(const PSDInfo *psd_info,
- const ImageInfo *image_info,Image *image,Image *next_image,
- unsigned char *compact_pixels,const QuantumType quantum_type,
- ExceptionInfo *exception)
+static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
+ const Image *next_image,const ssize_t channels)
{
- QuantumInfo
- *quantum_info;
-
- register const Quantum
- *p;
-
size_t
- length,
- packet_size;
+ length;
ssize_t
+ i,
y;
- unsigned char
- *pixels;
-
- if (next_image->depth > 8)
- next_image->depth=16;
- packet_size=next_image->depth > 8UL ? 2UL : 1UL;
- (void) packet_size;
- quantum_info=AcquireQuantumInfo(image_info,image);
- pixels=(unsigned char *) GetQuantumPixels(quantum_info);
- for (y=0; y < (ssize_t) next_image->rows; y++)
- {
- p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
- if (p == (const Quantum *) NULL)
- break;
- length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
- quantum_type,pixels,exception);
- length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
- exception);
- (void) SetPSDOffset(psd_info,image,length);
- }
- quantum_info=DestroyQuantumInfo(quantum_info);
+ if (next_image->compression == RLECompression)
+ {
+ length=WriteBlobMSBShort(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);
+#endif
+ else
+ length=WriteBlobMSBShort(image,Raw);
+ return(length);
}
-static void WriteOneChannel(const ImageInfo *image_info,Image *image,
- Image *next_image,unsigned char *compact_pixels,
- const QuantumType quantum_type,const MagickBooleanType compression_flag,
+static size_t WritePSDChannel(const PSDInfo *psd_info,
+ const ImageInfo *image_info,Image *image,Image *next_image,
+ const QuantumType quantum_type, unsigned char *compact_pixels,
+ MagickOffsetType size_offset,const MagickBooleanType separate,
ExceptionInfo *exception)
{
int
i;
size_t
- length,
- packet_size;
+ count,
+ length;
unsigned char
*pixels;
- if ((compression_flag != MagickFalse) &&
- (next_image->compression != RLECompression))
- (void) WriteBlobMSBShort(image,0);
+#ifdef MAGICKCORE_ZLIB_DELEGATE
+
+#define CHUNK 16384
+
+ int
+ flush,
+ level;
+
+ unsigned char
+ *compressed_pixels;
+
+ z_stream
+ stream;
+
+ compressed_pixels=(unsigned char *) NULL;
+ flush=Z_NO_FLUSH;
+#endif
+ count=0;
+ if (separate != MagickFalse)
+ {
+ size_offset=TellBlob(image)+2;
+ count+=WriteCompressionStart(psd_info,image,next_image,1);
+ }
if (next_image->depth > 8)
next_image->depth=16;
monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
MagickTrue : MagickFalse;
- packet_size=next_image->depth > 8UL ? 2UL : 1UL;
- (void) packet_size;
- quantum_info=AcquireQuantumInfo(image_info,image);
+ quantum_info=AcquireQuantumInfo(image_info,next_image);
+ if (quantum_info == (QuantumInfo *) NULL)
+ return(0);
pixels=(unsigned char *) GetQuantumPixels(quantum_info);
+#ifdef MAGICKCORE_ZLIB_DELEGATE
+ if (next_image->compression == ZipCompression)
+ {
+ compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
+ sizeof(*compressed_pixels));
+ if (compressed_pixels == (unsigned char *) NULL)
+ {
+ quantum_info=DestroyQuantumInfo(quantum_info);
+ return(0);
+ }
+ ResetMagickMemory(&stream,0,sizeof(stream));
+ stream.data_type=Z_BINARY;
+ level=Z_DEFAULT_COMPRESSION;
+ if ((image_info->quality > 0 && image_info->quality < 10))
+ level=(int) image_info->quality;
+ if (deflateInit(&stream,level) != Z_OK)
+ {
+ quantum_info=DestroyQuantumInfo(quantum_info);
+ return(0);
+ }
+ }
+#endif
for (y=0; y < (ssize_t) next_image->rows; y++)
{
p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
if (monochrome != MagickFalse)
for (i=0; i < (ssize_t) length; i++)
pixels[i]=(~pixels[i]);
- if (next_image->compression != RLECompression)
- (void) WriteBlob(image,length,pixels);
- else
+ if (next_image->compression == RLECompression)
{
length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
exception);
- (void) WriteBlob(image,length,compact_pixels);
+ count+=WriteBlob(image,length,compact_pixels);
+ size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
+ }
+#ifdef MAGICKCORE_ZLIB_DELEGATE
+ else if (next_image->compression == ZipCompression)
+ {
+ stream.avail_in=(uInt) length;
+ stream.next_in=(Bytef *) pixels;
+ if (y == (ssize_t) next_image->rows-1)
+ flush=Z_FINISH;
+ do {
+ stream.avail_out=(uInt) CHUNK;
+ stream.next_out=(Bytef *) compressed_pixels;
+ if (deflate(&stream,flush) == Z_STREAM_ERROR)
+ break;
+ length=(size_t) CHUNK-stream.avail_out;
+ if (length > 0)
+ count+=WriteBlob(image,length,compressed_pixels);
+ } while (stream.avail_out == 0);
}
+#endif
+ else
+ count+=WriteBlob(image,length,pixels);
}
+#ifdef MAGICKCORE_ZLIB_DELEGATE
+ if (next_image->compression == ZipCompression)
+ {
+ (void) deflateEnd(&stream);
+ compressed_pixels=(unsigned char *) RelinquishMagickMemory(
+ compressed_pixels);
+ }
+#endif
quantum_info=DestroyQuantumInfo(quantum_info);
+ return(count);
+}
+
+static unsigned char *AcquireCompactPixels(const Image *image,
+ ExceptionInfo *exception)
+{
+ size_t
+ packet_size;
+
+ unsigned char
+ *compact_pixels;
+
+ packet_size=image->depth > 8UL ? 2UL : 1UL;
+ compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
+ image->columns)+1,packet_size*sizeof(*compact_pixels));
+ if (compact_pixels == (unsigned char *) NULL)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),
+ ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+ }
+ return(compact_pixels);
}
-static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
+static size_t WritePSDChannels(const PSDInfo *psd_info,
const ImageInfo *image_info,Image *image,Image *next_image,
- const MagickBooleanType separate,ExceptionInfo *exception)
+ MagickOffsetType size_offset,const MagickBooleanType separate,
+ ExceptionInfo *exception)
{
+ Image
+ *mask;
+
+ MagickOffsetType
+ rows_offset;
+
size_t
channels,
- packet_size;
+ count,
+ length,
+ offset_length;
unsigned char
*compact_pixels;
- /*
- Write uncompressed pixels as separate planes.
- */
- channels=1;
- packet_size=next_image->depth > 8UL ? 2UL : 1UL;
+ count=0;
+ offset_length=0;
+ rows_offset=0;
compact_pixels=(unsigned char *) NULL;
if (next_image->compression == RLECompression)
{
- compact_pixels=(unsigned char *) AcquireQuantumMemory((9*channels*
- next_image->columns)+1,packet_size*sizeof(*compact_pixels));
+ compact_pixels=AcquireCompactPixels(next_image,exception);
if (compact_pixels == (unsigned char *) NULL)
- ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+ return(0);
}
- if (IsImageGray(next_image) != MagickFalse)
+ channels=1;
+ if (separate == MagickFalse)
{
- if (next_image->compression == RLECompression)
+ if (next_image->storage_class != PseudoClass)
{
- /*
- Packbits compression.
- */
- (void) WriteBlobMSBShort(image,1);
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,GrayQuantum,exception);
+ if (IsImageGray(next_image) == MagickFalse)
+ channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
if (next_image->alpha_trait != UndefinedPixelTrait)
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,AlphaQuantum,exception);
+ channels++;
}
- WriteOneChannel(image_info,image,next_image,compact_pixels,GrayQuantum,
- MagickTrue,exception);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- AlphaQuantum,separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,0,1);
+ rows_offset=TellBlob(image)+2;
+ count+=WriteCompressionStart(psd_info,image,next_image,channels);
+ offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
+ }
+ size_offset+=2;
+ if (next_image->storage_class == PseudoClass)
+ {
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ IndexQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
}
else
- if (next_image->storage_class == PseudoClass)
- {
- if (next_image->compression == RLECompression)
- {
- /*
- Packbits compression.
- */
- (void) WriteBlobMSBShort(image,1);
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,IndexQuantum,exception);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,AlphaQuantum,exception);
- }
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- IndexQuantum,MagickTrue,exception);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- AlphaQuantum,separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,0,1);
- }
- else
- {
- if (next_image->colorspace == CMYKColorspace)
- (void) NegateCMYK(next_image,exception);
- if (next_image->compression == RLECompression)
- {
- /*
- Packbits compression.
- */
- (void) WriteBlobMSBShort(image,1);
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,RedQuantum,exception);
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,GreenQuantum,exception);
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,BlueQuantum,exception);
- if (next_image->colorspace == CMYKColorspace)
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,BlackQuantum,exception);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- WritePackbitsLength(psd_info,image_info,image,next_image,
- compact_pixels,AlphaQuantum,exception);
- }
- (void) SetImageProgress(image,SaveImagesTag,0,6);
- WriteOneChannel(image_info,image,next_image,compact_pixels,RedQuantum,
- MagickTrue,exception);
- (void) SetImageProgress(image,SaveImagesTag,1,6);
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- GreenQuantum,separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,2,6);
- WriteOneChannel(image_info,image,next_image,compact_pixels,BlueQuantum,
- separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,3,6);
- if (next_image->colorspace == CMYKColorspace)
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- BlackQuantum,separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,4,6);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- WriteOneChannel(image_info,image,next_image,compact_pixels,
- AlphaQuantum,separate,exception);
- (void) SetImageProgress(image,SaveImagesTag,5,6);
- if (next_image->colorspace == CMYKColorspace)
- (void) NegateCMYK(next_image,exception);
- }
- if (next_image->compression == RLECompression)
- compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
- return(MagickTrue);
+ {
+ if (IsImageGray(next_image) != MagickFalse)
+ {
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ GrayQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+ }
+ else
+ {
+ if (next_image->colorspace == CMYKColorspace)
+ (void) NegateCMYK(next_image,exception);
+
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ RedQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ GreenQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ BlueQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+
+ if (next_image->colorspace == CMYKColorspace)
+ {
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ BlackQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+ }
+ }
+ if (next_image->alpha_trait != UndefinedPixelTrait)
+ {
+ length=WritePSDChannel(psd_info,image_info,image,next_image,
+ AlphaQuantum,compact_pixels,rows_offset,separate,exception);
+ if (separate != MagickFalse)
+ size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+ else
+ rows_offset+=offset_length;
+ count+=length;
+ }
+ }
+ compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
+ if (next_image->colorspace == CMYKColorspace)
+ (void) NegateCMYK(next_image,exception);
+ if (separate != MagickFalse)
+ {
+ const char
+ *property;
+
+ property=GetImageArtifact(next_image,"psd:opacity-mask");
+ if (property != (const char *) NULL)
+ {
+ mask=(Image *) GetImageRegistry(ImageRegistryType,property,
+ exception);
+ if (mask != (Image *) NULL)
+ {
+ if (mask->compression == RLECompression)
+ {
+ compact_pixels=AcquireCompactPixels(mask,exception);
+ if (compact_pixels == (unsigned char *) NULL)
+ return(0);
+ }
+ length=WritePSDChannel(psd_info,image_info,image,mask,
+ RedQuantum,compact_pixels,rows_offset,MagickTrue,exception);
+ (void) WritePSDSize(psd_info,image,length,size_offset);
+ count+=length;
+ compact_pixels=(unsigned char *) RelinquishMagickMemory(
+ compact_pixels);
+ }
+ }
+ }
+ return(count);
}
-static void WritePascalString(Image* inImage,const char *inString,int inPad)
+static size_t WritePascalString(Image *image,const char *value,size_t padding)
{
size_t
+ count,
length;
register ssize_t
/*
Max length is 255.
*/
- length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
+ count=0;
+ length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
if (length == 0)
- (void) WriteBlobByte(inImage,0);
+ count+=WriteBlobByte(image,0);
else
{
- (void) WriteBlobByte(inImage,(unsigned char) length);
- (void) WriteBlob(inImage, length, (const unsigned char *) inString);
+ count+=WriteBlobByte(image,(unsigned char) length);
+ count+=WriteBlob(image,length,(const unsigned char *) value);
}
length++;
- if ((length % inPad) == 0)
- return;
- for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
- (void) WriteBlobByte(inImage,0);
+ if ((length % padding) == 0)
+ return(count);
+ for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
+ count+=WriteBlobByte(image,0);
+ return(count);
}
static void WriteResolutionResourceBlock(Image *image)
(void) WriteBlobMSBShort(image,units); /* height unit */
}
+static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
+ const signed short channel)
+{
+ size_t
+ count;
+
+ count=WriteBlobMSBSignedShort(image,channel);
+ count+=SetPSDSize(psd_info,image,0);
+ return(count);
+}
+
static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
{
register const unsigned char
quantum;
quantum=PSDQuantum(count)+12;
- if ((quantum >= 12) && (quantum < length))
+ if ((quantum >= 12) && (quantum < (ssize_t) length))
{
if ((q+quantum < (datum+length-16)))
(void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
unsigned int
size;
- info=GetImageProfile(image,PSDAdditionalInfo);
+ info=GetImageProfile(image,"psd:additional-info");
if (info == (const StringInfo *) NULL)
return((const StringInfo *) NULL);
option=GetImageOption(image_info,"psd:additional-info");
return(info);
if (LocaleCompare(option,"selective") != 0)
{
- profile=RemoveImageProfile(image,PSDAdditionalInfo);
+ profile=RemoveImageProfile(image,"psd:additional-info");
return(DestroyStringInfo(profile));
}
length=GetStringInfoLength(info);
}
remaining_length-=(size_t) size;
if (found == MagickFalse)
- {
- if (remaining_length > 0)
- p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
- continue;
- }
+ {
+ if (remaining_length > 0)
+ p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
+ continue;
+ }
length+=(size_t) size+12;
p+=size;
}
- profile=RemoveImageProfile(image,PSDAdditionalInfo);
+ profile=RemoveImageProfile(image,"psd:additional-info");
if (length == 0)
return(DestroyStringInfo(profile));
SetStringInfoLength(profile,(const size_t) length);
- SetImageProfile(image,PSDAdditionalInfo,info,exception);
+ SetImageProfile(image,"psd:additional-info",info,exception);
return(profile);
}
MagickBooleanType
status;
+ MagickOffsetType
+ *layer_size_offsets,
+ size_offset;
+
PSDInfo
psd_info;
i;
size_t
- channel_size,
- channelLength,
layer_count,
- layer_info_size,
+ layer_index,
length,
name_length,
num_channels,
packet_size,
- rounded_layer_info_size;
+ rounded_size,
+ size;
StringInfo
*bim_profile;
(void) WriteBlobMSBShort(image,psd_info.version); /* version */
for (i=1; i <= 6; i++)
(void) WriteBlobByte(image, 0); /* 6 bytes of reserved */
- if (SetImageGray(image,exception) != MagickFalse)
+ /* When the image has a color profile it won't be converted to gray scale */
+ if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
+ (SetImageGray(image,exception) != MagickFalse))
num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
else
if ((image_info->type != TrueColorType) && (image_info->type !=
PSDQuantum(GetStringInfoLength(icc_profile)))
(void) WriteBlobByte(image,0);
}
- layer_count=0;
- layer_info_size=2;
base_image=GetNextImageInList(image);
if (base_image == (Image *) NULL)
base_image=image;
- next_image=base_image;
- while (next_image != (Image *) NULL)
+ 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; )
{
- packet_size=next_image->depth > 8 ? 2UL : 1UL;
- if (IsImageGray(next_image) != MagickFalse)
- num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
+ 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+=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
- if (next_image->storage_class == PseudoClass)
- num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
- else
- if (next_image->colorspace != CMYKColorspace)
- num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
- else
- num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
- channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
- layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
- 16)+4*1+4+num_channels*channelLength);
+ 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_count+1);
+ (double) layer_index);
property=layer_name;
}
name_length=strlen(property)+1;
if ((name_length % 4) != 0)
name_length+=(4-(name_length % 4));
- layer_info_size+=8+name_length;
- info=GetAdditionalInformation(image_info,next_image,exception);
if (info != (const StringInfo *) NULL)
- layer_info_size+=GetStringInfoLength(info);
- layer_count++;
- next_image=GetNextImageInList(next_image);
- }
- if (layer_count == 0)
- (void) SetPSDSize(&psd_info,image,0);
- else
- {
- CompressionType
- compression;
-
- (void) SetPSDSize(&psd_info,image,layer_info_size+
- (psd_info.version == 1 ? 8 : 16));
- if ((layer_info_size/2) != ((layer_info_size+1)/2))
- rounded_layer_info_size=layer_info_size+1;
- else
- rounded_layer_info_size=layer_info_size;
- (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
- if (image->alpha_trait != UndefinedPixelTrait)
- (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
- else
- (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
- layer_count=1;
- compression=base_image->compression;
- for (next_image=base_image; next_image != 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
{
- next_image->compression=NoCompression;
- (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
- (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
- (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
- next_image->rows));
- (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
- next_image->columns));
- packet_size=next_image->depth > 8 ? 2UL : 1UL;
- channel_size=(unsigned int) ((packet_size*next_image->rows*
- next_image->columns)+2);
- if ((IsImageGray(next_image) != MagickFalse) ||
- (next_image->storage_class == PseudoClass))
- {
- (void) WriteBlobMSBShort(image,(unsigned short)
- (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
- (void) WriteBlobMSBShort(image,0);
- (void) SetPSDSize(&psd_info,image,channel_size);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- {
- (void) WriteBlobMSBShort(image,(unsigned short) -1);
- (void) SetPSDSize(&psd_info,image,channel_size);
- }
- }
- else
- if (next_image->colorspace != CMYKColorspace)
- {
- (void) WriteBlobMSBShort(image,(unsigned short)
- (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
- (void) WriteBlobMSBShort(image,0);
- (void) SetPSDSize(&psd_info,image,channel_size);
- (void) WriteBlobMSBShort(image,1);
- (void) SetPSDSize(&psd_info,image,channel_size);
- (void) WriteBlobMSBShort(image,2);
- (void) SetPSDSize(&psd_info,image,channel_size);
- if (next_image->alpha_trait != UndefinedPixelTrait)
- {
- (void) WriteBlobMSBShort(image,(unsigned short) -1);
- (void) SetPSDSize(&psd_info,image,channel_size);
- }
- }
- else
- {
- (void) WriteBlobMSBShort(image,(unsigned short)
- (next_image->alpha_trait ? 5 : 4));
- (void) WriteBlobMSBShort(image,0);
- (void) SetPSDSize(&psd_info,image,channel_size);
- (void) WriteBlobMSBShort(image,1);
- (void) SetPSDSize(&psd_info,image,channel_size);
- (void) WriteBlobMSBShort(image,2);
- (void) SetPSDSize(&psd_info,image,channel_size);
- (void) WriteBlobMSBShort(image,3);
- (void) SetPSDSize(&psd_info,image,channel_size);
- if (next_image->alpha_trait)
- {
- (void) WriteBlobMSBShort(image,(unsigned short) -1);
- (void) SetPSDSize(&psd_info,image,channel_size);
- }
- }
- (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
- (void) WriteBlob(image,4,(const unsigned char *)
- CompositeOperatorToPSDBlendMode(next_image->compose));
- (void) WriteBlobByte(image,255); /* layer opacity */
- (void) WriteBlobByte(image,0);
- (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
- 1 << 0x02 : 1); /* layer properties - visible, etc. */
- (void) WriteBlobByte(image,0);
- info=GetImageProfile(next_image,PSDAdditionalInfo);
- property=(const char *) GetImageProperty(next_image,"label",exception);
- if (property == (const char *) NULL)
- {
- (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
- (double) layer_count++);
- 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);
- (void) WriteBlobMSBLong(image,(unsigned int)name_length+8);
- (void) WriteBlobMSBLong(image,0);
- (void) WriteBlobMSBLong(image,0);
- WritePascalString(image,property,4);
- if (info != (const StringInfo *) NULL)
- (void) WriteBlob(image,GetStringInfoLength(info),GetStringInfoDatum(info));
- next_image=GetNextImageInList(next_image);
+ 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+=WriteBlobMSBLong(image,(const unsigned int) mask->rows+
+ mask->page.y);
+ size+=WriteBlobMSBLong(image,(const unsigned int) mask->columns+
+ mask->page.x);
+ size+=WriteBlobByte(image,default_color);
+ size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
+ size+=WriteBlobMSBShort(image,0);
}
- /*
- Now the image data!
- */
- next_image=base_image;
- while (next_image != NULL)
+ 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=WriteImageChannels(&psd_info,image_info,image,next_image,
- MagickTrue,exception);
- next_image=GetNextImageInList(next_image);
+ status=MagickFalse;
+ break;
}
- (void) WriteBlobMSBLong(image,0); /* user mask data */
- base_image->compression=compression;
- }
+ size+=length;
+ next_image=GetNextImageInList(next_image);
+ }
+ (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.
*/
if (status != MagickFalse)
- status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
- exception);
+ {
+ CompressionType
+ compression;
+
+ compression=image->compression;
+ if (image->compression == ZipCompression)
+ image->compression=RLECompression;
+ if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
+ exception) == 0)
+ status=MagickFalse;
+ image->compression=compression;
+ }
(void) CloseBlob(image);
return(status);
}