Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
ImageMagick/coders/pdf.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
3288 lines (3149 sloc)
110 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% PPPP DDDD FFFFF % | |
% P P D D F % | |
% PPPP D D FFF % | |
% P D D F % | |
% P DDDD F % | |
% % | |
% % | |
% Read/Write Portable Document Format % | |
% % | |
% Software Design % | |
% Cristy % | |
% July 1992 % | |
% % | |
% % | |
% Copyright @ 1999 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/attribute.h" | |
#include "MagickCore/artifact.h" | |
#include "MagickCore/blob.h" | |
#include "MagickCore/blob-private.h" | |
#include "MagickCore/cache.h" | |
#include "MagickCore/channel.h" | |
#include "MagickCore/color.h" | |
#include "MagickCore/color-private.h" | |
#include "MagickCore/colorspace.h" | |
#include "MagickCore/colorspace-private.h" | |
#include "MagickCore/compress.h" | |
#include "MagickCore/constitute.h" | |
#include "MagickCore/delegate.h" | |
#include "MagickCore/delegate-private.h" | |
#include "MagickCore/distort.h" | |
#include "MagickCore/draw.h" | |
#include "MagickCore/exception.h" | |
#include "MagickCore/exception-private.h" | |
#include "MagickCore/geometry.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/monitor.h" | |
#include "MagickCore/montage.h" | |
#include "MagickCore/monitor-private.h" | |
#include "MagickCore/nt-base-private.h" | |
#include "MagickCore/option.h" | |
#include "MagickCore/pixel-accessor.h" | |
#include "MagickCore/profile.h" | |
#include "MagickCore/property.h" | |
#include "MagickCore/quantum-private.h" | |
#include "MagickCore/resource_.h" | |
#include "MagickCore/resize.h" | |
#include "MagickCore/signature.h" | |
#include "MagickCore/static.h" | |
#include "MagickCore/string_.h" | |
#include "MagickCore/string-private.h" | |
#include "MagickCore/timer-private.h" | |
#include "MagickCore/token.h" | |
#include "MagickCore/transform.h" | |
#include "MagickCore/utility.h" | |
#include "MagickCore/xml-tree-private.h" | |
#include "coders/bytebuffer-private.h" | |
#include "coders/coders-private.h" | |
#include "coders/ghostscript-private.h" | |
/* | |
Define declarations. | |
*/ | |
#if defined(MAGICKCORE_TIFF_DELEGATE) | |
#define CCITTParam "-1" | |
#else | |
#define CCITTParam "0" | |
#endif | |
/* | |
Typedef declarations. | |
*/ | |
typedef struct _PDFInfo | |
{ | |
double | |
angle; | |
MagickBooleanType | |
cmyk, | |
cropbox, | |
trimbox; | |
SegmentInfo | |
bounds; | |
StringInfo | |
*profile; | |
} PDFInfo; | |
/* | |
Forward declarations. | |
*/ | |
static MagickBooleanType | |
WritePDFImage(const ImageInfo *,Image *,ExceptionInfo *), | |
WritePOCKETMODImage(const ImageInfo *,Image *,ExceptionInfo *); | |
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% I s P D F % | |
% % | |
% % | |
% % | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% IsPDF() returns MagickTrue if the image format type, identified by the | |
% magick string, is PDF. | |
% | |
% The format of the IsPDF method is: | |
% | |
% MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset) | |
% | |
% A description of each parameter follows: | |
% | |
% o magick: compare image format pattern against these bytes. | |
% | |
% o offset: Specifies the offset of the magick string. | |
% | |
*/ | |
static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset) | |
{ | |
if (offset < 5) | |
return(MagickFalse); | |
if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0) | |
return(MagickTrue); | |
return(MagickFalse); | |
} | |
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% R e a d P D F I m a g e % | |
% % | |
% % | |
% % | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% ReadPDFImage() reads a Portable Document Format 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 ReadPDFImage method is: | |
% | |
% Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception) | |
% | |
% A description of each parameter follows: | |
% | |
% o image_info: the image info. | |
% | |
% o exception: return any errors or warnings in this structure. | |
% | |
*/ | |
static void ReadPDFInfo(const ImageInfo *image_info,Image *image, | |
PDFInfo *pdf_info,ExceptionInfo *exception) | |
{ | |
#define CMYKProcessColor "CMYKProcessColor" | |
#define CropBox "CropBox" | |
#define DefaultCMYK "DefaultCMYK" | |
#define DeviceCMYK "DeviceCMYK" | |
#define MediaBox "MediaBox" | |
#define PDFRotate "Rotate" | |
#define SpotColor "Separation" | |
#define TrimBox "TrimBox" | |
#define PDFVersion "PDF-" | |
char | |
version[MagickPathExtent]; | |
int | |
c, | |
percent_count; | |
MagickByteBuffer | |
buffer; | |
char | |
*p; | |
ssize_t | |
i; | |
SegmentInfo | |
bounds; | |
size_t | |
spotcolor; | |
ssize_t | |
count; | |
(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'; | |
spotcolor=0; | |
percent_count=0; | |
(void) memset(&buffer,0,sizeof(buffer)); | |
buffer.image=image; | |
for (c=ReadMagickByteBuffer(&buffer); c != EOF; c=ReadMagickByteBuffer(&buffer)) | |
{ | |
if (c == '%') | |
{ | |
if (*version == '\0') | |
{ | |
i=0; | |
for (c=ReadMagickByteBuffer(&buffer); c != EOF; c=ReadMagickByteBuffer(&buffer)) | |
{ | |
if ((c == '\r') || (c == '\n') || ((i+1) == MagickPathExtent)) | |
break; | |
version[i++]=(char) c; | |
} | |
version[i]='\0'; | |
if (c == EOF) | |
break; | |
} | |
if (++percent_count == 2) | |
percent_count=0; | |
else | |
continue; | |
} | |
else | |
{ | |
percent_count=0; | |
switch(c) | |
{ | |
case '<': | |
{ | |
ReadGhostScriptXMPProfile(&buffer,&pdf_info->profile); | |
continue; | |
} | |
case '/': | |
break; | |
default: | |
continue; | |
} | |
} | |
if (CompareMagickByteBuffer(&buffer,PDFRotate,strlen(PDFRotate)) != MagickFalse) | |
{ | |
p=GetMagickByteBufferDatum(&buffer); | |
(void) sscanf(p,PDFRotate" %lf",&pdf_info->angle); | |
} | |
if (pdf_info->cmyk == MagickFalse) | |
{ | |
if ((CompareMagickByteBuffer(&buffer,DefaultCMYK,strlen(DefaultCMYK)) != MagickFalse) || | |
(CompareMagickByteBuffer(&buffer,DeviceCMYK,strlen(DeviceCMYK)) != MagickFalse) || | |
(CompareMagickByteBuffer(&buffer,CMYKProcessColor,strlen(CMYKProcessColor)) != MagickFalse)) | |
{ | |
pdf_info->cmyk=MagickTrue; | |
continue; | |
} | |
} | |
if (CompareMagickByteBuffer(&buffer,SpotColor,strlen(SpotColor)) != MagickFalse) | |
{ | |
char | |
name[MagickPathExtent], | |
property[MagickPathExtent], | |
*value; | |
/* | |
Note spot names. | |
*/ | |
(void) FormatLocaleString(property,MagickPathExtent, | |
"pdf:SpotColor-%.20g",(double) spotcolor++); | |
i=0; | |
SkipMagickByteBuffer(&buffer,strlen(SpotColor)+1); | |
for (c=ReadMagickByteBuffer(&buffer); c != EOF; c=ReadMagickByteBuffer(&buffer)) | |
{ | |
if ((isspace((int) ((unsigned char) c)) != 0) || (c == '/') || ((i+1) == MagickPathExtent)) | |
break; | |
name[i++]=(char) c; | |
} | |
if (c == EOF) | |
break; | |
name[i]='\0'; | |
value=ConstantString(name); | |
(void) SubstituteString(&value,"#20"," "); | |
if (*value != '\0') | |
(void) SetImageProperty(image,property,value,exception); | |
value=DestroyString(value); | |
continue; | |
} | |
if (image_info->page != (char *) NULL) | |
continue; | |
count=0; | |
if (pdf_info->cropbox != MagickFalse) | |
{ | |
if (CompareMagickByteBuffer(&buffer,CropBox,strlen(CropBox)) != MagickFalse) | |
{ | |
/* | |
Note region defined by crop box. | |
*/ | |
p=GetMagickByteBufferDatum(&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(p,"CropBox[%lf %lf %lf %lf",&bounds.x1, | |
&bounds.y1,&bounds.x2,&bounds.y2); | |
} | |
} | |
else | |
if (pdf_info->trimbox != MagickFalse) | |
{ | |
if (CompareMagickByteBuffer(&buffer,TrimBox,strlen(TrimBox)) != MagickFalse) | |
{ | |
/* | |
Note region defined by trim box. | |
*/ | |
p=GetMagickByteBufferDatum(&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(p,"TrimBox[%lf %lf %lf %lf",&bounds.x1, | |
&bounds.y1,&bounds.x2,&bounds.y2); | |
} | |
} | |
else | |
if (CompareMagickByteBuffer(&buffer,MediaBox,strlen(MediaBox)) != MagickFalse) | |
{ | |
/* | |
Note region defined by media box. | |
*/ | |
p=GetMagickByteBufferDatum(&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(p,"MediaBox[%lf %lf %lf %lf",&bounds.x1, | |
&bounds.y1,&bounds.x2,&bounds.y2); | |
} | |
if (count != 4) | |
continue; | |
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; | |
pdf_info->bounds=bounds; | |
} | |
if (version[0] != '\0') | |
(void) SetImageProperty(image,"pdf:Version",version,exception); | |
} | |
static inline void CleanupPDFInfo(PDFInfo *pdf_info) | |
{ | |
if (pdf_info->profile != (StringInfo *) NULL) | |
pdf_info->profile=DestroyStringInfo(pdf_info->profile); | |
} | |
static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception) | |
{ | |
char | |
command[MagickPathExtent], | |
*density, | |
filename[MagickPathExtent], | |
input_filename[MagickPathExtent], | |
message[MagickPathExtent], | |
*options, | |
postscript_filename[MagickPathExtent]; | |
const char | |
*option; | |
const DelegateInfo | |
*delegate_info; | |
GeometryInfo | |
geometry_info; | |
Image | |
*image, | |
*next, | |
*pdf_image; | |
ImageInfo | |
*read_info; | |
int | |
file; | |
MagickBooleanType | |
fitPage, | |
status; | |
MagickStatusType | |
flags; | |
PDFInfo | |
pdf_info; | |
PointInfo | |
delta; | |
RectangleInfo | |
page; | |
ssize_t | |
i; | |
size_t | |
scene; | |
assert(image_info != (const ImageInfo *) NULL); | |
assert(image_info->signature == MagickCoreSignature); | |
assert(exception != (ExceptionInfo *) NULL); | |
assert(exception->signature == MagickCoreSignature); | |
if (IsEventLogging() != MagickFalse) | |
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", | |
image_info->filename); | |
/* | |
Open image file. | |
*/ | |
image=AcquireImage(image_info,exception); | |
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); | |
if (status == MagickFalse) | |
{ | |
image=DestroyImageList(image); | |
return((Image *) NULL); | |
} | |
status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); | |
if (status == MagickFalse) | |
{ | |
ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", | |
image_info->filename); | |
image=DestroyImageList(image); | |
return((Image *) NULL); | |
} | |
/* | |
Set the page density. | |
*/ | |
delta.x=DefaultResolution; | |
delta.y=DefaultResolution; | |
(void) memset(&page,0,sizeof(page)); | |
if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) | |
{ | |
flags=ParseGeometry(PSDensityGeometry,&geometry_info); | |
if ((flags & RhoValue) != 0) | |
image->resolution.x=geometry_info.rho; | |
image->resolution.y=image->resolution.x; | |
if ((flags & SigmaValue) != 0) | |
image->resolution.y=geometry_info.sigma; | |
} | |
if (image_info->density != (char *) NULL) | |
{ | |
flags=ParseGeometry(image_info->density,&geometry_info); | |
if ((flags & RhoValue) != 0) | |
image->resolution.x=geometry_info.rho; | |
image->resolution.y=image->resolution.x; | |
if ((flags & SigmaValue) != 0) | |
image->resolution.y=geometry_info.sigma; | |
} | |
(void) ParseAbsoluteGeometry(PSPageGeometry,&page); | |
if (image_info->page != (char *) NULL) | |
(void) ParseAbsoluteGeometry(image_info->page,&page); | |
page.width=(size_t) ((ssize_t) ceil((double) (page.width* | |
image->resolution.x/delta.x)-0.5)); | |
page.height=(size_t) ((ssize_t) ceil((double) (page.height* | |
image->resolution.y/delta.y)-0.5)); | |
/* | |
Determine page geometry from the PDF media box. | |
*/ | |
ReadPDFInfo(image_info,image,&pdf_info,exception); | |
(void) CloseBlob(image); | |
/* | |
Set PDF render geometry. | |
*/ | |
if ((fabs(pdf_info.bounds.x2-pdf_info.bounds.x1) >= MagickEpsilon) && | |
(fabs(pdf_info.bounds.y2-pdf_info.bounds.y1) >= MagickEpsilon)) | |
{ | |
(void) FormatImageProperty(image,"pdf:HiResBoundingBox", | |
"%gx%g%+.15g%+.15g",pdf_info.bounds.x2-pdf_info.bounds.x1, | |
pdf_info.bounds.y2-pdf_info.bounds.y1,pdf_info.bounds.x1, | |
pdf_info.bounds.y1); | |
page.width=(size_t) ((ssize_t) ceil((double) ((pdf_info.bounds.x2- | |
pdf_info.bounds.x1)*image->resolution.x/delta.x)-0.5)); | |
page.height=(size_t) ((ssize_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"); | |
if (option != (char *) NULL) | |
{ | |
char | |
*page_geometry; | |
page_geometry=GetPageGeometry(option); | |
flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width, | |
&page.height); | |
page_geometry=DestroyString(page_geometry); | |
if (flags == NoValue) | |
{ | |
(void) ThrowMagickException(exception,GetMagickModule(),OptionError, | |
"InvalidGeometry","`%s'",option); | |
CleanupPDFInfo(&pdf_info); | |
image=DestroyImage(image); | |
return((Image *) NULL); | |
} | |
page.width=(size_t) ((ssize_t) ceil((double) (page.width* | |
image->resolution.x/delta.x)-0.5)); | |
page.height=(size_t) ((ssize_t) ceil((double) (page.height* | |
image->resolution.y/delta.y)-0.5)); | |
fitPage=MagickTrue; | |
} | |
if ((fabs(pdf_info.angle) == 90.0) || (fabs(pdf_info.angle) == 270.0)) | |
{ | |
size_t | |
swap; | |
swap=page.width; | |
page.width=page.height; | |
page.height=swap; | |
} | |
if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse) | |
pdf_info.cmyk=MagickFalse; | |
/* | |
Create Ghostscript control file. | |
*/ | |
file=AcquireUniqueFileResource(postscript_filename); | |
if (file == -1) | |
{ | |
(void) RelinquishUniqueFileResource(input_filename); | |
ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", | |
image_info->filename); | |
CleanupPDFInfo(&pdf_info); | |
image=DestroyImage(image); | |
return((Image *) NULL); | |
} | |
if (write(file," ",1) != 1) | |
{ | |
file=close(file)-1; | |
(void) RelinquishUniqueFileResource(input_filename); | |
(void) RelinquishUniqueFileResource(postscript_filename); | |
CleanupPDFInfo(&pdf_info); | |
image=DestroyImage(image); | |
return((Image *) NULL); | |
} | |
file=close(file)-1; | |
/* | |
Render Postscript with the Ghostscript delegate. | |
*/ | |
if (image_info->monochrome != MagickFalse) | |
delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception); | |
else | |
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(input_filename); | |
(void) RelinquishUniqueFileResource(postscript_filename); | |
CleanupPDFInfo(&pdf_info); | |
image=DestroyImage(image); | |
return((Image *) NULL); | |
} | |
density=AcquireString(""); | |
options=AcquireString(""); | |
(void) FormatLocaleString(density,MagickPathExtent,"%gx%g", | |
image->resolution.x,image->resolution.y); | |
if (image_info->ping != MagickFalse) | |
(void) FormatLocaleString(density,MagickPathExtent,"2.0x2.0"); | |
else | |
if ((image_info->page != (char *) NULL) || (fitPage != MagickFalse)) | |
(void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ", | |
(double) page.width,(double) page.height); | |
(void) ConcatenateMagickString(options,"-dPrinted=false ",MagickPathExtent); | |
if (fitPage != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dPSFitPage ",MagickPathExtent); | |
if (pdf_info.cropbox != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dUseCropBox ",MagickPathExtent); | |
if (pdf_info.trimbox != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dUseTrimBox ",MagickPathExtent); | |
option=GetImageOption(image_info,"pdf:stop-on-error"); | |
if (IsStringTrue(option) != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dPDFSTOPONERROR ", | |
MagickPathExtent); | |
option=GetImageOption(image_info,"pdf:interpolate"); | |
if (IsStringTrue(option) != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dInterpolateControl=-1 ", | |
MagickPathExtent); | |
option=GetImageOption(image_info,"pdf:hide-annotations"); | |
if (IsStringTrue(option) != MagickFalse) | |
(void) ConcatenateMagickString(options,"-dShowAnnots=false ", | |
MagickPathExtent); | |
option=GetImageOption(image_info,"authenticate"); | |
if (option != (char *) NULL) | |
{ | |
char | |
passphrase[MagickPathExtent], | |
*sanitize_passphrase; | |
sanitize_passphrase=SanitizeDelegateString(option); | |
#if defined(MAGICKCORE_WINDOWS_SUPPORT) | |
(void) FormatLocaleString(passphrase,MagickPathExtent, | |
"\"-sPDFPassword=%s\" ",sanitize_passphrase); | |
#else | |
(void) FormatLocaleString(passphrase,MagickPathExtent, | |
"-sPDFPassword='%s' ",sanitize_passphrase); | |
#endif | |
sanitize_passphrase=DestroyString(sanitize_passphrase); | |
(void) ConcatenateMagickString(options,passphrase,MagickPathExtent); | |
} | |
read_info=CloneImageInfo(image_info); | |
*read_info->magick='\0'; | |
if (read_info->number_scenes != 0) | |
{ | |
char | |
pages[MagickPathExtent]; | |
(void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g " | |
"-dLastPage=%.20g",(double) read_info->scene+1,(double) | |
(read_info->scene+read_info->number_scenes)); | |
(void) ConcatenateMagickString(options,pages,MagickPathExtent); | |
read_info->number_scenes=0; | |
if (read_info->scenes != (char *) NULL) | |
*read_info->scenes='\0'; | |
} | |
(void) CopyMagickString(filename,read_info->filename,MagickPathExtent); | |
(void) AcquireUniqueFilename(filename); | |
(void) RelinquishUniqueFileResource(filename); | |
(void) ConcatenateMagickString(filename,"%d",MagickPathExtent); | |
(void) FormatLocaleString(command,MagickPathExtent, | |
GetDelegateCommands(delegate_info), | |
read_info->antialias != MagickFalse ? 4 : 1, | |
read_info->antialias != MagickFalse ? 4 : 1,density,options,filename, | |
postscript_filename,input_filename); | |
options=DestroyString(options); | |
density=DestroyString(density); | |
*message='\0'; | |
status=InvokeGhostscriptDelegate(read_info->verbose,command,message, | |
exception); | |
(void) RelinquishUniqueFileResource(postscript_filename); | |
(void) RelinquishUniqueFileResource(input_filename); | |
pdf_image=(Image *) NULL; | |
if (status == MagickFalse) | |
for (i=1; ; i++) | |
{ | |
(void) InterpretImageFilename(image_info,image,filename,(int) i, | |
read_info->filename,exception); | |
if (IsGhostscriptRendered(read_info->filename) == MagickFalse) | |
break; | |
(void) RelinquishUniqueFileResource(read_info->filename); | |
} | |
else | |
{ | |
next=(Image *) NULL; | |
for (i=1; ; i++) | |
{ | |
(void) InterpretImageFilename(image_info,image,filename,(int) i, | |
read_info->filename,exception); | |
if (IsGhostscriptRendered(read_info->filename) == MagickFalse) | |
break; | |
read_info->blob=NULL; | |
read_info->length=0; | |
next=ReadImage(read_info,exception); | |
(void) RelinquishUniqueFileResource(read_info->filename); | |
if (next == (Image *) NULL) | |
break; | |
AppendImageToList(&pdf_image,next); | |
} | |
/* Clean up remaining files */ | |
if (next == (Image *) NULL) | |
{ | |
ssize_t | |
j; | |
for (j=i+1; ; j++) | |
{ | |
(void) InterpretImageFilename(image_info,image,filename,(int) j, | |
read_info->filename,exception); | |
if (IsGhostscriptRendered(read_info->filename) == MagickFalse) | |
break; | |
(void) RelinquishUniqueFileResource(read_info->filename); | |
} | |
} | |
} | |
read_info=DestroyImageInfo(read_info); | |
if (pdf_image == (Image *) NULL) | |
{ | |
if (*message != '\0') | |
(void) ThrowMagickException(exception,GetMagickModule(),DelegateError, | |
"PDFDelegateFailed","`%s'",message); | |
CleanupPDFInfo(&pdf_info); | |
image=DestroyImage(image); | |
return((Image *) NULL); | |
} | |
if (LocaleCompare(pdf_image->magick,"BMP") == 0) | |
{ | |
Image | |
*cmyk_image; | |
cmyk_image=ConsolidateCMYKImages(pdf_image,exception); | |
if (cmyk_image != (Image *) NULL) | |
{ | |
pdf_image=DestroyImageList(pdf_image); | |
pdf_image=cmyk_image; | |
} | |
} | |
if (pdf_info.profile != (StringInfo *) NULL) | |
{ | |
char | |
*profile; | |
(void) SetImageProfile(image,"xmp",pdf_info.profile,exception); | |
profile=(char *) GetStringInfoDatum(pdf_info.profile); | |
if (strstr(profile,"Adobe Illustrator") != (char *) NULL) | |
(void) CopyMagickString(image->magick,"AI",MagickPathExtent); | |
} | |
CleanupPDFInfo(&pdf_info); | |
if (image_info->number_scenes != 0) | |
{ | |
Image | |
*clone_image; | |
/* | |
Add place holder images to meet the subimage specification requirement. | |
*/ | |
for (i=0; i < (ssize_t) image_info->scene; i++) | |
{ | |
clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception); | |
if (clone_image != (Image *) NULL) | |
PrependImageToList(&pdf_image,clone_image); | |
} | |
} | |
do | |
{ | |
(void) CopyMagickString(pdf_image->filename,filename,MagickPathExtent); | |
(void) CopyMagickString(pdf_image->magick,image->magick,MagickPathExtent); | |
pdf_image->page=page; | |
if (image_info->ping != MagickFalse) | |
{ | |
pdf_image->magick_columns=page.width; | |
pdf_image->magick_rows=page.height; | |
pdf_image->columns=page.width; | |
pdf_image->rows=page.height; | |
} | |
(void) CloneImageProfiles(pdf_image,image); | |
(void) CloneImageProperties(pdf_image,image); | |
next=SyncNextImageInList(pdf_image); | |
if (next != (Image *) NULL) | |
pdf_image=next; | |
} while (next != (Image *) NULL); | |
image=DestroyImage(image); | |
scene=0; | |
for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; ) | |
{ | |
next->scene=scene++; | |
next=GetNextImageInList(next); | |
} | |
return(GetFirstImageInList(pdf_image)); | |
} | |
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% R e g i s t e r P D F I m a g e % | |
% % | |
% % | |
% % | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% RegisterPDFImage() adds properties for the PDF image format to | |
% the list of supported formats. The properties 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 RegisterPDFImage method is: | |
% | |
% size_t RegisterPDFImage(void) | |
% | |
*/ | |
ModuleExport size_t RegisterPDFImage(void) | |
{ | |
MagickInfo | |
*entry; | |
entry=AcquireMagickInfo("PDF","AI","Adobe Illustrator CS2"); | |
entry->decoder=(DecodeImageHandler *) ReadPDFImage; | |
entry->encoder=(EncodeImageHandler *) WritePDFImage; | |
entry->flags|=CoderDecoderSeekableStreamFlag; | |
entry->flags|=CoderEncoderSeekableStreamFlag; | |
entry->flags^=CoderAdjoinFlag; | |
entry->flags^=CoderBlobSupportFlag; | |
entry->mime_type=ConstantString("application/pdf"); | |
(void) RegisterMagickInfo(entry); | |
entry=AcquireMagickInfo("PDF","EPDF", | |
"Encapsulated Portable Document Format"); | |
entry->decoder=(DecodeImageHandler *) ReadPDFImage; | |
entry->encoder=(EncodeImageHandler *) WritePDFImage; | |
entry->flags|=CoderDecoderSeekableStreamFlag; | |
entry->flags|=CoderEncoderSeekableStreamFlag; | |
entry->flags^=CoderAdjoinFlag; | |
entry->flags^=CoderBlobSupportFlag; | |
entry->mime_type=ConstantString("application/pdf"); | |
(void) RegisterMagickInfo(entry); | |
entry=AcquireMagickInfo("PDF","PDF","Portable Document Format"); | |
entry->decoder=(DecodeImageHandler *) ReadPDFImage; | |
entry->encoder=(EncodeImageHandler *) WritePDFImage; | |
entry->magick=(IsImageFormatHandler *) IsPDF; | |
entry->flags|=CoderDecoderSeekableStreamFlag; | |
entry->flags|=CoderEncoderSeekableStreamFlag; | |
entry->flags^=CoderBlobSupportFlag; | |
entry->mime_type=ConstantString("application/pdf"); | |
(void) RegisterMagickInfo(entry); | |
entry=AcquireMagickInfo("PDF","PDFA","Portable Document Archive Format"); | |
entry->decoder=(DecodeImageHandler *) ReadPDFImage; | |
entry->encoder=(EncodeImageHandler *) WritePDFImage; | |
entry->magick=(IsImageFormatHandler *) IsPDF; | |
entry->flags|=CoderDecoderSeekableStreamFlag; | |
entry->flags|=CoderEncoderSeekableStreamFlag; | |
entry->flags^=CoderBlobSupportFlag; | |
entry->mime_type=ConstantString("application/pdf"); | |
(void) RegisterMagickInfo(entry); | |
entry=AcquireMagickInfo("PDF","POCKETMOD","Pocketmod Personal Organizer"); | |
entry->decoder=(DecodeImageHandler *) ReadPDFImage; | |
entry->encoder=(EncodeImageHandler *) WritePOCKETMODImage; | |
entry->format_type=ImplicitFormatType; | |
entry->flags|=CoderDecoderSeekableStreamFlag; | |
entry->flags|=CoderEncoderSeekableStreamFlag; | |
entry->flags^=CoderBlobSupportFlag; | |
entry->mime_type=ConstantString("application/pdf"); | |
(void) RegisterMagickInfo(entry); | |
return(MagickImageCoderSignature); | |
} | |
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% U n r e g i s t e r P D F I m a g e % | |
% % | |
% % | |
% % | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% UnregisterPDFImage() removes format registrations made by the | |
% PDF module from the list of supported formats. | |
% | |
% The format of the UnregisterPDFImage method is: | |
% | |
% UnregisterPDFImage(void) | |
% | |
*/ | |
ModuleExport void UnregisterPDFImage(void) | |
{ | |
(void) UnregisterMagickInfo("AI"); | |
(void) UnregisterMagickInfo("EPDF"); | |
(void) UnregisterMagickInfo("PDF"); | |
(void) UnregisterMagickInfo("PDFA"); | |
} | |
/* | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% % | |
% % | |
% % | |
% W r i t e P D F I m a g e % | |
% % | |
% % | |
% % | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% WritePDFImage() writes an image in the Portable Document image | |
% format. | |
% | |
% The format of the WritePDFImage method is: | |
% | |
% MagickBooleanType WritePDFImage(const ImageInfo *image_info, | |
% Image *image,ExceptionInfo *exception) | |
% | |
% A description of each parameter follows. | |
% | |
% o image_info: the image info. | |
% | |
% o image: The image. | |
% | |
% o exception: return any errors or warnings in this structure. | |
% | |
*/ | |
static char *EscapeParenthesis(const char *source) | |
{ | |
char | |
*destination; | |
char | |
*q; | |
const char | |
*p; | |
size_t | |
length; | |
assert(source != (const char *) NULL); | |
length=0; | |
for (p=source; *p != '\0'; p++) | |
{ | |
if ((*p == '\\') || (*p == '(') || (*p == ')')) | |
{ | |
if (~length < 1) | |
ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString"); | |
length++; | |
} | |
length++; | |
} | |
destination=(char *) NULL; | |
if (~length >= (MagickPathExtent-1)) | |
destination=(char *) AcquireQuantumMemory(length+MagickPathExtent, | |
sizeof(*destination)); | |
if (destination == (char *) NULL) | |
ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString"); | |
*destination='\0'; | |
q=destination; | |
for (p=source; *p != '\0'; p++) | |
{ | |
if ((*p == '\\') || (*p == '(') || (*p == ')')) | |
*q++='\\'; | |
*q++=(*p); | |
} | |
*q='\0'; | |
return(destination); | |
} | |
static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16) | |
{ | |
const unsigned char | |
*p; | |
if (utf16 != (wchar_t *) NULL) | |
{ | |
wchar_t | |
*q; | |
wchar_t | |
c; | |
/* | |
Convert UTF-8 to UTF-16. | |
*/ | |
q=utf16; | |
for (p=utf8; *p != '\0'; p++) | |
{ | |
if ((*p & 0x80) == 0) | |
*q=(*p); | |
else | |
if ((*p & 0xE0) == 0xC0) | |
{ | |
c=(*p); | |
*q=(c & 0x1F) << 6; | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
*q|=(*p & 0x3F); | |
} | |
else | |
if ((*p & 0xF0) == 0xE0) | |
{ | |
c=(*p); | |
*q=c << 12; | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
c=(*p); | |
*q|=(c & 0x3F) << 6; | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
*q|=(*p & 0x3F); | |
} | |
else | |
return(0); | |
q++; | |
} | |
*q++=(wchar_t) '\0'; | |
return((size_t) (q-utf16)); | |
} | |
/* | |
Compute UTF-16 string length. | |
*/ | |
for (p=utf8; *p != '\0'; p++) | |
{ | |
if ((*p & 0x80) == 0) | |
; | |
else | |
if ((*p & 0xE0) == 0xC0) | |
{ | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
} | |
else | |
if ((*p & 0xF0) == 0xE0) | |
{ | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
p++; | |
if ((*p & 0xC0) != 0x80) | |
return(0); | |
} | |
else | |
return(0); | |
} | |
return((size_t) (p-utf8)); | |
} | |
static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source,size_t *length) | |
{ | |
wchar_t | |
*utf16; | |
*length=UTF8ToUTF16(source,(wchar_t *) NULL); | |
if (*length == 0) | |
{ | |
ssize_t | |
i; | |
/* | |
Not UTF-8, just copy. | |
*/ | |
*length=strlen((const char *) source); | |
utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16)); | |
if (utf16 == (wchar_t *) NULL) | |
return((wchar_t *) NULL); | |
for (i=0; i <= (ssize_t) *length; i++) | |
utf16[i]=source[i]; | |
return(utf16); | |
} | |
utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16)); | |
if (utf16 == (wchar_t *) NULL) | |
return((wchar_t *) NULL); | |
*length=UTF8ToUTF16(source,utf16); | |
return(utf16); | |
} | |
static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info, | |
Image *image,Image *inject_image,ExceptionInfo *exception) | |
{ | |
Image | |
*group4_image; | |
ImageInfo | |
*write_info; | |
MagickBooleanType | |
status; | |
size_t | |
length; | |
unsigned char | |
*group4; | |
group4_image=CloneImage(inject_image,0,0,MagickTrue,exception); | |
if (group4_image == (Image *) NULL) | |
return(MagickFalse); | |
status=MagickTrue; | |
write_info=CloneImageInfo(image_info); | |
(void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent); | |
(void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent); | |
(void) SetImageArtifact(group4_image,"tiff:photometric","min-is-white"); | |
group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length, | |
exception); | |
group4_image=DestroyImage(group4_image); | |
write_info=DestroyImageInfo(write_info); | |
if (group4 == (unsigned char *) NULL) | |
return(MagickFalse); | |
if (WriteBlob(image,length,group4) != (ssize_t) length) | |
status=MagickFalse; | |
group4=(unsigned char *) RelinquishMagickMemory(group4); | |
return(status); | |
} | |
static MagickBooleanType WritePOCKETMODImage(const ImageInfo *image_info, | |
Image *image,ExceptionInfo *exception) | |
{ | |
#define PocketPageOrder "1,2,3,4,0,7,6,5" | |
const Image | |
*next; | |
Image | |
*pages, | |
*pocket_mod; | |
MagickBooleanType | |
status; | |
ssize_t | |
i; | |
assert(image_info != (const ImageInfo *) NULL); | |
assert(image_info->signature == MagickCoreSignature); | |
assert(image != (Image *) NULL); | |
assert(image->signature == MagickCoreSignature); | |
assert(exception != (ExceptionInfo *) NULL); | |
assert(exception->signature == MagickCoreSignature); | |
if (IsEventLogging() != MagickFalse) | |
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); | |
pocket_mod=NewImageList(); | |
pages=NewImageList(); | |
i=0; | |
for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) | |
{ | |
Image | |
*page; | |
if ((i == 0) || (i == 5) || (i == 6) || (i == 7)) | |
page=RotateImage(next,180.0,exception); | |
else | |
page=CloneImage(next,0,0,MagickTrue,exception); | |
if (page == (Image *) NULL) | |
break; | |
(void) SetImageAlphaChannel(page,RemoveAlphaChannel,exception); | |
page->scene=(size_t) i++; | |
AppendImageToList(&pages,page); | |
if ((i == 8) || (GetNextImageInList(next) == (Image *) NULL)) | |
{ | |
Image | |
*images, | |
*page_layout; | |
MontageInfo | |
*montage_info; | |
/* | |
Create PocketMod page. | |
*/ | |
for (i=(ssize_t) GetImageListLength(pages); i < 8; i++) | |
{ | |
page=CloneImage(pages,0,0,MagickTrue,exception); | |
(void) QueryColorCompliance("#FFF",AllCompliance, | |
&page->background_color,exception); | |
(void) SetImageBackgroundColor(page,exception); | |
page->scene=(size_t) i; | |
AppendImageToList(&pages,page); | |
} | |
images=CloneImages(pages,PocketPageOrder,exception); | |
pages=DestroyImageList(pages); | |
if (images == (Image *) NULL) | |
break; | |
montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL); | |
(void) CloneString(&montage_info->geometry,"877x1240+0+0"); | |
(void) CloneString(&montage_info->tile,"4x2"); | |
(void) QueryColorCompliance("#000",AllCompliance, | |
&montage_info->border_color,exception); | |
montage_info->border_width=2; | |
page_layout=MontageImages(images,montage_info,exception); | |
montage_info=DestroyMontageInfo(montage_info); | |
images=DestroyImageList(images); | |
if (page_layout == (Image *) NULL) | |
break; | |
AppendImageToList(&pocket_mod,page_layout); | |
i=0; | |
} | |
} | |
if (pocket_mod == (Image *) NULL) | |
return(MagickFalse); | |
status=WritePDFImage(image_info,GetFirstImageInList(pocket_mod),exception); | |
pocket_mod=DestroyImageList(pocket_mod); | |
return(status); | |
} | |
static const char *GetPDFAuthor(const ImageInfo *image_info) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:author"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(MagickAuthoritativeURL); | |
} | |
static const char *GetPDFCreator(const ImageInfo *image_info) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:creator"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(MagickAuthoritativeURL); | |
} | |
static const char *GetPDFProducer(const ImageInfo *image_info) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:producer"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(MagickAuthoritativeURL); | |
} | |
static const char *GetPDFTitle(const ImageInfo *image_info, | |
const char *default_title) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:title"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(default_title); | |
} | |
static const time_t GetPdfCreationDate(const ImageInfo *image_info, | |
const Image* image) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:create-epoch"); | |
if (option != (const char *) NULL) | |
{ | |
time_t | |
epoch; | |
epoch=(time_t) StringToDouble(option,(char **) NULL); | |
if (epoch > 0) | |
return(epoch); | |
} | |
return(GetBlobProperties(image)->st_ctime); | |
} | |
static const time_t GetPdfModDate(const ImageInfo *image_info, | |
const Image* image) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:modify-epoch"); | |
if (option != (const char *) NULL) | |
{ | |
time_t | |
epoch; | |
epoch=(time_t) StringToDouble(option,(char **) NULL); | |
if (epoch > 0) | |
return(epoch); | |
} | |
return(GetBlobProperties(image)->st_mtime); | |
} | |
static const char *GetPDFSubject(const ImageInfo *image_info) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:subject"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(""); | |
} | |
static const char *GetPDFKeywords(const ImageInfo *image_info) | |
{ | |
const char | |
*option; | |
option=GetImageOption(image_info,"pdf:keywords"); | |
if (option != (const char *) NULL) | |
return(option); | |
return(""); | |
} | |
static void WritePDFValue(Image* image,const char *keyword, | |
const char *value,const MagickBooleanType is_pdfa) | |
{ | |
char | |
*escaped; | |
size_t | |
length; | |
ssize_t | |
i; | |
wchar_t | |
*utf16; | |
if (*value == '\0') | |
return; | |
if (is_pdfa != MagickFalse) | |
{ | |
escaped=EscapeParenthesis(value); | |
(void) WriteBlobString(image,"/"); | |
(void) WriteBlobString(image,keyword); | |
(void) WriteBlobString(image," ("); | |
(void) WriteBlobString(image,escaped); | |
escaped=DestroyString(escaped); | |
(void) WriteBlobString(image,")\n"); | |
return; | |
} | |
utf16=ConvertUTF8ToUTF16((const unsigned char *) value,&length); | |
if (utf16 != (wchar_t *) NULL) | |
{ | |
unsigned char | |
hex_digits[16]; | |
hex_digits[0]='0'; | |
hex_digits[1]='1'; | |
hex_digits[2]='2'; | |
hex_digits[3]='3'; | |
hex_digits[4]='4'; | |
hex_digits[5]='5'; | |
hex_digits[6]='6'; | |
hex_digits[7]='7'; | |
hex_digits[8]='8'; | |
hex_digits[9]='9'; | |
hex_digits[10]='A'; | |
hex_digits[11]='B'; | |
hex_digits[12]='C'; | |
hex_digits[13]='D'; | |
hex_digits[14]='E'; | |
hex_digits[15]='F'; | |
(void) WriteBlobString(image,"/"); | |
(void) WriteBlobString(image,keyword); | |
(void) WriteBlobString(image," <FEFF"); | |
for (i=0; i < (ssize_t) length; i++) | |
{ | |
(void) WriteBlobByte(image,hex_digits[(utf16[i] >> 12) & 0x0f]); | |
(void) WriteBlobByte(image,hex_digits[(utf16[i] >> 8) & 0x0f]); | |
(void) WriteBlobByte(image,hex_digits[(utf16[i] >> 4) & 0x0f]); | |
(void) WriteBlobByte(image,hex_digits[utf16[i] & 0x0f]); | |
} | |
(void) WriteBlobString(image,">\n"); | |
utf16=(wchar_t *) RelinquishMagickMemory(utf16); | |
} | |
} | |
static const StringInfo *GetCompatibleColorProfile(const Image* image) | |
{ | |
ColorspaceType | |
colorspace; | |
const StringInfo | |
*icc_profile; | |
colorspace=UndefinedColorspace; | |
icc_profile=GetImageProfile(image,"icc"); | |
if (icc_profile == (const StringInfo *) NULL) | |
return((const StringInfo *) NULL); | |
if (GetStringInfoLength(icc_profile) > 20) | |
{ | |
const char | |
*p; | |
unsigned int | |
value; | |
p=(const char *) GetStringInfoDatum(icc_profile)+16; | |
value=(unsigned int) (*p++) << 24; | |
value|=(unsigned int) (*p++) << 16; | |
value|=(unsigned int) (*p++) << 8; | |
value|=(unsigned int) *p; | |
switch (value) | |
{ | |
case 0x58595a20: | |
colorspace=XYZColorspace; | |
break; | |
case 0x4c616220: | |
colorspace=LabColorspace; | |
break; | |
case 0x4c757620: | |
colorspace=LuvColorspace; | |
break; | |
case 0x59436272: | |
colorspace=YCbCrColorspace; | |
break; | |
case 0x52474220: | |
if ((image->colorspace == sRGBColorspace) || | |
(image->colorspace == RGBColorspace)) | |
return(icc_profile); | |
break; | |
case 0x47524159: | |
colorspace=GRAYColorspace; | |
break; | |
case 0x48535620: | |
colorspace=HSVColorspace; | |
break; | |
case 0x434D594B: | |
colorspace=CMYKColorspace; | |
break; | |
case 0x434D5920: | |
colorspace=CMYColorspace; | |
break; | |
} | |
} | |
if (image->colorspace == colorspace) | |
return(icc_profile); | |
return((const StringInfo *) NULL); | |
} | |
static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image, | |
ExceptionInfo *exception) | |
{ | |
#define CFormat "/Filter [ /%s ]\n" | |
#define ObjectsPerImage 14 | |
#define ThrowPDFException(exception,message) \ | |
{ \ | |
if (xref != (MagickOffsetType *) NULL) \ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); \ | |
ThrowWriterException((exception),(message)); \ | |
} | |
static const char | |
XMPProfile[]= | |
{ | |
"<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" | |
"<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 4.0-c316 44.253921, Sun Oct 01 2006 17:08:23\">\n" | |
" <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" | |
" <rdf:Description rdf:about=\"\"\n" | |
" xmlns:xap=\"http://ns.adobe.com/xap/1.0/\"\n" | |
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" | |
" xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n" | |
" xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n" | |
" xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" | |
" <xap:CreateDate>%s</xap:CreateDate>\n" | |
" <xap:ModifyDate>%s</xap:ModifyDate>\n" | |
" <xap:MetadataDate>%s</xap:MetadataDate>\n" | |
" <xap:CreatorTool>%s</xap:CreatorTool>\n" | |
" <dc:format>application/pdf</dc:format>\n" | |
" <dc:title>\n" | |
" <rdf:Alt>\n" | |
" <rdf:li xml:lang=\"x-default\">%s</rdf:li>\n" | |
" </rdf:Alt>\n" | |
" </dc:title>\n" | |
" <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n" | |
" <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n" | |
" <pdf:Producer>%s</pdf:Producer>\n" | |
" <pdf:Keywords>%s</pdf:Keywords>\n" | |
" <pdfaid:part>3</pdfaid:part>\n" | |
" <pdfaid:conformance>B</pdfaid:conformance>\n" | |
" </rdf:Description>\n" | |
" </rdf:RDF>\n" | |
"</x:xmpmeta>\n" | |
"<?xpacket end=\"w\"?>\n" | |
}, | |
XMPProfileMagick[4]= { (char) -17, (char) -69, (char) -65, (char) 0 }; | |
char | |
basename[MagickPathExtent], | |
buffer[MagickPathExtent], | |
**labels, | |
temp[MagickPathExtent]; | |
CompressionType | |
compression; | |
const char | |
*device, | |
*option, | |
*value; | |
const Quantum | |
*p; | |
const StringInfo | |
*icc_profile; | |
double | |
pointsize, | |
version; | |
GeometryInfo | |
geometry_info; | |
Image | |
*next; | |
MagickBooleanType | |
is_pdfa, | |
status; | |
MagickOffsetType | |
offset, | |
scene, | |
*xref; | |
MagickSizeType | |
number_pixels; | |
MagickStatusType | |
flags; | |
PointInfo | |
delta, | |
resolution, | |
scale; | |
RectangleInfo | |
geometry, | |
media_info, | |
page_info; | |
size_t | |
channels, | |
info_id, | |
length, | |
number_scenes, | |
object, | |
pages_id, | |
root_id, | |
text_size; | |
ssize_t | |
count, | |
i, | |
page_count, | |
x, | |
y; | |
struct tm | |
utc_time; | |
time_t | |
seconds; | |
unsigned char | |
*pixels, | |
*q; | |
/* | |
Open output image file. | |
*/ | |
assert(image_info != (const ImageInfo *) NULL); | |
assert(image_info->signature == MagickCoreSignature); | |
assert(image != (Image *) NULL); | |
assert(image->signature == MagickCoreSignature); | |
assert(exception != (ExceptionInfo *) NULL); | |
assert(exception->signature == MagickCoreSignature); | |
if (IsEventLogging() != MagickFalse) | |
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); | |
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); | |
if (status == MagickFalse) | |
return(status); | |
/* | |
Allocate X ref memory. | |
*/ | |
xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref)); | |
if (xref == (MagickOffsetType *) NULL) | |
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); | |
(void) memset(xref,0,2048UL*sizeof(*xref)); | |
/* | |
Write Info object. | |
*/ | |
object=0; | |
version=1.3; | |
for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) | |
if (next->alpha_trait != UndefinedPixelTrait) | |
version=1.4; | |
if (image_info->compression == JPEG2000Compression) | |
version=1.5; | |
is_pdfa=LocaleCompare(image_info->magick,"PDFA") == 0 ? MagickTrue : | |
MagickFalse; | |
if (is_pdfa != MagickFalse) | |
version=1.6; | |
for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) | |
{ | |
icc_profile=GetCompatibleColorProfile(next); | |
if (icc_profile != (StringInfo *) NULL) | |
{ | |
(void) SetImageStorageClass(next,DirectClass,exception); | |
version=1.7; | |
} | |
if ((next->colorspace != CMYKColorspace) && | |
(IssRGBCompatibleColorspace(next->colorspace) == MagickFalse)) | |
(void) TransformImageColorspace(next,sRGBColorspace,exception); | |
(void) SetImageCoderGray(next,exception); | |
} | |
option=GetImageOption(image_info,"pdf:version"); | |
if (option != (const char *) NULL) | |
{ | |
double | |
preferred_version; | |
preferred_version=StringToDouble(option,(char**) NULL); | |
version=MagickMax(version,MagickMin(1.7,preferred_version)); | |
} | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%%PDF-%.2g \n",version); | |
(void) WriteBlobString(image,buffer); | |
if (is_pdfa != MagickFalse) | |
{ | |
(void) WriteBlobByte(image,'%'); | |
(void) WriteBlobByte(image,0xe2); | |
(void) WriteBlobByte(image,0xe3); | |
(void) WriteBlobByte(image,0xcf); | |
(void) WriteBlobByte(image,0xd3); | |
(void) WriteBlobByte(image,'\n'); | |
} | |
/* | |
Write Catalog object. | |
*/ | |
xref[object++]=TellBlob(image); | |
root_id=object; | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
if (is_pdfa == MagickFalse) | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n", | |
(double) object+1); | |
else | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Metadata %.20g 0 R\n", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n", | |
(double) object+2); | |
} | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"/Type /Catalog"); | |
option=GetImageOption(image_info,"pdf:page-direction"); | |
if ((option != (const char *) NULL) && | |
(LocaleCompare(option,"right-to-left") == 0)) | |
(void) WriteBlobString(image,"/ViewerPreferences<</PageDirection/R2L>>\n"); | |
(void) WriteBlobString(image,"\n"); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
GetPathComponent(image->filename,BasePath,basename); | |
if (is_pdfa != MagickFalse) | |
{ | |
char | |
create_date[MagickTimeExtent], | |
*creator, | |
*keywords, | |
modify_date[MagickTimeExtent], | |
*producer, | |
timestamp[MagickTimeExtent], | |
*title; | |
/* | |
Write XMP object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
(void) WriteBlobString(image,"/Subtype /XML\n"); | |
(void) FormatMagickTime(GetPdfCreationDate(image_info,image), | |
sizeof(create_date),create_date); | |
(void) FormatMagickTime(GetPdfModDate(image_info,image), | |
sizeof(modify_date),modify_date); | |
(void) FormatMagickTime(GetMagickTime(),sizeof(timestamp),timestamp); | |
creator=SubstituteXMLEntities(GetPDFCreator(image_info),MagickFalse); | |
title=SubstituteXMLEntities(GetPDFTitle(image_info,basename),MagickFalse); | |
producer=SubstituteXMLEntities(GetPDFProducer(image_info),MagickFalse); | |
keywords=SubstituteXMLEntities(GetPDFKeywords(image_info),MagickFalse); | |
i=FormatLocaleString(temp,MagickPathExtent,XMPProfile,XMPProfileMagick, | |
create_date,modify_date,timestamp,creator,title,producer,keywords); | |
producer=DestroyString(producer); | |
title=DestroyString(title); | |
creator=DestroyString(creator); | |
keywords=DestroyString(keywords); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g\n", | |
(double) i); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"/Type /Metadata\n"); | |
(void) WriteBlobString(image,">>\nstream\n"); | |
(void) WriteBlobString(image,temp); | |
(void) WriteBlobString(image,"\nendstream\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
} | |
/* | |
Write Pages object. | |
*/ | |
xref[object++]=TellBlob(image); | |
pages_id=object; | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
(void) WriteBlobString(image,"/Type /Pages\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Kids [ %.20g 0 R ", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
count=(ssize_t) (pages_id+ObjectsPerImage+1); | |
page_count=1; | |
if (image_info->adjoin != MagickFalse) | |
{ | |
Image | |
*kid_image; | |
/* | |
Predict page object id's. | |
*/ | |
kid_image=image; | |
for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage) | |
{ | |
page_count++; | |
icc_profile=GetCompatibleColorProfile(kid_image); | |
if (icc_profile != (StringInfo *) NULL) | |
count+=2; | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 R ",(double) | |
count); | |
(void) WriteBlobString(image,buffer); | |
kid_image=GetNextImageInList(kid_image); | |
} | |
xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL, | |
sizeof(*xref)); | |
if (xref == (MagickOffsetType *) NULL) | |
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); | |
} | |
(void) WriteBlobString(image,"]\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Count %.20g\n",(double) | |
page_count); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
scene=0; | |
number_scenes=GetImageListLength(image); | |
do | |
{ | |
Image | |
*tile_image; | |
MagickBooleanType | |
thumbnail; | |
icc_profile=GetCompatibleColorProfile(image); | |
compression=image->compression; | |
if (image_info->compression != UndefinedCompression) | |
compression=image_info->compression; | |
switch (compression) | |
{ | |
case FaxCompression: | |
case Group4Compression: | |
{ | |
if ((SetImageMonochrome(image,exception) == MagickFalse) || | |
(image->alpha_trait != UndefinedPixelTrait)) | |
compression=RLECompression; | |
break; | |
} | |
#if !defined(MAGICKCORE_JPEG_DELEGATE) | |
case JPEGCompression: | |
{ | |
compression=RLECompression; | |
(void) ThrowMagickException(exception,GetMagickModule(), | |
MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)", | |
image->filename); | |
break; | |
} | |
#endif | |
#if !defined(MAGICKCORE_LIBOPENJP2_DELEGATE) | |
case JPEG2000Compression: | |
{ | |
compression=RLECompression; | |
(void) ThrowMagickException(exception,GetMagickModule(), | |
MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)", | |
image->filename); | |
break; | |
} | |
#endif | |
#if !defined(MAGICKCORE_ZLIB_DELEGATE) | |
case ZipCompression: | |
{ | |
compression=RLECompression; | |
(void) ThrowMagickException(exception,GetMagickModule(), | |
MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)", | |
image->filename); | |
break; | |
} | |
#endif | |
case LZWCompression: | |
{ | |
if (is_pdfa != MagickFalse) | |
compression=RLECompression; /* LZW compression is forbidden */ | |
break; | |
} | |
case NoCompression: | |
{ | |
if (is_pdfa != MagickFalse) | |
compression=RLECompression; /* ASCII 85 compression is forbidden */ | |
break; | |
} | |
default: | |
break; | |
} | |
if (compression == JPEG2000Compression) | |
if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) | |
(void) TransformImageColorspace(image,sRGBColorspace,exception); | |
/* | |
Scale relative to dots-per-inch. | |
*/ | |
delta.x=DefaultResolution; | |
delta.y=DefaultResolution; | |
resolution.x=image->resolution.x; | |
resolution.y=image->resolution.y; | |
if ((resolution.x == 0.0) || (resolution.y == 0.0)) | |
{ | |
flags=ParseGeometry(PSDensityGeometry,&geometry_info); | |
if ((flags & RhoValue) != 0) | |
resolution.x=geometry_info.rho; | |
resolution.y=resolution.x; | |
if ((flags & SigmaValue) != 0) | |
resolution.y=geometry_info.sigma; | |
} | |
if (image_info->density != (char *) NULL) | |
{ | |
flags=ParseGeometry(image_info->density,&geometry_info); | |
if ((flags & RhoValue) != 0) | |
resolution.x=geometry_info.rho; | |
resolution.y=resolution.x; | |
if ((flags & SigmaValue) != 0) | |
resolution.y=geometry_info.sigma; | |
} | |
if (image->units == PixelsPerCentimeterResolution) | |
{ | |
resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0); | |
resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0); | |
} | |
SetGeometry(image,&geometry); | |
(void) FormatLocaleString(temp,MagickPathExtent,"%.20gx%.20g", | |
(double) image->columns,(double) image->rows); | |
if (image_info->page != (char *) NULL) | |
(void) CopyMagickString(temp,image_info->page,MagickPathExtent); | |
else | |
if ((image->page.width != 0) && (image->page.height != 0)) | |
(void) FormatLocaleString(temp,MagickPathExtent, | |
"%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double) | |
image->page.height,(double) image->page.x,(double) image->page.y); | |
else | |
if ((image->gravity != UndefinedGravity) && | |
(LocaleCompare(image_info->magick,"PDF") == 0)) | |
(void) CopyMagickString(temp,PSPageGeometry, | |
MagickPathExtent); | |
(void) ConcatenateMagickString(temp,">",MagickPathExtent); | |
(void) ParseMetaGeometry(temp,&geometry.x,&geometry.y, | |
&geometry.width,&geometry.height); | |
scale.x=(double) (geometry.width*delta.x)/resolution.x; | |
geometry.width=(size_t) floor(scale.x+0.5); | |
scale.y=(double) (geometry.height*delta.y)/resolution.y; | |
geometry.height=(size_t) floor(scale.y+0.5); | |
(void) ParseAbsoluteGeometry(temp,&media_info); | |
(void) ParseGravityGeometry(image,temp,&page_info,exception); | |
if (image->gravity != UndefinedGravity) | |
{ | |
geometry.x=(-page_info.x); | |
geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows); | |
} | |
pointsize=12.0; | |
if (image_info->pointsize != 0.0) | |
pointsize=image_info->pointsize; | |
text_size=0; | |
value=GetImageProperty(image,"label",exception); | |
if (value != (const char *) NULL) | |
text_size=(size_t) (MultilineCensus(value)*pointsize+12); | |
(void) text_size; | |
/* | |
Write Page object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
(void) WriteBlobString(image,"/Type /Page\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Parent %.20g 0 R\n", | |
(double) pages_id); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"/Resources <<\n"); | |
labels=(char **) NULL; | |
value=GetImageProperty(image,"label",exception); | |
if (value != (const char *) NULL) | |
labels=StringToList(value); | |
if (labels != (char **) NULL) | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double) | |
object+4); | |
(void) WriteBlobString(image,buffer); | |
} | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double) | |
object+5); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/ProcSet %.20g 0 R >>\n", | |
(double) object+3); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/MediaBox [0 0 %g %g]\n",DefaultResolution*media_info.width* | |
PerceptibleReciprocal(resolution.x),DefaultResolution*media_info.height* | |
PerceptibleReciprocal(resolution.y)); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/CropBox [0 0 %g %g]\n",DefaultResolution*media_info.width* | |
PerceptibleReciprocal(resolution.x),DefaultResolution*media_info.height* | |
PerceptibleReciprocal(resolution.y)); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Contents %.20g 0 R\n", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Thumb %.20g 0 R\n", | |
(double) object+(icc_profile != (StringInfo *) NULL ? 10 : 8)); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Contents object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"stream\n"); | |
offset=TellBlob(image); | |
(void) WriteBlobString(image,"q\n"); | |
if (labels != (char **) NULL) | |
for (i=0; labels[i] != (char *) NULL; i++) | |
{ | |
(void) WriteBlobString(image,"BT\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/F%.20g %g Tf\n", | |
(double) image->scene,pointsize); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g Td\n", | |
(double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+ | |
12)); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"(%s) Tj\n", | |
labels[i]); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"ET\n"); | |
labels[i]=DestroyString(labels[i]); | |
} | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"%g 0 0 %g %.20g %.20g cm\n",scale.x,scale.y,(double) geometry.x, | |
(double) geometry.y); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Im%.20g Do\n",(double) | |
image->scene); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"Q\n"); | |
offset=TellBlob(image)-offset; | |
(void) WriteBlobString(image,"\nendstream\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Length object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) | |
offset); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Procset object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
if ((compression == FaxCompression) || (compression == Group4Compression)) | |
(void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MagickPathExtent); | |
else | |
if ((image->storage_class == DirectClass) || (image->colors > 256)) | |
(void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MagickPathExtent); | |
else | |
(void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MagickPathExtent); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image," ]\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Font object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
if (labels != (char **) NULL) | |
{ | |
(void) WriteBlobString(image,"/Type /Font\n"); | |
(void) WriteBlobString(image,"/Subtype /Type1\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Name /F%.20g\n", | |
(double) image->scene); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"/BaseFont /Helvetica\n"); | |
(void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n"); | |
labels=(char **) RelinquishMagickMemory(labels); | |
} | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write XObject object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
(void) WriteBlobString(image,"/Type /XObject\n"); | |
(void) WriteBlobString(image,"/Subtype /Image\n"); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Im%.20g\n", | |
(double) image->scene); | |
(void) WriteBlobString(image,buffer); | |
switch (compression) | |
{ | |
case NoCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"ASCII85Decode"); | |
break; | |
} | |
case JPEGCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode"); | |
if (image->colorspace != CMYKColorspace) | |
break; | |
(void) WriteBlobString(image,buffer); | |
(void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", | |
MagickPathExtent); | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode"); | |
if (image->colorspace != CMYKColorspace) | |
break; | |
(void) WriteBlobString(image,buffer); | |
(void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", | |
MagickPathExtent); | |
break; | |
} | |
case LZWCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode"); | |
break; | |
} | |
case ZipCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"FlateDecode"); | |
break; | |
} | |
case FaxCompression: | |
case Group4Compression: | |
{ | |
(void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n", | |
MagickPathExtent); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << " | |
"/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam, | |
(double) image->columns,(double) image->rows); | |
break; | |
} | |
default: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"RunLengthDecode"); | |
break; | |
} | |
} | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double) | |
image->columns); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double) | |
image->rows); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n", | |
(double) object+2); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n", | |
(compression == FaxCompression) || (compression == Group4Compression) ? | |
1 : 8); | |
(void) WriteBlobString(image,buffer); | |
if (image->alpha_trait != UndefinedPixelTrait) | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/SMask %.20g 0 R\n", | |
(double) object+(icc_profile != (StringInfo *) NULL ? 9 : 7)); | |
(void) WriteBlobString(image,buffer); | |
} | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"stream\n"); | |
offset=TellBlob(image); | |
number_pixels=(MagickSizeType) image->columns*image->rows; | |
if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels))) | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
if ((compression == FaxCompression) || (compression == Group4Compression) || | |
(IsImageGray(image) != MagickFalse)) | |
{ | |
switch (compression) | |
{ | |
case FaxCompression: | |
case Group4Compression: | |
{ | |
if (LocaleCompare(CCITTParam,"0") == 0) | |
{ | |
(void) HuffmanEncodeImage(image_info,image,image,exception); | |
break; | |
} | |
(void) Huffman2DEncodeImage(image_info,image,image,exception); | |
break; | |
} | |
case JPEGCompression: | |
{ | |
status=InjectImageBlob(image_info,image,image,"jpeg",exception); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
status=InjectImageBlob(image_info,image,image,"jp2",exception); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); | |
/* | |
Dump Runlength encoded pixels. | |
*/ | |
q=pixels; | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
*q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p))); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) | |
y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
#if defined(MAGICKCORE_ZLIB_DELEGATE) | |
if (compression == ZipCompression) | |
status=ZLIBEncodeImage(image,length,pixels,exception); | |
else | |
#endif | |
if (compression == LZWCompression) | |
status=LZWEncodeImage(image,length,pixels,exception); | |
else | |
status=PackbitsEncodeImage(image,length,pixels,exception); | |
pixel_info=RelinquishVirtualMemory(pixel_info); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case NoCompression: | |
{ | |
/* | |
Dump uncompressed PseudoColor packets. | |
*/ | |
Ascii85Initialize(image); | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( | |
GetPixelLuma(image,p)))); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) | |
y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
Ascii85Flush(image); | |
break; | |
} | |
} | |
} | |
else | |
if ((image->storage_class == DirectClass) || (image->colors > 256) || | |
(compression == JPEGCompression) || | |
(compression == JPEG2000Compression)) | |
switch (compression) | |
{ | |
case JPEGCompression: | |
{ | |
status=InjectImageBlob(image_info,image,image,"jpeg",exception); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
status=InjectImageBlob(image_info,image,image,"jp2",exception); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
length*=image->colorspace == CMYKColorspace ? 4UL : 3UL; | |
pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); | |
/* | |
Dump runoffset encoded pixels. | |
*/ | |
q=pixels; | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
*q++=ScaleQuantumToChar(GetPixelRed(image,p)); | |
*q++=ScaleQuantumToChar(GetPixelGreen(image,p)); | |
*q++=ScaleQuantumToChar(GetPixelBlue(image,p)); | |
if (image->colorspace == CMYKColorspace) | |
*q++=ScaleQuantumToChar(GetPixelBlack(image,p)); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) | |
y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
#if defined(MAGICKCORE_ZLIB_DELEGATE) | |
if (compression == ZipCompression) | |
status=ZLIBEncodeImage(image,length,pixels,exception); | |
else | |
#endif | |
if (compression == LZWCompression) | |
status=LZWEncodeImage(image,length,pixels,exception); | |
else | |
status=PackbitsEncodeImage(image,length,pixels,exception); | |
pixel_info=RelinquishVirtualMemory(pixel_info); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case NoCompression: | |
{ | |
/* | |
Dump uncompressed DirectColor packets. | |
*/ | |
Ascii85Initialize(image); | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p))); | |
Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p))); | |
Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p))); | |
if (image->colorspace == CMYKColorspace) | |
Ascii85Encode(image,ScaleQuantumToChar( | |
GetPixelBlack(image,p))); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) | |
y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
Ascii85Flush(image); | |
break; | |
} | |
} | |
else | |
{ | |
/* | |
Dump number of colors and colormap. | |
*/ | |
switch (compression) | |
{ | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); | |
/* | |
Dump Runlength encoded pixels. | |
*/ | |
q=pixels; | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
*q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p)); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag, | |
(MagickOffsetType) y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
#if defined(MAGICKCORE_ZLIB_DELEGATE) | |
if (compression == ZipCompression) | |
status=ZLIBEncodeImage(image,length,pixels,exception); | |
else | |
#endif | |
if (compression == LZWCompression) | |
status=LZWEncodeImage(image,length,pixels,exception); | |
else | |
status=PackbitsEncodeImage(image,length,pixels,exception); | |
pixel_info=RelinquishVirtualMemory(pixel_info); | |
if (status == MagickFalse) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case NoCompression: | |
{ | |
/* | |
Dump uncompressed PseudoColor packets. | |
*/ | |
Ascii85Initialize(image); | |
for (y=0; y < (ssize_t) image->rows; y++) | |
{ | |
p=GetVirtualPixels(image,0,y,image->columns,1,exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) image->columns; x++) | |
{ | |
Ascii85Encode(image,(unsigned char) ((ssize_t) | |
GetPixelIndex(image,p))); | |
p+=GetPixelChannels(image); | |
} | |
if (image->previous == (Image *) NULL) | |
{ | |
status=SetImageProgress(image,SaveImageTag, | |
(MagickOffsetType) y,image->rows); | |
if (status == MagickFalse) | |
break; | |
} | |
} | |
Ascii85Flush(image); | |
break; | |
} | |
} | |
} | |
offset=TellBlob(image)-offset; | |
(void) WriteBlobString(image,"\nendstream\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Length object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) | |
offset); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Colorspace object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
device="DeviceRGB"; | |
channels=0; | |
if (image->colorspace == CMYKColorspace) | |
{ | |
device="DeviceCMYK"; | |
channels=4; | |
} | |
else | |
if ((compression == FaxCompression) || | |
(compression == Group4Compression) || | |
(IsImageGray(image) != MagickFalse)) | |
{ | |
device="DeviceGray"; | |
channels=1; | |
} | |
else | |
if ((image->storage_class == DirectClass) || | |
(image->colors > 256) || (compression == JPEGCompression) || | |
(compression == JPEG2000Compression)) | |
{ | |
device="DeviceRGB"; | |
channels=3; | |
} | |
if (icc_profile == (StringInfo *) NULL) | |
{ | |
if (channels != 0) | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/%s\n",device); | |
else | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"[ /Indexed /%s %.20g %.20g 0 R ]\n",device,(double) image->colors- | |
1,(double) object+3); | |
(void) WriteBlobString(image,buffer); | |
} | |
else | |
{ | |
const unsigned char | |
*r; | |
/* | |
Write ICC profile. | |
*/ | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"[/ICCBased %.20g 0 R]\n",(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"endobj\n"); | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n", | |
(double) object); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"<<\n/N %.20g\n" | |
"/Filter /ASCII85Decode\n/Length %.20g 0 R\n/Alternate /%s\n>>\n" | |
"stream\n",(double) channels,(double) object+1,device); | |
(void) WriteBlobString(image,buffer); | |
offset=TellBlob(image); | |
Ascii85Initialize(image); | |
r=GetStringInfoDatum(icc_profile); | |
for (i=0; i < (ssize_t) GetStringInfoLength(icc_profile); i++) | |
Ascii85Encode(image,(unsigned char) *r++); | |
Ascii85Flush(image); | |
offset=TellBlob(image)-offset; | |
(void) WriteBlobString(image,"endstream\n"); | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Length object. | |
*/ | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n", | |
(double) object); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) | |
offset); | |
(void) WriteBlobString(image,buffer); | |
} | |
(void) WriteBlobString(image,"endobj\n"); | |
/* | |
Write Thumb object. | |
*/ | |
SetGeometry(image,&geometry); | |
(void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y, | |
&geometry.width,&geometry.height); | |
thumbnail=IsStringTrue(GetImageOption(image_info,"pdf:thumbnail")); | |
if (thumbnail == MagickFalse) | |
(void) ParseMetaGeometry("1x1+0+0>",&geometry.x,&geometry.y, | |
&geometry.width,&geometry.height); | |
tile_image=ThumbnailImage(image,geometry.width,geometry.height,exception); | |
if (tile_image == (Image *) NULL) | |
{ | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
xref[object++]=TellBlob(image); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) | |
object); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,"<<\n"); | |
switch (compression) | |
{ | |
case NoCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"ASCII85Decode"); | |
break; | |
} | |
case JPEGCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode"); | |
if (tile_image->colorspace != CMYKColorspace) | |
break; | |
(void) WriteBlobString(image,buffer); | |
(void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", | |
MagickPathExtent); | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode"); | |
if (tile_image->colorspace != CMYKColorspace) | |
break; | |
(void) WriteBlobString(image,buffer); | |
(void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", | |
MagickPathExtent); | |
break; | |
} | |
case LZWCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode"); | |
break; | |
} | |
case ZipCompression: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"FlateDecode"); | |
break; | |
} | |
case FaxCompression: | |
case Group4Compression: | |
{ | |
(void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n", | |
MagickPathExtent); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ " | |
"<< /K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n", | |
CCITTParam,(double) tile_image->columns,(double) tile_image->rows); | |
break; | |
} | |
default: | |
{ | |
(void) FormatLocaleString(buffer,MagickPathExtent,CFormat, | |
"RunLengthDecode"); | |
break; | |
} | |
} | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double) | |
tile_image->columns); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double) | |
tile_image->rows); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/ColorSpace %.20g 0 R\n",(double) object- | |
(icc_profile != (StringInfo *) NULL ? 3 : 1)); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent, | |
"/BitsPerComponent %d\n",(compression == FaxCompression) || | |
(compression == Group4Compression) ? 1 : 8); | |
(void) WriteBlobString(image,buffer); | |
(void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n", | |
(double) object+1); | |
(void) WriteBlobString(image,buffer); | |
(void) WriteBlobString(image,">>\n"); | |
(void) WriteBlobString(image,"stream\n"); | |
offset=TellBlob(image); | |
number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows; | |
if ((compression == FaxCompression) || | |
(compression == Group4Compression) || | |
(SetImageCoderGray(tile_image,exception) != MagickFalse)) | |
{ | |
switch (compression) | |
{ | |
case FaxCompression: | |
case Group4Compression: | |
{ | |
if (LocaleCompare(CCITTParam,"0") == 0) | |
{ | |
(void) HuffmanEncodeImage(image_info,image,tile_image, | |
exception); | |
break; | |
} | |
(void) Huffman2DEncodeImage(image_info,image,tile_image,exception); | |
break; | |
} | |
case JPEGCompression: | |
{ | |
status=InjectImageBlob(image_info,image,tile_image,"jpeg", | |
exception); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
status=InjectImageBlob(image_info,image,tile_image,"jp2",exception); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
{ | |
tile_image=DestroyImage(tile_image); | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
} | |
pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); | |
/* | |
Dump runlength encoded pixels. | |
*/ | |
q=pixels; | |
for (y=0; y < (ssize_t) tile_image->rows; y++) | |
{ | |
p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1, | |
exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) tile_image->columns; x++) | |
{ | |
*q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(tile_image, | |
p))); | |
p+=GetPixelChannels(tile_image); | |
} | |
} | |
#if defined(MAGICKCORE_ZLIB_DELEGATE) | |
if (compression == ZipCompression) | |
status=ZLIBEncodeImage(image,length,pixels,exception); | |
else | |
#endif | |
if (compression == LZWCompression) | |
status=LZWEncodeImage(image,length,pixels,exception); | |
else | |
status=PackbitsEncodeImage(image,length,pixels,exception); | |
pixel_info=RelinquishVirtualMemory(pixel_info); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case NoCompression: | |
{ | |
/* | |
Dump uncompressed PseudoColor packets. | |
*/ | |
Ascii85Initialize(image); | |
for (y=0; y < (ssize_t) tile_image->rows; y++) | |
{ | |
p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1, | |
exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) tile_image->columns; x++) | |
{ | |
Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( | |
GetPixelLuma(tile_image,p)))); | |
p+=GetPixelChannels(tile_image); | |
} | |
} | |
Ascii85Flush(image); | |
break; | |
} | |
} | |
} | |
else | |
if ((tile_image->storage_class == DirectClass) || | |
(tile_image->colors > 256) || (compression == JPEGCompression) || | |
(compression == JPEG2000Compression)) | |
switch (compression) | |
{ | |
case JPEGCompression: | |
{ | |
status=InjectImageBlob(image_info,image,tile_image,"jpeg", | |
exception); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case JPEG2000Compression: | |
{ | |
status=InjectImageBlob(image_info,image,tile_image,"jp2",exception); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL; | |
pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
{ | |
tile_image=DestroyImage(tile_image); | |
ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed"); | |
} | |
pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); | |
/* | |
Dump runlength encoded pixels. | |
*/ | |
q=pixels; | |
for (y=0; y < (ssize_t) tile_image->rows; y++) | |
{ | |
p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1, | |
exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) tile_image->columns; x++) | |
{ | |
*q++=ScaleQuantumToChar(GetPixelRed(tile_image,p)); | |
*q++=ScaleQuantumToChar(GetPixelGreen(tile_image,p)); | |
*q++=ScaleQuantumToChar(GetPixelBlue(tile_image,p)); | |
if (tile_image->colorspace == CMYKColorspace) | |
*q++=ScaleQuantumToChar(GetPixelBlack(tile_image,p)); | |
p+=GetPixelChannels(tile_image); | |
} | |
} | |
#if defined(MAGICKCORE_ZLIB_DELEGATE) | |
if (compression == ZipCompression) | |
status=ZLIBEncodeImage(image,length,pixels,exception); | |
else | |
#endif | |
if (compression == LZWCompression) | |
status=LZWEncodeImage(image,length,pixels,exception); | |
else | |
status=PackbitsEncodeImage(image,length,pixels,exception); | |
pixel_info=RelinquishVirtualMemory(pixel_info); | |
if (status == MagickFalse) | |
{ | |
tile_image=DestroyImage(tile_image); | |
xref=(MagickOffsetType *) RelinquishMagickMemory(xref); | |
(void) CloseBlob(image); | |
return(MagickFalse); | |
} | |
break; | |
} | |
case NoCompression: | |
{ | |
/* | |
Dump uncompressed DirectColor packets. | |
*/ | |
Ascii85Initialize(image); | |
for (y=0; y < (ssize_t) tile_image->rows; y++) | |
{ | |
p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1, | |
exception); | |
if (p == (const Quantum *) NULL) | |
break; | |
for (x=0; x < (ssize_t) tile_image->columns; x++) | |
{ | |
Ascii85Encode(image,ScaleQuantumToChar( | |
GetPixelRed(tile_image,p))); | |
Ascii85Encode(image,ScaleQuantumToChar( | |
GetPixelGreen(tile_image,p))); | |
Ascii85Encode(image,ScaleQuantumToChar( | |
GetPixelBlue(tile_image,p))); | |
if (image->colorspace == CMYKColorspace) | |
Ascii85Encode(image,ScaleQuantumToChar( | |
GetPixelBlack(tile_image,p))); | |
p+=GetPixelChannels(tile_image); | |
} | |
} | |
Ascii85Flush(image); | |
break; | |
} | |
} | |
else | |
{ | |
/* | |
Dump number of colors and colormap. | |
*/ | |
switch (compression) | |
{ | |
case RLECompression: | |
default: | |
{ | |
MemoryInfo | |
*pixel_info; | |
/* | |
Allocate pixel array. | |
*/ | |
length=(size_t) number_pixels; | |
pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); | |
if (pixel_info == (MemoryInfo *) NULL) | |
{ | |
tile_image=DestroyImage(tile_image); | |
ThrowPDFException(ResourceLimitError, | |
"MemoryAllocationFailed"); |