forked from openkylin/imagemagick
2476 lines
68 KiB
C
2476 lines
68 KiB
C
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% 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 "magick/studio.h"
|
||
#include "magick/blob.h"
|
||
#include "magick/blob-private.h"
|
||
#include "magick/exception.h"
|
||
#include "magick/exception-private.h"
|
||
#include "magick/image.h"
|
||
#include "magick/image-private.h"
|
||
#include "magick/list.h"
|
||
#include "magick/magick.h"
|
||
#include "magick/memory_.h"
|
||
#include "magick/module.h"
|
||
#include "magick/pixel-accessor.h"
|
||
#include "magick/profile.h"
|
||
#include "magick/quantum-private.h"
|
||
#include "magick/splay-tree.h"
|
||
#include "magick/static.h"
|
||
#include "magick/string_.h"
|
||
#include "magick/string-private.h"
|
||
#include "magick/token.h"
|
||
#include "magick/utility.h"
|
||
|
||
/*
|
||
Forward declarations.
|
||
*/
|
||
static MagickBooleanType
|
||
WriteMETAImage(const ImageInfo *,Image *);
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% 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 = MaxTextExtent;
|
||
|
||
ssize_t
|
||
savedolen = 0L,
|
||
outputlen = 0L;
|
||
|
||
TokenInfo
|
||
*token_info;
|
||
|
||
dataset = 0;
|
||
recnum = 0;
|
||
line = (char *) AcquireQuantumMemory((size_t) 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)+MaxTextExtent,
|
||
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,
|
||
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 ((q-p+1) >= (int) 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)
|
||
{
|
||
p=(unsigned char *) RelinquishMagickMemory(p);
|
||
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 = MaxTextExtent;
|
||
|
||
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)+MaxTextExtent,
|
||
sizeof(*name));
|
||
if (name)
|
||
(void) CopyMagickString(name,newstr,strlen(newstr)+MaxTextExtent);
|
||
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 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);
|
||
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) == MagickFalse)
|
||
{
|
||
InheritException(exception,&image->exception);
|
||
image=DestroyImageList(image);
|
||
return((Image *) NULL);
|
||
}
|
||
length=1;
|
||
if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
|
||
{
|
||
/*
|
||
Read 8BIM binary metadata.
|
||
*/
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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=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=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=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
}
|
||
status=SetImageProfile(image,"8bim",profile);
|
||
profile=DestroyStringInfo(profile);
|
||
blob=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[MaxTextExtent];
|
||
|
||
(void) FormatLocaleString(name,MaxTextExtent,"APP%d",1);
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
|
||
}
|
||
profile=CloneStringInfo((StringInfo *) image_info->profile);
|
||
iptc=AcquireImage((ImageInfo *) NULL);
|
||
if (iptc == (Image *) NULL)
|
||
{
|
||
blob=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=DetachBlob(iptc->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
iptc=DestroyImage(iptc);
|
||
if (result == 0)
|
||
ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
|
||
}
|
||
else
|
||
CopyBlob(image,buff);
|
||
profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
|
||
GetBlobSize(buff));
|
||
if (profile == (StringInfo *) NULL)
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
status=SetImageProfile(image,name,profile);
|
||
profile=DestroyStringInfo(profile);
|
||
blob=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
if (status == MagickFalse)
|
||
{
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
}
|
||
}
|
||
if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
|
||
(LocaleCompare(image_info->magick,"ICM") == 0))
|
||
{
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
}
|
||
(void) SetImageProfile(image,"icc",profile);
|
||
profile=DestroyStringInfo(profile);
|
||
blob=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
}
|
||
if (LocaleCompare(image_info->magick,"IPTC") == 0)
|
||
{
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
}
|
||
(void) SetImageProfile(image,"iptc",profile);
|
||
profile=DestroyStringInfo(profile);
|
||
blob=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
}
|
||
if (LocaleCompare(image_info->magick,"XMP") == 0)
|
||
{
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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=DetachBlob(buff->blob);
|
||
blob=(unsigned char *) RelinquishMagickMemory(blob);
|
||
buff=DestroyImage(buff);
|
||
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
|
||
}
|
||
(void) SetImageProfile(image,"xmp",profile);
|
||
profile=DestroyStringInfo(profile);
|
||
blob=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=SetMagickInfo("8BIM");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Photoshop resource format");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("8BIMTEXT");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Photoshop resource text format");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("8BIMWTEXT");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Photoshop resource wide text format");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("APP1");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Raw application information");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("APP1JPEG");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Raw JPEG binary data");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("EXIF");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Exif digital camera binary data");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("XMP");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("Adobe XML metadata");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("ICM");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("ICC Color Profile");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("ICC");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("ICC Color Profile");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("IPTC");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("IPTC Newsphoto");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("IPTCTEXT");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("IPTC Newsphoto text format");
|
||
entry->magick_module=ConstantString("META");
|
||
(void) RegisterMagickInfo(entry);
|
||
entry=SetMagickInfo("IPTCWTEXT");
|
||
entry->decoder=(DecodeImageHandler *) ReadMETAImage;
|
||
entry->encoder=(EncodeImageHandler *) WriteMETAImage;
|
||
entry->adjoin=MagickFalse;
|
||
entry->stealth=MagickTrue;
|
||
entry->seekable_stream=MagickTrue;
|
||
entry->description=ConstantString("IPTC Newsphoto text format");
|
||
entry->magick_module=ConstantString("META");
|
||
(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)
|
||
%
|
||
% 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.
|
||
%
|
||
*/
|
||
|
||
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[MaxTextExtent];
|
||
|
||
(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,MaxTextExtent,"&#%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[MaxTextExtent];
|
||
|
||
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+MaxTextExtent),
|
||
sizeof(*str));
|
||
if (str == (unsigned char *) NULL)
|
||
{
|
||
(void) printf("MemoryAllocationFailed");
|
||
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,MaxTextExtent,"%d#%d#%s=",
|
||
(unsigned int) dataset, (unsigned int) recnum, readable);
|
||
else
|
||
(void) FormatLocaleString(temp,MaxTextExtent,"%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[MaxTextExtent];
|
||
|
||
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+MaxTextExtent),
|
||
sizeof(*str));
|
||
if (str == (unsigned char *) NULL)
|
||
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,MaxTextExtent,"%d#%d#%s=",
|
||
(unsigned int) dataset,(unsigned int) recnum, readable);
|
||
else
|
||
(void) FormatLocaleString(temp,MaxTextExtent,"%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[MaxTextExtent];
|
||
|
||
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+
|
||
MaxTextExtent),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,MaxTextExtent,"8BIM#%d#%s=",ID,
|
||
PString);
|
||
else
|
||
(void) FormatLocaleString(temp,MaxTextExtent,"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)
|
||
{
|
||
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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
|
||
if (status == MagickFalse)
|
||
return(status);
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
|
||
if (status == MagickFalse)
|
||
return(status);
|
||
buff=AcquireImage((ImageInfo *) NULL);
|
||
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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->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");
|
||
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
|
||
if (status == MagickFalse)
|
||
return(status);
|
||
(void) WriteBlob(image,GetStringInfoLength(profile),
|
||
GetStringInfoDatum(profile));
|
||
(void) CloseBlob(image);
|
||
return(MagickTrue);
|
||
}
|
||
return(MagickFalse);
|
||
}
|