| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % 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 % |
| % John Cristy % |
| % July 1992 % |
| % % |
| % % |
| % Copyright 1999-2011 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 % |
| % % |
| % http://www.imagemagick.org/script/license.php % |
| % % |
| % Unless required by applicable law or agreed to in writing, software % |
| % distributed under the License is distributed on an "AS IS" BASIS, % |
| % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
| % See the License for the specific language governing permissions and % |
| % limitations under the License. % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % |
| */ |
| |
| /* |
| Include declarations. |
| */ |
| #include "magick/studio.h" |
| #include "magick/blob.h" |
| #include "magick/blob-private.h" |
| #include "magick/cache.h" |
| #include "magick/color.h" |
| #include "magick/color-private.h" |
| #include "magick/colorspace.h" |
| #include "magick/compress.h" |
| #include "magick/constitute.h" |
| #include "magick/delegate.h" |
| #include "magick/delegate-private.h" |
| #include "magick/draw.h" |
| #include "magick/exception.h" |
| #include "magick/exception-private.h" |
| #include "magick/geometry.h" |
| #include "magick/image.h" |
| #include "magick/image-private.h" |
| #include "magick/list.h" |
| #include "magick/magick.h" |
| #include "magick/memory_.h" |
| #include "magick/monitor.h" |
| #include "magick/monitor-private.h" |
| #include "magick/option.h" |
| #include "magick/profile.h" |
| #include "magick/property.h" |
| #include "magick/quantum-private.h" |
| #include "magick/resource_.h" |
| #include "magick/resize.h" |
| #include "magick/static.h" |
| #include "magick/string_.h" |
| #include "magick/module.h" |
| #include "magick/transform.h" |
| #include "magick/utility.h" |
| #include "magick/module.h" |
| |
| /* |
| Define declarations. |
| */ |
| #if defined(MAGICKCORE_TIFF_DELEGATE) |
| #define CCITTParam "-1" |
| #else |
| #define CCITTParam "0" |
| #endif |
| |
| /* |
| Forward declarations. |
| */ |
| static MagickBooleanType |
| WritePDFImage(const ImageInfo *,Image *); |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % I n v o k e P D F D e l e g a t e % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % InvokePDFDelegate() executes the PDF interpreter with the specified command. |
| % |
| % The format of the InvokePDFDelegate method is: |
| % |
| % MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose, |
| % const char *command,ExceptionInfo *exception) |
| % |
| % A description of each parameter follows: |
| % |
| % o verbose: A value other than zero displays the command prior to |
| % executing it. |
| % |
| % o command: the address of a character string containing the command to |
| % execute. |
| % |
| % o exception: return any errors or warnings in this structure. |
| % |
| */ |
| static MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose, |
| const char *command,ExceptionInfo *exception) |
| { |
| int |
| status; |
| |
| #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) |
| char |
| **argv; |
| |
| const GhostInfo |
| *ghost_info; |
| |
| gs_main_instance |
| *interpreter; |
| |
| int |
| argc, |
| code; |
| |
| register ssize_t |
| i; |
| |
| #if defined(MAGICKCORE_WINDOWS_SUPPORT) |
| ghost_info=NTGhostscriptDLLVectors(); |
| #else |
| GhostInfo |
| ghost_info_struct; |
| |
| ghost_info=(&ghost_info_struct); |
| (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info)); |
| ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *)) |
| gsapi_new_instance; |
| ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **)) |
| gsapi_init_with_args; |
| ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int, |
| int *)) gsapi_run_string; |
| ghost_info_struct.delete_instance=(void (*)(gs_main_instance *)) |
| gsapi_delete_instance; |
| ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit; |
| #endif |
| if (ghost_info == (GhostInfo *) NULL) |
| { |
| status=SystemCommand(MagickFalse,verbose,command,exception); |
| return(status == 0 ? MagickTrue : MagickFalse); |
| } |
| if (verbose != MagickFalse) |
| { |
| (void) fputs("[ghostscript library]",stdout); |
| (void) fputs(strchr(command,' '),stdout); |
| } |
| status=(ghost_info->new_instance)(&interpreter,(void *) NULL); |
| if (status < 0) |
| { |
| status=SystemCommand(MagickFalse,verbose,command,exception); |
| return(status == 0 ? MagickTrue : MagickFalse); |
| } |
| argv=StringToArgv(command,&argc); |
| status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1); |
| if (status == 0) |
| status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n", |
| 0,&code); |
| (ghost_info->exit)(interpreter); |
| (ghost_info->delete_instance)(interpreter); |
| #if defined(MAGICKCORE_WINDOWS_SUPPORT) |
| NTGhostscriptUnLoadDLL(); |
| #endif |
| for (i=0; i < (ssize_t) argc; i++) |
| argv[i]=DestroyString(argv[i]); |
| argv=(char **) RelinquishMagickMemory(argv); |
| if ((status != 0) && (status != -101)) |
| { |
| char |
| *message; |
| |
| message=GetExceptionMessage(errno); |
| (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, |
| "`%s': %s",command,message); |
| message=DestroyString(message); |
| (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
| "Ghostscript returns status %d, exit code %d",status,code); |
| return(MagickFalse); |
| } |
| return(MagickTrue); |
| #else |
| status=SystemCommand(MagickFalse,verbose,command,exception); |
| return(status == 0 ? MagickTrue : MagickFalse); |
| #endif |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % 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 MagickBooleanType IsPDFRendered(const char *path) |
| { |
| MagickBooleanType |
| status; |
| |
| struct stat |
| attributes; |
| |
| if ((path == (const char *) NULL) || (*path == '\0')) |
| return(MagickFalse); |
| status=GetPathAttributes(path,&attributes); |
| if ((status != MagickFalse) && S_ISREG(attributes.st_mode) && |
| (attributes.st_size > 0)) |
| return(MagickTrue); |
| return(MagickFalse); |
| } |
| |
| static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception) |
| { |
| #define CropBox "CropBox" |
| #define DeviceCMYK "DeviceCMYK" |
| #define MediaBox "MediaBox" |
| #define RenderPostscriptText "Rendering Postscript... " |
| #define PDFRotate "Rotate" |
| #define SpotColor "Separation" |
| #define TrimBox "TrimBox" |
| #define PDFVersion "PDF-" |
| |
| char |
| command[MaxTextExtent], |
| density[MaxTextExtent], |
| filename[MaxTextExtent], |
| geometry[MaxTextExtent], |
| options[MaxTextExtent], |
| input_filename[MaxTextExtent], |
| postscript_filename[MaxTextExtent]; |
| |
| const char |
| *option; |
| |
| const DelegateInfo |
| *delegate_info; |
| |
| double |
| angle; |
| |
| GeometryInfo |
| geometry_info; |
| |
| Image |
| *image, |
| *next, |
| *pdf_image; |
| |
| ImageInfo |
| *read_info; |
| |
| int |
| file; |
| |
| MagickBooleanType |
| cmyk, |
| cropbox, |
| trimbox, |
| status; |
| |
| MagickStatusType |
| flags; |
| |
| PointInfo |
| delta; |
| |
| RectangleInfo |
| bounding_box, |
| page; |
| |
| register char |
| *p; |
| |
| register int |
| c; |
| |
| SegmentInfo |
| bounds, |
| hires_bounds; |
| |
| ssize_t |
| count; |
| |
| size_t |
| scene, |
| spotcolor; |
| |
| assert(image_info != (const ImageInfo *) NULL); |
| assert(image_info->signature == MagickSignature); |
| if (image_info->debug != MagickFalse) |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
| image_info->filename); |
| assert(exception != (ExceptionInfo *) NULL); |
| assert(exception->signature == MagickSignature); |
| /* |
| Open image file. |
| */ |
| image=AcquireImage(image_info); |
| 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; |
| if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0)) |
| { |
| flags=ParseGeometry(PSDensityGeometry,&geometry_info); |
| image->x_resolution=geometry_info.rho; |
| image->y_resolution=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| image->y_resolution=image->x_resolution; |
| } |
| /* |
| Determine page geometry from the PDF media box. |
| */ |
| cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse; |
| cropbox=MagickFalse; |
| option=GetImageOption(image_info,"pdf:use-cropbox"); |
| if (option != (const char *) NULL) |
| cropbox=IsMagickTrue(option); |
| trimbox=MagickFalse; |
| option=GetImageOption(image_info,"pdf:use-trimbox"); |
| if (option != (const char *) NULL) |
| trimbox=IsMagickTrue(option); |
| count=0; |
| spotcolor=0; |
| (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box)); |
| (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); |
| (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds)); |
| (void) ResetMagickMemory(&page,0,sizeof(page)); |
| (void) ResetMagickMemory(command,0,sizeof(command)); |
| hires_bounds.x2=0.0; |
| hires_bounds.y2=0.0; |
| angle=0.0; |
| p=command; |
| for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) |
| { |
| /* |
| Note PDF elements. |
| */ |
| if (c == '\n') |
| c=' '; |
| *p++=(char) c; |
| if ((c != (int) '/') && (c != (int) '%') && |
| ((size_t) (p-command) < (MaxTextExtent-1))) |
| continue; |
| *(--p)='\0'; |
| p=command; |
| if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0) |
| count=(ssize_t) sscanf(command,"Rotate %lf",&angle); |
| /* |
| Is this a CMYK document? |
| */ |
| if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0) |
| cmyk=MagickTrue; |
| if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0) |
| { |
| char |
| name[MaxTextExtent], |
| property[MaxTextExtent], |
| *value; |
| |
| register ssize_t |
| i; |
| |
| /* |
| Note spot names. |
| */ |
| (void) FormatMagickString(property,MaxTextExtent,"pdf:SpotColor-%.20g", |
| (double) spotcolor++); |
| i=0; |
| for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) |
| { |
| if ((isspace(c) != 0) || (c == '/') || ((i+1) == MaxTextExtent)) |
| break; |
| name[i++]=(char) c; |
| } |
| name[i]='\0'; |
| value=AcquireString(name); |
| (void) SubstituteString(&value,"#20"," "); |
| (void) SetImageProperty(image,property,value); |
| value=DestroyString(value); |
| continue; |
| } |
| if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0) |
| (void) SetImageProperty(image,"pdf:Version",command); |
| count=0; |
| if (cropbox != MagickFalse) |
| { |
| if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0) |
| { |
| /* |
| Note region defined by crop box. |
| */ |
| count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| if (count != 4) |
| count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| } |
| } |
| else |
| if (trimbox != MagickFalse) |
| { |
| if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0) |
| { |
| /* |
| Note region defined by trim box. |
| */ |
| count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| if (count != 4) |
| count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| } |
| } |
| else |
| if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0) |
| { |
| /* |
| Note region defined by media box. |
| */ |
| count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| if (count != 4) |
| count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf", |
| &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); |
| } |
| if (count != 4) |
| continue; |
| if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) || |
| ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0))) |
| { |
| /* |
| Set PDF render geometry. |
| */ |
| (void) FormatMagickString(geometry,MaxTextExtent, |
| "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1, |
| bounds.x1,bounds.y1); |
| (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry); |
| page.width=(size_t) floor(bounds.x2-bounds.x1+0.5); |
| page.height=(size_t) floor(bounds.y2-bounds.y1+0.5); |
| hires_bounds=bounds; |
| } |
| } |
| (void) CloseBlob(image); |
| if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0)) |
| { |
| size_t |
| swap; |
| |
| swap=page.width; |
| page.width=page.height; |
| page.height=swap; |
| } |
| if (image_info->colorspace == RGBColorspace) |
| cmyk=MagickFalse; |
| /* |
| Create Ghostscript control file. |
| */ |
| file=AcquireUniqueFileResource(postscript_filename); |
| if (file == -1) |
| { |
| ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", |
| image_info->filename); |
| image=DestroyImage(image); |
| return((Image *) NULL); |
| } |
| count=write(file," ",1); |
| file=close(file)-1; |
| /* |
| Render Postscript with the Ghostscript delegate. |
| */ |
| if ((image_info->ping != MagickFalse) || |
| (image_info->monochrome != MagickFalse)) |
| delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception); |
| else |
| if (cmyk != MagickFalse) |
| delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception); |
| else |
| if (LocaleCompare(image_info->magick,"AI") == 0) |
| delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception); |
| else |
| delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception); |
| if (delegate_info == (const DelegateInfo *) NULL) |
| { |
| (void) RelinquishUniqueFileResource(postscript_filename); |
| image=DestroyImage(image); |
| return((Image *) NULL); |
| } |
| *options='\0'; |
| if (image_info->density != (char *) NULL) |
| { |
| flags=ParseGeometry(image_info->density,&geometry_info); |
| image->x_resolution=geometry_info.rho; |
| image->y_resolution=geometry_info.sigma; |
| if ((flags & SigmaValue) == 0) |
| image->y_resolution=image->x_resolution; |
| } |
| (void) FormatMagickString(density,MaxTextExtent,"%gx%g", |
| image->x_resolution,image->y_resolution); |
| if (image_info->page != (char *) NULL) |
| { |
| (void) ParseAbsoluteGeometry(image_info->page,&page); |
| page.width=(size_t) floor(page.width*image->x_resolution/delta.x+ |
| 0.5); |
| page.height=(size_t) floor(page.height*image->y_resolution/delta.y+ |
| 0.5); |
| (void) FormatMagickString(options,MaxTextExtent,"-g%.20gx%.20g ", |
| (double) page.width,(double) page.height); |
| } |
| if (cmyk != MagickFalse) |
| (void) ConcatenateMagickString(options,"-dUseCIEColor ",MaxTextExtent); |
| if (cropbox != MagickFalse) |
| (void) ConcatenateMagickString(options,"-dUseCropBox ",MaxTextExtent); |
| if (trimbox != MagickFalse) |
| (void) ConcatenateMagickString(options,"-dUseTrimBox ",MaxTextExtent); |
| read_info=CloneImageInfo(image_info); |
| *read_info->magick='\0'; |
| if (read_info->number_scenes != 0) |
| { |
| char |
| pages[MaxTextExtent]; |
| |
| (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%.20g " |
| "-dLastPage=%.20g",(double) read_info->scene+1,(double) |
| (read_info->scene+read_info->number_scenes)); |
| (void) ConcatenateMagickString(options,pages,MaxTextExtent); |
| read_info->number_scenes=0; |
| if (read_info->scenes != (char *) NULL) |
| *read_info->scenes='\0'; |
| } |
| if (read_info->authenticate != (char *) NULL) |
| (void) FormatMagickString(options+strlen(options),MaxTextExtent, |
| " -sPDFPassword=%s",read_info->authenticate); |
| (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); |
| (void) AcquireUniqueFilename(read_info->filename); |
| (void) FormatMagickString(command,MaxTextExtent, |
| GetDelegateCommands(delegate_info), |
| read_info->antialias != MagickFalse ? 4 : 1, |
| read_info->antialias != MagickFalse ? 4 : 1,density,options, |
| read_info->filename,postscript_filename,input_filename); |
| status=InvokePDFDelegate(read_info->verbose,command,exception); |
| pdf_image=(Image *) NULL; |
| if ((status != MagickFalse) && |
| (IsPDFRendered(read_info->filename) != MagickFalse)) |
| pdf_image=ReadImage(read_info,exception); |
| (void) RelinquishUniqueFileResource(postscript_filename); |
| (void) RelinquishUniqueFileResource(read_info->filename); |
| (void) RelinquishUniqueFileResource(input_filename); |
| read_info=DestroyImageInfo(read_info); |
| if (pdf_image == (Image *) NULL) |
| { |
| ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed", |
| image_info->filename); |
| 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 (image_info->number_scenes != 0) |
| { |
| Image |
| *clone_image; |
| |
| register ssize_t |
| i; |
| |
| /* |
| 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,MaxTextExtent); |
| pdf_image->page=page; |
| (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=SetMagickInfo("AI"); |
| entry->decoder=(DecodeImageHandler *) ReadPDFImage; |
| entry->encoder=(EncodeImageHandler *) WritePDFImage; |
| entry->adjoin=MagickFalse; |
| entry->blob_support=MagickFalse; |
| entry->seekable_stream=MagickTrue; |
| entry->thread_support=EncoderThreadSupport; |
| entry->description=ConstantString("Adobe Illustrator CS2"); |
| entry->module=ConstantString("PDF"); |
| (void) RegisterMagickInfo(entry); |
| entry=SetMagickInfo("EPDF"); |
| entry->decoder=(DecodeImageHandler *) ReadPDFImage; |
| entry->encoder=(EncodeImageHandler *) WritePDFImage; |
| entry->adjoin=MagickFalse; |
| entry->blob_support=MagickFalse; |
| entry->seekable_stream=MagickTrue; |
| entry->thread_support=EncoderThreadSupport; |
| entry->description=ConstantString("Encapsulated Portable Document Format"); |
| entry->module=ConstantString("PDF"); |
| (void) RegisterMagickInfo(entry); |
| entry=SetMagickInfo("PDF"); |
| entry->decoder=(DecodeImageHandler *) ReadPDFImage; |
| entry->encoder=(EncodeImageHandler *) WritePDFImage; |
| entry->magick=(IsImageFormatHandler *) IsPDF; |
| entry->blob_support=MagickFalse; |
| entry->seekable_stream=MagickTrue; |
| entry->thread_support=EncoderThreadSupport; |
| entry->description=ConstantString("Portable Document Format"); |
| entry->module=ConstantString("PDF"); |
| (void) RegisterMagickInfo(entry); |
| entry=SetMagickInfo("PDFA"); |
| entry->decoder=(DecodeImageHandler *) ReadPDFImage; |
| entry->encoder=(EncodeImageHandler *) WritePDFImage; |
| entry->magick=(IsImageFormatHandler *) IsPDF; |
| entry->blob_support=MagickFalse; |
| entry->seekable_stream=MagickTrue; |
| entry->thread_support=EncoderThreadSupport; |
| entry->description=ConstantString("Portable Document Archive Format"); |
| entry->module=ConstantString("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) |
| % |
| % A description of each parameter follows. |
| % |
| % o image_info: the image info. |
| % |
| % o image: The image. |
| % |
| */ |
| |
| static inline size_t MagickMax(const size_t x,const size_t y) |
| { |
| if (x > y) |
| return(x); |
| return(y); |
| } |
| |
| static inline size_t MagickMin(const size_t x,const size_t y) |
| { |
| if (x < y) |
| return(x); |
| return(y); |
| } |
| |
| static char *EscapeParenthesis(const char *text) |
| { |
| register char |
| *p; |
| |
| register ssize_t |
| i; |
| |
| static char |
| buffer[MaxTextExtent]; |
| |
| size_t |
| escapes; |
| |
| escapes=0; |
| p=buffer; |
| for (i=0; i < (ssize_t) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++) |
| { |
| if ((text[i] == '(') || (text[i] == ')')) |
| { |
| *p++='\\'; |
| escapes++; |
| } |
| *p++=text[i]; |
| } |
| *p='\0'; |
| return(buffer); |
| } |
| |
| static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info, |
| Image *image,Image *inject_image) |
| { |
| Image |
| *group4_image; |
| |
| ImageInfo |
| *write_info; |
| |
| MagickBooleanType |
| status; |
| |
| size_t |
| length; |
| |
| unsigned char |
| *group4; |
| |
| status=MagickTrue; |
| write_info=CloneImageInfo(image_info); |
| (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent); |
| (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent); |
| group4_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception); |
| if (group4_image == (Image *) NULL) |
| return(MagickFalse); |
| group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length, |
| &image->exception); |
| group4_image=DestroyImage(group4_image); |
| if (group4 == (unsigned char *) NULL) |
| return(MagickFalse); |
| write_info=DestroyImageInfo(write_info); |
| if (WriteBlob(image,length,group4) != (ssize_t) length) |
| status=MagickFalse; |
| group4=(unsigned char *) RelinquishMagickMemory(group4); |
| return(status); |
| } |
| |
| static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image) |
| { |
| #define CFormat "/Filter [ /%s ]\n" |
| #define ObjectsPerImage 14 |
| |
| 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" |
| " </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>1</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) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 }; |
| |
| char |
| buffer[MaxTextExtent], |
| date[MaxTextExtent], |
| **labels, |
| page_geometry[MaxTextExtent]; |
| |
| CompressionType |
| compression; |
| |
| const char |
| *value; |
| |
| double |
| pointsize; |
| |
| GeometryInfo |
| geometry_info; |
| |
| ssize_t |
| count, |
| y; |
| |
| Image |
| *next, |
| *tile_image; |
| |
| MagickBooleanType |
| status; |
| |
| MagickOffsetType |
| offset, |
| scene, |
| *xref; |
| |
| MagickSizeType |
| number_pixels; |
| |
| MagickStatusType |
| flags; |
| |
| PointInfo |
| delta, |
| resolution, |
| scale; |
| |
| RectangleInfo |
| geometry, |
| media_info, |
| page_info; |
| |
| register const IndexPacket |
| *indexes; |
| |
| register const PixelPacket |
| *p; |
| |
| register unsigned char |
| *q; |
| |
| register ssize_t |
| i, |
| x; |
| |
| size_t |
| length; |
| |
| struct tm |
| local_time; |
| |
| time_t |
| seconds; |
| |
| unsigned char |
| *pixels; |
| |
| size_t |
| info_id, |
| object, |
| pages_id, |
| root_id, |
| text_size, |
| version; |
| |
| /* |
| Open output image file. |
| */ |
| assert(image_info != (const ImageInfo *) NULL); |
| assert(image_info->signature == MagickSignature); |
| assert(image != (Image *) NULL); |
| assert(image->signature == MagickSignature); |
| if (image->debug != MagickFalse) |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
| status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
| if (status == MagickFalse) |
| return(status); |
| /* |
| Allocate X ref memory. |
| */ |
| xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref)); |
| if (xref == (MagickOffsetType *) NULL) |
| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
| (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref)); |
| /* |
| Write Info object. |
| */ |
| object=0; |
| version=3; |
| if (image_info->compression == JPEG2000Compression) |
| version=(size_t) MagickMax(version,5); |
| for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) |
| if (next->matte != MagickFalse) |
| version=(size_t) MagickMax(version,4); |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| version=(size_t) MagickMax(version,6); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%%PDF-1.%.20g \n", |
| (double) version); |
| (void) WriteBlobString(image,buffer); |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| (void) WriteBlobString(image,"%âãÏÓ\n"); |
| /* |
| Write Catalog object. |
| */ |
| xref[object++]=TellBlob(image); |
| root_id=object; |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| if (LocaleCompare(image_info->magick,"PDFA") != 0) |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n", |
| (double) object+1); |
| else |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Metadata %.20g 0 R\n", |
| (double) object+1); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n", |
| (double) object+2); |
| } |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"/Type /Catalog\n"); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| if (LocaleCompare(image_info->magick,"PDFA") == 0) |
| { |
| char |
| create_date[MaxTextExtent], |
| modify_date[MaxTextExtent], |
| timestamp[MaxTextExtent], |
| xmp_profile[MaxTextExtent]; |
| |
| size_t |
| version; |
| |
| /* |
| Write XMP object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.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"); |
| if (value != (const char *) NULL) |
| (void) CopyMagickString(modify_date,value,MaxTextExtent); |
| *create_date='\0'; |
| value=GetImageProperty(image,"date:create"); |
| if (value != (const char *) NULL) |
| (void) CopyMagickString(create_date,value,MaxTextExtent); |
| (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp); |
| i=FormatMagickString(xmp_profile,MaxTextExtent,XMPProfile, |
| XMPProfileMagick,modify_date,create_date,timestamp, |
| GetMagickVersion(&version),GetMagickVersion(&version)); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g\n", |
| (double) i); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"/Type /Metadata\n"); |
| (void) WriteBlobString(image,">>\nstream\n"); |
| (void) WriteBlobString(image,xmp_profile); |
| (void) WriteBlobString(image,"endstream\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| } |
| /* |
| Write Pages object. |
| */ |
| xref[object++]=TellBlob(image); |
| pages_id=object; |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) WriteBlobString(image,"/Type /Pages\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Kids [ %.20g 0 R ", |
| (double) object+1); |
| (void) WriteBlobString(image,buffer); |
| count=(ssize_t) (pages_id+ObjectsPerImage+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) |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.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) FormatMagickString(buffer,MaxTextExtent,"/Count %.20g\n", |
| (double) ((count-pages_id)/ObjectsPerImage)); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| scene=0; |
| do |
| { |
| compression=image->compression; |
| if (image_info->compression != UndefinedCompression) |
| compression=image_info->compression; |
| switch (compression) |
| { |
| case FaxCompression: |
| case Group4Compression: |
| { |
| if ((IsMonochromeImage(image,&image->exception) == MagickFalse) || |
| (image->matte != MagickFalse)) |
| compression=RLECompression; |
| break; |
| } |
| #if !defined(MAGICKCORE_JPEG_DELEGATE) |
| case JPEGCompression: |
| { |
| compression=RLECompression; |
| (void) ThrowMagickException(&image->exception,GetMagickModule(), |
| MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)", |
| image->filename); |
| break; |
| } |
| #endif |
| #if !defined(MAGICKCORE_JP2_DELEGATE) |
| case JPEG2000Compression: |
| { |
| compression=RLECompression; |
| (void) ThrowMagickException(&image->exception,GetMagickModule(), |
| MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)", |
| image->filename); |
| break; |
| } |
| #endif |
| #if !defined(MAGICKCORE_ZLIB_DELEGATE) |
| case ZipCompression: |
| { |
| compression=RLECompression; |
| (void) ThrowMagickException(&image->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) |
| { |
| if (image->colorspace != RGBColorspace) |
| (void) TransformImageColorspace(image,RGBColorspace); |
| } |
| /* |
| Scale relative to dots-per-inch. |
| */ |
| delta.x=DefaultResolution; |
| delta.y=DefaultResolution; |
| resolution.x=image->x_resolution; |
| resolution.y=image->y_resolution; |
| 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=(size_t) (100.0*2.54*resolution.x+0.5)/100.0; |
| resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0; |
| } |
| SetGeometry(image,&geometry); |
| (void) FormatMagickString(page_geometry,MaxTextExtent,"%.20gx%.20g", |
| (double) image->columns,(double) image->rows); |
| if (image_info->page != (char *) NULL) |
| (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent); |
| else |
| if ((image->page.width != 0) && (image->page.height != 0)) |
| (void) FormatMagickString(page_geometry,MaxTextExtent, |
| "%.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(page_geometry,PSPageGeometry,MaxTextExtent); |
| (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent); |
| (void) ParseMetaGeometry(page_geometry,&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(page_geometry,&media_info); |
| (void) ParseGravityGeometry(image,page_geometry,&page_info, |
| &image->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"); |
| if (value != (const char *) NULL) |
| text_size=(size_t) (MultilineCensus(value)*pointsize+12); |
| /* |
| Write Page object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) WriteBlobString(image,"/Type /Page\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Parent %.20g 0 R\n", |
| (double) pages_id); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"/Resources <<\n"); |
| labels=(char **) NULL; |
| value=GetImageProperty(image,"Label"); |
| if (value != (const char *) NULL) |
| labels=StringToList(value); |
| if (labels != (char **) NULL) |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent, |
| "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double) |
| object+4); |
| (void) WriteBlobString(image,buffer); |
| } |
| (void) FormatMagickString(buffer,MaxTextExtent, |
| "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double) |
| object+5); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/ProcSet %.20g 0 R >>\n", |
| (double) object+3); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent, |
| "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x, |
| 72.0*media_info.height/resolution.y); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent, |
| "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x, |
| 72.0*media_info.height/resolution.y); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Contents %.20g 0 R\n", |
| (double) object+1); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Thumb %.20g 0 R\n", |
| (double) object+8); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Contents object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/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) FormatMagickString(buffer,MaxTextExtent,"/F%.20g %g Tf\n", |
| (double) image->scene,pointsize); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g Td\n", |
| (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+ |
| 12)); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"ET\n"); |
| labels[i]=DestroyString(labels[i]); |
| } |
| (void) FormatMagickString(buffer,MaxTextExtent,"%g 0 0 %g %.20g %.20g cm\n", |
| scale.x,scale.y,(double) geometry.x,(double) geometry.y); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Im%.20g Do\n", |
| (double) image->scene); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"Q\n"); |
| offset=TellBlob(image)-offset; |
| (void) WriteBlobString(image,"endstream\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Length object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Procset object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n", |
| (double) object); |
| (void) WriteBlobString(image,buffer); |
| if ((image->storage_class == DirectClass) || (image->colors > 256)) |
| (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent); |
| else |
| if ((compression == FaxCompression) || (compression == Group4Compression)) |
| (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent); |
| else |
| (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image," ]\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Font object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.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) FormatMagickString(buffer,MaxTextExtent,"/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) FormatMagickString(buffer,MaxTextExtent,"%.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) FormatMagickString(buffer,MaxTextExtent,"/Name /Im%.20g\n", |
| (double) image->scene); |
| (void) WriteBlobString(image,buffer); |
| switch (compression) |
| { |
| case NoCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode"); |
| break; |
| } |
| case JPEGCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode"); |
| if (image->colorspace != CMYKColorspace) |
| break; |
| (void) WriteBlobString(image,buffer); |
| (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", |
| MaxTextExtent); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode"); |
| if (image->colorspace != CMYKColorspace) |
| break; |
| (void) WriteBlobString(image,buffer); |
| (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", |
| MaxTextExtent); |
| break; |
| } |
| case LZWCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode"); |
| break; |
| } |
| case ZipCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode"); |
| break; |
| } |
| case FaxCompression: |
| case Group4Compression: |
| { |
| (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n", |
| MaxTextExtent); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << " |
| "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam, |
| (double) image->columns,(double) image->rows); |
| break; |
| } |
| default: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat, |
| "RunLengthDecode"); |
| break; |
| } |
| } |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n",(double) |
| image->columns); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n",(double) |
| image->rows); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n", |
| (double) object+2); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n", |
| (compression == FaxCompression) || (compression == Group4Compression) ? |
| 1 : 8); |
| (void) WriteBlobString(image,buffer); |
| if (image->matte != MagickFalse) |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,"/SMask %.20g 0 R\n", |
| (double) object+7); |
| (void) WriteBlobString(image,buffer); |
| } |
| (void) FormatMagickString(buffer,MaxTextExtent,"/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))) |
| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
| if ((compression == FaxCompression) || (compression == Group4Compression) || |
| ((image_info->type != TrueColorType) && |
| (IsGrayImage(image,&image->exception) != MagickFalse))) |
| { |
| switch (compression) |
| { |
| case FaxCompression: |
| case Group4Compression: |
| { |
| if (LocaleCompare(CCITTParam,"0") == 0) |
| { |
| (void) HuffmanEncodeImage(image_info,image,image); |
| break; |
| } |
| (void) Huffman2DEncodeImage(image_info,image,image); |
| break; |
| } |
| case JPEGCompression: |
| { |
| status=InjectImageBlob(image_info,image,image,"jpeg", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,image->exception.reason); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,image,"jp2", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,image->exception.reason); |
| break; |
| } |
| case RLECompression: |
| default: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| sizeof(*pixels)); |
| if (pixels == (unsigned char *) NULL) |
| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
| /* |
| Dump Runlength encoded pixels. |
| */ |
| q=pixels; |
| for (y=0; y < (ssize_t) image->rows; y++) |
| { |
| p=GetVirtualPixels(image,0,y,image->columns,1, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p)); |
| p++; |
| } |
| 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); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| Ascii85Encode(image, |
| ScaleQuantumToChar(PixelIntensityToQuantum(p))); |
| p++; |
| } |
| 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", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,image->exception.reason); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,image,"jp2", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,image->exception.reason); |
| break; |
| } |
| case RLECompression: |
| default: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| 4*sizeof(*pixels)); |
| length*=image->colorspace == CMYKColorspace ? 4UL : 3UL; |
| if (pixels == (unsigned char *) NULL) |
| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
| /* |
| Dump runoffset encoded pixels. |
| */ |
| q=pixels; |
| for (y=0; y < (ssize_t) image->rows; y++) |
| { |
| p=GetVirtualPixels(image,0,y,image->columns,1, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(image); |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| *q++=ScaleQuantumToChar(GetRedPixelComponent(p)); |
| *q++=ScaleQuantumToChar(GetGreenPixelComponent(p)); |
| *q++=ScaleQuantumToChar(GetBluePixelComponent(p)); |
| if (image->colorspace == CMYKColorspace) |
| *q++=ScaleQuantumToChar(indexes[x]); |
| p++; |
| } |
| 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); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(image); |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p))); |
| Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p))); |
| Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p))); |
| if (image->colorspace == CMYKColorspace) |
| Ascii85Encode(image,ScaleQuantumToChar(indexes[x])); |
| p++; |
| } |
| 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: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| sizeof(*pixels)); |
| if (pixels == (unsigned char *) NULL) |
| ThrowWriterException(ResourceLimitError, |
| "MemoryAllocationFailed"); |
| /* |
| Dump Runlength encoded pixels. |
| */ |
| q=pixels; |
| for (y=0; y < (ssize_t) image->rows; y++) |
| { |
| p=GetVirtualPixels(image,0,y,image->columns,1, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(image); |
| for (x=0; x < (ssize_t) image->columns; x++) |
| *q++=(unsigned char) indexes[x]; |
| 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); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(image); |
| for (x=0; x < (ssize_t) image->columns; x++) |
| Ascii85Encode(image,(unsigned char) indexes[x]); |
| 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) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n", |
| (double) offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Colorspace object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| if (image->colorspace == CMYKColorspace) |
| (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent); |
| else |
| if ((compression == FaxCompression) || |
| (compression == Group4Compression) || |
| ((image_info->type != TrueColorType) && |
| (IsGrayImage(image,&image->exception) != MagickFalse))) |
| (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent); |
| else |
| if ((image->storage_class == DirectClass) || (image->colors > 256) || |
| (compression == JPEGCompression) || |
| (compression == JPEG2000Compression)) |
| (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent); |
| else |
| (void) FormatMagickString(buffer,MaxTextExtent, |
| "[ /Indexed /DeviceRGB %.20g %.20g 0 R ]\n",(double) image->colors- |
| 1,(double) object+3); |
| (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); |
| tile_image=ThumbnailImage(image,geometry.width,geometry.height, |
| &image->exception); |
| if (tile_image == (Image *) NULL) |
| ThrowWriterException(ResourceLimitError,image->exception.reason); |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| switch (compression) |
| { |
| case NoCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode"); |
| break; |
| } |
| case JPEGCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode"); |
| if (image->colorspace != CMYKColorspace) |
| break; |
| (void) WriteBlobString(image,buffer); |
| (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", |
| MaxTextExtent); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode"); |
| if (image->colorspace != CMYKColorspace) |
| break; |
| (void) WriteBlobString(image,buffer); |
| (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n", |
| MaxTextExtent); |
| break; |
| } |
| case LZWCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode"); |
| break; |
| } |
| case ZipCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode"); |
| break; |
| } |
| case FaxCompression: |
| case Group4Compression: |
| { |
| (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n", |
| MaxTextExtent); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << " |
| "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam, |
| (double) tile_image->columns,(double) tile_image->rows); |
| break; |
| } |
| default: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat, |
| "RunLengthDecode"); |
| break; |
| } |
| } |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n",(double) |
| tile_image->columns); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n",(double) |
| tile_image->rows); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n", |
| (double) object-1); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n", |
| (compression == FaxCompression) || (compression == Group4Compression) ? |
| 1 : 8); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/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) && |
| (IsGrayImage(tile_image,&image->exception) != MagickFalse))) |
| { |
| switch (compression) |
| { |
| case FaxCompression: |
| case Group4Compression: |
| { |
| if (LocaleCompare(CCITTParam,"0") == 0) |
| { |
| (void) HuffmanEncodeImage(image_info,image,tile_image); |
| break; |
| } |
| (void) Huffman2DEncodeImage(image_info,image,tile_image); |
| break; |
| } |
| case JPEGCompression: |
| { |
| status=InjectImageBlob(image_info,image,tile_image,"jpeg", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,tile_image->exception.reason); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,tile_image,"jp2", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,tile_image->exception.reason); |
| break; |
| } |
| case RLECompression: |
| default: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| sizeof(*pixels)); |
| if (pixels == (unsigned char *) NULL) |
| { |
| tile_image=DestroyImage(tile_image); |
| ThrowWriterException(ResourceLimitError, |
| "MemoryAllocationFailed"); |
| } |
| /* |
| 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, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| { |
| *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p)); |
| p++; |
| } |
| } |
| #if defined(MAGICKCORE_ZLIB_DELEGATE) |
| if (compression == ZipCompression) |
| status=ZLIBEncodeImage(image,length,pixels); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| { |
| Ascii85Encode(image, |
| ScaleQuantumToChar(PixelIntensityToQuantum(p))); |
| p++; |
| } |
| } |
| 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", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,tile_image->exception.reason); |
| break; |
| } |
| case JPEG2000Compression: |
| { |
| status=InjectImageBlob(image_info,image,tile_image,"jp2", |
| &image->exception); |
| if (status == MagickFalse) |
| ThrowWriterException(CoderError,tile_image->exception.reason); |
| break; |
| } |
| case RLECompression: |
| default: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length,4* |
| sizeof(*pixels)); |
| length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL; |
| if (pixels == (unsigned char *) NULL) |
| { |
| tile_image=DestroyImage(tile_image); |
| ThrowWriterException(ResourceLimitError, |
| "MemoryAllocationFailed"); |
| } |
| /* |
| Dump runoffset encoded pixels. |
| */ |
| q=pixels; |
| for (y=0; y < (ssize_t) tile_image->rows; y++) |
| { |
| p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(tile_image); |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| { |
| *q++=ScaleQuantumToChar(GetRedPixelComponent(p)); |
| *q++=ScaleQuantumToChar(GetGreenPixelComponent(p)); |
| *q++=ScaleQuantumToChar(GetBluePixelComponent(p)); |
| if (image->colorspace == CMYKColorspace) |
| *q++=ScaleQuantumToChar(indexes[x]); |
| p++; |
| } |
| } |
| #if defined(MAGICKCORE_ZLIB_DELEGATE) |
| if (compression == ZipCompression) |
| status=ZLIBEncodeImage(image,length,pixels); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(tile_image); |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| { |
| Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p))); |
| Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p))); |
| Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p))); |
| if (image->colorspace == CMYKColorspace) |
| Ascii85Encode(image,ScaleQuantumToChar(indexes[x])); |
| p++; |
| } |
| } |
| Ascii85Flush(image); |
| break; |
| } |
| } |
| else |
| { |
| /* |
| Dump number of colors and colormap. |
| */ |
| switch (compression) |
| { |
| case RLECompression: |
| default: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| sizeof(*pixels)); |
| if (pixels == (unsigned char *) NULL) |
| { |
| tile_image=DestroyImage(tile_image); |
| ThrowWriterException(ResourceLimitError, |
| "MemoryAllocationFailed"); |
| } |
| /* |
| 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, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(tile_image); |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| *q++=(unsigned char) indexes[x]; |
| } |
| #if defined(MAGICKCORE_ZLIB_DELEGATE) |
| if (compression == ZipCompression) |
| status=ZLIBEncodeImage(image,length,pixels); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &tile_image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| indexes=GetVirtualIndexQueue(tile_image); |
| for (x=0; x < (ssize_t) tile_image->columns; x++) |
| Ascii85Encode(image,(unsigned char) indexes[x]); |
| } |
| 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) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"endobj\n"); |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| if ((image->storage_class != DirectClass) && (image->colors <= 256) && |
| (compression != FaxCompression) && (compression != Group4Compression)) |
| { |
| /* |
| Write Colormap object. |
| */ |
| (void) WriteBlobString(image,"<<\n"); |
| if (compression == NoCompression) |
| (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/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(image->colormap[i].red)); |
| Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green)); |
| Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue)); |
| continue; |
| } |
| (void) WriteBlobByte(image, |
| ScaleQuantumToChar(image->colormap[i].red)); |
| (void) WriteBlobByte(image, |
| ScaleQuantumToChar(image->colormap[i].green)); |
| (void) WriteBlobByte(image, |
| ScaleQuantumToChar(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) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) |
| offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write softmask object. |
| */ |
| xref[object++]=TellBlob(image); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| if (image->matte == MagickFalse) |
| (void) WriteBlobString(image,">>\n"); |
| else |
| { |
| (void) WriteBlobString(image,"/Type /XObject\n"); |
| (void) WriteBlobString(image,"/Subtype /Image\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Ma%.20g\n", |
| (double) image->scene); |
| (void) WriteBlobString(image,buffer); |
| switch (compression) |
| { |
| case NoCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat, |
| "ASCII85Decode"); |
| break; |
| } |
| case LZWCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode"); |
| break; |
| } |
| case ZipCompression: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat, |
| "FlateDecode"); |
| break; |
| } |
| default: |
| { |
| (void) FormatMagickString(buffer,MaxTextExtent,CFormat, |
| "RunLengthDecode"); |
| break; |
| } |
| } |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n", |
| (double) image->columns); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n", |
| (double) image->rows); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n", |
| (compression == FaxCompression) || (compression == Group4Compression) |
| ? 1 : 8); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/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: |
| { |
| /* |
| Allocate pixel array. |
| */ |
| length=(size_t) number_pixels; |
| pixels=(unsigned char *) AcquireQuantumMemory(length, |
| sizeof(*pixels)); |
| if (pixels == (unsigned char *) NULL) |
| { |
| image=DestroyImage(image); |
| ThrowWriterException(ResourceLimitError, |
| "MemoryAllocationFailed"); |
| } |
| /* |
| Dump Runlength encoded pixels. |
| */ |
| q=pixels; |
| for (y=0; y < (ssize_t) image->rows; y++) |
| { |
| p=GetVirtualPixels(image,0,y,image->columns,1, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| *q++=ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p))); |
| p++; |
| } |
| } |
| #if defined(MAGICKCORE_ZLIB_DELEGATE) |
| if (compression == ZipCompression) |
| status=ZLIBEncodeImage(image,length,pixels); |
| else |
| #endif |
| if (compression == LZWCompression) |
| status=LZWEncodeImage(image,length,pixels); |
| else |
| status=PackbitsEncodeImage(image,length,pixels); |
| pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
| if (status == MagickFalse) |
| { |
| (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, |
| &image->exception); |
| if (p == (const PixelPacket *) NULL) |
| break; |
| for (x=0; x < (ssize_t) image->columns; x++) |
| { |
| Ascii85Encode(image,ScaleQuantumToChar((Quantum) (QuantumRange- |
| GetOpacityPixelComponent(p)))); |
| p++; |
| } |
| } |
| 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) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.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++, |
| GetImageListLength(image)); |
| if (status == MagickFalse) |
| break; |
| } while (image_info->adjoin != MagickFalse); |
| /* |
| Write Metadata object. |
| */ |
| xref[object++]=TellBlob(image); |
| info_id=object; |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double) |
| object); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Title (%s)\n", |
| EscapeParenthesis(image->filename)); |
| (void) WriteBlobString(image,buffer); |
| seconds=time((time_t *) NULL); |
| #if defined(MAGICKCORE_HAVE_LOCALTIME_R) |
| (void) localtime_r(&seconds,&local_time); |
| #else |
| (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time)); |
| #endif |
| (void) FormatMagickString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d", |
| local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday, |
| local_time.tm_hour,local_time.tm_min,local_time.tm_sec); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/ModDate (%s)\n",date); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Producer (%s)\n", |
| EscapeParenthesis(GetMagickVersion((size_t *) NULL))); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"endobj\n"); |
| /* |
| Write Xref object. |
| */ |
| offset=TellBlob(image)-xref[0]+10; |
| (void) WriteBlobString(image,"xref\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"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) FormatMagickString(buffer,MaxTextExtent,"%010lu 00000 n \n", |
| (unsigned long) xref[i]); |
| (void) WriteBlobString(image,buffer); |
| } |
| (void) WriteBlobString(image,"trailer\n"); |
| (void) WriteBlobString(image,"<<\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Size %.20g\n",(double) |
| object+1); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Info %.20g 0 R\n",(double) |
| info_id); |
| (void) WriteBlobString(image,buffer); |
| (void) FormatMagickString(buffer,MaxTextExtent,"/Root %.20g 0 R\n",(double) |
| root_id); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,">>\n"); |
| (void) WriteBlobString(image,"startxref\n"); |
| (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset); |
| (void) WriteBlobString(image,buffer); |
| (void) WriteBlobString(image,"%%EOF\n"); |
| xref=(MagickOffsetType *) RelinquishMagickMemory(xref); |
| (void) CloseBlob(image); |
| return(MagickTrue); |
| } |