|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% M M EEEEE TTTTT AAA %
|
|
|
% MM MM E T A A %
|
|
|
% M M M EEE T AAAAA %
|
|
|
% M M E T A A %
|
|
|
% M M EEEEE T A A %
|
|
|
% %
|
|
|
% %
|
|
|
% Read/Write Embedded Image Profiles. %
|
|
|
% %
|
|
|
% Software Design %
|
|
|
% William Radcliffe %
|
|
|
% July 2001 %
|
|
|
% %
|
|
|
% %
|
|
|
% Copyright 1999-2021 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 %
|
|
|
% %
|
|
|
% https://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, %
|
|
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
|
|
|
% See the License for the specific language governing permissions and %
|
|
|
% limitations under the License. %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
Include declarations.
|
|
|
*/
|
|
|
#include "MagickCore/studio.h"
|
|
|
#include "MagickCore/blob.h"
|
|
|
#include "MagickCore/blob-private.h"
|
|
|
#include "MagickCore/channel.h"
|
|
|
#include "MagickCore/exception.h"
|
|
|
#include "MagickCore/exception-private.h"
|
|
|
#include "MagickCore/image.h"
|
|
|
#include "MagickCore/image-private.h"
|
|
|
#include "MagickCore/list.h"
|
|
|
#include "MagickCore/magick.h"
|
|
|
#include "MagickCore/memory_.h"
|
|
|
#include "MagickCore/module.h"
|
|
|
#include "MagickCore/profile.h"
|
|
|
#include "MagickCore/splay-tree.h"
|
|
|
#include "MagickCore/quantum-private.h"
|
|
|
#include "MagickCore/static.h"
|
|
|
#include "MagickCore/string_.h"
|
|
|
#include "MagickCore/string-private.h"
|
|
|
#include "MagickCore/token.h"
|
|
|
#include "MagickCore/utility.h"
|
|
|
|
|
|
/*
|
|
|
Forward declarations.
|
|
|
*/
|
|
|
static MagickBooleanType
|
|
|
WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *);
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% I s M E T A %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% IsMETA() returns MagickTrue if the image format type, identified by the
|
|
|
% magick string, is META.
|
|
|
%
|
|
|
% The format of the IsMETA method is:
|
|
|
%
|
|
|
% MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o magick: compare image format pattern against these bytes.
|
|
|
%
|
|
|
% o length: Specifies the length of the magick string.
|
|
|
%
|
|
|
%
|
|
|
*/
|
|
|
#ifdef IMPLEMENT_IS_FUNCTION
|
|
|
static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
|
|
|
{
|
|
|
if (length < 4)
|
|
|
return(MagickFalse);
|
|
|
if (LocaleNCompare((char *) magick,"8BIM",4) == 0)
|
|
|
return(MagickTrue);
|
|
|
if (LocaleNCompare((char *) magick,"APP1",4) == 0)
|
|
|
return(MagickTrue);
|
|
|
if (LocaleNCompare((char *) magick,"\034\002",2) == 0)
|
|
|
return(MagickTrue);
|
|
|
return(MagickFalse);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% R e a d M E T A I m a g e %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% ReadMETAImage() reads a META image file and returns it. It
|
|
|
% allocates the memory necessary for the new Image structure and returns a
|
|
|
% pointer to the new image.
|
|
|
%
|
|
|
% The format of the ReadMETAImage method is:
|
|
|
%
|
|
|
% Image *ReadMETAImage(const ImageInfo *image_info,
|
|
|
% ExceptionInfo *exception)
|
|
|
%
|
|
|
% Decompression code contributed by Kyle Shorter.
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o image: Method ReadMETAImage returns a pointer to the image after
|
|
|
% reading. A null image is returned if there is a memory shortage or
|
|
|
% if the image cannot be read.
|
|
|
%
|
|
|
% o image_info: Specifies a pointer to an ImageInfo structure.
|
|
|
%
|
|
|
% o exception: return any errors or warnings in this structure.
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
static const struct
|
|
|
{
|
|
|
const unsigned char
|
|
|
len;
|
|
|
|
|
|
const char
|
|
|
code[7],
|
|
|
val;
|
|
|
} html_codes[] = {
|
|
|
#ifdef HANDLE_GT_LT
|
|
|
{ 4,"<",'<' },
|
|
|
{ 4,">",'>' },
|
|
|
#endif
|
|
|
{ 5,"&",'&' },
|
|
|
{ 6,""",'"' },
|
|
|
{ 6,"'",'\''}
|
|
|
};
|
|
|
|
|
|
static int stringnicmp(const char *p,const char *q,size_t n)
|
|
|
{
|
|
|
ssize_t
|
|
|
i,
|
|
|
j;
|
|
|
|
|
|
if (p == q)
|
|
|
return(0);
|
|
|
if (p == (char *) NULL)
|
|
|
return(-1);
|
|
|
if (q == (char *) NULL)
|
|
|
return(1);
|
|
|
while ((*p != '\0') && (*q != '\0'))
|
|
|
{
|
|
|
if ((*p == '\0') || (*q == '\0'))
|
|
|
break;
|
|
|
i=(*p);
|
|
|
if (islower((int) ((unsigned char) i)) != 0)
|
|
|
i=LocaleUppercase(i);
|
|
|
j=(*q);
|
|
|
if (islower((int) ((unsigned char) j)) != 0)
|
|
|
j=LocaleUppercase(j);
|
|
|
if (i != j)
|
|
|
break;
|
|
|
n--;
|
|
|
if (n == 0)
|
|
|
break;
|
|
|
p++;
|
|
|
q++;
|
|
|
}
|
|
|
return(LocaleUppercase((int) *p)-LocaleUppercase((int) *q));
|
|
|
}
|
|
|
|
|
|
static size_t convertHTMLcodes(char *s)
|
|
|
{
|
|
|
int
|
|
|
value;
|
|
|
|
|
|
size_t
|
|
|
i;
|
|
|
|
|
|
size_t
|
|
|
length;
|
|
|
|
|
|
length=0;
|
|
|
for (i=0; (i < 7U) && (s[i] != '\0'); i++)
|
|
|
if (s[i] == ';')
|
|
|
{
|
|
|
length=i+1;
|
|
|
break;
|
|
|
}
|
|
|
if ((length == 0) || (s == (char *) NULL) || (*s == '\0'))
|
|
|
return(0);
|
|
|
if ((length > 3) && (s[1] == '#') && (sscanf(s,"&#%d;",&value) == 1))
|
|
|
{
|
|
|
size_t
|
|
|
o;
|
|
|
|
|
|
o=3;
|
|
|
while (s[o] != ';')
|
|
|
{
|
|
|
o++;
|
|
|
if (o > 5)
|
|
|
break;
|
|
|
}
|
|
|
if (o < 6)
|
|
|
(void) memmove(s+1,s+1+o,strlen(s+1+o)+1);
|
|
|
*s=value;
|
|
|
return(o);
|
|
|
}
|
|
|
for (i=0; i < (ssize_t) (sizeof(html_codes)/sizeof(html_codes[0])); i++)
|
|
|
{
|
|
|
if (html_codes[i].len <= (ssize_t) length)
|
|
|
if (stringnicmp(s,html_codes[i].code,(size_t) (html_codes[i].len)) == 0)
|
|
|
{
|
|
|
(void) memmove(s+1,s+html_codes[i].len,strlen(s+html_codes[i].len)+1);
|
|
|
*s=html_codes[i].val;
|
|
|
return(html_codes[i].len-1);
|
|
|
}
|
|
|
}
|
|
|
return(0);
|
|
|
}
|
|
|
|
|
|
static char *super_fgets(char **b, size_t *blen, Image *file)
|
|
|
{
|
|
|
int
|
|
|
c;
|
|
|
|
|
|
size_t
|
|
|
len;
|
|
|
|
|
|
unsigned char
|
|
|
*p,
|
|
|
*q;
|
|
|
|
|
|
len=*blen;
|
|
|
p=(unsigned char *) (*b);
|
|
|
for (q=p; ; q++)
|
|
|
{
|
|
|
c=ReadBlobByte(file);
|
|
|
if (c == EOF || c == '\n')
|
|
|
break;
|
|
|
if ((size_t) (q-p+1) >= len)
|
|
|
{
|
|
|
size_t
|
|
|
tlen;
|
|
|
|
|
|
unsigned char
|
|
|
*buffer;
|
|
|
|
|
|
tlen=(size_t) (q-p);
|
|
|
len<<=1;
|
|
|
buffer=(unsigned char *) ResizeQuantumMemory(p,len+2UL,sizeof(*p));
|
|
|
if (buffer == (unsigned char *) NULL)
|
|
|
{
|
|
|
p=(unsigned char *) RelinquishMagickMemory(p);
|
|
|
break;
|
|
|
}
|
|
|
p=buffer;
|
|
|
q=p+tlen;
|
|
|
}
|
|
|
*q=(unsigned char) c;
|
|
|
}
|
|
|
*b=(char *) p;
|
|
|
*blen=0;
|
|
|
if (p != (unsigned char *) NULL)
|
|
|
{
|
|
|
size_t
|
|
|
tlen;
|
|
|
|
|
|
tlen=(size_t) (q-p);
|
|
|
if (tlen == 0)
|
|
|
return (char *) NULL;
|
|
|
p[tlen] = '\0';
|
|
|
*blen=++tlen;
|
|
|
}
|
|
|
return(*b);
|
|
|
}
|
|
|
|
|
|
#define IPTC_ID 1028
|
|
|
#define THUMBNAIL_ID 1033
|
|
|
|
|
|
static ssize_t parse8BIM(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
char
|
|
|
brkused,
|
|
|
quoted,
|
|
|
*line,
|
|
|
*token,
|
|
|
*newstr,
|
|
|
*name;
|
|
|
|
|
|
int
|
|
|
state,
|
|
|
next;
|
|
|
|
|
|
unsigned char
|
|
|
dataset;
|
|
|
|
|
|
unsigned int
|
|
|
recnum;
|
|
|
|
|
|
MagickOffsetType
|
|
|
savedpos,
|
|
|
currentpos;
|
|
|
|
|
|
size_t
|
|
|
inputlen = MagickPathExtent;
|
|
|
|
|
|
ssize_t
|
|
|
savedolen = 0L,
|
|
|
outputlen = 0L;
|
|
|
|
|
|
TokenInfo
|
|
|
*token_info;
|
|
|
|
|
|
dataset = 0;
|
|
|
recnum = 0;
|
|
|
line = (char *) AcquireQuantumMemory(inputlen,sizeof(*line));
|
|
|
if (line == (char *) NULL)
|
|
|
return(-1);
|
|
|
newstr = name = token = (char *) NULL;
|
|
|
savedpos = 0;
|
|
|
token_info=AcquireTokenInfo();
|
|
|
while (super_fgets(&line,&inputlen,ifile)!=NULL)
|
|
|
{
|
|
|
state=0;
|
|
|
next=0;
|
|
|
|
|
|
token=(char *) AcquireQuantumMemory(inputlen,sizeof(*token));
|
|
|
if (token == (char *) NULL)
|
|
|
break;
|
|
|
newstr=(char *) AcquireQuantumMemory(inputlen,sizeof(*newstr));
|
|
|
if (newstr == (char *) NULL)
|
|
|
break;
|
|
|
while (Tokenizer(token_info,0,token,inputlen,line,"","=","\"",0,
|
|
|
&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
if (state == 0)
|
|
|
{
|
|
|
int
|
|
|
state,
|
|
|
next;
|
|
|
|
|
|
char
|
|
|
brkused,
|
|
|
quoted;
|
|
|
|
|
|
state=0;
|
|
|
next=0;
|
|
|
while (Tokenizer(token_info,0,newstr,inputlen,token,"","#",
|
|
|
"", 0,&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
switch (state)
|
|
|
{
|
|
|
case 0:
|
|
|
if (strcmp(newstr,"8BIM")==0)
|
|
|
dataset = 255;
|
|
|
else
|
|
|
dataset = (unsigned char) StringToLong(newstr);
|
|
|
break;
|
|
|
case 1:
|
|
|
recnum = (unsigned int) StringToUnsignedLong(newstr);
|
|
|
break;
|
|
|
case 2:
|
|
|
name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent,
|
|
|
sizeof(*name));
|
|
|
if (name)
|
|
|
(void) strcpy(name,newstr);
|
|
|
break;
|
|
|
}
|
|
|
state++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
if (state == 1)
|
|
|
{
|
|
|
int
|
|
|
next;
|
|
|
|
|
|
ssize_t
|
|
|
len;
|
|
|
|
|
|
char
|
|
|
brkused,
|
|
|
quoted;
|
|
|
|
|
|
next=0;
|
|
|
len = (ssize_t) strlen(token);
|
|
|
while (Tokenizer(token_info,0,newstr,inputlen,token,"","&",
|
|
|
"",0,&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
if (brkused && next > 0)
|
|
|
{
|
|
|
size_t
|
|
|
codes_length;
|
|
|
|
|
|
char
|
|
|
*s = &token[next-1];
|
|
|
|
|
|
codes_length=convertHTMLcodes(s);
|
|
|
if ((ssize_t) codes_length > len)
|
|
|
len=0;
|
|
|
else
|
|
|
len-=codes_length;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (dataset == 255)
|
|
|
{
|
|
|
unsigned char
|
|
|
nlen = 0;
|
|
|
|
|
|
int
|
|
|
i;
|
|
|
|
|
|
if (savedolen > 0)
|
|
|
{
|
|
|
MagickOffsetType
|
|
|
offset;
|
|
|
|
|
|
ssize_t diff = outputlen - savedolen;
|
|
|
currentpos = TellBlob(ofile);
|
|
|
if (currentpos < 0)
|
|
|
{
|
|
|
line=DestroyString(line);
|
|
|
return(-1);
|
|
|
}
|
|
|
offset=SeekBlob(ofile,savedpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
{
|
|
|
line=DestroyString(line);
|
|
|
return(-1);
|
|
|
}
|
|
|
(void) WriteBlobMSBLong(ofile,(unsigned int) diff);
|
|
|
offset=SeekBlob(ofile,currentpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
{
|
|
|
line=DestroyString(line);
|
|
|
return(-1);
|
|
|
}
|
|
|
savedolen = 0L;
|
|
|
}
|
|
|
if (outputlen & 1)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
(void) WriteBlobString(ofile,"8BIM");
|
|
|
(void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
|
|
|
outputlen += 6;
|
|
|
if (name)
|
|
|
nlen = (unsigned char) strlen(name);
|
|
|
(void) WriteBlobByte(ofile,nlen);
|
|
|
outputlen++;
|
|
|
for (i=0; i<nlen; i++)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) name[i]);
|
|
|
outputlen += nlen;
|
|
|
if ((nlen & 0x01) == 0)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
if (recnum != IPTC_ID)
|
|
|
{
|
|
|
(void) WriteBlobMSBLong(ofile, (unsigned int) len);
|
|
|
outputlen += 4;
|
|
|
|
|
|
next=0;
|
|
|
outputlen += len;
|
|
|
while (len-- > 0)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) token[next++]);
|
|
|
|
|
|
if (outputlen & 1)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/* patch in a fake length for now and fix it later */
|
|
|
savedpos = TellBlob(ofile);
|
|
|
if (savedpos < 0)
|
|
|
return(-1);
|
|
|
(void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
|
|
|
outputlen += 4;
|
|
|
savedolen = outputlen;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (len <= 0x7FFF)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x1c);
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) dataset);
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
|
|
|
(void) WriteBlobMSBShort(ofile,(unsigned short) len);
|
|
|
outputlen += 5;
|
|
|
next=0;
|
|
|
outputlen += len;
|
|
|
while (len-- > 0)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) token[next++]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
state++;
|
|
|
}
|
|
|
if (token != (char *) NULL)
|
|
|
token=DestroyString(token);
|
|
|
if (newstr != (char *) NULL)
|
|
|
newstr=DestroyString(newstr);
|
|
|
if (name != (char *) NULL)
|
|
|
name=DestroyString(name);
|
|
|
}
|
|
|
token_info=DestroyTokenInfo(token_info);
|
|
|
if (token != (char *) NULL)
|
|
|
token=DestroyString(token);
|
|
|
if (newstr != (char *) NULL)
|
|
|
newstr=DestroyString(newstr);
|
|
|
if (name != (char *) NULL)
|
|
|
name=DestroyString(name);
|
|
|
line=DestroyString(line);
|
|
|
if (savedolen > 0)
|
|
|
{
|
|
|
MagickOffsetType
|
|
|
offset;
|
|
|
|
|
|
ssize_t diff = outputlen - savedolen;
|
|
|
|
|
|
currentpos = TellBlob(ofile);
|
|
|
if (currentpos < 0)
|
|
|
return(-1);
|
|
|
offset=SeekBlob(ofile,savedpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
(void) WriteBlobMSBLong(ofile,(unsigned int) diff);
|
|
|
offset=SeekBlob(ofile,currentpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
savedolen = 0L;
|
|
|
}
|
|
|
return outputlen;
|
|
|
}
|
|
|
|
|
|
static char *super_fgets_w(char **b, size_t *blen, Image *file)
|
|
|
{
|
|
|
int
|
|
|
c;
|
|
|
|
|
|
size_t
|
|
|
len;
|
|
|
|
|
|
unsigned char
|
|
|
*p,
|
|
|
*q;
|
|
|
|
|
|
len=*blen;
|
|
|
p=(unsigned char *) (*b);
|
|
|
for (q=p; ; q++)
|
|
|
{
|
|
|
c=ReadBlobLSBSignedShort(file);
|
|
|
if ((c == -1) || (c == '\n'))
|
|
|
break;
|
|
|
if (EOFBlob(file))
|
|
|
break;
|
|
|
if ((size_t) (q-p+1) >= len)
|
|
|
{
|
|
|
size_t
|
|
|
tlen;
|
|
|
|
|
|
unsigned char
|
|
|
*buffer;
|
|
|
|
|
|
tlen=(size_t) (q-p);
|
|
|
len<<=1;
|
|
|
buffer=(unsigned char *) ResizeQuantumMemory(p,len+2,sizeof(*p));
|
|
|
if (buffer == (unsigned char *) NULL)
|
|
|
break;
|
|
|
p=buffer;
|
|
|
q=p+tlen;
|
|
|
}
|
|
|
*q=(unsigned char) c;
|
|
|
}
|
|
|
*b=(char *) p;
|
|
|
*blen=0;
|
|
|
if ((*b) != (char *) NULL)
|
|
|
{
|
|
|
size_t
|
|
|
tlen;
|
|
|
|
|
|
tlen=(size_t) (q-p);
|
|
|
if (tlen == 0)
|
|
|
return (char *) NULL;
|
|
|
p[tlen]='\0';
|
|
|
*blen=++tlen;
|
|
|
}
|
|
|
return(*b);
|
|
|
}
|
|
|
|
|
|
static ssize_t parse8BIMW(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
char
|
|
|
brkused,
|
|
|
quoted,
|
|
|
*line,
|
|
|
*token,
|
|
|
*newstr,
|
|
|
*name;
|
|
|
|
|
|
int
|
|
|
state,
|
|
|
next;
|
|
|
|
|
|
unsigned char
|
|
|
dataset;
|
|
|
|
|
|
unsigned int
|
|
|
recnum;
|
|
|
|
|
|
size_t
|
|
|
inputlen = MagickPathExtent;
|
|
|
|
|
|
ssize_t
|
|
|
savedolen = 0L,
|
|
|
outputlen = 0L;
|
|
|
|
|
|
MagickOffsetType
|
|
|
savedpos,
|
|
|
currentpos;
|
|
|
|
|
|
TokenInfo
|
|
|
*token_info;
|
|
|
|
|
|
dataset = 0;
|
|
|
recnum = 0;
|
|
|
line=(char *) AcquireQuantumMemory(inputlen,sizeof(*line));
|
|
|
if (line == (char *) NULL)
|
|
|
return(-1);
|
|
|
newstr = name = token = (char *) NULL;
|
|
|
savedpos = 0;
|
|
|
token_info=AcquireTokenInfo();
|
|
|
while (super_fgets_w(&line,&inputlen,ifile) != NULL)
|
|
|
{
|
|
|
state=0;
|
|
|
next=0;
|
|
|
|
|
|
token=(char *) AcquireQuantumMemory(inputlen,sizeof(*token));
|
|
|
if (token == (char *) NULL)
|
|
|
break;
|
|
|
newstr=(char *) AcquireQuantumMemory(inputlen,sizeof(*newstr));
|
|
|
if (newstr == (char *) NULL)
|
|
|
break;
|
|
|
while (Tokenizer(token_info,0,token,inputlen,line,"","=","\"",0,
|
|
|
&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
if (state == 0)
|
|
|
{
|
|
|
int
|
|
|
state,
|
|
|
next;
|
|
|
|
|
|
char
|
|
|
brkused,
|
|
|
quoted;
|
|
|
|
|
|
state=0;
|
|
|
next=0;
|
|
|
while (Tokenizer(token_info,0,newstr,inputlen,token,"","#",
|
|
|
"",0,&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
switch (state)
|
|
|
{
|
|
|
case 0:
|
|
|
if (strcmp(newstr,"8BIM")==0)
|
|
|
dataset = 255;
|
|
|
else
|
|
|
dataset = (unsigned char) StringToLong(newstr);
|
|
|
break;
|
|
|
case 1:
|
|
|
recnum=(unsigned int) StringToUnsignedLong(newstr);
|
|
|
break;
|
|
|
case 2:
|
|
|
name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent,
|
|
|
sizeof(*name));
|
|
|
if (name)
|
|
|
(void) CopyMagickString(name,newstr,strlen(newstr)+MagickPathExtent);
|
|
|
break;
|
|
|
}
|
|
|
state++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
if (state == 1)
|
|
|
{
|
|
|
int
|
|
|
next;
|
|
|
|
|
|
ssize_t
|
|
|
len;
|
|
|
|
|
|
char
|
|
|
brkused,
|
|
|
quoted;
|
|
|
|
|
|
next=0;
|
|
|
len = (ssize_t) strlen(token);
|
|
|
while (Tokenizer(token_info,0,newstr,inputlen,token,"","&",
|
|
|
"",0,&brkused,&next,"ed)==0)
|
|
|
{
|
|
|
if (brkused && next > 0)
|
|
|
{
|
|
|
size_t
|
|
|
codes_length;
|
|
|
|
|
|
char
|
|
|
*s = &token[next-1];
|
|
|
|
|
|
codes_length=convertHTMLcodes(s);
|
|
|
if ((ssize_t) codes_length > len)
|
|
|
len=0;
|
|
|
else
|
|
|
len-=codes_length;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (dataset == 255)
|
|
|
{
|
|
|
unsigned char
|
|
|
nlen = 0;
|
|
|
|
|
|
int
|
|
|
i;
|
|
|
|
|
|
if (savedolen > 0)
|
|
|
{
|
|
|
MagickOffsetType
|
|
|
offset;
|
|
|
|
|
|
ssize_t diff = outputlen - savedolen;
|
|
|
currentpos = TellBlob(ofile);
|
|
|
if (currentpos < 0)
|
|
|
return(-1);
|
|
|
offset=SeekBlob(ofile,savedpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
(void) WriteBlobMSBLong(ofile,(unsigned int) diff);
|
|
|
offset=SeekBlob(ofile,currentpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
savedolen = 0L;
|
|
|
}
|
|
|
if (outputlen & 1)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
(void) WriteBlobString(ofile,"8BIM");
|
|
|
(void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
|
|
|
outputlen += 6;
|
|
|
if (name)
|
|
|
nlen = (unsigned char) strlen(name);
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) nlen);
|
|
|
outputlen++;
|
|
|
for (i=0; i<nlen; i++)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) name[i]);
|
|
|
outputlen += nlen;
|
|
|
if ((nlen & 0x01) == 0)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
if (recnum != IPTC_ID)
|
|
|
{
|
|
|
(void) WriteBlobMSBLong(ofile,(unsigned int) len);
|
|
|
outputlen += 4;
|
|
|
|
|
|
next=0;
|
|
|
outputlen += len;
|
|
|
while (len--)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) token[next++]);
|
|
|
|
|
|
if (outputlen & 1)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x00);
|
|
|
outputlen++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/* patch in a fake length for now and fix it later */
|
|
|
savedpos = TellBlob(ofile);
|
|
|
if (savedpos < 0)
|
|
|
return(-1);
|
|
|
(void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
|
|
|
outputlen += 4;
|
|
|
savedolen = outputlen;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (len <= 0x7FFF)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0x1c);
|
|
|
(void) WriteBlobByte(ofile,dataset);
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
|
|
|
(void) WriteBlobMSBShort(ofile,(unsigned short) len);
|
|
|
outputlen += 5;
|
|
|
next=0;
|
|
|
outputlen += len;
|
|
|
while (len--)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) token[next++]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
state++;
|
|
|
}
|
|
|
if (token != (char *) NULL)
|
|
|
token=DestroyString(token);
|
|
|
if (newstr != (char *) NULL)
|
|
|
newstr=DestroyString(newstr);
|
|
|
if (name != (char *) NULL)
|
|
|
name=DestroyString(name);
|
|
|
}
|
|
|
token_info=DestroyTokenInfo(token_info);
|
|
|
if (token != (char *) NULL)
|
|
|
token=DestroyString(token);
|
|
|
if (newstr != (char *) NULL)
|
|
|
newstr=DestroyString(newstr);
|
|
|
if (name != (char *) NULL)
|
|
|
name=DestroyString(name);
|
|
|
line=DestroyString(line);
|
|
|
if (savedolen > 0)
|
|
|
{
|
|
|
MagickOffsetType
|
|
|
offset;
|
|
|
|
|
|
ssize_t diff = outputlen - savedolen;
|
|
|
|
|
|
currentpos = TellBlob(ofile);
|
|
|
if (currentpos < 0)
|
|
|
return(-1);
|
|
|
offset=SeekBlob(ofile,savedpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
(void) WriteBlobMSBLong(ofile,(unsigned int) diff);
|
|
|
offset=SeekBlob(ofile,currentpos,SEEK_SET);
|
|
|
if (offset < 0)
|
|
|
return(-1);
|
|
|
savedolen = 0L;
|
|
|
}
|
|
|
return(outputlen);
|
|
|
}
|
|
|
|
|
|
/* some defines for the different JPEG block types */
|
|
|
#define M_SOF0 0xC0 /* Start Of Frame N */
|
|
|
#define M_SOF1 0xC1 /* N indicates which compression process */
|
|
|
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
|
|
|
#define M_SOF3 0xC3
|
|
|
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
|
|
|
#define M_SOF6 0xC6
|
|
|
#define M_SOF7 0xC7
|
|
|
#define M_SOF9 0xC9
|
|
|
#define M_SOF10 0xCA
|
|
|
#define M_SOF11 0xCB
|
|
|
#define M_SOF13 0xCD
|
|
|
#define M_SOF14 0xCE
|
|
|
#define M_SOF15 0xCF
|
|
|
#define M_SOI 0xD8
|
|
|
#define M_EOI 0xD9 /* End Of Image (end of datastream) */
|
|
|
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
|
|
|
#define M_APP0 0xe0
|
|
|
#define M_APP1 0xe1
|
|
|
#define M_APP2 0xe2
|
|
|
#define M_APP3 0xe3
|
|
|
#define M_APP4 0xe4
|
|
|
#define M_APP5 0xe5
|
|
|
#define M_APP6 0xe6
|
|
|
#define M_APP7 0xe7
|
|
|
#define M_APP8 0xe8
|
|
|
#define M_APP9 0xe9
|
|
|
#define M_APP10 0xea
|
|
|
#define M_APP11 0xeb
|
|
|
#define M_APP12 0xec
|
|
|
#define M_APP13 0xed
|
|
|
#define M_APP14 0xee
|
|
|
#define M_APP15 0xef
|
|
|
|
|
|
static int jpeg_transfer_1(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
int c;
|
|
|
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return EOF;
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) c);
|
|
|
return c;
|
|
|
}
|
|
|
|
|
|
#if defined(future)
|
|
|
static int jpeg_skip_1(Image *ifile)
|
|
|
{
|
|
|
int c;
|
|
|
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return EOF;
|
|
|
return c;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
static int jpeg_read_remaining(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
int c;
|
|
|
|
|
|
while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
|
|
|
continue;
|
|
|
return M_EOI;
|
|
|
}
|
|
|
|
|
|
static int jpeg_skip_variable(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
unsigned int length;
|
|
|
int c1,c2;
|
|
|
|
|
|
if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
|
|
|
return M_EOI;
|
|
|
if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
|
|
|
return M_EOI;
|
|
|
|
|
|
length = (((unsigned int) c1) << 8) + ((unsigned int) c2);
|
|
|
length -= 2;
|
|
|
|
|
|
while (length--)
|
|
|
if (jpeg_transfer_1(ifile, ofile) == EOF)
|
|
|
return M_EOI;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int jpeg_skip_variable2(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
unsigned int length;
|
|
|
int c1,c2;
|
|
|
|
|
|
(void) ofile;
|
|
|
if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
|
|
|
if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
|
|
|
|
|
|
length = (((unsigned int) c1) << 8) + ((unsigned int) c2);
|
|
|
length -= 2;
|
|
|
|
|
|
while (length--)
|
|
|
if (ReadBlobByte(ifile) == EOF)
|
|
|
return M_EOI;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int jpeg_nextmarker(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
int c;
|
|
|
|
|
|
/* transfer anything until we hit 0xff */
|
|
|
do
|
|
|
{
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return M_EOI; /* we hit EOF */
|
|
|
else
|
|
|
if (c != 0xff)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) c);
|
|
|
} while (c != 0xff);
|
|
|
|
|
|
/* get marker byte, swallowing possible padding */
|
|
|
do
|
|
|
{
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return M_EOI; /* we hit EOF */
|
|
|
} while (c == 0xff);
|
|
|
|
|
|
return c;
|
|
|
}
|
|
|
|
|
|
#if defined(future)
|
|
|
static int jpeg_skip_till_marker(Image *ifile, int marker)
|
|
|
{
|
|
|
int c, i;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
/* skip anything until we hit 0xff */
|
|
|
i = 0;
|
|
|
do
|
|
|
{
|
|
|
c = ReadBlobByte(ifile);
|
|
|
i++;
|
|
|
if (c == EOF)
|
|
|
return M_EOI; /* we hit EOF */
|
|
|
} while (c != 0xff);
|
|
|
|
|
|
/* get marker byte, swallowing possible padding */
|
|
|
do
|
|
|
{
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return M_EOI; /* we hit EOF */
|
|
|
} while (c == 0xff);
|
|
|
} while (c != marker);
|
|
|
return c;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
/* Embed binary IPTC data into a JPEG image. */
|
|
|
static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
|
|
|
{
|
|
|
unsigned int marker;
|
|
|
unsigned int done = 0;
|
|
|
unsigned int len;
|
|
|
int inx;
|
|
|
|
|
|
if (jpeg_transfer_1(ifile, ofile) != 0xFF)
|
|
|
return 0;
|
|
|
if (jpeg_transfer_1(ifile, ofile) != M_SOI)
|
|
|
return 0;
|
|
|
|
|
|
while (done == MagickFalse)
|
|
|
{
|
|
|
marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
|
|
|
if (marker == M_EOI)
|
|
|
{ /* EOF */
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (marker != M_APP13)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0xff);
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) marker);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
switch (marker)
|
|
|
{
|
|
|
case M_APP13:
|
|
|
/* we are going to write a new APP13 marker, so don't output the old one */
|
|
|
jpeg_skip_variable2(ifile, ofile);
|
|
|
break;
|
|
|
|
|
|
case M_APP0:
|
|
|
/* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
|
|
|
jpeg_skip_variable(ifile, ofile);
|
|
|
|
|
|
if (iptc != (Image *) NULL)
|
|
|
{
|
|
|
char
|
|
|
psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0";
|
|
|
|
|
|
len=(unsigned int) GetBlobSize(iptc);
|
|
|
if (len & 1)
|
|
|
len++; /* make the length even */
|
|
|
psheader[2]=(char) ((len+16)>>8);
|
|
|
psheader[3]=(char) ((len+16)&0xff);
|
|
|
for (inx = 0; inx < 18; inx++)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
|
|
|
jpeg_read_remaining(iptc, ofile);
|
|
|
len=(unsigned int) GetBlobSize(iptc);
|
|
|
if (len & 1)
|
|
|
(void) WriteBlobByte(ofile,0);
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case M_SOS:
|
|
|
/* we hit data, no more marker-inserting can be done! */
|
|
|
jpeg_read_remaining(ifile, ofile);
|
|
|
done = 1;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
jpeg_skip_variable(ifile, ofile);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
/* handle stripping the APP13 data out of a JPEG */
|
|
|
#if defined(future)
|
|
|
static void jpeg_strip(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
unsigned int marker;
|
|
|
|
|
|
marker = jpeg_skip_till_marker(ifile, M_SOI);
|
|
|
if (marker == M_SOI)
|
|
|
{
|
|
|
(void) WriteBlobByte(ofile,0xff);
|
|
|
(void) WriteBlobByte(ofile,M_SOI);
|
|
|
jpeg_read_remaining(ifile, ofile);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Extract any APP13 binary data into a file. */
|
|
|
static int jpeg_extract(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
unsigned int marker;
|
|
|
unsigned int done = 0;
|
|
|
|
|
|
if (jpeg_skip_1(ifile) != 0xff)
|
|
|
return 0;
|
|
|
if (jpeg_skip_1(ifile) != M_SOI)
|
|
|
return 0;
|
|
|
|
|
|
while (done == MagickFalse)
|
|
|
{
|
|
|
marker = jpeg_skip_till_marker(ifile, M_APP13);
|
|
|
if (marker == M_APP13)
|
|
|
{
|
|
|
marker = jpeg_nextmarker(ifile, ofile);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
static inline void CopyBlob(Image *source,Image *destination)
|
|
|
{
|
|
|
ssize_t
|
|
|
i;
|
|
|
|
|
|
unsigned char
|
|
|
*buffer;
|
|
|
|
|
|
ssize_t
|
|
|
count,
|
|
|
length;
|
|
|
|
|
|
buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
|
|
|
sizeof(*buffer));
|
|
|
if (buffer != (unsigned char *) NULL)
|
|
|
{
|
|
|
(void) memset(buffer,0,MagickMaxBufferExtent*sizeof(*buffer));
|
|
|
i=0;
|
|
|
while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0)
|
|
|
{
|
|
|
count=0;
|
|
|
for (i=0; i < (ssize_t) length; i+=count)
|
|
|
{
|
|
|
count=WriteBlob(destination,(size_t) (length-i),buffer+i);
|
|
|
if (count <= 0)
|
|
|
break;
|
|
|
}
|
|
|
if (i < (ssize_t) length)
|
|
|
break;
|
|
|
}
|
|
|
buffer=(unsigned char *) RelinquishMagickMemory(buffer);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static Image *ReadMETAImage(const ImageInfo *image_info,
|
|
|
ExceptionInfo *exception)
|
|
|
{
|
|
|
Image
|
|
|
*buff,
|
|
|
*image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
StringInfo
|
|
|
*profile;
|
|
|
|
|
|
size_t
|
|
|
length;
|
|
|
|
|
|
unsigned char
|
|
|
*blob;
|
|
|
|
|
|
/*
|
|
|
Open file containing binary metadata
|
|
|
*/
|
|
|
assert(image_info != (const ImageInfo *) NULL);
|
|
|
assert(image_info->signature == MagickCoreSignature);
|
|
|
if (image_info->debug != MagickFalse)
|
|
|
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
|
|
|
image_info->filename);
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
image=AcquireImage(image_info,exception);
|
|
|
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
{
|
|
|
image=DestroyImageList(image);
|
|
|
return((Image *) NULL);
|
|
|
}
|
|
|
image->columns=1;
|
|
|
image->rows=1;
|
|
|
if (SetImageBackgroundColor(image,exception) == MagickFalse)
|
|
|
{
|
|
|
image=DestroyImageList(image);
|
|
|
return((Image *) NULL);
|
|
|
}
|
|
|
length=1;
|
|
|
if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
|
|
|
{
|
|
|
/*
|
|
|
Read 8BIM binary metadata.
|
|
|
*/
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
|
|
|
if (blob == (unsigned char *) NULL)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
(void) memset(blob,0,length);
|
|
|
AttachBlob(buff->blob,blob,length);
|
|
|
if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
|
|
|
{
|
|
|
length=(size_t) parse8BIM(image, buff);
|
|
|
if (length == 0)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(CorruptImageError,"CorruptImage");
|
|
|
}
|
|
|
if (length & 1)
|
|
|
(void) WriteBlobByte(buff,0x0);
|
|
|
}
|
|
|
else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
|
|
|
{
|
|
|
length=(size_t) parse8BIMW(image, buff);
|
|
|
if (length == 0)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(CorruptImageError,"CorruptImage");
|
|
|
}
|
|
|
if (length & 1)
|
|
|
(void) WriteBlobByte(buff,0x0);
|
|
|
}
|
|
|
else
|
|
|
CopyBlob(image,buff);
|
|
|
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
|
|
GetBlobSize(buff));
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
status=SetImageProfile(image,"8bim",profile,exception);
|
|
|
profile=DestroyStringInfo(profile);
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
if (status == MagickFalse)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
|
|
|
{
|
|
|
char
|
|
|
name[MagickPathExtent];
|
|
|
|
|
|
(void) FormatLocaleString(name,MagickPathExtent,"APP%d",1);
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
|
|
|
if (blob == (unsigned char *) NULL)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
AttachBlob(buff->blob,blob,length);
|
|
|
if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
|
|
|
{
|
|
|
Image
|
|
|
*iptc;
|
|
|
|
|
|
int
|
|
|
result;
|
|
|
|
|
|
if (image_info->profile == (void *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
|
|
|
}
|
|
|
profile=CloneStringInfo((StringInfo *) image_info->profile);
|
|
|
iptc=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (iptc == (Image *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
AttachBlob(iptc->blob,GetStringInfoDatum(profile),
|
|
|
GetStringInfoLength(profile));
|
|
|
result=jpeg_embed(image,buff,iptc);
|
|
|
blob=(unsigned char *) DetachBlob(iptc->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
iptc=DestroyImage(iptc);
|
|
|
if (result == 0)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
CopyBlob(image,buff);
|
|
|
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
|
|
GetBlobSize(buff));
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
status=SetImageProfile(image,name,profile,exception);
|
|
|
profile=DestroyStringInfo(profile);
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
if (status == MagickFalse)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
|
|
|
(LocaleCompare(image_info->magick,"ICM") == 0))
|
|
|
{
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
|
|
|
if (blob == (unsigned char *) NULL)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
AttachBlob(buff->blob,blob,length);
|
|
|
CopyBlob(image,buff);
|
|
|
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
|
|
GetBlobSize(buff));
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
(void) SetImageProfile(image,"icc",profile,exception);
|
|
|
profile=DestroyStringInfo(profile);
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"IPTC") == 0)
|
|
|
{
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
|
|
|
if (blob == (unsigned char *) NULL)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
AttachBlob(buff->blob,blob,length);
|
|
|
CopyBlob(image,buff);
|
|
|
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
|
|
GetBlobSize(buff));
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
(void) SetImageProfile(image,"iptc",profile,exception);
|
|
|
profile=DestroyStringInfo(profile);
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"XMP") == 0)
|
|
|
{
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
|
|
|
if (blob == (unsigned char *) NULL)
|
|
|
{
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
AttachBlob(buff->blob,blob,length);
|
|
|
CopyBlob(image,buff);
|
|
|
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
|
|
GetBlobSize(buff));
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
{
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
}
|
|
|
(void) SetImageProfile(image,"xmp",profile,exception);
|
|
|
profile=DestroyStringInfo(profile);
|
|
|
blob=(unsigned char *) DetachBlob(buff->blob);
|
|
|
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
}
|
|
|
(void) CloseBlob(image);
|
|
|
return(GetFirstImageInList(image));
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% R e g i s t e r M E T A I m a g e %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% RegisterMETAImage() adds attributes for the META image format to
|
|
|
% the list of supported formats. The attributes include the image format
|
|
|
% tag, a method to read and/or write the format, whether the format
|
|
|
% supports the saving of more than one frame to the same file or blob,
|
|
|
% whether the format supports native in-memory I/O, and a brief
|
|
|
% description of the format.
|
|
|
%
|
|
|
% The format of the RegisterMETAImage method is:
|
|
|
%
|
|
|
% size_t RegisterMETAImage(void)
|
|
|
%
|
|
|
*/
|
|
|
ModuleExport size_t RegisterMETAImage(void)
|
|
|
{
|
|
|
MagickInfo
|
|
|
*entry;
|
|
|
|
|
|
entry=AcquireMagickInfo("META","8BIM","Photoshop resource format");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","8BIMTEXT","Photoshop resource text format");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","8BIMWTEXT",
|
|
|
"Photoshop resource wide text format");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","APP1","Raw application information");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","APP1JPEG","Raw JPEG binary data");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","EXIF","Exif digital camera binary data");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","XMP","Adobe XML metadata");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","ICM","ICC Color Profile");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","ICC","ICC Color Profile");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","IPTC","IPTC Newsphoto");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","IPTCTEXT","IPTC Newsphoto text format");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
entry=AcquireMagickInfo("META","IPTCWTEXT","IPTC Newsphoto text format");
|
|
|
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
|
|
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
|
|
entry->flags^=CoderAdjoinFlag;
|
|
|
entry->flags|=CoderStealthFlag;
|
|
|
entry->flags|=CoderDecoderSeekableStreamFlag;
|
|
|
(void) RegisterMagickInfo(entry);
|
|
|
return(MagickImageCoderSignature);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% U n r e g i s t e r M E T A I m a g e %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% UnregisterMETAImage() removes format registrations made by the
|
|
|
% META module from the list of supported formats.
|
|
|
%
|
|
|
% The format of the UnregisterMETAImage method is:
|
|
|
%
|
|
|
% UnregisterMETAImage(void)
|
|
|
%
|
|
|
*/
|
|
|
ModuleExport void UnregisterMETAImage(void)
|
|
|
{
|
|
|
(void) UnregisterMagickInfo("8BIM");
|
|
|
(void) UnregisterMagickInfo("8BIMTEXT");
|
|
|
(void) UnregisterMagickInfo("8BIMWTEXT");
|
|
|
(void) UnregisterMagickInfo("EXIF");
|
|
|
(void) UnregisterMagickInfo("APP1");
|
|
|
(void) UnregisterMagickInfo("APP1JPEG");
|
|
|
(void) UnregisterMagickInfo("ICCTEXT");
|
|
|
(void) UnregisterMagickInfo("ICM");
|
|
|
(void) UnregisterMagickInfo("ICC");
|
|
|
(void) UnregisterMagickInfo("IPTC");
|
|
|
(void) UnregisterMagickInfo("IPTCTEXT");
|
|
|
(void) UnregisterMagickInfo("IPTCWTEXT");
|
|
|
(void) UnregisterMagickInfo("XMP");
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% W r i t e M E T A I m a g e %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% WriteMETAImage() writes a META image to a file.
|
|
|
%
|
|
|
% The format of the WriteMETAImage method is:
|
|
|
%
|
|
|
% MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
|
|
|
% Image *image,ExceptionInfo *exception)
|
|
|
%
|
|
|
% Compression code contributed by Kyle Shorter.
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o image_info: Specifies a pointer to an ImageInfo structure.
|
|
|
%
|
|
|
% o image: A pointer to a Image structure.
|
|
|
%
|
|
|
% o exception: return any errors or warnings in this structure.
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
static size_t GetIPTCStream(unsigned char **info,size_t length)
|
|
|
{
|
|
|
int
|
|
|
c;
|
|
|
|
|
|
ssize_t
|
|
|
i;
|
|
|
|
|
|
unsigned char
|
|
|
*p;
|
|
|
|
|
|
size_t
|
|
|
extent,
|
|
|
info_length;
|
|
|
|
|
|
unsigned int
|
|
|
marker;
|
|
|
|
|
|
size_t
|
|
|
tag_length;
|
|
|
|
|
|
p=(*info);
|
|
|
extent=length;
|
|
|
if ((*p == 0x1c) && (*(p+1) == 0x02))
|
|
|
return(length);
|
|
|
/*
|
|
|
Extract IPTC from 8BIM resource block.
|
|
|
*/
|
|
|
while (extent >= 12)
|
|
|
{
|
|
|
if (strncmp((const char *) p,"8BIM",4))
|
|
|
break;
|
|
|
p+=4;
|
|
|
extent-=4;
|
|
|
marker=(unsigned int) (*p) << 8 | *(p+1);
|
|
|
p+=2;
|
|
|
extent-=2;
|
|
|
c=*p++;
|
|
|
extent--;
|
|
|
c|=0x01;
|
|
|
if ((size_t) c >= extent)
|
|
|
break;
|
|
|
p+=c;
|
|
|
extent-=c;
|
|
|
if (extent < 4)
|
|
|
break;
|
|
|
tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
|
|
|
(((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
|
|
|
p+=4;
|
|
|
extent-=4;
|
|
|
if (tag_length > extent)
|
|
|
break;
|
|
|
if (marker == IPTC_ID)
|
|
|
{
|
|
|
*info=p;
|
|
|
return(tag_length);
|
|
|
}
|
|
|
if ((tag_length & 0x01) != 0)
|
|
|
tag_length++;
|
|
|
p+=tag_length;
|
|
|
extent-=tag_length;
|
|
|
}
|
|
|
/*
|
|
|
Find the beginning of the IPTC info.
|
|
|
*/
|
|
|
p=(*info);
|
|
|
tag_length=0;
|
|
|
iptc_find:
|
|
|
info_length=0;
|
|
|
marker=MagickFalse;
|
|
|
while (length != 0)
|
|
|
{
|
|
|
c=(*p++);
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
if (c == 0x1c)
|
|
|
{
|
|
|
p--;
|
|
|
*info=p; /* let the caller know were it is */
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
/*
|
|
|
Determine the length of the IPTC info.
|
|
|
*/
|
|
|
while (length != 0)
|
|
|
{
|
|
|
c=(*p++);
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
if (c == 0x1c)
|
|
|
marker=MagickTrue;
|
|
|
else
|
|
|
if (marker)
|
|
|
break;
|
|
|
else
|
|
|
continue;
|
|
|
info_length++;
|
|
|
/*
|
|
|
Found the 0x1c tag; skip the dataset and record number tags.
|
|
|
*/
|
|
|
c=(*p++); /* should be 2 */
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
if ((info_length == 1) && (c != 2))
|
|
|
goto iptc_find;
|
|
|
info_length++;
|
|
|
c=(*p++); /* should be 0 */
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
if ((info_length == 2) && (c != 0))
|
|
|
goto iptc_find;
|
|
|
info_length++;
|
|
|
/*
|
|
|
Decode the length of the block that follows - ssize_t or short format.
|
|
|
*/
|
|
|
c=(*p++);
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
info_length++;
|
|
|
if ((c & 0x80) != 0)
|
|
|
{
|
|
|
/*
|
|
|
Long format.
|
|
|
*/
|
|
|
tag_length=0;
|
|
|
for (i=0; i < 4; i++)
|
|
|
{
|
|
|
tag_length<<=8;
|
|
|
tag_length|=(*p++);
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
info_length++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/*
|
|
|
Short format.
|
|
|
*/
|
|
|
tag_length=((long) c) << 8;
|
|
|
c=(*p++);
|
|
|
length--;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
info_length++;
|
|
|
tag_length|=(long) c;
|
|
|
}
|
|
|
if (tag_length > (length+1))
|
|
|
break;
|
|
|
p+=tag_length;
|
|
|
length-=tag_length;
|
|
|
if (length == 0)
|
|
|
break;
|
|
|
info_length+=tag_length;
|
|
|
}
|
|
|
return(info_length);
|
|
|
}
|
|
|
|
|
|
static void formatString(Image *ofile, const char *s, ssize_t len)
|
|
|
{
|
|
|
char
|
|
|
temp[MagickPathExtent];
|
|
|
|
|
|
(void) WriteBlobByte(ofile,'"');
|
|
|
for (; len > 0; len--, s++) {
|
|
|
int c = (*s) & 255;
|
|
|
switch (c) {
|
|
|
case '&':
|
|
|
(void) WriteBlobString(ofile,"&");
|
|
|
break;
|
|
|
#ifdef HANDLE_GT_LT
|
|
|
case '<':
|
|
|
(void) WriteBlobString(ofile,"<");
|
|
|
break;
|
|
|
case '>':
|
|
|
(void) WriteBlobString(ofile,">");
|
|
|
break;
|
|
|
#endif
|
|
|
case '"':
|
|
|
(void) WriteBlobString(ofile,""");
|
|
|
break;
|
|
|
default:
|
|
|
if (isprint((int) ((unsigned char) c)) != 0)
|
|
|
(void) WriteBlobByte(ofile,(unsigned char) *s);
|
|
|
else
|
|
|
{
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"&#%d;", c & 255);
|
|
|
(void) WriteBlobString(ofile,temp);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
#if defined(MAGICKCORE_WINDOWS_SUPPORT)
|
|
|
(void) WriteBlobString(ofile,"\"\r\n");
|
|
|
#else
|
|
|
#if defined(macintosh)
|
|
|
(void) WriteBlobString(ofile,"\"\r");
|
|
|
#else
|
|
|
(void) WriteBlobString(ofile,"\"\n");
|
|
|
#endif
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
typedef struct _tag_spec
|
|
|
{
|
|
|
const short
|
|
|
id;
|
|
|
|
|
|
const char
|
|
|
*name;
|
|
|
} tag_spec;
|
|
|
|
|
|
static const tag_spec tags[] = {
|
|
|
{ 5, "Image Name" },
|
|
|
{ 7, "Edit Status" },
|
|
|
{ 10, "Priority" },
|
|
|
{ 15, "Category" },
|
|
|
{ 20, "Supplemental Category" },
|
|
|
{ 22, "Fixture Identifier" },
|
|
|
{ 25, "Keyword" },
|
|
|
{ 30, "Release Date" },
|
|
|
{ 35, "Release Time" },
|
|
|
{ 40, "Special Instructions" },
|
|
|
{ 45, "Reference Service" },
|
|
|
{ 47, "Reference Date" },
|
|
|
{ 50, "Reference Number" },
|
|
|
{ 55, "Created Date" },
|
|
|
{ 60, "Created Time" },
|
|
|
{ 65, "Originating Program" },
|
|
|
{ 70, "Program Version" },
|
|
|
{ 75, "Object Cycle" },
|
|
|
{ 80, "Byline" },
|
|
|
{ 85, "Byline Title" },
|
|
|
{ 90, "City" },
|
|
|
{ 92, "Sub-Location" },
|
|
|
{ 95, "Province State" },
|
|
|
{ 100, "Country Code" },
|
|
|
{ 101, "Country" },
|
|
|
{ 103, "Original Transmission Reference" },
|
|
|
{ 105, "Headline" },
|
|
|
{ 110, "Credit" },
|
|
|
{ 115, "Source" },
|
|
|
{ 116, "Copyright String" },
|
|
|
{ 120, "Caption" },
|
|
|
{ 121, "Image Orientation" },
|
|
|
{ 122, "Caption Writer" },
|
|
|
{ 131, "Local Caption" },
|
|
|
{ 200, "Custom Field 1" },
|
|
|
{ 201, "Custom Field 2" },
|
|
|
{ 202, "Custom Field 3" },
|
|
|
{ 203, "Custom Field 4" },
|
|
|
{ 204, "Custom Field 5" },
|
|
|
{ 205, "Custom Field 6" },
|
|
|
{ 206, "Custom Field 7" },
|
|
|
{ 207, "Custom Field 8" },
|
|
|
{ 208, "Custom Field 9" },
|
|
|
{ 209, "Custom Field 10" },
|
|
|
{ 210, "Custom Field 11" },
|
|
|
{ 211, "Custom Field 12" },
|
|
|
{ 212, "Custom Field 13" },
|
|
|
{ 213, "Custom Field 14" },
|
|
|
{ 214, "Custom Field 15" },
|
|
|
{ 215, "Custom Field 16" },
|
|
|
{ 216, "Custom Field 17" },
|
|
|
{ 217, "Custom Field 18" },
|
|
|
{ 218, "Custom Field 19" },
|
|
|
{ 219, "Custom Field 20" }
|
|
|
};
|
|
|
|
|
|
static int formatIPTC(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
char
|
|
|
temp[MagickPathExtent];
|
|
|
|
|
|
unsigned int
|
|
|
foundiptc,
|
|
|
tagsfound;
|
|
|
|
|
|
unsigned char
|
|
|
recnum,
|
|
|
dataset;
|
|
|
|
|
|
unsigned char
|
|
|
*readable,
|
|
|
*str;
|
|
|
|
|
|
ssize_t
|
|
|
tagindx,
|
|
|
taglen;
|
|
|
|
|
|
int
|
|
|
i,
|
|
|
tagcount = (int) (sizeof(tags) / sizeof(tags[0]));
|
|
|
|
|
|
int
|
|
|
c;
|
|
|
|
|
|
foundiptc = 0; /* found the IPTC-Header */
|
|
|
tagsfound = 0; /* number of tags found */
|
|
|
|
|
|
c = ReadBlobByte(ifile);
|
|
|
while (c != EOF)
|
|
|
{
|
|
|
if (c == 0x1c)
|
|
|
foundiptc = 1;
|
|
|
else
|
|
|
{
|
|
|
if (foundiptc)
|
|
|
return(-1);
|
|
|
else
|
|
|
{
|
|
|
c=0;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* we found the 0x1c tag and now grab the dataset and record number tags */
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return(-1);
|
|
|
dataset = (unsigned char) c;
|
|
|
c = ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return(-1);
|
|
|
recnum = (unsigned char) c;
|
|
|
/* try to match this record to one of the ones in our named table */
|
|
|
for (i=0; i< tagcount; i++)
|
|
|
{
|
|
|
if (tags[i].id == (short) recnum)
|
|
|
break;
|
|
|
}
|
|
|
if (i < tagcount)
|
|
|
readable = (unsigned char *) tags[i].name;
|
|
|
else
|
|
|
readable = (unsigned char *) "";
|
|
|
/*
|
|
|
We decode the length of the block that follows - ssize_t or short fmt.
|
|
|
*/
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return(-1);
|
|
|
if (c & (unsigned char) 0x80)
|
|
|
return(0);
|
|
|
else
|
|
|
{
|
|
|
int
|
|
|
c0;
|
|
|
|
|
|
c0=ReadBlobByte(ifile);
|
|
|
if (c0 == EOF)
|
|
|
return(-1);
|
|
|
taglen = (c << 8) | c0;
|
|
|
}
|
|
|
if (taglen < 0)
|
|
|
return(-1);
|
|
|
/* make a buffer to hold the tag datand snag it from the input stream */
|
|
|
str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+
|
|
|
MagickPathExtent),sizeof(*str));
|
|
|
if (str == (unsigned char *) NULL)
|
|
|
return(0);
|
|
|
for (tagindx=0; tagindx<taglen; tagindx++)
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
{
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
return(-1);
|
|
|
}
|
|
|
str[tagindx] = (unsigned char) c;
|
|
|
}
|
|
|
str[taglen] = 0;
|
|
|
|
|
|
/* now finish up by formatting this binary data into ASCII equivalent */
|
|
|
if (strlen((char *)readable) > 0)
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
|
|
|
(unsigned int) dataset, (unsigned int) recnum, readable);
|
|
|
else
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
|
|
|
(unsigned int) dataset,(unsigned int) recnum);
|
|
|
(void) WriteBlobString(ofile,temp);
|
|
|
formatString( ofile, (char *)str, taglen );
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
|
|
|
tagsfound++;
|
|
|
|
|
|
c=ReadBlobByte(ifile);
|
|
|
}
|
|
|
return((int) tagsfound);
|
|
|
}
|
|
|
|
|
|
static int readWordFromBuffer(char **s, ssize_t *len)
|
|
|
{
|
|
|
unsigned char
|
|
|
buffer[2];
|
|
|
|
|
|
int
|
|
|
i,
|
|
|
c;
|
|
|
|
|
|
for (i=0; i<2; i++)
|
|
|
{
|
|
|
c = *(*s)++; (*len)--;
|
|
|
if (*len < 0) return -1;
|
|
|
buffer[i] = (unsigned char) c;
|
|
|
}
|
|
|
return (((int) buffer[ 0 ]) << 8) |
|
|
|
(((int) buffer[ 1 ]));
|
|
|
}
|
|
|
|
|
|
static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
|
|
|
{
|
|
|
char
|
|
|
temp[MagickPathExtent];
|
|
|
|
|
|
unsigned int
|
|
|
foundiptc,
|
|
|
tagsfound;
|
|
|
|
|
|
unsigned char
|
|
|
recnum,
|
|
|
dataset;
|
|
|
|
|
|
unsigned char
|
|
|
*readable,
|
|
|
*str;
|
|
|
|
|
|
ssize_t
|
|
|
tagindx,
|
|
|
taglen;
|
|
|
|
|
|
int
|
|
|
i,
|
|
|
tagcount = (int) (sizeof(tags) / sizeof(tags[0]));
|
|
|
|
|
|
int
|
|
|
c;
|
|
|
|
|
|
foundiptc = 0; /* found the IPTC-Header */
|
|
|
tagsfound = 0; /* number of tags found */
|
|
|
|
|
|
while (len > 0)
|
|
|
{
|
|
|
c = *s++; len--;
|
|
|
if (c == 0x1c)
|
|
|
foundiptc = 1;
|
|
|
else
|
|
|
{
|
|
|
if (foundiptc)
|
|
|
return -1;
|
|
|
else
|
|
|
continue;
|
|
|
}
|
|
|
/*
|
|
|
We found the 0x1c tag and now grab the dataset and record number tags.
|
|
|
*/
|
|
|
c = *s++; len--;
|
|
|
if (len < 0) return -1;
|
|
|
dataset = (unsigned char) c;
|
|
|
c = *s++; len--;
|
|
|
if (len < 0) return -1;
|
|
|
recnum = (unsigned char) c;
|
|
|
/* try to match this record to one of the ones in our named table */
|
|
|
for (i=0; i< tagcount; i++)
|
|
|
if (tags[i].id == (short) recnum)
|
|
|
break;
|
|
|
if (i < tagcount)
|
|
|
readable=(unsigned char *) tags[i].name;
|
|
|
else
|
|
|
readable=(unsigned char *) "";
|
|
|
/*
|
|
|
We decode the length of the block that follows - ssize_t or short fmt.
|
|
|
*/
|
|
|
c=(*s++);
|
|
|
len--;
|
|
|
if (len < 0)
|
|
|
return(-1);
|
|
|
if (c & (unsigned char) 0x80)
|
|
|
return(0);
|
|
|
else
|
|
|
{
|
|
|
s--;
|
|
|
len++;
|
|
|
taglen=readWordFromBuffer(&s, &len);
|
|
|
}
|
|
|
if (taglen < 0)
|
|
|
return(-1);
|
|
|
if (taglen > 65535)
|
|
|
return(-1);
|
|
|
/* make a buffer to hold the tag datand snag it from the input stream */
|
|
|
str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+
|
|
|
MagickPathExtent),sizeof(*str));
|
|
|
if (str == (unsigned char *) NULL)
|
|
|
{
|
|
|
(void) printf("MemoryAllocationFailed");
|
|
|
return 0;
|
|
|
}
|
|
|
for (tagindx=0; tagindx<taglen; tagindx++)
|
|
|
{
|
|
|
c = *s++; len--;
|
|
|
if (len < 0)
|
|
|
{
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
return(-1);
|
|
|
}
|
|
|
str[tagindx]=(unsigned char) c;
|
|
|
}
|
|
|
str[taglen]=0;
|
|
|
|
|
|
/* now finish up by formatting this binary data into ASCII equivalent */
|
|
|
if (strlen((char *)readable) > 0)
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
|
|
|
(unsigned int) dataset,(unsigned int) recnum, readable);
|
|
|
else
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
|
|
|
(unsigned int) dataset,(unsigned int) recnum);
|
|
|
(void) WriteBlobString(ofile,temp);
|
|
|
formatString( ofile, (char *)str, taglen );
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
|
|
|
tagsfound++;
|
|
|
}
|
|
|
return ((int) tagsfound);
|
|
|
}
|
|
|
|
|
|
static int format8BIM(Image *ifile, Image *ofile)
|
|
|
{
|
|
|
char
|
|
|
temp[MagickPathExtent];
|
|
|
|
|
|
unsigned int
|
|
|
foundOSType;
|
|
|
|
|
|
int
|
|
|
ID,
|
|
|
resCount,
|
|
|
i,
|
|
|
c;
|
|
|
|
|
|
ssize_t
|
|
|
count;
|
|
|
|
|
|
unsigned char
|
|
|
*PString,
|
|
|
*str;
|
|
|
|
|
|
resCount=0;
|
|
|
foundOSType=0; /* found the OSType */
|
|
|
(void) foundOSType;
|
|
|
c=ReadBlobByte(ifile);
|
|
|
while (c != EOF)
|
|
|
{
|
|
|
if (c == '8')
|
|
|
{
|
|
|
unsigned char
|
|
|
buffer[5];
|
|
|
|
|
|
buffer[0]=(unsigned char) c;
|
|
|
for (i=1; i<4; i++)
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return(-1);
|
|
|
buffer[i] = (unsigned char) c;
|
|
|
}
|
|
|
buffer[4]=0;
|
|
|
if (strcmp((const char *)buffer, "8BIM") == 0)
|
|
|
foundOSType=1;
|
|
|
else
|
|
|
continue;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
continue;
|
|
|
}
|
|
|
/*
|
|
|
We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
|
|
|
*/
|
|
|
ID=ReadBlobMSBSignedShort(ifile);
|
|
|
if (ID < 0)
|
|
|
return(-1);
|
|
|
{
|
|
|
unsigned char
|
|
|
plen;
|
|
|
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
return(-1);
|
|
|
plen = (unsigned char) c;
|
|
|
PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
|
|
|
MagickPathExtent),sizeof(*PString));
|
|
|
if (PString == (unsigned char *) NULL)
|
|
|
return 0;
|
|
|
for (i=0; i<plen; i++)
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
{
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
return -1;
|
|
|
}
|
|
|
PString[i] = (unsigned char) c;
|
|
|
}
|
|
|
PString[ plen ] = 0;
|
|
|
if ((plen & 0x01) == 0)
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
{
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
count=(ssize_t) ReadBlobMSBSignedLong(ifile);
|
|
|
if ((count < 0) || (count > (ssize_t) GetBlobSize(ifile)))
|
|
|
{
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
return -1;
|
|
|
}
|
|
|
/* make a buffer to hold the data and snag it from the input stream */
|
|
|
str=(unsigned char *) AcquireQuantumMemory((size_t) count+1,sizeof(*str));
|
|
|
if (str == (unsigned char *) NULL)
|
|
|
{
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
return 0;
|
|
|
}
|
|
|
for (i=0; i < (ssize_t) count; i++)
|
|
|
{
|
|
|
c=ReadBlobByte(ifile);
|
|
|
if (c == EOF)
|
|
|
{
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
return -1;
|
|
|
}
|
|
|
str[i]=(unsigned char) c;
|
|
|
}
|
|
|
|
|
|
/* we currently skip thumbnails, since it does not make
|
|
|
* any sense preserving them in a real world application
|
|
|
*/
|
|
|
if (ID != THUMBNAIL_ID)
|
|
|
{
|
|
|
/* now finish up by formatting this binary data into
|
|
|
* ASCII equivalent
|
|
|
*/
|
|
|
if (strlen((const char *)PString) > 0)
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d#%s=",ID,
|
|
|
PString);
|
|
|
else
|
|
|
(void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d=",ID);
|
|
|
(void) WriteBlobString(ofile,temp);
|
|
|
if (ID == IPTC_ID)
|
|
|
{
|
|
|
formatString(ofile, "IPTC", 4);
|
|
|
formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
|
|
|
}
|
|
|
else
|
|
|
formatString(ofile, (char *)str, (ssize_t) count);
|
|
|
}
|
|
|
str=(unsigned char *) RelinquishMagickMemory(str);
|
|
|
PString=(unsigned char *) RelinquishMagickMemory(PString);
|
|
|
resCount++;
|
|
|
c=ReadBlobByte(ifile);
|
|
|
}
|
|
|
return resCount;
|
|
|
}
|
|
|
|
|
|
static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
|
|
|
Image *image,ExceptionInfo *exception)
|
|
|
{
|
|
|
const StringInfo
|
|
|
*profile;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
size_t
|
|
|
length;
|
|
|
|
|
|
/*
|
|
|
Open image file.
|
|
|
*/
|
|
|
assert(image_info != (const ImageInfo *) NULL);
|
|
|
assert(image_info->signature == MagickCoreSignature);
|
|
|
assert(image != (Image *) NULL);
|
|
|
assert(image->signature == MagickCoreSignature);
|
|
|
if (image->debug != MagickFalse)
|
|
|
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
|
|
length=0;
|
|
|
if (LocaleCompare(image_info->magick,"8BIM") == 0)
|
|
|
{
|
|
|
/*
|
|
|
Write 8BIM image.
|
|
|
*/
|
|
|
profile=GetImageProfile(image,"8bim");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(status);
|
|
|
(void) WriteBlob(image,GetStringInfoLength(profile),
|
|
|
GetStringInfoDatum(profile));
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"iptc") == 0)
|
|
|
{
|
|
|
size_t
|
|
|
length;
|
|
|
|
|
|
unsigned char
|
|
|
*info;
|
|
|
|
|
|
profile=GetImageProfile(image,"iptc");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
profile=GetImageProfile(image,"8bim");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
info=GetStringInfoDatum(profile);
|
|
|
length=GetStringInfoLength(profile);
|
|
|
length=GetIPTCStream(&info,length);
|
|
|
if (length == 0)
|
|
|
ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
|
|
|
(void) WriteBlob(image,length,info);
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
|
|
|
{
|
|
|
Image
|
|
|
*buff;
|
|
|
|
|
|
profile=GetImageProfile(image,"8bim");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(status);
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
AttachBlob(buff->blob,GetStringInfoDatum(profile),
|
|
|
GetStringInfoLength(profile));
|
|
|
format8BIM(buff,image);
|
|
|
(void) DetachBlob(buff->blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
|
|
|
return(MagickFalse);
|
|
|
if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
|
|
|
{
|
|
|
Image
|
|
|
*buff;
|
|
|
|
|
|
unsigned char
|
|
|
*info;
|
|
|
|
|
|
profile=GetImageProfile(image,"8bim");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
|
|
|
info=GetStringInfoDatum(profile);
|
|
|
length=GetStringInfoLength(profile);
|
|
|
length=GetIPTCStream(&info,length);
|
|
|
if (length == 0)
|
|
|
ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(status);
|
|
|
buff=AcquireImage((ImageInfo *) NULL,exception);
|
|
|
if (buff == (Image *) NULL)
|
|
|
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
|
|
|
AttachBlob(buff->blob,info,length);
|
|
|
formatIPTC(buff,image);
|
|
|
(void) DetachBlob(buff->blob);
|
|
|
buff=DestroyImage(buff);
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
|
|
|
return(MagickFalse);
|
|
|
if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
|
|
|
(LocaleCompare(image_info->magick,"EXIF") == 0) ||
|
|
|
(LocaleCompare(image_info->magick,"XMP") == 0))
|
|
|
{
|
|
|
/*
|
|
|
(void) Write APP1 image.
|
|
|
*/
|
|
|
profile=GetImageProfile(image,image_info->magick);
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(status);
|
|
|
(void) WriteBlob(image,GetStringInfoLength(profile),
|
|
|
GetStringInfoDatum(profile));
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
|
|
|
(LocaleCompare(image_info->magick,"ICM") == 0))
|
|
|
{
|
|
|
/*
|
|
|
Write ICM image.
|
|
|
*/
|
|
|
profile=GetImageProfile(image,"icc");
|
|
|
if (profile == (StringInfo *) NULL)
|
|
|
ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
|
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
|
assert(exception->signature == MagickCoreSignature);
|
|
|
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(status);
|
|
|
(void) WriteBlob(image,GetStringInfoLength(profile),
|
|
|
GetStringInfoDatum(profile));
|
|
|
(void) CloseBlob(image);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
return(MagickFalse);
|
|
|
}
|