% MagickCore Image Profile Methods %
% %
% Software Design %
-% John Cristy %
+% Cristy %
% July 1992 %
% %
% %
-% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2014 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 %
#define cmsOpenProfileFromMemTHR(context,profile,length) \
cmsOpenProfileFromMem(profile,length)
#endif
+
+/*
+ Forward declarations
+*/
+static MagickBooleanType
+ SetImageProfileInternal(Image *,const char *,const StringInfo *,
+ const MagickBooleanType,ExceptionInfo *);
+
+static void
+ WriteTo8BimProfile(Image *,const char*,const StringInfo *);
\f
/*
Typedef declarations
assert(clone_image != (const Image *) NULL);
assert(clone_image->signature == MagickSignature);
if (clone_image->profiles != (void *) NULL)
- image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
- (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
+ {
+ if (image->profiles != (void *) NULL)
+ DestroyImageProfiles(image);
+ image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
+ (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
+ }
return(MagickTrue);
}
\f
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
if (image->profiles == (SplayTreeInfo *) NULL)
return(MagickFalse);
+ WriteTo8BimProfile(image,name,(StringInfo *) NULL);
return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
}
\f
(void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
for (i=0; i < (ssize_t) number_threads; i++)
{
- transform[i]=cmsCreateTransformTHR(image,source_profile,source_type,
- target_profile,target_type,intent,flags);
+ transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
+ source_type,target_profile,target_type,intent,flags);
if (transform[i] == (cmsHTRANSFORM) NULL)
return(DestroyTransformThreadSet(transform));
}
cms_exception.image=image;
cms_exception.exception=exception;
(void) cms_exception;
- source_profile=cmsOpenProfileFromMemTHR(&cms_exception,
+ source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
GetStringInfoDatum(profile),(cmsUInt32Number)
GetStringInfoLength(profile));
if (source_profile == (cmsHPROFILE) NULL)
if (icc_profile != (StringInfo *) NULL)
{
target_profile=source_profile;
- source_profile=cmsOpenProfileFromMemTHR(&cms_exception,
- GetStringInfoDatum(icc_profile),(cmsUInt32Number)
- GetStringInfoLength(icc_profile));
+ source_profile=cmsOpenProfileFromMemTHR((cmsContext)
+ &cms_exception,GetStringInfoDatum(icc_profile),
+ (cmsUInt32Number) GetStringInfoLength(icc_profile));
if (source_profile == (cmsHPROFILE) NULL)
ThrowProfileException(ResourceLimitError,
"ColorspaceColorProfileMismatch",name);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
if (image->profiles == (SplayTreeInfo *) NULL)
return((StringInfo *) NULL);
+ WriteTo8BimProfile(image,name,(StringInfo *) NULL);
profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
image->profiles,name);
return(profile);
}
static inline const unsigned char *ReadResourceLong(const unsigned char *p,
- size_t *quantum)
+ unsigned int *quantum)
{
*quantum=(size_t) (*p++ << 24);
*quantum|=(size_t) (*p++ << 16);
*quantum=(unsigned short) (*p++ << 8);
*quantum|=(unsigned short) (*p++ << 0);
return(p);
+}static inline void WriteResourceLong(unsigned char *p,
+ const unsigned int quantum)
+{
+ unsigned char
+ buffer[4];
+
+ buffer[0]=(unsigned char) (quantum >> 24);
+ buffer[1]=(unsigned char) (quantum >> 16);
+ buffer[2]=(unsigned char) (quantum >> 8);
+ buffer[3]=(unsigned char) quantum;
+ (void) CopyMagickMemory(p,buffer,4);
}
-static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
+static void WriteTo8BimProfile(Image *image,const char *name,
+ const StringInfo *profile)
+{
+
+ const unsigned char
+ *datum,
+ *s;
+
+ register const unsigned char
+ *p;
+
+ size_t
+ length;
+
+ StringInfo
+ *profile_8bim;
+
+ ssize_t
+ count;
+
+ unsigned char
+ length_byte;
+
+ unsigned int
+ value;
+
+ unsigned short
+ id,
+ profile_id;
+
+ if (LocaleCompare(name,"icc") == 0)
+ profile_id=0x040f;
+ else if (LocaleCompare(name,"iptc") == 0)
+ profile_id=0x0404;
+ else if (LocaleCompare(name,"xmp") == 0)
+ profile_id=0x0424;
+ else
+ return;
+ profile_8bim=(StringInfo *)GetValueFromSplayTree((SplayTreeInfo *)
+ image->profiles,"8bim");
+ if (profile_8bim == (StringInfo *) NULL)
+ return;
+ datum=GetStringInfoDatum(profile_8bim);
+ length=GetStringInfoLength(profile_8bim);
+ for (p=datum; p < (datum+length-16); )
+ {
+ s=p;
+ if (LocaleNCompare((char *) p,"8BIM",4) != 0)
+ break;
+ p+=4;
+ p=ReadResourceShort(p,&id);
+ p=ReadResourceByte(p,&length_byte);
+ p+=length_byte;
+ if (((length_byte+1) & 0x01) != 0)
+ p++;
+ if (p > (datum+length-4))
+ break;
+ p=ReadResourceLong(p,&value);
+ count=(ssize_t) value;
+ if ((p > (datum+length-count)) || (count > length))
+ break;
+ if ((count & 0x01) != 0)
+ count++;
+ if (id == profile_id)
+ {
+ size_t
+ offset,
+ rest;
+
+ ssize_t
+ new_count;
+
+ StringInfo
+ *new_profile;
+
+ new_count=0;
+ rest=(datum+length)-(p+count);
+ if (profile == (StringInfo *) NULL)
+ {
+ offset=(s-datum);
+ new_profile=AcquireStringInfo(offset+rest);
+ (void) CopyMagickMemory(new_profile->datum,datum,offset);
+ }
+ else
+ {
+ offset=(p-datum);
+ new_count=profile->length;
+ if ((new_count & 0x01) != 0)
+ new_count++;
+ new_profile=AcquireStringInfo(offset+new_count+rest);
+ (void) CopyMagickMemory(new_profile->datum,datum,offset-4);
+ WriteResourceLong(new_profile->datum+offset-4,profile->length);
+ (void) CopyMagickMemory(new_profile->datum+offset,profile->datum,
+ profile->length);
+ }
+ (void) CopyMagickMemory(new_profile->datum+offset+new_count,p+count,
+ rest);
+ (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
+ ConstantString("8bim"),CloneStringInfo(new_profile));
+ new_profile=DestroyStringInfo(new_profile);
+ break;
+ }
+ else
+ p+=count;
+ }
+}
+
+static void GetProfilesFromResourceBlock(Image *image,
const StringInfo *resource_block,ExceptionInfo *exception)
{
const unsigned char
size_t
length;
+ ssize_t
+ count;
+
StringInfo
*profile;
unsigned char
length_byte;
- size_t
- count;
+ unsigned int
+ value;
unsigned short
id;
p++;
if (p > (datum+length-4))
break;
- p=ReadResourceLong(p,&count);
+ p=ReadResourceLong(p,&value);
+ count=(ssize_t) value;
if ((p > (datum+length-count)) || (count > length))
break;
switch (id)
{
case 0x03ed:
{
- unsigned short
+ unsigned int
resolution;
+ unsigned short
+ units;
+
/*
Resolution.
*/
- p=ReadResourceShort(p,&resolution)+6;
- image->resolution.x=(double) resolution;
- p=ReadResourceShort(p,&resolution)+6;
- image->resolution.y=(double) resolution;
+ p=ReadResourceLong(p,&resolution);
+ image->resolution.x=((double) resolution)/65536.0;
+ p=ReadResourceShort(p,&units)+2;
+ p=ReadResourceLong(p,&resolution)+4;
+ image->resolution.y=((double) resolution)/65536.0;
+ /*
+ Values are always stored as pixels per inch.
+ */
+ if ((ResolutionType) units != PixelsPerCentimeterResolution)
+ image->units=PixelsPerInchResolution;
+ else
+ {
+ image->units=PixelsPerCentimeterResolution;
+ image->resolution.x/=2.54;
+ image->resolution.y/=2.54;
+ }
break;
}
case 0x0404:
*/
profile=AcquireStringInfo(count);
SetStringInfoDatum(profile,p);
- (void) SetImageProfile(image,"iptc",profile,exception);
+ (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
+ exception);
profile=DestroyStringInfo(profile);
p+=count;
break;
*/
profile=AcquireStringInfo(count);
SetStringInfoDatum(profile,p);
- (void) SetImageProfile(image,"icc",profile,exception);
+ (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
+ exception);
profile=DestroyStringInfo(profile);
p+=count;
break;
*/
profile=AcquireStringInfo(count);
SetStringInfoDatum(profile,p);
- (void) SetImageProfile(image,"exif",profile,exception);
+ (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
+ exception);
profile=DestroyStringInfo(profile);
p+=count;
break;
*/
profile=AcquireStringInfo(count);
SetStringInfoDatum(profile,p);
- (void) SetImageProfile(image,"xmp",profile,exception);
+ (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
+ exception);
profile=DestroyStringInfo(profile);
p+=count;
break;
if ((count & 0x01) != 0)
p++;
}
- return(MagickTrue);
}
-MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
- const StringInfo *profile,ExceptionInfo *exception)
+static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
+ const StringInfo *profile,const MagickBooleanType recursive,
+ ExceptionInfo *exception)
{
char
key[MaxTextExtent],
image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
DestroyProfile);
(void) CopyMagickString(key,name,MaxTextExtent);
+ LocaleLower(key);
status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
ConstantString(key),CloneStringInfo(profile));
- if ((status != MagickFalse) &&
- ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
- (void) GetProfilesFromResourceBlock(image,profile,exception);
+ if (status != MagickFalse)
+ {
+ if (LocaleCompare(name,"8bim") == 0)
+ GetProfilesFromResourceBlock(image,profile,exception);
+ else if (recursive == MagickFalse)
+ WriteTo8BimProfile(image,name,profile);
+ }
/*
Inject profile into image properties.
*/
- (void) FormatLocaleString(property,MaxTextExtent,"%s:sans",name);
+ (void) FormatLocaleString(property,MaxTextExtent,"%s:*",name);
(void) GetImageProperty(image,property,exception);
return(status);
}
+
+MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
+ const StringInfo *profile,ExceptionInfo *exception)
+{
+ return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
+}
\f
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
return((size_t) (value & 0xffffffff));
}
+static inline size_t ReadProfileMSBLong(unsigned char **p,
+ size_t *length)
+{
+ size_t
+ value;
+
+ if (*length < 4)
+ return(0);
+
+ value=ReadProfileLong(MSBEndian,*p);
+ (*length)-=4;
+ *p+=4;
+ return(value);
+}
+
+static inline unsigned short ReadProfileMSBShort(unsigned char **p,
+ size_t *length)
+{
+ unsigned short
+ value;
+
+ if (*length < 2)
+ return(0);
+
+ value=ReadProfileShort(MSBEndian,*p);
+ (*length)-=2;
+ *p+=2;
+ return(value);
+}
+
static inline void WriteProfileLong(const EndianType endian,
const size_t value,unsigned char *p)
{
(void) CopyMagickMemory(p,buffer,2);
}
-MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
+static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
+{
+ size_t
+ count,
+ length;
+
+ unsigned char
+ *p;
+
+ unsigned short
+ id;
+
+ length=GetStringInfoLength(profile);
+ p=GetStringInfoDatum(profile);
+ while(length != 0)
+ {
+ if (ReadProfileByte(&p,&length) != 0x38)
+ continue;
+ if (ReadProfileByte(&p,&length) != 0x42)
+ continue;
+ if (ReadProfileByte(&p,&length) != 0x49)
+ continue;
+ if (ReadProfileByte(&p,&length) != 0x4D)
+ continue;
+ if (length < 7)
+ return(MagickFalse);
+ id=ReadProfileMSBShort(&p,&length);
+ count=ReadProfileByte(&p,&length);
+ if (count > length)
+ return(MagickFalse);
+ p+=count;
+ if ((*p & 0x01) == 0)
+ p++;
+ count=ReadProfileMSBLong(&p,&length);
+ if (count > length)
+ return(MagickFalse);
+ if (id == 0x3ED && count == 16)
+ {
+ if (image->units == PixelsPerCentimeterResolution)
+ WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*2.54*
+ 65536.0),p);
+ else
+ WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*
+ 65536.0),p);
+ WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
+ if (image->units == PixelsPerCentimeterResolution)
+ WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*2.54*
+ 65536.0),p+8);
+ else
+ WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*
+ 65536.0),p+8);
+ WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
+ }
+ p+=count;
+ length-=count;
+ }
+ return(MagickTrue);
+}
+
+MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
{
#define MaxDirectoryStack 16
#define EXIF_DELIMITER "\n"
static int
format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
- StringInfo
- *profile;
-
unsigned char
*directory,
*exif;
/*
Set EXIF resolution tag.
*/
- profile=(StringInfo *) GetImageProfile(image,"EXIF");
- if (profile == (StringInfo *) NULL)
- return(MagickTrue);
length=GetStringInfoLength(profile);
exif=GetStringInfoDatum(profile);
- while (length != 0)
- {
- if (ReadProfileByte(&exif,&length) != 0x45)
- continue;
- if (ReadProfileByte(&exif,&length) != 0x78)
- continue;
- if (ReadProfileByte(&exif,&length) != 0x69)
- continue;
- if (ReadProfileByte(&exif,&length) != 0x66)
- continue;
- if (ReadProfileByte(&exif,&length) != 0x00)
- continue;
- if (ReadProfileByte(&exif,&length) != 0x00)
- continue;
- break;
- }
if (length < 16)
return(MagickFalse);
id=(ssize_t) ReadProfileShort(LSBEndian,exif);
+ if ((id != 0x4949) && (id != 0x4D4D))
+ {
+ while (length != 0)
+ {
+ if (ReadProfileByte(&exif,&length) != 0x45)
+ continue;
+ if (ReadProfileByte(&exif,&length) != 0x78)
+ continue;
+ if (ReadProfileByte(&exif,&length) != 0x69)
+ continue;
+ if (ReadProfileByte(&exif,&length) != 0x66)
+ continue;
+ if (ReadProfileByte(&exif,&length) != 0x00)
+ continue;
+ if (ReadProfileByte(&exif,&length) != 0x00)
+ continue;
+ break;
+ }
+ if (length < 16)
+ return(MagickFalse);
+ id=(ssize_t) ReadProfileShort(LSBEndian,exif);
+ }
endian=LSBEndian;
if (id == 0x4949)
endian=LSBEndian;
} while (level > 0);
return(MagickTrue);
}
+
+MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
+{
+ MagickBooleanType
+ status;
+
+ StringInfo
+ *profile;
+
+ status=MagickTrue;
+ profile=(StringInfo *) GetImageProfile(image,"8BIM");
+ if (profile != (StringInfo *) NULL)
+ if (Sync8BimProfile(image,profile) == MagickFalse)
+ status=MagickFalse;
+ profile=(StringInfo *) GetImageProfile(image,"EXIF");
+ if (profile != (StringInfo *) NULL)
+ if (SyncExifProfile(image,profile) == MagickFalse)
+ status=MagickFalse;
+ return(status);
+}