2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2016 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/nt-base-private.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/profile.h"
69 #include "MagickCore/resource_.h"
70 #include "MagickCore/pixel-accessor.h"
71 #include "MagickCore/property.h"
72 #include "MagickCore/quantum-private.h"
73 #include "MagickCore/static.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/module.h"
76 #include "MagickCore/token.h"
77 #include "MagickCore/transform.h"
78 #include "MagickCore/utility.h"
83 static MagickBooleanType
84 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *);
87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % I n v o k e P o s t s r i p t D e l e g a t e %
95 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 % InvokePostscriptDelegate() executes the Postscript interpreter with the
100 % The format of the InvokePostscriptDelegate method is:
102 % MagickBooleanType InvokePostscriptDelegate(
103 % const MagickBooleanType verbose,const char *command,
104 % ExceptionInfo *exception)
106 % A description of each parameter follows:
108 % o verbose: A value other than zero displays the command prior to
111 % o command: the address of a character string containing the command to
114 % o exception: return any errors or warnings in this structure.
117 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
118 static int MagickDLLCall PostscriptDelegateMessage(void *handle,
119 const char *message,int length)
128 messages=(char **) handle;
129 if (*messages == (char *) NULL)
130 *messages=(char *) AcquireQuantumMemory(length+1,sizeof(char *));
133 offset=strlen(*messages);
134 *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1,
137 (void) memcpy(*messages+offset,message,length);
138 (*messages)[length+offset] ='\0';
143 static MagickBooleanType InvokePostscriptDelegate(
144 const MagickBooleanType verbose,const char *command,char *message,
145 ExceptionInfo *exception)
150 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
151 #define SetArgsStart(command,args_start) \
152 if (args_start == (const char *) NULL) \
154 if (*command != '"') \
155 args_start=strchr(command,' '); \
158 args_start=strchr(command+1,'"'); \
159 if (args_start != (const char *) NULL) \
164 #define ExecuteGhostscriptCommand(command,status) \
166 status=ExternalDelegateCommand(MagickFalse,verbose,command,message, \
169 return(MagickTrue); \
171 return(MagickFalse); \
172 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \
173 "FailedToExecuteCommand","`%s' (%d)",command,status); \
174 return(MagickFalse); \
182 *args_start = (const char *) NULL;
200 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
201 ghost_info=NTGhostscriptDLLVectors();
206 ghost_info=(&ghost_info_struct);
207 (void) ResetMagickMemory(&ghost_info_struct,0,sizeof(ghost_info_struct));
208 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
209 gsapi_delete_instance;
210 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
211 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
213 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
214 gsapi_init_with_args;
215 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
216 int *)) gsapi_run_string;
217 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int(*)(void *,char *,
218 int),int(*)(void *,const char *,int),int(*)(void *, const char *, int)))
220 ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision;
222 if (ghost_info == (GhostInfo *) NULL)
223 ExecuteGhostscriptCommand(command,status);
224 if ((ghost_info->revision)(&revision,sizeof(revision)) != 0)
226 if (verbose != MagickFalse)
228 (void) fprintf(stdout,"[ghostscript library %.2f]",(double)
229 revision.revision/100.0);
230 SetArgsStart(command,args_start);
231 (void) fputs(args_start,stdout);
233 errors=(char *) NULL;
234 status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
236 ExecuteGhostscriptCommand(command,status);
238 argv=StringToArgv(command,&argc);
239 if (argv == (char **) NULL)
241 (ghost_info->delete_instance)(interpreter);
244 (void) (ghost_info->set_stdio)(interpreter,(int(MagickDLLCall *)(void *,
245 char *,int)) NULL,PostscriptDelegateMessage,PostscriptDelegateMessage);
246 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
248 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
250 (ghost_info->exit)(interpreter);
251 (ghost_info->delete_instance)(interpreter);
252 for (i=0; i < (ssize_t) argc; i++)
253 argv[i]=DestroyString(argv[i]);
254 argv=(char **) RelinquishMagickMemory(argv);
257 SetArgsStart(command,args_start);
258 if (status == -101) /* quit */
259 (void) FormatLocaleString(message,MagickPathExtent,
260 "[ghostscript library %.2f]%s: %s",(double)revision.revision / 100,
264 (void) ThrowMagickException(exception,GetMagickModule(),
265 DelegateError,"PostscriptDelegateFailed",
266 "`[ghostscript library %.2f]%s': %s",
267 (double)revision.revision / 100,args_start,errors);
268 if (errors != (char *) NULL)
269 errors=DestroyString(errors);
270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
271 "Ghostscript returns status %d, exit code %d",status,code);
275 if (errors != (char *) NULL)
276 errors=DestroyString(errors);
279 status=ExternalDelegateCommand(MagickFalse,verbose,command,message,exception);
280 return(status == 0 ? MagickTrue : MagickFalse);
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295 % IsPS() returns MagickTrue if the image format type, identified by the
296 % magick string, is PS.
298 % The format of the IsPS method is:
300 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
302 % A description of each parameter follows:
304 % o magick: compare image format pattern against these bytes.
306 % o length: Specifies the length of the magick string.
309 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
313 if (memcmp(magick,"%!",2) == 0)
315 if (memcmp(magick,"\004%!",3) == 0)
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 % R e a d P S I m a g e %
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 % ReadPSImage() reads a Postscript image file and returns it. It allocates
332 % the memory necessary for the new Image structure and returns a pointer
335 % The format of the ReadPSImage method is:
337 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
339 % A description of each parameter follows:
341 % o image_info: the image info.
343 % o exception: return any errors or warnings in this structure.
347 static MagickBooleanType IsPostscriptRendered(const char *path)
355 if ((path == (const char *) NULL) || (*path == '\0'))
357 status=GetPathAttributes(path,&attributes);
358 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
359 (attributes.st_size > 0))
364 static inline int ProfileInteger(Image *image,short int *hex_digits)
378 c=ReadBlobByte(image);
379 if ((c == EOF) || ((c == '%') && (l == '%')))
386 if (isxdigit(c) == MagickFalse)
388 value=(int) ((size_t) value << 4)+hex_digits[c];
394 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
396 #define BoundingBox "BoundingBox:"
397 #define BeginDocument "BeginDocument:"
398 #define BeginXMPPacket "<?xpacket begin="
399 #define EndXMPPacket "<?xpacket end="
400 #define ICCProfile "BeginICCProfile:"
401 #define CMYKCustomColor "CMYKCustomColor:"
402 #define CMYKProcessColor "CMYKProcessColor:"
403 #define DocumentMedia "DocumentMedia:"
404 #define DocumentCustomColors "DocumentCustomColors:"
405 #define DocumentProcessColors "DocumentProcessColors:"
406 #define EndDocument "EndDocument:"
407 #define HiResBoundingBox "HiResBoundingBox:"
408 #define ImageData "ImageData:"
409 #define PageBoundingBox "PageBoundingBox:"
410 #define LanguageLevel "LanguageLevel:"
411 #define PageMedia "PageMedia:"
412 #define Pages "Pages:"
413 #define PhotoshopProfile "BeginPhotoshop:"
414 #define PostscriptLevel "!PS-"
415 #define RenderPostscriptText " Rendering Postscript... "
416 #define SpotColor "+ "
419 command[MagickPathExtent],
421 filename[MagickPathExtent],
422 geometry[MagickPathExtent],
423 input_filename[MagickPathExtent],
424 message[MagickPathExtent],
426 postscript_filename[MagickPathExtent];
500 assert(image_info != (const ImageInfo *) NULL);
501 assert(image_info->signature == MagickCoreSignature);
502 if (image_info->debug != MagickFalse)
503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
504 image_info->filename);
505 assert(exception != (ExceptionInfo *) NULL);
506 assert(exception->signature == MagickCoreSignature);
507 image=AcquireImage(image_info,exception);
508 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
509 if (status == MagickFalse)
511 image=DestroyImageList(image);
512 return((Image *) NULL);
514 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
515 if (status == MagickFalse)
517 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
518 image_info->filename);
519 image=DestroyImageList(image);
520 return((Image *) NULL);
523 Initialize hex values.
525 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
526 hex_digits[(int) '0']=0;
527 hex_digits[(int) '1']=1;
528 hex_digits[(int) '2']=2;
529 hex_digits[(int) '3']=3;
530 hex_digits[(int) '4']=4;
531 hex_digits[(int) '5']=5;
532 hex_digits[(int) '6']=6;
533 hex_digits[(int) '7']=7;
534 hex_digits[(int) '8']=8;
535 hex_digits[(int) '9']=9;
536 hex_digits[(int) 'a']=10;
537 hex_digits[(int) 'b']=11;
538 hex_digits[(int) 'c']=12;
539 hex_digits[(int) 'd']=13;
540 hex_digits[(int) 'e']=14;
541 hex_digits[(int) 'f']=15;
542 hex_digits[(int) 'A']=10;
543 hex_digits[(int) 'B']=11;
544 hex_digits[(int) 'C']=12;
545 hex_digits[(int) 'D']=13;
546 hex_digits[(int) 'E']=14;
547 hex_digits[(int) 'F']=15;
549 Set the page density.
551 delta.x=DefaultResolution;
552 delta.y=DefaultResolution;
553 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
555 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
556 image->resolution.x=geometry_info.rho;
557 image->resolution.y=geometry_info.sigma;
558 if ((flags & SigmaValue) == 0)
559 image->resolution.y=image->resolution.x;
561 if (image_info->density != (char *) NULL)
563 flags=ParseGeometry(image_info->density,&geometry_info);
564 image->resolution.x=geometry_info.rho;
565 image->resolution.y=geometry_info.sigma;
566 if ((flags & SigmaValue) == 0)
567 image->resolution.y=image->resolution.x;
569 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
570 if (image_info->page != (char *) NULL)
571 (void) ParseAbsoluteGeometry(image_info->page,&page);
572 resolution=image->resolution;
573 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5);
574 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5);
576 Determine page geometry from the Postscript bounding box.
578 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
579 (void) ResetMagickMemory(command,0,sizeof(command));
580 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
581 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
592 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
595 Note document structuring comments.
598 if ((strchr("\n\r%",c) == (char *) NULL) &&
599 ((size_t) (p-command) < (MagickPathExtent-1)))
604 Skip %%BeginDocument thru %%EndDocument.
606 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
608 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
610 if (skip != MagickFalse)
612 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
614 (void) SetImageProperty(image,"ps:Level",command+4,exception);
615 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
618 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
619 (void) sscanf(command,LanguageLevel " %lu",&language_level);
620 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
621 (void) sscanf(command,Pages " %lu",&pages);
622 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
623 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
624 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
632 profile=AcquireStringInfo(65536);
633 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
635 SetStringInfoLength(profile,(size_t) i+1);
636 datum=GetStringInfoDatum(profile);
637 datum[i]=(unsigned char) c;
639 (void) SetImageProfile(image,"icc",profile,exception);
640 profile=DestroyStringInfo(profile);
643 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
649 Read Photoshop profile.
651 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
655 profile=BlobToStringInfo((const void *) NULL,length);
656 if (profile != (StringInfo *) NULL)
658 q=GetStringInfoDatum(profile);
659 for (i=0; i < (ssize_t) length; i++)
660 *q++=(unsigned char) ProfileInteger(image,hex_digits);
661 (void) SetImageProfile(image,"8bim",profile,exception);
662 profile=DestroyStringInfo(profile);
666 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
672 profile=StringToStringInfo(command);
673 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
675 SetStringInfoLength(profile,i+1);
676 c=ReadBlobByte(image);
677 GetStringInfoDatum(profile)[i]=(unsigned char) c;
679 if ((strchr("\n\r%",c) == (char *) NULL) &&
680 ((size_t) (p-command) < (MagickPathExtent-1)))
684 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
687 SetStringInfoLength(profile,i);
688 (void) SetImageProfile(image,"xmp",profile,exception);
689 profile=DestroyStringInfo(profile);
693 Is this a CMYK document?
695 length=strlen(DocumentProcessColors);
696 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
698 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
699 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
700 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
703 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
705 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
707 length=strlen(DocumentCustomColors);
708 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
709 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
710 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
713 property[MagickPathExtent],
722 (void) FormatLocaleString(property,MagickPathExtent,"ps:SpotColor-%.20g",
723 (double) (spotcolor++));
724 for (q=command; *q != '\0'; q++)
725 if (isspace((int) (unsigned char) *q) != 0)
727 value=AcquireString(q);
728 (void) SubstituteString(&value,"(","");
729 (void) SubstituteString(&value,")","");
730 (void) StripString(value);
731 (void) SetImageProperty(image,property,value,exception);
732 value=DestroyString(value);
735 if (image_info->page != (char *) NULL)
738 Note region defined by bounding box.
742 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
744 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
745 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
748 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
750 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
751 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
754 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
756 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
757 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
760 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
762 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
763 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
766 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
768 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
769 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
772 if ((count != 4) || (i < (ssize_t) priority))
774 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
775 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
776 if (i == (ssize_t) priority)
781 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
782 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
785 Set Postscript render geometry.
787 (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g",
788 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
789 hires_bounds.x1,hires_bounds.y1);
790 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
791 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
792 resolution.x/delta.x)-0.5);
793 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
794 resolution.y/delta.y)-0.5);
797 option=GetImageOption(image_info,"eps:fit-page");
798 if (option != (char *) NULL)
803 page_geometry=GetPageGeometry(option);
804 flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width,
806 if (flags == NoValue)
808 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
809 "InvalidGeometry","`%s'",option);
810 image=DestroyImage(image);
811 return((Image *) NULL);
813 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)
815 page.height=(size_t) ceil((double) (page.height*image->resolution.y/
817 page_geometry=DestroyString(page_geometry);
820 (void) CloseBlob(image);
821 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
824 Create Ghostscript control file.
826 file=AcquireUniqueFileResource(postscript_filename);
829 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
830 image_info->filename);
831 image=DestroyImageList(image);
832 return((Image *) NULL);
834 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
835 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
836 "<</UseCIEColor true>>setpagedevice\n",MagickPathExtent);
837 count=write(file,command,(unsigned int) strlen(command));
838 if (image_info->page == (char *) NULL)
841 translate_geometry[MagickPathExtent];
843 (void) FormatLocaleString(translate_geometry,MagickPathExtent,
844 "%g %g translate\n",-bounds.x1,-bounds.y1);
845 count=write(file,translate_geometry,(unsigned int)
846 strlen(translate_geometry));
850 Render Postscript with the Ghostscript delegate.
852 if (image_info->monochrome != MagickFalse)
853 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
855 if (cmyk != MagickFalse)
856 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
858 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
859 if (delegate_info == (const DelegateInfo *) NULL)
861 (void) RelinquishUniqueFileResource(postscript_filename);
862 image=DestroyImageList(image);
863 return((Image *) NULL);
865 density=AcquireString("");
866 options=AcquireString("");
867 (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",resolution.x,
869 (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double)
870 page.width,(double) page.height);
871 read_info=CloneImageInfo(image_info);
872 *read_info->magick='\0';
873 if (read_info->number_scenes != 0)
876 pages[MagickPathExtent];
878 (void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g "
879 "-dLastPage=%.20g ",(double) read_info->scene+1,(double)
880 (read_info->scene+read_info->number_scenes));
881 (void) ConcatenateMagickString(options,pages,MagickPathExtent);
882 read_info->number_scenes=0;
883 if (read_info->scenes != (char *) NULL)
884 *read_info->scenes='\0';
886 if (*image_info->magick == 'E')
888 option=GetImageOption(image_info,"eps:use-cropbox");
889 if ((option == (const char *) NULL) ||
890 (IsStringTrue(option) != MagickFalse))
891 (void) ConcatenateMagickString(options,"-dEPSCrop ",MagickPathExtent);
892 if (fitPage != MagickFalse)
893 (void) ConcatenateMagickString(options,"-dEPSFitPage ",MagickPathExtent);
895 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
896 (void) AcquireUniqueFilename(filename);
897 (void) RelinquishUniqueFileResource(filename);
898 (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
899 (void) FormatLocaleString(command,MagickPathExtent,
900 GetDelegateCommands(delegate_info),
901 read_info->antialias != MagickFalse ? 4 : 1,
902 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
903 postscript_filename,input_filename);
904 options=DestroyString(options);
905 density=DestroyString(density);
907 status=InvokePostscriptDelegate(read_info->verbose,command,message,exception);
908 (void) InterpretImageFilename(image_info,image,filename,1,
909 read_info->filename,exception);
910 if ((status == MagickFalse) ||
911 (IsPostscriptRendered(read_info->filename) == MagickFalse))
913 (void) ConcatenateMagickString(command," -c showpage",MagickPathExtent);
914 status=InvokePostscriptDelegate(read_info->verbose,command,message,
917 (void) RelinquishUniqueFileResource(postscript_filename);
918 (void) RelinquishUniqueFileResource(input_filename);
919 postscript_image=(Image *) NULL;
920 if (status == MagickFalse)
923 (void) InterpretImageFilename(image_info,image,filename,(int) i,
924 read_info->filename,exception);
925 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
927 (void) RelinquishUniqueFileResource(read_info->filename);
932 (void) InterpretImageFilename(image_info,image,filename,(int) i,
933 read_info->filename,exception);
934 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
936 read_info->blob=NULL;
938 next=ReadImage(read_info,exception);
939 (void) RelinquishUniqueFileResource(read_info->filename);
940 if (next == (Image *) NULL)
942 AppendImageToList(&postscript_image,next);
944 (void) RelinquishUniqueFileResource(read_info->filename);
945 read_info=DestroyImageInfo(read_info);
946 if (postscript_image == (Image *) NULL)
948 if (*message != '\0')
949 (void) ThrowMagickException(exception,GetMagickModule(),
950 DelegateError,"PostscriptDelegateFailed","`%s'",message);
951 image=DestroyImageList(image);
952 return((Image *) NULL);
954 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
959 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
960 if (cmyk_image != (Image *) NULL)
962 postscript_image=DestroyImageList(postscript_image);
963 postscript_image=cmyk_image;
966 if (image_info->number_scenes != 0)
972 Add place holder images to meet the subimage specification requirement.
974 for (i=0; i < (ssize_t) image_info->scene; i++)
976 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
977 if (clone_image != (Image *) NULL)
978 PrependImageToList(&postscript_image,clone_image);
983 (void) CopyMagickString(postscript_image->filename,filename,
985 (void) CopyMagickString(postscript_image->magick,image->magick,
988 postscript_image->magick_columns=columns;
990 postscript_image->magick_rows=rows;
991 postscript_image->page=page;
992 (void) CloneImageProfiles(postscript_image,image);
993 (void) CloneImageProperties(postscript_image,image);
994 next=SyncNextImageInList(postscript_image);
995 if (next != (Image *) NULL)
996 postscript_image=next;
997 } while (next != (Image *) NULL);
998 image=DestroyImageList(image);
1000 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
1002 next->scene=scene++;
1003 next=GetNextImageInList(next);
1005 return(GetFirstImageInList(postscript_image));
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1013 % R e g i s t e r P S I m a g e %
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1019 % RegisterPSImage() adds properties for the PS image format to
1020 % the list of supported formats. The properties include the image format
1021 % tag, a method to read and/or write the format, whether the format
1022 % supports the saving of more than one frame to the same file or blob,
1023 % whether the format supports native in-memory I/O, and a brief
1024 % description of the format.
1026 % The format of the RegisterPSImage method is:
1028 % size_t RegisterPSImage(void)
1031 ModuleExport size_t RegisterPSImage(void)
1036 entry=AcquireMagickInfo("PS","EPI",
1037 "Encapsulated PostScript Interchange format");
1038 entry->decoder=(DecodeImageHandler *) ReadPSImage;
1039 entry->encoder=(EncodeImageHandler *) WritePSImage;
1040 entry->magick=(IsImageFormatHandler *) IsPS;
1041 entry->flags^=CoderAdjoinFlag;
1042 entry->flags^=CoderBlobSupportFlag;
1043 entry->flags|=CoderSeekableStreamFlag;
1044 entry->mime_type=ConstantString("application/postscript");
1045 (void) RegisterMagickInfo(entry);
1046 entry=AcquireMagickInfo("PS","EPS","Encapsulated PostScript");
1047 entry->decoder=(DecodeImageHandler *) ReadPSImage;
1048 entry->encoder=(EncodeImageHandler *) WritePSImage;
1049 entry->magick=(IsImageFormatHandler *) IsPS;
1050 entry->flags^=CoderAdjoinFlag;
1051 entry->flags^=CoderBlobSupportFlag;
1052 entry->flags|=CoderSeekableStreamFlag;
1053 entry->mime_type=ConstantString("application/postscript");
1054 (void) RegisterMagickInfo(entry);
1055 entry=AcquireMagickInfo("PS","EPSF","Encapsulated PostScript");
1056 entry->decoder=(DecodeImageHandler *) ReadPSImage;
1057 entry->encoder=(EncodeImageHandler *) WritePSImage;
1058 entry->magick=(IsImageFormatHandler *) IsPS;
1059 entry->flags^=CoderAdjoinFlag;
1060 entry->flags^=CoderBlobSupportFlag;
1061 entry->flags|=CoderSeekableStreamFlag;
1062 entry->mime_type=ConstantString("application/postscript");
1063 (void) RegisterMagickInfo(entry);
1064 entry=AcquireMagickInfo("PS","EPSI",
1065 "Encapsulated PostScript Interchange format");
1066 entry->decoder=(DecodeImageHandler *) ReadPSImage;
1067 entry->encoder=(EncodeImageHandler *) WritePSImage;
1068 entry->magick=(IsImageFormatHandler *) IsPS;
1069 entry->flags^=CoderAdjoinFlag;
1070 entry->flags^=CoderBlobSupportFlag;
1071 entry->flags|=CoderSeekableStreamFlag;
1072 entry->mime_type=ConstantString("application/postscript");
1073 (void) RegisterMagickInfo(entry);
1074 entry=AcquireMagickInfo("PS","PS","PostScript");
1075 entry->decoder=(DecodeImageHandler *) ReadPSImage;
1076 entry->encoder=(EncodeImageHandler *) WritePSImage;
1077 entry->magick=(IsImageFormatHandler *) IsPS;
1078 entry->mime_type=ConstantString("application/postscript");
1079 entry->flags^=CoderBlobSupportFlag;
1080 entry->flags|=CoderSeekableStreamFlag;
1081 (void) RegisterMagickInfo(entry);
1082 return(MagickImageCoderSignature);
1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 % U n r e g i s t e r P S I m a g e %
1094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 % UnregisterPSImage() removes format registrations made by the
1097 % PS module from the list of supported formats.
1099 % The format of the UnregisterPSImage method is:
1101 % UnregisterPSImage(void)
1104 ModuleExport void UnregisterPSImage(void)
1106 (void) UnregisterMagickInfo("EPI");
1107 (void) UnregisterMagickInfo("EPS");
1108 (void) UnregisterMagickInfo("EPSF");
1109 (void) UnregisterMagickInfo("EPSI");
1110 (void) UnregisterMagickInfo("PS");
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 % W r i t e P S I m a g e %
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 % WritePSImage translates an image to encapsulated Postscript
1125 % Level I for printing. If the supplied geometry is null, the image is
1126 % centered on the Postscript page. Otherwise, the image is positioned as
1127 % specified by the geometry.
1129 % The format of the WritePSImage method is:
1131 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
1132 % Image *image,ExceptionInfo *exception)
1134 % A description of each parameter follows:
1136 % o image_info: the image info.
1138 % o image: the image.
1140 % o exception: return any errors or warnings in this structure.
1144 static inline unsigned char *PopHexPixel(const char *const *hex_digits,
1145 const size_t pixel,unsigned char *pixels)
1150 hex=hex_digits[pixel];
1151 *pixels++=(unsigned char) (*hex++);
1152 *pixels++=(unsigned char) (*hex);
1156 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1157 ExceptionInfo *exception)
1159 #define WriteRunlengthPacket(image,pixel,length,p) \
1161 if ((image->alpha_trait != UndefinedPixelTrait) && \
1162 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1164 q=PopHexPixel(hex_digits,0xff,q); \
1165 q=PopHexPixel(hex_digits,0xff,q); \
1166 q=PopHexPixel(hex_digits,0xff,q); \
1170 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.red)),q); \
1171 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.green)),q); \
1172 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.blue)),q); \
1174 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1178 *const hex_digits[] =
1180 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1181 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1182 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1183 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1184 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1185 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1186 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1187 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1188 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1189 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1190 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1191 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1192 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1193 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1194 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1195 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1196 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1197 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1198 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1199 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1200 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1201 "FC", "FD", "FE", "FF", (const char *) NULL
1203 *const PostscriptProlog[]=
1207 "% Display a color image. The image is displayed in color on",
1208 "% Postscript viewers or printers that support color, otherwise",
1209 "% it is displayed as grayscale.",
1211 "/DirectClassPacket",
1214 " % Get a DirectClass packet.",
1220 " % length: number of pixels minus one of this color (optional).",
1222 " currentfile color_packet readhexstring pop pop",
1223 " compression 0 eq",
1225 " /number_pixels 3 def",
1228 " currentfile byte readhexstring pop 0 get",
1229 " /number_pixels exch 1 add 3 mul def",
1231 " 0 3 number_pixels 1 sub",
1233 " pixels exch color_packet putinterval",
1235 " pixels 0 number_pixels getinterval",
1238 "/DirectClassImage",
1241 " % Display a DirectClass image.",
1243 " systemdict /colorimage known",
1250 " { DirectClassPacket } false 3 colorimage",
1254 " % No colorimage operator; convert to grayscale.",
1261 " { GrayDirectClassPacket } image",
1265 "/GrayDirectClassPacket",
1268 " % Get a DirectClass packet; convert to grayscale.",
1274 " % length: number of pixels minus one of this color (optional).",
1276 " currentfile color_packet readhexstring pop pop",
1277 " color_packet 0 get 0.299 mul",
1278 " color_packet 1 get 0.587 mul add",
1279 " color_packet 2 get 0.114 mul add",
1281 " /gray_packet exch def",
1282 " compression 0 eq",
1284 " /number_pixels 1 def",
1287 " currentfile byte readhexstring pop 0 get",
1288 " /number_pixels exch 1 add def",
1290 " 0 1 number_pixels 1 sub",
1292 " pixels exch gray_packet put",
1294 " pixels 0 number_pixels getinterval",
1297 "/GrayPseudoClassPacket",
1300 " % Get a PseudoClass packet; convert to grayscale.",
1303 " % index: index into the colormap.",
1304 " % length: number of pixels minus one of this color (optional).",
1306 " currentfile byte readhexstring pop 0 get",
1307 " /offset exch 3 mul def",
1308 " /color_packet colormap offset 3 getinterval def",
1309 " color_packet 0 get 0.299 mul",
1310 " color_packet 1 get 0.587 mul add",
1311 " color_packet 2 get 0.114 mul add",
1313 " /gray_packet exch def",
1314 " compression 0 eq",
1316 " /number_pixels 1 def",
1319 " currentfile byte readhexstring pop 0 get",
1320 " /number_pixels exch 1 add def",
1322 " 0 1 number_pixels 1 sub",
1324 " pixels exch gray_packet put",
1326 " pixels 0 number_pixels getinterval",
1329 "/PseudoClassPacket",
1332 " % Get a PseudoClass packet.",
1335 " % index: index into the colormap.",
1336 " % length: number of pixels minus one of this color (optional).",
1338 " currentfile byte readhexstring pop 0 get",
1339 " /offset exch 3 mul def",
1340 " /color_packet colormap offset 3 getinterval def",
1341 " compression 0 eq",
1343 " /number_pixels 3 def",
1346 " currentfile byte readhexstring pop 0 get",
1347 " /number_pixels exch 1 add 3 mul def",
1349 " 0 3 number_pixels 1 sub",
1351 " pixels exch color_packet putinterval",
1353 " pixels 0 number_pixels getinterval",
1356 "/PseudoClassImage",
1359 " % Display a PseudoClass image.",
1362 " % class: 0-PseudoClass or 1-Grayscale.",
1364 " currentfile buffer readline pop",
1365 " token pop /class exch def pop",
1368 " currentfile buffer readline pop",
1369 " token pop /depth exch def pop",
1370 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1371 " columns rows depth",
1376 " { currentfile grays readhexstring pop } image",
1381 " % colors: number of colors in the colormap.",
1382 " % colormap: red, green, blue color packets.",
1384 " currentfile buffer readline pop",
1385 " token pop /colors exch def pop",
1386 " /colors colors 3 mul def",
1387 " /colormap colors string def",
1388 " currentfile colormap readhexstring pop pop",
1389 " systemdict /colorimage known",
1396 " { PseudoClassPacket } false 3 colorimage",
1400 " % No colorimage operator; convert to grayscale.",
1407 " { GrayPseudoClassPacket } image",
1415 " % Display a DirectClass or PseudoClass image.",
1418 " % x & y translation.",
1420 " % label pointsize.",
1422 " % image columns & rows.",
1423 " % class: 0-DirectClass or 1-PseudoClass.",
1424 " % compression: 0-none or 1-RunlengthEncoded.",
1425 " % hex color packets.",
1428 " /buffer 512 string def",
1429 " /byte 1 string def",
1430 " /color_packet 3 string def",
1431 " /pixels 768 string def",
1433 " currentfile buffer readline pop",
1434 " token pop /x exch def",
1435 " token pop /y exch def pop",
1437 " currentfile buffer readline pop",
1438 " token pop /x exch def",
1439 " token pop /y exch def pop",
1440 " currentfile buffer readline pop",
1441 " token pop /pointsize exch def pop",
1442 " /Times-Roman findfont pointsize scalefont setfont",
1445 *const PostscriptEpilog[]=
1448 " currentfile buffer readline pop",
1449 " token pop /columns exch def",
1450 " token pop /rows exch def pop",
1451 " currentfile buffer readline pop",
1452 " token pop /class exch def pop",
1453 " currentfile buffer readline pop",
1454 " token pop /compression exch def pop",
1455 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1461 buffer[MagickPathExtent],
1462 date[MagickPathExtent],
1464 page_geometry[MagickPathExtent];
1507 register const Quantum
1514 register unsigned char
1538 Open output image file.
1540 assert(image_info != (const ImageInfo *) NULL);
1541 assert(image_info->signature == MagickCoreSignature);
1542 assert(image != (Image *) NULL);
1543 assert(image->signature == MagickCoreSignature);
1544 if (image->debug != MagickFalse)
1545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1546 assert(exception != (ExceptionInfo *) NULL);
1547 assert(exception->signature == MagickCoreSignature);
1548 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1549 if (status == MagickFalse)
1551 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1552 compression=image->compression;
1553 if (image_info->compression != UndefinedCompression)
1554 compression=image_info->compression;
1560 Scale relative to dots-per-inch.
1562 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1563 delta.x=DefaultResolution;
1564 delta.y=DefaultResolution;
1565 resolution.x=image->resolution.x;
1566 resolution.y=image->resolution.y;
1567 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1569 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1570 resolution.x=geometry_info.rho;
1571 resolution.y=geometry_info.sigma;
1572 if ((flags & SigmaValue) == 0)
1573 resolution.y=resolution.x;
1575 if (image_info->density != (char *) NULL)
1577 flags=ParseGeometry(image_info->density,&geometry_info);
1578 resolution.x=geometry_info.rho;
1579 resolution.y=geometry_info.sigma;
1580 if ((flags & SigmaValue) == 0)
1581 resolution.y=resolution.x;
1583 if (image->units == PixelsPerCentimeterResolution)
1585 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1586 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1588 SetGeometry(image,&geometry);
1589 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1590 (double) image->columns,(double) image->rows);
1591 if (image_info->page != (char *) NULL)
1592 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1594 if ((image->page.width != 0) && (image->page.height != 0))
1595 (void) FormatLocaleString(page_geometry,MagickPathExtent,
1596 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1597 image->page.height,(double) image->page.x,(double) image->page.y);
1599 if ((image->gravity != UndefinedGravity) &&
1600 (LocaleCompare(image_info->magick,"PS") == 0))
1601 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent);
1602 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1603 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1604 &geometry.width,&geometry.height);
1605 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1606 geometry.width=(size_t) floor(scale.x+0.5);
1607 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1608 geometry.height=(size_t) floor(scale.y+0.5);
1609 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1610 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1611 if (image->gravity != UndefinedGravity)
1613 geometry.x=(-page_info.x);
1614 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1617 if (image_info->pointsize != 0.0)
1618 pointsize=image_info->pointsize;
1620 value=GetImageProperty(image,"label",exception);
1621 if (value != (const char *) NULL)
1622 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1626 Output Postscript header.
1628 if (LocaleCompare(image_info->magick,"PS") == 0)
1629 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
1631 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1633 (void) WriteBlobString(image,buffer);
1634 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1635 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
1637 (void) WriteBlobString(image,buffer);
1638 timer=time((time_t *) NULL);
1639 (void) FormatMagickTime(timer,MagickPathExtent,date);
1640 (void) FormatLocaleString(buffer,MagickPathExtent,
1641 "%%%%CreationDate: (%s)\n",date);
1642 (void) WriteBlobString(image,buffer);
1643 bounds.x1=(double) geometry.x;
1644 bounds.y1=(double) geometry.y;
1645 bounds.x2=(double) geometry.x+scale.x;
1646 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1647 if ((image_info->adjoin != MagickFalse) &&
1648 (GetNextImageInList(image) != (Image *) NULL))
1649 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1653 (void) FormatLocaleString(buffer,MagickPathExtent,
1654 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1655 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1656 (void) WriteBlobString(image,buffer);
1657 (void) FormatLocaleString(buffer,MagickPathExtent,
1658 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1659 bounds.y1,bounds.x2,bounds.y2);
1661 (void) WriteBlobString(image,buffer);
1662 profile=GetImageProfile(image,"8bim");
1663 if (profile != (StringInfo *) NULL)
1666 Embed Photoshop profile.
1668 (void) FormatLocaleString(buffer,MagickPathExtent,
1669 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1670 (void) WriteBlobString(image,buffer);
1671 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1674 (void) WriteBlobString(image,"\n% ");
1675 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X",
1676 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1677 (void) WriteBlobString(image,buffer);
1679 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1681 profile=GetImageProfile(image,"xmp");
1682 DisableMSCWarning(4127)
1683 if (0 && (profile != (StringInfo *) NULL))
1689 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1690 (void) FormatLocaleString(buffer,MagickPathExtent,
1691 "\n%%begin_xml_packet: %.20g\n",(double)
1692 GetStringInfoLength(profile));
1693 (void) WriteBlobString(image,buffer);
1694 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1695 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1696 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1698 value=GetImageProperty(image,"label",exception);
1699 if (value != (const char *) NULL)
1700 (void) WriteBlobString(image,
1701 "%%DocumentNeededResources: font Times-Roman\n");
1702 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1703 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1704 if (LocaleCompare(image_info->magick,"PS") != 0)
1705 (void) WriteBlobString(image,"%%Pages: 1\n");
1709 Compute the number of pages.
1711 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1712 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1713 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Pages: %.20g\n",
1714 image_info->adjoin != MagickFalse ? (double)
1715 GetImageListLength(image) : 1.0);
1716 (void) WriteBlobString(image,buffer);
1718 (void) WriteBlobString(image,"%%EndComments\n");
1719 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1720 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1721 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1722 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1723 (LocaleCompare(image_info->magick,"EPT") == 0))
1738 Create preview image.
1740 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1741 if (preview_image == (Image *) NULL)
1742 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1744 Dump image as bitmap.
1746 (void) FormatLocaleString(buffer,MagickPathExtent,
1747 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1748 preview_image->columns,(double) preview_image->rows,1.0,
1749 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1751 (void) WriteBlobString(image,buffer);
1753 for (y=0; y < (ssize_t) image->rows; y++)
1755 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1757 if (p == (const Quantum *) NULL)
1761 for (x=0; x < (ssize_t) preview_image->columns; x++)
1764 pixel=ClampToQuantum(GetPixelLuma(preview_image,p));
1765 if (pixel >= (Quantum) (QuantumRange/2))
1770 q=PopHexPixel(hex_digits,byte,q);
1771 if ((q-pixels+8) >= 80)
1774 (void) WriteBlob(image,q-pixels,pixels);
1776 (void) WriteBlobString(image,"% ");
1785 q=PopHexPixel(hex_digits,byte,q);
1786 if ((q-pixels+8) >= 80)
1789 (void) WriteBlob(image,q-pixels,pixels);
1791 (void) WriteBlobString(image,"% ");
1798 (void) WriteBlob(image,q-pixels,pixels);
1800 (void) WriteBlobString(image,"\n%%EndPreview\n");
1801 preview_image=DestroyImage(preview_image);
1804 Output Postscript commands.
1806 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1808 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s);
1809 (void) WriteBlobString(image,buffer);
1811 value=GetImageProperty(image,"label",exception);
1812 if (value != (const char *) NULL)
1813 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1815 (void) WriteBlobString(image," /label 512 string def\n");
1816 (void) WriteBlobString(image," currentfile label readline pop\n");
1817 (void) FormatLocaleString(buffer,MagickPathExtent,
1818 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1819 (void) WriteBlobString(image,buffer);
1821 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1823 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s);
1824 (void) WriteBlobString(image,buffer);
1826 if (LocaleCompare(image_info->magick,"PS") == 0)
1827 (void) WriteBlobString(image," showpage\n");
1828 (void) WriteBlobString(image,"} bind def\n");
1829 (void) WriteBlobString(image,"%%EndProlog\n");
1831 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
1833 (void) WriteBlobString(image,buffer);
1834 (void) FormatLocaleString(buffer,MagickPathExtent,
1835 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1836 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1837 (geometry.height+text_size));
1838 (void) WriteBlobString(image,buffer);
1839 if ((double) geometry.x < bounds.x1)
1840 bounds.x1=(double) geometry.x;
1841 if ((double) geometry.y < bounds.y1)
1842 bounds.y1=(double) geometry.y;
1843 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1844 bounds.x2=(double) geometry.x+geometry.width-1;
1845 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1846 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1847 value=GetImageProperty(image,"label",exception);
1848 if (value != (const char *) NULL)
1849 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1850 if (LocaleCompare(image_info->magick,"PS") != 0)
1851 (void) WriteBlobString(image,"userdict begin\n");
1852 (void) WriteBlobString(image,"DisplayImage\n");
1856 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
1857 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1858 (void) WriteBlobString(image,buffer);
1859 labels=(char **) NULL;
1860 value=GetImageProperty(image,"label",exception);
1861 if (value != (const char *) NULL)
1862 labels=StringToList(value);
1863 if (labels != (char **) NULL)
1865 for (i=0; labels[i] != (char *) NULL; i++)
1867 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",
1869 (void) WriteBlobString(image,buffer);
1870 labels[i]=DestroyString(labels[i]);
1872 labels=(char **) RelinquishMagickMemory(labels);
1874 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1875 pixel.alpha=(MagickRealType) TransparentAlpha;
1878 if ((image_info->type != TrueColorType) &&
1879 (SetImageGray(image,exception) != MagickFalse))
1881 if (SetImageMonochrome(image,exception) == MagickFalse)
1887 Dump image as grayscale.
1889 (void) FormatLocaleString(buffer,MagickPathExtent,
1890 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1892 (void) WriteBlobString(image,buffer);
1894 for (y=0; y < (ssize_t) image->rows; y++)
1896 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1897 if (p == (const Quantum *) NULL)
1899 for (x=0; x < (ssize_t) image->columns; x++)
1901 pixel=(Quantum) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
1903 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1904 if ((q-pixels+8) >= 80)
1907 (void) WriteBlob(image,q-pixels,pixels);
1910 p+=GetPixelChannels(image);
1912 if (image->previous == (Image *) NULL)
1914 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1916 if (status == MagickFalse)
1923 (void) WriteBlob(image,q-pixels,pixels);
1935 Dump image as bitmap.
1937 (void) FormatLocaleString(buffer,MagickPathExtent,
1938 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1940 (void) WriteBlobString(image,buffer);
1942 for (y=0; y < (ssize_t) image->rows; y++)
1944 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1945 if (p == (const Quantum *) NULL)
1949 for (x=0; x < (ssize_t) image->columns; x++)
1952 pixel=ClampToQuantum(GetPixelLuma(image,p));
1953 if (pixel >= (Quantum) (QuantumRange/2))
1958 q=PopHexPixel(hex_digits,byte,q);
1959 if ((q-pixels+2) >= 80)
1962 (void) WriteBlob(image,q-pixels,pixels);
1968 p+=GetPixelChannels(image);
1973 q=PopHexPixel(hex_digits,byte,q);
1974 if ((q-pixels+2) >= 80)
1977 (void) WriteBlob(image,q-pixels,pixels);
1981 if (image->previous == (Image *) NULL)
1983 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1985 if (status == MagickFalse)
1992 (void) WriteBlob(image,q-pixels,pixels);
1997 if ((image->storage_class == DirectClass) ||
1998 (image->colors > 256) || (image->alpha_trait != UndefinedPixelTrait))
2001 Dump DirectClass image.
2003 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n0\n%d\n",
2004 (double) image->columns,(double) image->rows,
2005 compression == RLECompression ? 1 : 0);
2006 (void) WriteBlobString(image,buffer);
2007 switch (compression)
2009 case RLECompression:
2012 Dump runlength-encoded DirectColor packets.
2015 for (y=0; y < (ssize_t) image->rows; y++)
2017 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2018 if (p == (const Quantum *) NULL)
2020 GetPixelInfoPixel(image,p,&pixel);
2022 for (x=0; x < (ssize_t) image->columns; x++)
2024 if ((GetPixelRed(image,p) == ClampToQuantum(pixel.red)) &&
2025 (GetPixelGreen(image,p) == ClampToQuantum(pixel.green)) &&
2026 (GetPixelBlue(image,p) == ClampToQuantum(pixel.blue)) &&
2027 (GetPixelAlpha(image,p) == ClampToQuantum(pixel.alpha)) &&
2028 (length < 255) && (x < (ssize_t) (image->columns-1)))
2034 WriteRunlengthPacket(image,pixel,length,p);
2035 if ((q-pixels+10) >= 80)
2038 (void) WriteBlob(image,q-pixels,pixels);
2044 GetPixelInfoPixel(image,p,&pixel);
2045 p+=GetPixelChannels(image);
2047 WriteRunlengthPacket(image,pixel,length,p);
2048 if ((q-pixels+10) >= 80)
2051 (void) WriteBlob(image,q-pixels,pixels);
2054 if (image->previous == (Image *) NULL)
2056 status=SetImageProgress(image,SaveImageTag,
2057 (MagickOffsetType) y,image->rows);
2058 if (status == MagickFalse)
2065 (void) WriteBlob(image,q-pixels,pixels);
2073 Dump uncompressed DirectColor packets.
2076 for (y=0; y < (ssize_t) image->rows; y++)
2078 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2079 if (p == (const Quantum *) NULL)
2081 for (x=0; x < (ssize_t) image->columns; x++)
2083 if ((image->alpha_trait != UndefinedPixelTrait) &&
2084 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
2086 q=PopHexPixel(hex_digits,0xff,q);
2087 q=PopHexPixel(hex_digits,0xff,q);
2088 q=PopHexPixel(hex_digits,0xff,q);
2092 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2093 GetPixelRed(image,p)),q);
2094 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2095 GetPixelGreen(image,p)),q);
2096 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2097 GetPixelBlue(image,p)),q);
2099 if ((q-pixels+6) >= 80)
2102 (void) WriteBlob(image,q-pixels,pixels);
2105 p+=GetPixelChannels(image);
2107 if (image->previous == (Image *) NULL)
2109 status=SetImageProgress(image,SaveImageTag,
2110 (MagickOffsetType) y,image->rows);
2111 if (status == MagickFalse)
2118 (void) WriteBlob(image,q-pixels,pixels);
2123 (void) WriteBlobByte(image,'\n');
2128 Dump PseudoClass image.
2130 (void) FormatLocaleString(buffer,MagickPathExtent,
2131 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2132 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2133 compression == RLECompression ? 1 : 0);
2134 (void) WriteBlobString(image,buffer);
2136 Dump number of colors and colormap.
2138 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2140 (void) WriteBlobString(image,buffer);
2141 for (i=0; i < (ssize_t) image->colors; i++)
2143 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n",
2144 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)),
2145 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)),
2146 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue)));
2147 (void) WriteBlobString(image,buffer);
2149 switch (compression)
2151 case RLECompression:
2154 Dump runlength-encoded PseudoColor packets.
2157 for (y=0; y < (ssize_t) image->rows; y++)
2159 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2160 if (p == (const Quantum *) NULL)
2162 index=GetPixelIndex(image,p);
2164 for (x=0; x < (ssize_t) image->columns; x++)
2166 if ((index == GetPixelIndex(image,p)) &&
2167 (length < 255) && (x < ((ssize_t) image->columns-1)))
2173 q=PopHexPixel(hex_digits,(size_t) index,q);
2174 q=PopHexPixel(hex_digits,(size_t)
2175 MagickMin(length,0xff),q);
2177 if ((q-pixels+6) >= 80)
2180 (void) WriteBlob(image,q-pixels,pixels);
2186 index=GetPixelIndex(image,p);
2187 pixel.red=(MagickRealType) GetPixelRed(image,p);
2188 pixel.green=(MagickRealType) GetPixelGreen(image,p);
2189 pixel.blue=(MagickRealType) GetPixelBlue(image,p);
2190 pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
2191 p+=GetPixelChannels(image);
2193 q=PopHexPixel(hex_digits,(size_t) index,q);
2194 q=PopHexPixel(hex_digits,(size_t)
2195 MagickMin(length,0xff),q);
2196 if (image->previous == (Image *) NULL)
2198 status=SetImageProgress(image,SaveImageTag,
2199 (MagickOffsetType) y,image->rows);
2200 if (status == MagickFalse)
2207 (void) WriteBlob(image,q-pixels,pixels);
2215 Dump uncompressed PseudoColor packets.
2218 for (y=0; y < (ssize_t) image->rows; y++)
2220 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2221 if (p == (const Quantum *) NULL)
2223 for (x=0; x < (ssize_t) image->columns; x++)
2225 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2226 if ((q-pixels+4) >= 80)
2229 (void) WriteBlob(image,q-pixels,pixels);
2232 p+=GetPixelChannels(image);
2234 if (image->previous == (Image *) NULL)
2236 status=SetImageProgress(image,SaveImageTag,
2237 (MagickOffsetType) y,image->rows);
2238 if (status == MagickFalse)
2245 (void) WriteBlob(image,q-pixels,pixels);
2250 (void) WriteBlobByte(image,'\n');
2252 if (LocaleCompare(image_info->magick,"PS") != 0)
2253 (void) WriteBlobString(image,"end\n");
2254 (void) WriteBlobString(image,"%%PageTrailer\n");
2255 if (GetNextImageInList(image) == (Image *) NULL)
2257 image=SyncNextImageInList(image);
2258 status=SetImageProgress(image,SaveImagesTag,scene++,
2259 GetImageListLength(image));
2260 if (status == MagickFalse)
2262 } while (image_info->adjoin != MagickFalse);
2263 (void) WriteBlobString(image,"%%Trailer\n");
2266 (void) FormatLocaleString(buffer,MagickPathExtent,
2267 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2268 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5));
2269 (void) WriteBlobString(image,buffer);
2270 (void) FormatLocaleString(buffer,MagickPathExtent,
2271 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2273 (void) WriteBlobString(image,buffer);
2275 (void) WriteBlobString(image,"%%EOF\n");
2276 (void) CloseBlob(image);