2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/color.h"
49 #include "MagickCore/color-private.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/delegate.h"
54 #include "MagickCore/delegate-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/geometry.h"
59 #include "MagickCore/image.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/list.h"
62 #include "MagickCore/magick.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/option.h"
67 #include "MagickCore/profile.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum-private.h"
72 #include "MagickCore/static.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/module.h"
75 #include "MagickCore/token.h"
76 #include "MagickCore/transform.h"
77 #include "MagickCore/utility.h"
82 static MagickBooleanType
83 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *);
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 % I n v o k e P o s t s r i p t D e l e g a t e %
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 % InvokePostscriptDelegate() executes the Postscript interpreter with the
99 % The format of the InvokePostscriptDelegate method is:
101 % MagickBooleanType InvokePostscriptDelegate(
102 % const MagickBooleanType verbose,const char *command,
103 % ExceptionInfo *exception)
105 % A description of each parameter follows:
107 % o verbose: A value other than zero displays the command prior to
110 % o command: the address of a character string containing the command to
113 % o exception: return any errors or warnings in this structure.
116 static MagickBooleanType InvokePostscriptDelegate(
117 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
122 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
139 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
140 ghost_info=NTGhostscriptDLLVectors();
145 ghost_info=(&ghost_info_struct);
146 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
147 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
149 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
150 gsapi_init_with_args;
151 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
152 int *)) gsapi_run_string;
153 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
154 gsapi_delete_instance;
155 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
157 if (ghost_info == (GhostInfo *) NULL)
159 status=SystemCommand(MagickFalse,verbose,command,exception);
160 return(status == 0 ? MagickTrue : MagickFalse);
162 if (verbose != MagickFalse)
164 (void) fputs("[ghostscript library]",stdout);
165 (void) fputs(strchr(command,' '),stdout);
167 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
170 status=SystemCommand(MagickFalse,verbose,command,exception);
171 return(status == 0 ? MagickTrue : MagickFalse);
174 argv=StringToArgv(command,&argc);
175 if (argv == (char **) NULL)
177 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
179 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
181 (ghost_info->exit)(interpreter);
182 (ghost_info->delete_instance)(interpreter);
183 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
184 NTGhostscriptUnLoadDLL();
186 for (i=0; i < (ssize_t) argc; i++)
187 argv[i]=DestroyString(argv[i]);
188 argv=(char **) RelinquishMagickMemory(argv);
189 if ((status != 0) && (status != -101))
194 message=GetExceptionMessage(errno);
195 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
196 "`%s': %s",command,message);
197 message=DestroyString(message);
198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
199 "Ghostscript returns status %d, exit code %d",status,code);
204 status=SystemCommand(MagickFalse,verbose,command,exception);
205 return(status == 0 ? MagickTrue : MagickFalse);
210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % IsPS() returns MagickTrue if the image format type, identified by the
221 % magick string, is PS.
223 % The format of the IsPS method is:
225 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
227 % A description of each parameter follows:
229 % o magick: compare image format pattern against these bytes.
231 % o length: Specifies the length of the magick string.
234 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
238 if (memcmp(magick,"%!",2) == 0)
240 if (memcmp(magick,"\004%!",3) == 0)
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 % R e a d P S I m a g e %
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256 % ReadPSImage() reads a Postscript image file and returns it. It allocates
257 % the memory necessary for the new Image structure and returns a pointer
260 % The format of the ReadPSImage method is:
262 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
264 % A description of each parameter follows:
266 % o image_info: the image info.
268 % o exception: return any errors or warnings in this structure.
272 static MagickBooleanType IsPostscriptRendered(const char *path)
280 if ((path == (const char *) NULL) || (*path == '\0'))
282 status=GetPathAttributes(path,&attributes);
283 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
284 (attributes.st_size > 0))
289 static inline int ProfileInteger(Image *image,short int *hex_digits)
303 c=ReadBlobByte(image);
304 if ((c == EOF) || ((c == '%') && (l == '%')))
311 if (isxdigit(c) == MagickFalse)
313 value=(int) ((size_t) value << 4)+hex_digits[c];
319 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
321 #define BoundingBox "BoundingBox:"
322 #define BeginDocument "BeginDocument:"
323 #define BeginXMPPacket "<?xpacket begin="
324 #define EndXMPPacket "<?xpacket end="
325 #define ICCProfile "BeginICCProfile:"
326 #define CMYKCustomColor "CMYKCustomColor:"
327 #define CMYKProcessColor "CMYKProcessColor:"
328 #define DocumentMedia "DocumentMedia:"
329 #define DocumentCustomColors "DocumentCustomColors:"
330 #define DocumentProcessColors "DocumentProcessColors:"
331 #define EndDocument "EndDocument:"
332 #define HiResBoundingBox "HiResBoundingBox:"
333 #define ImageData "ImageData:"
334 #define PageBoundingBox "PageBoundingBox:"
335 #define LanguageLevel "LanguageLevel:"
336 #define PageMedia "PageMedia:"
337 #define Pages "Pages:"
338 #define PhotoshopProfile "BeginPhotoshop:"
339 #define PostscriptLevel "!PS-"
340 #define RenderPostscriptText " Rendering Postscript... "
341 #define SpotColor "+ "
344 command[MaxTextExtent],
345 density[MaxTextExtent],
346 filename[MaxTextExtent],
347 geometry[MaxTextExtent],
348 input_filename[MaxTextExtent],
349 options[MaxTextExtent],
350 postscript_filename[MaxTextExtent];
423 assert(image_info != (const ImageInfo *) NULL);
424 assert(image_info->signature == MagickSignature);
425 if (image_info->debug != MagickFalse)
426 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
427 image_info->filename);
428 assert(exception != (ExceptionInfo *) NULL);
429 assert(exception->signature == MagickSignature);
430 image=AcquireImage(image_info,exception);
431 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
432 if (status == MagickFalse)
434 image=DestroyImageList(image);
435 return((Image *) NULL);
437 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
438 if (status == MagickFalse)
440 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
441 image_info->filename);
442 image=DestroyImageList(image);
443 return((Image *) NULL);
446 Initialize hex values.
448 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
449 hex_digits[(int) '0']=0;
450 hex_digits[(int) '1']=1;
451 hex_digits[(int) '2']=2;
452 hex_digits[(int) '3']=3;
453 hex_digits[(int) '4']=4;
454 hex_digits[(int) '5']=5;
455 hex_digits[(int) '6']=6;
456 hex_digits[(int) '7']=7;
457 hex_digits[(int) '8']=8;
458 hex_digits[(int) '9']=9;
459 hex_digits[(int) 'a']=10;
460 hex_digits[(int) 'b']=11;
461 hex_digits[(int) 'c']=12;
462 hex_digits[(int) 'd']=13;
463 hex_digits[(int) 'e']=14;
464 hex_digits[(int) 'f']=15;
465 hex_digits[(int) 'A']=10;
466 hex_digits[(int) 'B']=11;
467 hex_digits[(int) 'C']=12;
468 hex_digits[(int) 'D']=13;
469 hex_digits[(int) 'E']=14;
470 hex_digits[(int) 'F']=15;
472 Set the page density.
474 delta.x=DefaultResolution;
475 delta.y=DefaultResolution;
476 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
478 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
479 image->resolution.x=geometry_info.rho;
480 image->resolution.y=geometry_info.sigma;
481 if ((flags & SigmaValue) == 0)
482 image->resolution.y=image->resolution.x;
484 if (image_info->density != (char *) NULL)
486 flags=ParseGeometry(image_info->density,&geometry_info);
487 image->resolution.x=geometry_info.rho;
488 image->resolution.y=geometry_info.sigma;
489 if ((flags & SigmaValue) == 0)
490 image->resolution.y=image->resolution.x;
492 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
493 if (image_info->page != (char *) NULL)
494 (void) ParseAbsoluteGeometry(image_info->page,&page);
495 resolution=image->resolution;
496 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5);
497 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5);
499 Determine page geometry from the Postscript bounding box.
501 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
502 (void) ResetMagickMemory(command,0,sizeof(command));
503 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
504 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
513 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
516 Note document structuring comments.
519 if ((strchr("\n\r%",c) == (char *) NULL) &&
520 ((size_t) (p-command) < (MaxTextExtent-1)))
525 Skip %%BeginDocument thru %%EndDocument.
527 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
529 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
531 if (skip != MagickFalse)
533 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
535 (void) SetImageProperty(image,"ps:Level",command+4,exception);
536 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
539 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
540 (void) sscanf(command,LanguageLevel " %lu",&language_level);
541 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
542 (void) sscanf(command,Pages " %lu",&pages);
543 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
544 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
545 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
553 profile=AcquireStringInfo(65536);
554 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
556 SetStringInfoLength(profile,(size_t) i+1);
557 datum=GetStringInfoDatum(profile);
558 datum[i]=(unsigned char) c;
560 (void) SetImageProfile(image,"icc",profile,exception);
561 profile=DestroyStringInfo(profile);
564 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
570 Read Photoshop profile.
572 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
576 profile=BlobToStringInfo((const void *) NULL,length);
577 p=GetStringInfoDatum(profile);
578 for (i=0; i < (ssize_t) length; i++)
579 *p++=(unsigned char) ProfileInteger(image,hex_digits);
580 (void) SetImageProfile(image,"8bim",profile,exception);
581 profile=DestroyStringInfo(profile);
584 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
593 profile=StringToStringInfo(command);
594 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
596 SetStringInfoLength(profile,i+1);
597 c=ReadBlobByte(image);
598 GetStringInfoDatum(profile)[i]=(unsigned char) c;
600 if ((strchr("\n\r%",c) == (char *) NULL) &&
601 ((size_t) (p-command) < (MaxTextExtent-1)))
605 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
608 SetStringInfoLength(profile,i);
609 (void) SetImageProfile(image,"xmp",profile,exception);
610 profile=DestroyStringInfo(profile);
614 Is this a CMYK document?
616 length=strlen(DocumentProcessColors);
617 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
619 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
620 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
621 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
624 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
626 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
628 length=strlen(DocumentCustomColors);
629 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
630 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
631 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
634 property[MaxTextExtent],
643 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
644 (double) (spotcolor++));
645 for (p=command; *p != '\0'; p++)
646 if (isspace((int) (unsigned char) *p) != 0)
648 value=AcquireString(p);
649 (void) SubstituteString(&value,"(","");
650 (void) SubstituteString(&value,")","");
651 (void) StripString(value);
652 (void) SetImageProperty(image,property,value,exception);
653 value=DestroyString(value);
656 if (image_info->page != (char *) NULL)
659 Note region defined by bounding box.
663 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
665 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
666 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
669 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
671 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
672 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
675 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
677 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
678 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
681 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
683 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
684 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
687 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
689 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
690 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
693 if ((count != 4) || (i < (ssize_t) priority))
695 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
696 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
701 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
702 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
705 Set Postscript render geometry.
707 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
708 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
709 hires_bounds.x1,hires_bounds.y1);
710 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
711 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
712 resolution.x/delta.x)-0.5);
713 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
714 resolution.y/delta.y)-0.5);
716 (void) CloseBlob(image);
717 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
720 Create Ghostscript control file.
722 file=AcquireUniqueFileResource(postscript_filename);
725 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
726 image_info->filename);
727 image=DestroyImageList(image);
728 return((Image *) NULL);
730 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
731 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
732 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
733 count=write(file,command,(unsigned int) strlen(command));
734 if (image_info->page == (char *) NULL)
737 translate_geometry[MaxTextExtent];
739 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
740 "%g %g translate\n",-bounds.x1,-bounds.y1);
741 count=write(file,translate_geometry,(unsigned int)
742 strlen(translate_geometry));
746 Render Postscript with the Ghostscript delegate.
748 if (image_info->monochrome != MagickFalse)
749 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
751 if (cmyk != MagickFalse)
752 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
754 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
755 if (delegate_info == (const DelegateInfo *) NULL)
757 (void) RelinquishUniqueFileResource(postscript_filename);
758 image=DestroyImageList(image);
759 return((Image *) NULL);
762 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",resolution.x,
764 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
765 page.width,(double) page.height);
766 read_info=CloneImageInfo(image_info);
767 *read_info->magick='\0';
768 if (read_info->number_scenes != 0)
771 pages[MaxTextExtent];
773 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
774 "-dLastPage=%.20g ",(double) read_info->scene+1,(double)
775 (read_info->scene+read_info->number_scenes));
776 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
777 read_info->number_scenes=0;
778 if (read_info->scenes != (char *) NULL)
779 *read_info->scenes='\0';
781 option=GetImageOption(image_info,"eps:use-cropbox");
782 if ((*image_info->magick == 'E') && ((option == (const char *) NULL) ||
783 (IsStringTrue(option) != MagickFalse)))
784 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
785 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
786 (void) AcquireUniqueFilename(filename);
787 (void) ConcatenateMagickString(filename,"%d",MaxTextExtent);
788 (void) FormatLocaleString(command,MaxTextExtent,
789 GetDelegateCommands(delegate_info),
790 read_info->antialias != MagickFalse ? 4 : 1,
791 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
792 postscript_filename,input_filename);
793 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
794 (void) InterpretImageFilename(image_info,image,filename,1,
795 read_info->filename,exception);
796 if ((status == MagickFalse) ||
797 (IsPostscriptRendered(read_info->filename) == MagickFalse))
799 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
800 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
802 (void) RelinquishUniqueFileResource(postscript_filename);
803 (void) RelinquishUniqueFileResource(input_filename);
804 postscript_image=(Image *) NULL;
805 if (status == MagickFalse)
808 (void) InterpretImageFilename(image_info,image,filename,(int) i,
809 read_info->filename,exception);
810 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
812 (void) RelinquishUniqueFileResource(read_info->filename);
817 (void) InterpretImageFilename(image_info,image,filename,(int) i,
818 read_info->filename,exception);
819 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
821 read_info->blob=NULL;
823 next=ReadImage(read_info,exception);
824 (void) RelinquishUniqueFileResource(read_info->filename);
825 if (next == (Image *) NULL)
827 AppendImageToList(&postscript_image,next);
829 (void) RelinquishUniqueFileResource(read_info->filename);
830 read_info=DestroyImageInfo(read_info);
831 if (postscript_image == (Image *) NULL)
833 image=DestroyImageList(image);
834 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
835 image_info->filename);
836 return((Image *) NULL);
838 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
843 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
844 if (cmyk_image != (Image *) NULL)
846 postscript_image=DestroyImageList(postscript_image);
847 postscript_image=cmyk_image;
850 if (image_info->number_scenes != 0)
859 Add place holder images to meet the subimage specification requirement.
861 for (i=0; i < (ssize_t) image_info->scene; i++)
863 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
864 if (clone_image != (Image *) NULL)
865 PrependImageToList(&postscript_image,clone_image);
870 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
872 postscript_image->magick_columns=columns;
874 postscript_image->magick_rows=rows;
875 postscript_image->page=page;
876 (void) CloneImageProfiles(postscript_image,image);
877 (void) CloneImageProperties(postscript_image,image);
878 next=SyncNextImageInList(postscript_image);
879 if (next != (Image *) NULL)
880 postscript_image=next;
881 } while (next != (Image *) NULL);
882 image=DestroyImageList(image);
884 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
887 next=GetNextImageInList(next);
889 return(GetFirstImageInList(postscript_image));
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897 % R e g i s t e r P S I m a g e %
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903 % RegisterPSImage() adds properties for the PS image format to
904 % the list of supported formats. The properties include the image format
905 % tag, a method to read and/or write the format, whether the format
906 % supports the saving of more than one frame to the same file or blob,
907 % whether the format supports native in-memory I/O, and a brief
908 % description of the format.
910 % The format of the RegisterPSImage method is:
912 % size_t RegisterPSImage(void)
915 ModuleExport size_t RegisterPSImage(void)
920 entry=SetMagickInfo("EPI");
921 entry->decoder=(DecodeImageHandler *) ReadPSImage;
922 entry->encoder=(EncodeImageHandler *) WritePSImage;
923 entry->magick=(IsImageFormatHandler *) IsPS;
924 entry->adjoin=MagickFalse;
925 entry->blob_support=MagickFalse;
926 entry->seekable_stream=MagickTrue;
927 entry->description=ConstantString(
928 "Encapsulated PostScript Interchange format");
929 entry->mime_type=ConstantString("application/postscript");
930 entry->module=ConstantString("PS");
931 (void) RegisterMagickInfo(entry);
932 entry=SetMagickInfo("EPS");
933 entry->decoder=(DecodeImageHandler *) ReadPSImage;
934 entry->encoder=(EncodeImageHandler *) WritePSImage;
935 entry->magick=(IsImageFormatHandler *) IsPS;
936 entry->adjoin=MagickFalse;
937 entry->blob_support=MagickFalse;
938 entry->seekable_stream=MagickTrue;
939 entry->description=ConstantString("Encapsulated PostScript");
940 entry->mime_type=ConstantString("application/postscript");
941 entry->module=ConstantString("PS");
942 (void) RegisterMagickInfo(entry);
943 entry=SetMagickInfo("EPSF");
944 entry->decoder=(DecodeImageHandler *) ReadPSImage;
945 entry->encoder=(EncodeImageHandler *) WritePSImage;
946 entry->magick=(IsImageFormatHandler *) IsPS;
947 entry->adjoin=MagickFalse;
948 entry->blob_support=MagickFalse;
949 entry->seekable_stream=MagickTrue;
950 entry->description=ConstantString("Encapsulated PostScript");
951 entry->mime_type=ConstantString("application/postscript");
952 entry->module=ConstantString("PS");
953 (void) RegisterMagickInfo(entry);
954 entry=SetMagickInfo("EPSI");
955 entry->decoder=(DecodeImageHandler *) ReadPSImage;
956 entry->encoder=(EncodeImageHandler *) WritePSImage;
957 entry->magick=(IsImageFormatHandler *) IsPS;
958 entry->adjoin=MagickFalse;
959 entry->blob_support=MagickFalse;
960 entry->seekable_stream=MagickTrue;
961 entry->description=ConstantString(
962 "Encapsulated PostScript Interchange format");
963 entry->mime_type=ConstantString("application/postscript");
964 entry->module=ConstantString("PS");
965 (void) RegisterMagickInfo(entry);
966 entry=SetMagickInfo("PS");
967 entry->decoder=(DecodeImageHandler *) ReadPSImage;
968 entry->encoder=(EncodeImageHandler *) WritePSImage;
969 entry->magick=(IsImageFormatHandler *) IsPS;
970 entry->mime_type=ConstantString("application/postscript");
971 entry->module=ConstantString("PS");
972 entry->blob_support=MagickFalse;
973 entry->seekable_stream=MagickTrue;
974 entry->description=ConstantString("PostScript");
975 (void) RegisterMagickInfo(entry);
976 return(MagickImageCoderSignature);
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % U n r e g i s t e r P S I m a g e %
988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990 % UnregisterPSImage() removes format registrations made by the
991 % PS module from the list of supported formats.
993 % The format of the UnregisterPSImage method is:
995 % UnregisterPSImage(void)
998 ModuleExport void UnregisterPSImage(void)
1000 (void) UnregisterMagickInfo("EPI");
1001 (void) UnregisterMagickInfo("EPS");
1002 (void) UnregisterMagickInfo("EPSF");
1003 (void) UnregisterMagickInfo("EPSI");
1004 (void) UnregisterMagickInfo("PS");
1008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 % W r i t e P S I m a g e %
1016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 % WritePSImage translates an image to encapsulated Postscript
1019 % Level I for printing. If the supplied geometry is null, the image is
1020 % centered on the Postscript page. Otherwise, the image is positioned as
1021 % specified by the geometry.
1023 % The format of the WritePSImage method is:
1025 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
1026 % Image *image,ExceptionInfo *exception)
1028 % A description of each parameter follows:
1030 % o image_info: the image info.
1032 % o image: the image.
1034 % o exception: return any errors or warnings in this structure.
1038 static inline size_t MagickMin(const size_t x,const size_t y)
1045 static inline unsigned char *PopHexPixel(const char **hex_digits,
1046 const size_t pixel,unsigned char *pixels)
1051 hex=hex_digits[pixel];
1052 *pixels++=(unsigned char) (*hex++);
1053 *pixels++=(unsigned char) (*hex);
1057 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1058 ExceptionInfo *exception)
1060 #define WriteRunlengthPacket(image,pixel,length,p) \
1062 if ((image->alpha_trait == BlendPixelTrait) && \
1063 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1065 q=PopHexPixel(hex_digits,0xff,q); \
1066 q=PopHexPixel(hex_digits,0xff,q); \
1067 q=PopHexPixel(hex_digits,0xff,q); \
1071 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.red)),q); \
1072 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.green)),q); \
1073 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.blue)),q); \
1075 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1081 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1082 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1083 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1084 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1085 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1086 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1087 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1088 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1089 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1090 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1091 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1092 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1093 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1094 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1095 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1096 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1097 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1098 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1099 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1100 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1101 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1102 "FC", "FD", "FE", "FF", (char *) NULL
1104 *PostscriptProlog[]=
1108 "% Display a color image. The image is displayed in color on",
1109 "% Postscript viewers or printers that support color, otherwise",
1110 "% it is displayed as grayscale.",
1112 "/DirectClassPacket",
1115 " % Get a DirectClass packet.",
1121 " % length: number of pixels minus one of this color (optional).",
1123 " currentfile color_packet readhexstring pop pop",
1124 " compression 0 eq",
1126 " /number_pixels 3 def",
1129 " currentfile byte readhexstring pop 0 get",
1130 " /number_pixels exch 1 add 3 mul def",
1132 " 0 3 number_pixels 1 sub",
1134 " pixels exch color_packet putinterval",
1136 " pixels 0 number_pixels getinterval",
1139 "/DirectClassImage",
1142 " % Display a DirectClass image.",
1144 " systemdict /colorimage known",
1151 " { DirectClassPacket } false 3 colorimage",
1155 " % No colorimage operator; convert to grayscale.",
1162 " { GrayDirectClassPacket } image",
1166 "/GrayDirectClassPacket",
1169 " % Get a DirectClass packet; convert to grayscale.",
1175 " % length: number of pixels minus one of this color (optional).",
1177 " currentfile color_packet readhexstring pop pop",
1178 " color_packet 0 get 0.299 mul",
1179 " color_packet 1 get 0.587 mul add",
1180 " color_packet 2 get 0.114 mul add",
1182 " /gray_packet exch def",
1183 " compression 0 eq",
1185 " /number_pixels 1 def",
1188 " currentfile byte readhexstring pop 0 get",
1189 " /number_pixels exch 1 add def",
1191 " 0 1 number_pixels 1 sub",
1193 " pixels exch gray_packet put",
1195 " pixels 0 number_pixels getinterval",
1198 "/GrayPseudoClassPacket",
1201 " % Get a PseudoClass packet; convert to grayscale.",
1204 " % index: index into the colormap.",
1205 " % length: number of pixels minus one of this color (optional).",
1207 " currentfile byte readhexstring pop 0 get",
1208 " /offset exch 3 mul def",
1209 " /color_packet colormap offset 3 getinterval def",
1210 " color_packet 0 get 0.299 mul",
1211 " color_packet 1 get 0.587 mul add",
1212 " color_packet 2 get 0.114 mul add",
1214 " /gray_packet exch def",
1215 " compression 0 eq",
1217 " /number_pixels 1 def",
1220 " currentfile byte readhexstring pop 0 get",
1221 " /number_pixels exch 1 add def",
1223 " 0 1 number_pixels 1 sub",
1225 " pixels exch gray_packet put",
1227 " pixels 0 number_pixels getinterval",
1230 "/PseudoClassPacket",
1233 " % Get a PseudoClass packet.",
1236 " % index: index into the colormap.",
1237 " % length: number of pixels minus one of this color (optional).",
1239 " currentfile byte readhexstring pop 0 get",
1240 " /offset exch 3 mul def",
1241 " /color_packet colormap offset 3 getinterval def",
1242 " compression 0 eq",
1244 " /number_pixels 3 def",
1247 " currentfile byte readhexstring pop 0 get",
1248 " /number_pixels exch 1 add 3 mul def",
1250 " 0 3 number_pixels 1 sub",
1252 " pixels exch color_packet putinterval",
1254 " pixels 0 number_pixels getinterval",
1257 "/PseudoClassImage",
1260 " % Display a PseudoClass image.",
1263 " % class: 0-PseudoClass or 1-Grayscale.",
1265 " currentfile buffer readline pop",
1266 " token pop /class exch def pop",
1269 " currentfile buffer readline pop",
1270 " token pop /depth exch def pop",
1271 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1272 " columns rows depth",
1277 " { currentfile grays readhexstring pop } image",
1282 " % colors: number of colors in the colormap.",
1283 " % colormap: red, green, blue color packets.",
1285 " currentfile buffer readline pop",
1286 " token pop /colors exch def pop",
1287 " /colors colors 3 mul def",
1288 " /colormap colors string def",
1289 " currentfile colormap readhexstring pop pop",
1290 " systemdict /colorimage known",
1297 " { PseudoClassPacket } false 3 colorimage",
1301 " % No colorimage operator; convert to grayscale.",
1308 " { GrayPseudoClassPacket } image",
1316 " % Display a DirectClass or PseudoClass image.",
1319 " % x & y translation.",
1321 " % label pointsize.",
1323 " % image columns & rows.",
1324 " % class: 0-DirectClass or 1-PseudoClass.",
1325 " % compression: 0-none or 1-RunlengthEncoded.",
1326 " % hex color packets.",
1329 " /buffer 512 string def",
1330 " /byte 1 string def",
1331 " /color_packet 3 string def",
1332 " /pixels 768 string def",
1334 " currentfile buffer readline pop",
1335 " token pop /x exch def",
1336 " token pop /y exch def pop",
1338 " currentfile buffer readline pop",
1339 " token pop /x exch def",
1340 " token pop /y exch def pop",
1341 " currentfile buffer readline pop",
1342 " token pop /pointsize exch def pop",
1343 " /Times-Roman findfont pointsize scalefont setfont",
1346 *PostscriptEpilog[]=
1349 " currentfile buffer readline pop",
1350 " token pop /columns exch def",
1351 " token pop /rows exch def pop",
1352 " currentfile buffer readline pop",
1353 " token pop /class exch def pop",
1354 " currentfile buffer readline pop",
1355 " token pop /compression exch def pop",
1356 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1362 buffer[MaxTextExtent],
1363 date[MaxTextExtent],
1365 page_geometry[MaxTextExtent];
1405 register const Quantum
1412 register unsigned char
1436 Open output image file.
1438 assert(image_info != (const ImageInfo *) NULL);
1439 assert(image_info->signature == MagickSignature);
1440 assert(image != (Image *) NULL);
1441 assert(image->signature == MagickSignature);
1442 if (image->debug != MagickFalse)
1443 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1444 assert(exception != (ExceptionInfo *) NULL);
1445 assert(exception->signature == MagickSignature);
1446 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1447 if (status == MagickFalse)
1449 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1455 Scale relative to dots-per-inch.
1457 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1458 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1459 delta.x=DefaultResolution;
1460 delta.y=DefaultResolution;
1461 resolution.x=image->resolution.x;
1462 resolution.y=image->resolution.y;
1463 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1465 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1466 resolution.x=geometry_info.rho;
1467 resolution.y=geometry_info.sigma;
1468 if ((flags & SigmaValue) == 0)
1469 resolution.y=resolution.x;
1471 if (image_info->density != (char *) NULL)
1473 flags=ParseGeometry(image_info->density,&geometry_info);
1474 resolution.x=geometry_info.rho;
1475 resolution.y=geometry_info.sigma;
1476 if ((flags & SigmaValue) == 0)
1477 resolution.y=resolution.x;
1479 if (image->units == PixelsPerCentimeterResolution)
1481 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1482 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1484 SetGeometry(image,&geometry);
1485 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1486 (double) image->columns,(double) image->rows);
1487 if (image_info->page != (char *) NULL)
1488 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1490 if ((image->page.width != 0) && (image->page.height != 0))
1491 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1492 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1493 image->page.height,(double) image->page.x,(double) image->page.y);
1495 if ((image->gravity != UndefinedGravity) &&
1496 (LocaleCompare(image_info->magick,"PS") == 0))
1497 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1498 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1499 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1500 &geometry.width,&geometry.height);
1501 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1502 geometry.width=(size_t) floor(scale.x+0.5);
1503 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1504 geometry.height=(size_t) floor(scale.y+0.5);
1505 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1506 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1507 if (image->gravity != UndefinedGravity)
1509 geometry.x=(-page_info.x);
1510 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1513 if (image_info->pointsize != 0.0)
1514 pointsize=image_info->pointsize;
1516 value=GetImageProperty(image,"label",exception);
1517 if (value != (const char *) NULL)
1518 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1522 Output Postscript header.
1524 if (LocaleCompare(image_info->magick,"PS") == 0)
1525 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1527 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1529 (void) WriteBlobString(image,buffer);
1530 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1531 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1533 (void) WriteBlobString(image,buffer);
1534 timer=time((time_t *) NULL);
1535 (void) FormatMagickTime(timer,MaxTextExtent,date);
1536 (void) FormatLocaleString(buffer,MaxTextExtent,
1537 "%%%%CreationDate: (%s)\n",date);
1538 (void) WriteBlobString(image,buffer);
1539 bounds.x1=(double) geometry.x;
1540 bounds.y1=(double) geometry.y;
1541 bounds.x2=(double) geometry.x+scale.x;
1542 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1543 if ((image_info->adjoin != MagickFalse) &&
1544 (GetNextImageInList(image) != (Image *) NULL))
1545 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1549 (void) FormatLocaleString(buffer,MaxTextExtent,
1550 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1551 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1552 (void) WriteBlobString(image,buffer);
1553 (void) FormatLocaleString(buffer,MaxTextExtent,
1554 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1555 bounds.y1,bounds.x2,bounds.y2);
1557 (void) WriteBlobString(image,buffer);
1558 profile=GetImageProfile(image,"8bim");
1559 if (profile != (StringInfo *) NULL)
1562 Embed Photoshop profile.
1564 (void) FormatLocaleString(buffer,MaxTextExtent,
1565 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1566 (void) WriteBlobString(image,buffer);
1567 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1570 (void) WriteBlobString(image,"\n% ");
1571 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1572 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1573 (void) WriteBlobString(image,buffer);
1575 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1577 profile=GetImageProfile(image,"xmp");
1578 if (0 && (profile != (StringInfo *) NULL))
1583 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1584 (void) FormatLocaleString(buffer,MaxTextExtent,
1585 "\n%%begin_xml_packet: %.20g\n",(double)
1586 GetStringInfoLength(profile));
1587 (void) WriteBlobString(image,buffer);
1588 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1589 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1590 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1592 value=GetImageProperty(image,"label",exception);
1593 if (value != (const char *) NULL)
1594 (void) WriteBlobString(image,
1595 "%%DocumentNeededResources: font Times-Roman\n");
1596 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1597 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1598 if (LocaleCompare(image_info->magick,"PS") != 0)
1599 (void) WriteBlobString(image,"%%Pages: 1\n");
1603 Compute the number of pages.
1605 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1606 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1607 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1608 image_info->adjoin != MagickFalse ? (double)
1609 GetImageListLength(image) : 1.0);
1610 (void) WriteBlobString(image,buffer);
1612 (void) WriteBlobString(image,"%%EndComments\n");
1613 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1614 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1615 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1616 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1617 (LocaleCompare(image_info->magick,"EPT") == 0))
1632 Create preview image.
1634 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1635 if (preview_image == (Image *) NULL)
1636 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1638 Dump image as bitmap.
1640 (void) FormatLocaleString(buffer,MaxTextExtent,
1641 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1642 preview_image->columns,(double) preview_image->rows,1.0,
1643 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1645 (void) WriteBlobString(image,buffer);
1647 for (y=0; y < (ssize_t) image->rows; y++)
1649 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1651 if (p == (const Quantum *) NULL)
1655 for (x=0; x < (ssize_t) preview_image->columns; x++)
1658 pixel=ClampToQuantum(GetPixelLuma(preview_image,p));
1659 if (pixel >= (Quantum) (QuantumRange/2))
1664 q=PopHexPixel(hex_digits,byte,q);
1665 if ((q-pixels+8) >= 80)
1668 (void) WriteBlob(image,q-pixels,pixels);
1670 (void) WriteBlobString(image,"% ");
1679 q=PopHexPixel(hex_digits,byte,q);
1680 if ((q-pixels+8) >= 80)
1683 (void) WriteBlob(image,q-pixels,pixels);
1685 (void) WriteBlobString(image,"% ");
1692 (void) WriteBlob(image,q-pixels,pixels);
1694 (void) WriteBlobString(image,"\n%%EndPreview\n");
1695 preview_image=DestroyImage(preview_image);
1698 Output Postscript commands.
1700 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1702 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1703 (void) WriteBlobString(image,buffer);
1705 value=GetImageProperty(image,"label",exception);
1706 if (value != (const char *) NULL)
1707 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1709 (void) WriteBlobString(image," /label 512 string def\n");
1710 (void) WriteBlobString(image," currentfile label readline pop\n");
1711 (void) FormatLocaleString(buffer,MaxTextExtent,
1712 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1713 (void) WriteBlobString(image,buffer);
1715 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1717 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1718 (void) WriteBlobString(image,buffer);
1720 if (LocaleCompare(image_info->magick,"PS") == 0)
1721 (void) WriteBlobString(image," showpage\n");
1722 (void) WriteBlobString(image,"} bind def\n");
1723 (void) WriteBlobString(image,"%%EndProlog\n");
1725 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1727 (void) WriteBlobString(image,buffer);
1728 (void) FormatLocaleString(buffer,MaxTextExtent,
1729 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1730 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1731 (geometry.height+text_size));
1732 (void) WriteBlobString(image,buffer);
1733 if ((double) geometry.x < bounds.x1)
1734 bounds.x1=(double) geometry.x;
1735 if ((double) geometry.y < bounds.y1)
1736 bounds.y1=(double) geometry.y;
1737 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1738 bounds.x2=(double) geometry.x+geometry.width-1;
1739 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1740 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1741 value=GetImageProperty(image,"label",exception);
1742 if (value != (const char *) NULL)
1743 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1744 if (LocaleCompare(image_info->magick,"PS") != 0)
1745 (void) WriteBlobString(image,"userdict begin\n");
1746 (void) WriteBlobString(image,"DisplayImage\n");
1750 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1751 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1752 (void) WriteBlobString(image,buffer);
1753 labels=(char **) NULL;
1754 value=GetImageProperty(image,"label",exception);
1755 if (value != (const char *) NULL)
1756 labels=StringToList(value);
1757 if (labels != (char **) NULL)
1759 for (i=0; labels[i] != (char *) NULL; i++)
1761 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1763 (void) WriteBlobString(image,buffer);
1764 labels[i]=DestroyString(labels[i]);
1766 labels=(char **) RelinquishMagickMemory(labels);
1768 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1769 pixel.alpha=(MagickRealType) TransparentAlpha;
1772 if ((image_info->type != TrueColorType) &&
1773 (IsImageGray(image,exception) != MagickFalse))
1775 if (IsImageMonochrome(image,exception) == MagickFalse)
1781 Dump image as grayscale.
1783 (void) FormatLocaleString(buffer,MaxTextExtent,
1784 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1786 (void) WriteBlobString(image,buffer);
1788 for (y=0; y < (ssize_t) image->rows; y++)
1790 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1791 if (p == (const Quantum *) NULL)
1793 for (x=0; x < (ssize_t) image->columns; x++)
1795 pixel=(Quantum) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
1797 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1799 if ((q-pixels+8) >= 80)
1802 (void) WriteBlob(image,q-pixels,pixels);
1805 p+=GetPixelChannels(image);
1807 if (image->previous == (Image *) NULL)
1809 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1811 if (status == MagickFalse)
1818 (void) WriteBlob(image,q-pixels,pixels);
1830 Dump image as bitmap.
1832 (void) FormatLocaleString(buffer,MaxTextExtent,
1833 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1835 (void) WriteBlobString(image,buffer);
1837 for (y=0; y < (ssize_t) image->rows; y++)
1839 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1840 if (p == (const Quantum *) NULL)
1844 for (x=0; x < (ssize_t) image->columns; x++)
1847 pixel=ClampToQuantum(GetPixelLuma(image,p));
1848 if (pixel >= (Quantum) (QuantumRange/2))
1853 q=PopHexPixel(hex_digits,byte,q);
1854 if ((q-pixels+2) >= 80)
1857 (void) WriteBlob(image,q-pixels,pixels);
1863 p+=GetPixelChannels(image);
1868 q=PopHexPixel(hex_digits,byte,q);
1869 if ((q-pixels+2) >= 80)
1872 (void) WriteBlob(image,q-pixels,pixels);
1876 if (image->previous == (Image *) NULL)
1878 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1880 if (status == MagickFalse)
1887 (void) WriteBlob(image,q-pixels,pixels);
1892 if ((image->storage_class == DirectClass) ||
1893 (image->colors > 256) || (image->alpha_trait == BlendPixelTrait))
1896 Dump DirectClass image.
1898 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1899 (double) image->columns,(double) image->rows,
1900 image_info->compression == RLECompression ? 1 : 0);
1901 (void) WriteBlobString(image,buffer);
1902 switch (image_info->compression)
1904 case RLECompression:
1907 Dump runlength-encoded DirectColor packets.
1910 for (y=0; y < (ssize_t) image->rows; y++)
1912 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1913 if (p == (const Quantum *) NULL)
1915 GetPixelInfoPixel(image,p,&pixel);
1917 for (x=0; x < (ssize_t) image->columns; x++)
1919 if ((GetPixelRed(image,p) == ClampToQuantum(pixel.red)) &&
1920 (GetPixelGreen(image,p) == ClampToQuantum(pixel.green)) &&
1921 (GetPixelBlue(image,p) == ClampToQuantum(pixel.blue)) &&
1922 (GetPixelAlpha(image,p) == ClampToQuantum(pixel.alpha)) &&
1923 (length < 255) && (x < (ssize_t) (image->columns-1)))
1929 WriteRunlengthPacket(image,pixel,length,p);
1930 if ((q-pixels+10) >= 80)
1933 (void) WriteBlob(image,q-pixels,pixels);
1939 GetPixelInfoPixel(image,p,&pixel);
1940 p+=GetPixelChannels(image);
1942 WriteRunlengthPacket(image,pixel,length,p);
1943 if ((q-pixels+10) >= 80)
1946 (void) WriteBlob(image,q-pixels,pixels);
1949 if (image->previous == (Image *) NULL)
1951 status=SetImageProgress(image,SaveImageTag,
1952 (MagickOffsetType) y,image->rows);
1953 if (status == MagickFalse)
1960 (void) WriteBlob(image,q-pixels,pixels);
1968 Dump uncompressed DirectColor packets.
1971 for (y=0; y < (ssize_t) image->rows; y++)
1973 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1974 if (p == (const Quantum *) NULL)
1976 for (x=0; x < (ssize_t) image->columns; x++)
1978 if ((image->alpha_trait == BlendPixelTrait) &&
1979 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1981 q=PopHexPixel(hex_digits,0xff,q);
1982 q=PopHexPixel(hex_digits,0xff,q);
1983 q=PopHexPixel(hex_digits,0xff,q);
1987 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1988 GetPixelRed(image,p)),q);
1989 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1990 GetPixelGreen(image,p)),q);
1991 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1992 GetPixelBlue(image,p)),q);
1994 if ((q-pixels+6) >= 80)
1997 (void) WriteBlob(image,q-pixels,pixels);
2000 p+=GetPixelChannels(image);
2002 if (image->previous == (Image *) NULL)
2004 status=SetImageProgress(image,SaveImageTag,
2005 (MagickOffsetType) y,image->rows);
2006 if (status == MagickFalse)
2013 (void) WriteBlob(image,q-pixels,pixels);
2018 (void) WriteBlobByte(image,'\n');
2023 Dump PseudoClass image.
2025 (void) FormatLocaleString(buffer,MaxTextExtent,
2026 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2027 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2028 image_info->compression == RLECompression ? 1 : 0);
2029 (void) WriteBlobString(image,buffer);
2031 Dump number of colors and colormap.
2033 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2035 (void) WriteBlobString(image,buffer);
2036 for (i=0; i < (ssize_t) image->colors; i++)
2038 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2039 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)),
2040 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)),
2041 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue)));
2042 (void) WriteBlobString(image,buffer);
2044 switch (image_info->compression)
2046 case RLECompression:
2049 Dump runlength-encoded PseudoColor packets.
2052 for (y=0; y < (ssize_t) image->rows; y++)
2054 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2055 if (p == (const Quantum *) NULL)
2057 index=GetPixelIndex(image,p);
2059 for (x=0; x < (ssize_t) image->columns; x++)
2061 if ((index == GetPixelIndex(image,p)) &&
2062 (length < 255) && (x < ((ssize_t) image->columns-1)))
2068 q=PopHexPixel(hex_digits,(size_t) index,q);
2069 q=PopHexPixel(hex_digits,(size_t)
2070 MagickMin(length,0xff),q);
2072 if ((q-pixels+6) >= 80)
2075 (void) WriteBlob(image,q-pixels,pixels);
2081 index=GetPixelIndex(image,p);
2082 pixel.red=(MagickRealType) GetPixelRed(image,p);
2083 pixel.green=(MagickRealType) GetPixelGreen(image,p);
2084 pixel.blue=(MagickRealType) GetPixelBlue(image,p);
2085 pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
2086 p+=GetPixelChannels(image);
2088 q=PopHexPixel(hex_digits,(size_t) index,q);
2089 q=PopHexPixel(hex_digits,(size_t)
2090 MagickMin(length,0xff),q);
2091 if (image->previous == (Image *) NULL)
2093 status=SetImageProgress(image,SaveImageTag,
2094 (MagickOffsetType) y,image->rows);
2095 if (status == MagickFalse)
2102 (void) WriteBlob(image,q-pixels,pixels);
2110 Dump uncompressed PseudoColor packets.
2113 for (y=0; y < (ssize_t) image->rows; y++)
2115 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2116 if (p == (const Quantum *) NULL)
2118 for (x=0; x < (ssize_t) image->columns; x++)
2120 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2121 if ((q-pixels+4) >= 80)
2124 (void) WriteBlob(image,q-pixels,pixels);
2127 p+=GetPixelChannels(image);
2129 if (image->previous == (Image *) NULL)
2131 status=SetImageProgress(image,SaveImageTag,
2132 (MagickOffsetType) y,image->rows);
2133 if (status == MagickFalse)
2140 (void) WriteBlob(image,q-pixels,pixels);
2145 (void) WriteBlobByte(image,'\n');
2147 if (LocaleCompare(image_info->magick,"PS") != 0)
2148 (void) WriteBlobString(image,"end\n");
2149 (void) WriteBlobString(image,"%%PageTrailer\n");
2150 if (GetNextImageInList(image) == (Image *) NULL)
2152 image=SyncNextImageInList(image);
2153 status=SetImageProgress(image,SaveImagesTag,scene++,
2154 GetImageListLength(image));
2155 if (status == MagickFalse)
2157 } while (image_info->adjoin != MagickFalse);
2158 (void) WriteBlobString(image,"%%Trailer\n");
2161 (void) FormatLocaleString(buffer,MaxTextExtent,
2162 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2163 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5));
2164 (void) WriteBlobString(image,buffer);
2165 (void) FormatLocaleString(buffer,MaxTextExtent,
2166 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2168 (void) WriteBlobString(image,buffer);
2170 (void) WriteBlobString(image,"%%EOF\n");
2171 (void) CloseBlob(image);