trimbox;
SegmentInfo
- bounds,
- hires_bounds;
+ bounds;
StringInfo
*profile;
} PDFInfo;
+
+typedef struct _PDFBuffer
+{
+ Image
+ *image;
+
+ size_t
+ offset;
+
+ ssize_t
+ count;
+
+ unsigned char
+ data[MagickPathExtent];
+} PDFBuffer;
\f
/*
Forward declarations.
return(MagickFalse);
}
-static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *info,
+static inline int ReadPDFByte(PDFBuffer *buffer)
+{
+ if (((ssize_t)buffer->offset == buffer->count) && (buffer->offset > 0))
+ {
+ if (buffer->count != sizeof(buffer->data))
+ return(EOF);
+ buffer->offset=0;
+ }
+ if (buffer->offset == 0)
+ {
+ buffer->count=ReadBlob(buffer->image,sizeof(buffer->data),buffer->data);
+ if (buffer->count < 1)
+ return(EOF);
+ }
+ return(buffer->data[buffer->offset++]);
+}
+
+static char *MovePDFBuffer(PDFBuffer *buffer)
+{
+ ssize_t
+ i;
+
+ i=1; // Skip first to avoid reload of buffer;
+ while ((ssize_t)buffer->offset != buffer->count)
+ buffer->data[i++] = buffer->data[buffer->offset++];
+ buffer->count=ReadBlob(buffer->image,sizeof(buffer->data)-i,
+ buffer->data+i);
+ buffer->count+=i;
+ buffer->offset=1;
+ return((char *) buffer->data+1);
+}
+
+static inline void CheckRemainingPDFBuffer(PDFBuffer *buffer,size_t length)
+{
+ if (buffer->offset + length > sizeof(buffer->data))
+ (void)MovePDFBuffer(buffer);
+}
+
+static inline void SkipPDFBytes(PDFBuffer *buffer,size_t count)
+{
+ CheckRemainingPDFBuffer(buffer,count);
+ buffer->offset+=count;
+}
+
+static inline MagickBooleanType ComparePDFBuffer(const char *p,
+ PDFBuffer *buffer,const size_t length)
+{
+ const char
+ *q;
+
+ CheckRemainingPDFBuffer(buffer,length);
+ q=(const char *) buffer->data+buffer->offset;
+ if (LocaleNCompare(p,q,length) != 0)
+ return(MagickFalse);
+ return(MagickTrue);
+}
+
+static void ReadPDFXMPProfile(PDFInfo *pdf_info,PDFBuffer *buffer)
+{
+#define BeginXMPPacket "?xpacket begin="
+#define EndXMPPacket "<?xpacket end="
+
+ int
+ c;
+
+ MagickBooleanType
+ found_end;
+
+ register char
+ *p;
+
+ size_t
+ length,
+ count;
+
+ if (pdf_info->profile != (StringInfo *) NULL)
+ return;
+ if (ComparePDFBuffer(BeginXMPPacket,buffer,strlen(BeginXMPPacket)) == MagickFalse)
+ return;
+ length=MagickPathExtent;
+ pdf_info->profile=AcquireStringInfo(length);
+ found_end=MagickFalse;
+ p=(char *) GetStringInfoDatum(pdf_info->profile);
+ *p++='<';
+ count=1;
+ for (c=ReadPDFByte(buffer); c != EOF; c=ReadPDFByte(buffer))
+ {
+ if (count == length)
+ {
+ length+=MagickPathExtent;
+ SetStringInfoLength(pdf_info->profile,length);
+ p=(char *) GetStringInfoDatum(pdf_info->profile)+count;
+ }
+ count++;
+ *p++=(char) c;
+ if (found_end == MagickFalse)
+ found_end=ComparePDFBuffer(EndXMPPacket,buffer,strlen(EndXMPPacket));
+ else
+ {
+ if (c == (int)'>')
+ break;
+ }
+ }
+ SetStringInfoLength(pdf_info->profile,count);
+}
+
+static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *pdf_info,
ExceptionInfo *exception)
{
-#define BeginXMPPacket "<?xpacket begin="
#define CMYKProcessColor "CMYKProcessColor"
#define CropBox "CropBox"
#define DefaultCMYK "DefaultCMYK"
#define DeviceCMYK "DeviceCMYK"
-#define EndXMPPacket "<?xpacket end="
#define MediaBox "MediaBox"
#define PDFRotate "Rotate"
#define SpotColor "Separation"
#define PDFVersion "PDF-"
char
- buffer[MagickPathExtent];
+ version[MagickPathExtent];
int
c;
+ PDFBuffer
+ buffer;
+
register char
*p;
register ssize_t
i;
+ SegmentInfo
+ bounds;
+
size_t
spotcolor;
ssize_t
count;
- (void) memset(info,0,sizeof(*info));
- info->cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
- info->cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
- info->trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
+ (void) memset(&bounds,0,sizeof(bounds));
+ (void) memset(pdf_info,0,sizeof(*pdf_info));
+ pdf_info->cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
+ pdf_info->cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
+ pdf_info->trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
+ version[0]='\0';
spotcolor=0;
- (void) memset(buffer,0,sizeof(buffer));
- p=buffer;
- for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
+ (void) memset(&buffer,0,sizeof(buffer));
+ buffer.image=image;
+ for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
{
- /*
- Note PDF elements.
- */
- if (c == '\n')
- c=' ';
- *p++=(char) c;
- if ((c != (int) '/') && (c != (int) '%') &&
- ((size_t) (p-buffer) < (MagickPathExtent-1)))
- continue;
- *(--p)='\0';
- p=buffer;
- if (LocaleNCompare(PDFRotate,buffer,strlen(PDFRotate)) == 0)
- (void) sscanf(buffer,"Rotate %lf",&info->angle);
- /*
- Is this a CMYK document?
- */
- if (info->cmyk == MagickFalse)
+ switch(c)
{
- if ((LocaleNCompare(DefaultCMYK,buffer,strlen(DefaultCMYK)) == 0) ||
- (LocaleNCompare(DeviceCMYK,buffer,strlen(DeviceCMYK)) == 0) ||
- (LocaleNCompare(CMYKProcessColor,buffer,strlen(CMYKProcessColor)) == 0))
- {
- info->cmyk=MagickTrue;
- continue;
- }
+ case '%':
+ if (version[0] == '\0')
+ {
+ i=0;
+ for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
+ {
+ if ((c == '\r') || (c == '\n') || ((i+1) == MagickPathExtent))
+ break;
+ version[i++]=(char) c;
+ }
+ version[i]='\0';
+ }
+ continue;
+ case '<':
+ ReadPDFXMPProfile(pdf_info,&buffer);
+ continue;
+ case '/':
+ break;
+ default:
+ continue;
}
- if (LocaleNCompare(SpotColor,buffer,strlen(SpotColor)) == 0)
+ if (ComparePDFBuffer(PDFRotate,&buffer,strlen(PDFRotate)) != MagickFalse)
+ {
+ p=MovePDFBuffer(&buffer);
+ (void) sscanf(p,PDFRotate" %lf",&pdf_info->angle);
+ }
+ if (pdf_info->cmyk == MagickFalse)
+ {
+ if ((ComparePDFBuffer(DefaultCMYK,&buffer,strlen(DefaultCMYK)) != MagickFalse) ||
+ (ComparePDFBuffer(DeviceCMYK,&buffer,strlen(DeviceCMYK)) != MagickFalse) ||
+ (ComparePDFBuffer(CMYKProcessColor,&buffer,strlen(CMYKProcessColor)) != MagickFalse))
+ {
+ pdf_info->cmyk=MagickTrue;
+ continue;
+ }
+ }
+ if (ComparePDFBuffer(SpotColor,&buffer,strlen(SpotColor)) != MagickFalse)
{
char
name[MagickPathExtent],
(void) FormatLocaleString(property,MagickPathExtent,
"pdf:SpotColor-%.20g",(double) spotcolor++);
i=0;
- for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
+ SkipPDFBytes(&buffer,strlen(SpotColor)+1);
+ for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
{
if ((isspace(c) != 0) || (c == '/') || ((i+1) == MagickPathExtent))
break;
value=DestroyString(value);
continue;
}
- if (LocaleNCompare(PDFVersion,buffer,strlen(PDFVersion)) == 0)
- {
- (void) SetImageProperty(image,"pdf:Version",buffer,exception);
- continue;
- }
- if ((info->profile == (StringInfo *) NULL) &&
- (LocaleNCompare(BeginXMPPacket,buffer,strlen(BeginXMPPacket)) == 0))
- {
- /*
- Read XMP profile.
- */
- p=buffer;
- info->profile=StringToStringInfo(buffer);
- for (i=(ssize_t) GetStringInfoLength(info->profile)-1; c != EOF; i++)
- {
- SetStringInfoLength(info->profile,(size_t) (i+1));
- c=ReadBlobByte(image);
- GetStringInfoDatum(info->profile)[i]=(unsigned char) c;
- *p++=(char) c;
- if ((strchr("\n\r%",c) == (char *) NULL) &&
- ((size_t) (p-buffer) < (MagickPathExtent-1)))
- continue;
- *p='\0';
- p=buffer;
- if (LocaleNCompare(EndXMPPacket,buffer,strlen(EndXMPPacket)) == 0)
- break;
- }
- SetStringInfoLength(info->profile,(size_t) i);
- continue;
- }
if (image_info->page != (char *) NULL)
continue;
count=0;
- if (info->cropbox != MagickFalse)
+ if (pdf_info->cropbox != MagickFalse)
{
- if (LocaleNCompare(CropBox,buffer,strlen(CropBox)) == 0)
+ if (ComparePDFBuffer(CropBox,&buffer,strlen(CropBox)) != MagickFalse)
{
/*
Note region defined by crop box.
*/
- count=(ssize_t) sscanf(buffer,"CropBox [%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ p=MovePDFBuffer(&buffer);
+ count=(ssize_t) sscanf(p,"CropBox [%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
if (count != 4)
- count=(ssize_t) sscanf(buffer,"CropBox[%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ count=(ssize_t) sscanf(p,"CropBox[%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
}
}
else
- if (info->trimbox != MagickFalse)
+ if (pdf_info->trimbox != MagickFalse)
{
- if (LocaleNCompare(TrimBox,buffer,strlen(TrimBox)) == 0)
+ if (ComparePDFBuffer(TrimBox,&buffer,strlen(TrimBox)) != MagickFalse)
{
/*
Note region defined by trim box.
*/
- count=(ssize_t) sscanf(buffer,"TrimBox [%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ p=MovePDFBuffer(&buffer);
+ count=(ssize_t) sscanf(p,"TrimBox [%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
if (count != 4)
- count=(ssize_t) sscanf(buffer,"TrimBox[%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ count=(ssize_t) sscanf(p,"TrimBox[%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
}
}
else
- if (LocaleNCompare(MediaBox,buffer,strlen(MediaBox)) == 0)
+ if (ComparePDFBuffer(MediaBox,&buffer,strlen(MediaBox)) != MagickFalse)
{
/*
Note region defined by media box.
*/
- count=(ssize_t) sscanf(buffer,"MediaBox [%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ p=MovePDFBuffer(&buffer);
+ count=(ssize_t) sscanf(p,"MediaBox [%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
if (count != 4)
- count=(ssize_t) sscanf(buffer,"MediaBox[%lf %lf %lf %lf",
- &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
- &info->bounds.y2);
+ count=(ssize_t) sscanf(p,"MediaBox[%lf %lf %lf %lf",
+ &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
}
if (count != 4)
continue;
- if ((fabs(info->bounds.x2-info->bounds.x1) <= fabs(info->hires_bounds.x2-info->hires_bounds.x1)) ||
- (fabs(info->bounds.y2-info->bounds.y1) <= fabs(info->hires_bounds.y2-info->hires_bounds.y1)))
+ if ((fabs(bounds.x2-bounds.x1) <= fabs(pdf_info->bounds.x2-pdf_info->bounds.x1)) ||
+ (fabs(bounds.y2-bounds.y1) <= fabs(pdf_info->bounds.y2-pdf_info->bounds.y1)))
continue;
- info->hires_bounds=info->bounds;
+ pdf_info->bounds=bounds;
}
+ if (version[0] != '\0')
+ (void) SetImageProperty(image,"pdf:Version",version,exception);
}
-static inline void CleanupPDFInfo(PDFInfo *info)
+static inline void CleanupPDFInfo(PDFInfo *pdf_info)
{
- if (info->profile != (StringInfo *) NULL)
- info->profile=DestroyStringInfo(info->profile);
+ if (pdf_info->profile != (StringInfo *) NULL)
+ pdf_info->profile=DestroyStringInfo(pdf_info->profile);
}
static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
flags;
PDFInfo
- info;
+ pdf_info;
PointInfo
delta;
/*
Determine page geometry from the PDF media box.
*/
- ReadPDFInfo(image_info,image,&info,exception);
+ ReadPDFInfo(image_info,image,&pdf_info,exception);
(void) CloseBlob(image);
/*
Set PDF render geometry.
*/
- if ((fabs(info.hires_bounds.x2-info.hires_bounds.x1) >= MagickEpsilon) &&
- (fabs(info.hires_bounds.y2-info.hires_bounds.y1) >= MagickEpsilon))
+ if ((fabs(pdf_info.bounds.x2-pdf_info.bounds.x1) >= MagickEpsilon) &&
+ (fabs(pdf_info.bounds.y2-pdf_info.bounds.y1) >= MagickEpsilon))
{
(void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g",
- info.hires_bounds.x2-info.bounds.x1,info.hires_bounds.y2-
- info.hires_bounds.y1,info.hires_bounds.x1,info.hires_bounds.y1);
+ pdf_info.bounds.x2-pdf_info.bounds.x1,pdf_info.bounds.y2-
+ pdf_info.bounds.y1,pdf_info.bounds.x1,pdf_info.bounds.y1);
(void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry,exception);
- page.width=(size_t) ceil((double) ((info.hires_bounds.x2-info.hires_bounds.x1)*
- image->resolution.x/delta.x)-0.5);
- page.height=(size_t) ceil((double) ((info.hires_bounds.y2-info.hires_bounds.y1)*
- image->resolution.y/delta.y)-0.5);
+ page.width=(size_t) ceil((double) ((pdf_info.bounds.x2-
+ pdf_info.bounds.x1)*image->resolution.x/delta.x)-0.5);
+ page.height=(size_t) ceil((double) ((pdf_info.bounds.y2-
+ pdf_info.bounds.y1)*image->resolution.y/delta.y)-0.5);
}
fitPage=MagickFalse;
option=GetImageOption(image_info,"pdf:fit-page");
{
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
"InvalidGeometry","`%s'",option);
- CleanupPDFInfo(&info);
+ CleanupPDFInfo(&pdf_info);
image=DestroyImage(image);
return((Image *) NULL);
}
delta.y) -0.5);
fitPage=MagickTrue;
}
- if ((fabs(info.angle) == 90.0) || (fabs(info.angle) == 270.0))
+ if ((fabs(pdf_info.angle) == 90.0) || (fabs(pdf_info.angle) == 270.0))
{
size_t
swap;
page.height=swap;
}
if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
- info.cmyk=MagickFalse;
+ pdf_info.cmyk=MagickFalse;
stop_on_error=IsStringTrue(GetImageOption(image_info,"pdf:stop-on-error"));
/*
Create Ghostscript control file.
{
ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
image_info->filename);
- CleanupPDFInfo(&info);
+ CleanupPDFInfo(&pdf_info);
image=DestroyImage(image);
return((Image *) NULL);
}
if (image_info->monochrome != MagickFalse)
delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
else
- if (info.cmyk != MagickFalse)
+ if (pdf_info.cmyk != MagickFalse)
delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
else
delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
if (delegate_info == (const DelegateInfo *) NULL)
{
(void) RelinquishUniqueFileResource(postscript_filename);
- CleanupPDFInfo(&info);
+ CleanupPDFInfo(&pdf_info);
image=DestroyImage(image);
return((Image *) NULL);
}
page.width,(double) page.height);
if (fitPage != MagickFalse)
(void) ConcatenateMagickString(options,"-dPSFitPage ",MagickPathExtent);
- if (info.cmyk != MagickFalse)
+ if (pdf_info.cmyk != MagickFalse)
(void) ConcatenateMagickString(options,"-dUseCIEColor ",MagickPathExtent);
- if (info.cropbox != MagickFalse)
+ if (pdf_info.cropbox != MagickFalse)
(void) ConcatenateMagickString(options,"-dUseCropBox ",MagickPathExtent);
if (stop_on_error != MagickFalse)
(void) ConcatenateMagickString(options,"-dPDFSTOPONERROR ",
MagickPathExtent);
- if (info.trimbox != MagickFalse)
+ if (pdf_info.trimbox != MagickFalse)
(void) ConcatenateMagickString(options,"-dUseTrimBox ",MagickPathExtent);
option=GetImageOption(image_info,"authenticate");
if (option != (char *) NULL)
if (*message != '\0')
(void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
"PDFDelegateFailed","`%s'",message);
- CleanupPDFInfo(&info);
+ CleanupPDFInfo(&pdf_info);
image=DestroyImage(image);
return((Image *) NULL);
}
pdf_image=cmyk_image;
}
}
- if (info.profile != (StringInfo *) NULL)
- (void) SetImageProfile(image,"xmp",info.profile,exception);
- CleanupPDFInfo(&info);
+ if (pdf_info.profile != (StringInfo *) NULL)
+ (void) SetImageProfile(image,"xmp",pdf_info.profile,exception);
+ CleanupPDFInfo(&pdf_info);
if (image_info->number_scenes != 0)
{
Image