| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % 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-2021 ImageMagick Studio LLC, a non-profit organization % |
| % dedicated to making software imaging solutions freely available. % |
| % % |
| % You may not use this file except in compliance with the License. You may % |
| % obtain a copy of the License at % |
| % % |
| % https://imagemagick.org/script/license.php % |
| % % |
| % Unless required by applicable law or agreed to in writing, software % |
| % distributed under the License is distributed on an "AS IS" BASIS, % |
| % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
| % See the License for the specific language governing permissions and % |
| % limitations under the License. % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % |
| */ |
| |
| /* |
| Include declarations. |
| */ |
| #include "MagickCore/studio.h" |
| #include "MagickCore/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/module.h" |
| #include "coders/bytebuffer-private.h" |
| #include "coders/ghostscript-private.h" |
| |
| /* |
| Define declarations. |
| */ |
| #if defined(MAGICKCORE_TIFF_DELEGATE) |
| #define CCITTParam "-1" |
| #else |
| #define CCITTParam "0" |
| #endif |
| |
| /* |
| Typedef declaractions. |
| */ |
| 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; |
| |
| 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; |
| (void) memset(&buffer,0,sizeof(buffer)); |
| buffer.image=image; |
| for (c=ReadMagickByteBuffer(&buffer); c != EOF; c=ReadMagickByteBuffer(&buffer)) |
| { |
| switch(c) |
| { |
| case '%': |
| { |
| 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'; |
| } |
| continue; |
| } |
| 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; |
| } |
| 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); |
| if (image_info->debug != MagickFalse) |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
| image_info->filename); |
| assert(exception != (ExceptionInfo *) NULL); |
| assert(exception->signature == MagickCoreSignature); |
| /* |
| 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); |
| image->resolution.x=geometry_info.rho; |
| image->resolution.y=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| image->resolution.y=image->resolution.x; |
| } |
| if (image_info->density != (char *) NULL) |
| { |
| flags=ParseGeometry(image_info->density,&geometry_info); |
| image->resolution.x=geometry_info.rho; |
| image->resolution.y=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| image->resolution.y=image->resolution.x; |
| } |
| (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"); |
| if ((image_info->page != (char *) NULL) || (fitPage != MagickFalse)) |
| (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double) |
| page.width,(double) page.height); |
| 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,"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 |
| 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); |
| } |
| 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*=image->resolution.x/2.0; |
| pdf_image->magick_rows*=image->resolution.y/2.0; |
| pdf_image->columns*=image->resolution.x/2.0; |
| pdf_image->rows*=image->resolution.y/2.0; |
| } |
| (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); |
| 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); |
| if (image->debug != MagickFalse) |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
| assert(exception != (ExceptionInfo *) NULL); |
| assert(exception->signature == MagickCoreSignature); |
| 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 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" |
| " <xap:ModifyDate>%s</xap:ModifyDate>\n" |
| " <xap:CreateDate>%s</xap:CreateDate>\n" |
| " <xap:MetadataDate>%s</xap:MetadataDate>\n" |
| " <xap:CreatorTool>%s</xap:CreatorTool>\n" |
| " </rdf:Description>\n" |
| " <rdf:Description rdf:about=\"\"\n" |
| " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\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" |
| " </rdf:Description>\n" |
| " <rdf:Description rdf:about=\"\"\n" |
| " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n" |
| " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n" |
| " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n" |
| " </rdf:Description>\n" |
| " <rdf:Description rdf:about=\"\"\n" |
| " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" |
| " <pdf:Producer>%s</pdf:Producer>\n" |
| " </rdf:Description>\n" |
| " <rdf:Description rdf:about=\"\"\n" |
| " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\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], |
| *escape, |
| **labels, |
| temp[MagickPathExtent], |
| *url; |
| |
| CompressionType |
| compression; |
| |
| const char |
| *device, |
| *option, |
| *value; |
| |
| const StringInfo |
| *profile; |
| |
| double |
| pointsize, |
| version; |
| |
| GeometryInfo |
| geometry_info; |
| |
| Image |
| *next; |
| |
| MagickBooleanType |
| status; |
| |
| MagickOffsetType |
| offset, |
| scene, |
| *xref; |
| |
| MagickSizeType |
| number_pixels; |
| |
| MagickStatusType |
| flags; |
| |
| PointInfo |
| delta, |
| resolution, |
| scale; |
| |
| RectangleInfo |
| geometry, |
| media_info, |
| page_info; |
| |
| const Quantum |
| *p; |
| |
| unsigned char |
| *q; |
| |
| ssize_t |
| i, |
| x; |
| |
| size_t |
| channels, |
| imageListLength, |
| info_id, |
| length, |
| object, |
| pages_id, |
| root_id, |
| text_size; |
| |
| ssize_t |
| count, |
| page_count, |
| y; |
| |
| struct tm |
| utc_time; |
| |
| time_t |
| seconds; |
| |
| unsigned char |
| *pixels; |
| |
| /* |
| Open output image file. |
| */ |
| assert(image_info != (const ImageInfo *) NULL); |
| assert(image_info->signature == MagickCoreSignature); |
| assert(image != (Image *) NULL); |
| assert(image->signature == MagickCoreSignature); |
| if (image->debug != MagickFalse) |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
| assert(exception != (ExceptionInfo *) NULL); |
| assert(exception->signature == MagickCoreSignature); |
| 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; |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| version=1.6; |
| for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) |
| { |
| (void) SetImageGray(next,exception); |
| profile=GetImageProfile(next,"icc"); |
| if (profile != (StringInfo *) NULL) |
| { |
| (void) SetImageStorageClass(next,DirectClass,exception); |
| version=1.7; |
| } |
| if ((next->colorspace != CMYKColorspace) && |
| (IssRGBCompatibleColorspace(next->colorspace) == MagickFalse)) |
| (void) TransformImageColorspace(next,sRGBColorspace,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 (LocaleCompare(image_info->magick,"PDFA") == 0) |
| { |
| (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 (LocaleCompare(image_info->magick,"PDFA") != 0) |
| (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 (LocaleCompare(image_info->magick,"PDFA") == 0) |
| { |
| char |
| create_date[MagickTimeExtent], |
| modify_date[MagickTimeExtent], |
| timestamp[MagickTimeExtent]; |
| |
| /* |
| 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"); |
| *modify_date='\0'; |
| value=GetImageProperty(image,"date:modify",exception); |
| if (value != (const char *) NULL) |
| (void) CopyMagickString(modify_date,value,sizeof(modify_date)); |
| *create_date='\0'; |
| value=GetImageProperty(image,"date:create",exception); |
| if (value != (const char *) NULL) |
| (void) CopyMagickString(create_date,value,sizeof(create_date)); |
| (void) FormatMagickTime(GetMagickTime(),sizeof(timestamp),timestamp); |
| url=(char *) MagickAuthoritativeURL; |
| escape=EscapeParenthesis(basename); |
| i=FormatLocaleString(temp,MagickPathExtent,XMPProfile, |
| XMPProfileMagick,modify_date,create_date,timestamp,url,escape,url); |
| escape=DestroyString(escape); |
| (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++; |
| profile=GetImageProfile(kid_image,"icc"); |
| if (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; |
| imageListLength=GetImageListLength(image); |
| do |
| { |
| Image |
| *tile_image; |
| |
| MagickBooleanType |
| has_icc_profile, |
| thumbnail; |
| |
| profile=GetImageProfile(image,"icc"); |
| has_icc_profile=profile != (StringInfo *) NULL ? MagickTrue : MagickFalse; |
| 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 (LocaleCompare(image_info->magick,"PDFA") == 0) |
| compression=RLECompression; /* LZW compression is forbidden */ |
| break; |
| } |
| case NoCompression: |
| { |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| compression=RLECompression; /* ASCII 85 compression is forbidden */ |
| break; |
| } |
| default: |
| break; |
| } |
| if (compression == JPEG2000Compression) |
| (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); |
| resolution.x=geometry_info.rho; |
| resolution.y=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| resolution.y=resolution.x; |
| } |
| if (image_info->density != (char *) NULL) |
| { |
| flags=ParseGeometry(image_info->density,&geometry_info); |
| resolution.x=geometry_info.rho; |
| resolution.y=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| resolution.y=resolution.x; |
| } |
| 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+(has_icc_profile != MagickFalse ? 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 ((image->storage_class == DirectClass) || (image->colors > 256)) |
| (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MagickPathExtent); |
| else |
| if ((compression == FaxCompression) || (compression == Group4Compression)) |
| (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",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+(has_icc_profile != MagickFalse ? 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) || |
| ((image_info->type != TrueColorType) && |
| (SetImageGray(image,exception) != 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) || |
| ((image_info->type != TrueColorType) && |
| (SetImageGray(image,exception) != MagickFalse))) |
| { |
| device="DeviceGray"; |
| channels=1; |
| } |
| else |
| if ((image->storage_class == DirectClass) || |
| (image->colors > 256) || (compression == JPEGCompression) || |
| (compression == JPEG2000Compression)) |
| { |
| device="DeviceRGB"; |
| channels=3; |
| } |
| if (has_icc_profile == MagickFalse) |
| { |
| 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 |
| *p; |
| |
| /* |
| 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); |
| p=GetStringInfoDatum(profile); |
| for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++) |
| Ascii85Encode(image,(unsigned char) *p++); |
| 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) |
| 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- |
| (has_icc_profile != MagickFalse ? 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) || |
| ((image_info->type != TrueColorType) && |
| (SetImageGray(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) |
| { |
| xref=(MagickOffsetType *) RelinquishMagickMemory(xref); |
| (void) CloseBlob(image); |
| return(MagickFalse); |
| } |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,tile_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) |
| { |
| 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) |
| { |
| 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) |
| { |
| xref=(MagickOffsetType *) RelinquishMagickMemory(xref); |
| (void) CloseBlob(image); |
| return(MagickFalse); |
| } |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,tile_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*=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) |
| { |
| 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"); |
| } |
| 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++=(unsigned char) ((ssize_t) GetPixelIndex(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) |
| { |
| 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,(unsigned char) ((ssize_t) |
| GetPixelIndex(tile_image,p))); |
| p+=GetPixelChannels(image); |
| } |
| } |
| Ascii85Flush(image); |
| break; |
| } |
| } |
| } |
| tile_image=DestroyImage(tile_image); |
| 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"); |
| xref[object++]=TellBlob(image); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| if ((image->storage_class == DirectClass) || (image->colors > 256) || |
| (compression == FaxCompression) || (compression == Group4Compression)) |
| (void) WriteBlobString(image,">>\n"); |
| else |
| { |
| /* |
| Write Colormap object. |
| */ |
| if (compression == NoCompression) |
| (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\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); |
| if (compression == NoCompression) |
| Ascii85Initialize(image); |
| for (i=0; i < (ssize_t) image->colors; i++) |
| { |
| if (compression == NoCompression) |
| { |
| Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( |
| image->colormap[i].red))); |
| Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( |
| image->colormap[i].green))); |
| Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( |
| image->colormap[i].blue))); |
| continue; |
| } |
| (void) WriteBlobByte(image,ScaleQuantumToChar( |
| ClampToQuantum(image->colormap[i].red))); |
| (void) WriteBlobByte(image,ScaleQuantumToChar( |
| ClampToQuantum(image->colormap[i].green))); |
| (void) WriteBlobByte(image,ScaleQuantumToChar( |
| ClampToQuantum(image->colormap[i].blue))); |
| } |
| if (compression == NoCompression) |
| Ascii85Flush(image); |
| 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 softmask object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| if (image->alpha_trait == UndefinedPixelTrait) |
| (void) WriteBlobString(image,">>\n"); |
| else |
| { |
| (void) WriteBlobString(image,"/Type /XObject\n"); |
| (void) WriteBlobString(image,"/Subtype /Image\n"); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Ma%.20g\n", |
| (double) image->scene); |
| (void) WriteBlobString(image,buffer); |
| switch (compression) |
| { |
| case NoCompression: |
| { |
| (void) FormatLocaleString(buffer,MagickPathExtent,CFormat, |
| "ASCII85Decode"); |
| break; |
| } |
| case LZWCompression: |
| { |
| (void) FormatLocaleString(buffer,MagickPathExtent,CFormat, |
| "LZWDecode"); |
| break; |
| } |
| case ZipCompression: |
| { |
| (void) FormatLocaleString(buffer,MagickPathExtent,CFormat, |
| "FlateDecode"); |
| 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) WriteBlobString(image,"/ColorSpace /DeviceGray\n"); |
| (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) image->columns*image->rows; |
| switch (compression) |
| { |
| case RLECompression: |
| default: |
| { |
| MemoryInfo |
| *pixel_info; |
| |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels)); |
| if (pixel_info == (MemoryInfo *) NULL) |
| { |
| image=DestroyImage(image); |
| 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(GetPixelAlpha(image,p)); |
| p+=GetPixelChannels(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) |
| { |
| 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(GetPixelAlpha(image,p))); |
| p+=GetPixelChannels(image); |
| } |
| } |
| 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"); |
| if (GetNextImageInList(image) == (Image *) NULL) |
| break; |
| image=SyncNextImageInList(image); |
| status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength); |
| if (status == MagickFalse) |
| break; |
| } while (image_info->adjoin != MagickFalse); |
| /* |
| Write Metadata object. |
| */ |
| xref[object++]=TellBlob(image); |
| info_id=object; |
| (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| { |
| escape=EscapeParenthesis(basename); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Title (%s)\n", |
| escape); |
| escape=DestroyString(escape); |
| } |
| else |
| { |
| wchar_t |
| *utf16; |
| |
| utf16=ConvertUTF8ToUTF16((unsigned char *) basename,&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) FormatLocaleString(buffer,MagickPathExtent,"/Title <"); |
| (void) WriteBlobString(image,buffer); |
| for (i=0; i < (ssize_t) length; i++) |
| { |
| (void) WriteBlobByte(image,'0'); |
| (void) WriteBlobByte(image,'0'); |
| (void) WriteBlobByte(image,hex_digits[(utf16[i] >> 4) & 0x0f]); |
| (void) WriteBlobByte(image,hex_digits[utf16[i] & 0x0f]); |
| } |
| (void) FormatLocaleString(buffer,MagickPathExtent,">\n"); |
| utf16=(wchar_t *) RelinquishMagickMemory(utf16); |
| } |
| } |
| (void) WriteBlobString(image,buffer); |
| seconds=GetMagickTime(); |
| GetMagickUTCtime(&seconds,&utc_time); |
| (void) FormatLocaleString(temp,MagickPathExtent,"D:%04d%02d%02d%02d%02d%02d", |
| utc_time.tm_year+1900,utc_time.tm_mon+1,utc_time.tm_mday, |
| utc_time.tm_hour,utc_time.tm_min,utc_time.tm_sec); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/CreationDate (%s)\n", |
| temp); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/ModDate (%s)\n",temp); |
| (void) WriteBlobString(image,buffer); |
| url=(char *) MagickAuthoritativeURL; |
| escape=EscapeParenthesis(url); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Producer (%s)\n",escape); |
| escape=DestroyString(escape); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Xref object. |
| */ |
| offset=TellBlob(image)-xref[0]+ |
| (LocaleCompare(image_info->magick,"PDFA") == 0 ? 6 : 0)+10; |
| (void) WriteBlobString(image,"xref\n"); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"0 %.20g\n",(double) |
| object+1); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"0000000000 65535 f \n"); |
| for (i=0; i < (ssize_t) object; i++) |
| { |
| (void) FormatLocaleString(buffer,MagickPathExtent,"%010lu 00000 n \n", |
| (unsigned long) xref[i]); |
| (void) WriteBlobString(image,buffer); |
| } |
| (void) WriteBlobString(image,"trailer\n"); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Size %.20g\n",(double) |
| object+1); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Info %.20g 0 R\n",(double) |
| info_id); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/Root %.20g 0 R\n",(double) |
| root_id); |
| (void) WriteBlobString(image,buffer); |
| (void) SignatureImage(image,exception); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"/ID [<%s> <%s>]\n", |
| GetImageProperty(image,"signature",exception), |
| GetImageProperty(image,"signature",exception)); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"startxref\n"); |
| (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"%%EOF\n"); |
| xref=(MagickOffsetType *) RelinquishMagickMemory(xref); |
| (void) CloseBlob(image); |
| return(MagickTrue); |
| } |