2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2017 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",
1444 *const PostscriptEpilog[]=
1447 " currentfile buffer readline pop",
1448 " token pop /columns exch def",
1449 " token pop /rows exch def pop",
1450 " currentfile buffer readline pop",
1451 " token pop /class exch def pop",
1452 " currentfile buffer readline pop",
1453 " token pop /compression exch def pop",
1454 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1460 buffer[MagickPathExtent],
1461 date[MagickPathExtent],
1463 page_geometry[MagickPathExtent];
1506 register const Quantum
1513 register unsigned char
1537 Open output image file.
1539 assert(image_info != (const ImageInfo *) NULL);
1540 assert(image_info->signature == MagickCoreSignature);
1541 assert(image != (Image *) NULL);
1542 assert(image->signature == MagickCoreSignature);
1543 if (image->debug != MagickFalse)
1544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1545 assert(exception != (ExceptionInfo *) NULL);
1546 assert(exception->signature == MagickCoreSignature);
1547 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1548 if (status == MagickFalse)
1550 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1551 compression=image->compression;
1552 if (image_info->compression != UndefinedCompression)
1553 compression=image_info->compression;
1559 Scale relative to dots-per-inch.
1561 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1562 delta.x=DefaultResolution;
1563 delta.y=DefaultResolution;
1564 resolution.x=image->resolution.x;
1565 resolution.y=image->resolution.y;
1566 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1568 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1569 resolution.x=geometry_info.rho;
1570 resolution.y=geometry_info.sigma;
1571 if ((flags & SigmaValue) == 0)
1572 resolution.y=resolution.x;
1574 if (image_info->density != (char *) NULL)
1576 flags=ParseGeometry(image_info->density,&geometry_info);
1577 resolution.x=geometry_info.rho;
1578 resolution.y=geometry_info.sigma;
1579 if ((flags & SigmaValue) == 0)
1580 resolution.y=resolution.x;
1582 if (image->units == PixelsPerCentimeterResolution)
1584 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1585 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1587 SetGeometry(image,&geometry);
1588 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1589 (double) image->columns,(double) image->rows);
1590 if (image_info->page != (char *) NULL)
1591 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1593 if ((image->page.width != 0) && (image->page.height != 0))
1594 (void) FormatLocaleString(page_geometry,MagickPathExtent,
1595 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1596 image->page.height,(double) image->page.x,(double) image->page.y);
1598 if ((image->gravity != UndefinedGravity) &&
1599 (LocaleCompare(image_info->magick,"PS") == 0))
1600 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent);
1601 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1602 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1603 &geometry.width,&geometry.height);
1604 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1605 geometry.width=(size_t) floor(scale.x+0.5);
1606 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1607 geometry.height=(size_t) floor(scale.y+0.5);
1608 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1609 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1610 if (image->gravity != UndefinedGravity)
1612 geometry.x=(-page_info.x);
1613 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1616 if (image_info->pointsize != 0.0)
1617 pointsize=image_info->pointsize;
1619 value=GetImageProperty(image,"label",exception);
1620 if (value != (const char *) NULL)
1621 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1625 Output Postscript header.
1627 if (LocaleCompare(image_info->magick,"PS") == 0)
1628 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
1630 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1632 (void) WriteBlobString(image,buffer);
1633 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1634 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
1636 (void) WriteBlobString(image,buffer);
1637 timer=time((time_t *) NULL);
1638 (void) FormatMagickTime(timer,MagickPathExtent,date);
1639 (void) FormatLocaleString(buffer,MagickPathExtent,
1640 "%%%%CreationDate: (%s)\n",date);
1641 (void) WriteBlobString(image,buffer);
1642 bounds.x1=(double) geometry.x;
1643 bounds.y1=(double) geometry.y;
1644 bounds.x2=(double) geometry.x+scale.x;
1645 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1646 if ((image_info->adjoin != MagickFalse) &&
1647 (GetNextImageInList(image) != (Image *) NULL))
1648 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1652 (void) FormatLocaleString(buffer,MagickPathExtent,
1653 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1654 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1655 (void) WriteBlobString(image,buffer);
1656 (void) FormatLocaleString(buffer,MagickPathExtent,
1657 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1658 bounds.y1,bounds.x2,bounds.y2);
1660 (void) WriteBlobString(image,buffer);
1661 profile=GetImageProfile(image,"8bim");
1662 if (profile != (StringInfo *) NULL)
1665 Embed Photoshop profile.
1667 (void) FormatLocaleString(buffer,MagickPathExtent,
1668 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1669 (void) WriteBlobString(image,buffer);
1670 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1673 (void) WriteBlobString(image,"\n% ");
1674 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X",
1675 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1676 (void) WriteBlobString(image,buffer);
1678 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1680 profile=GetImageProfile(image,"xmp");
1681 DisableMSCWarning(4127)
1682 if (0 && (profile != (StringInfo *) NULL))
1688 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1689 (void) FormatLocaleString(buffer,MagickPathExtent,
1690 "\n%%begin_xml_packet: %.20g\n",(double)
1691 GetStringInfoLength(profile));
1692 (void) WriteBlobString(image,buffer);
1693 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1694 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1695 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1697 value=GetImageProperty(image,"label",exception);
1698 if (value != (const char *) NULL)
1699 (void) WriteBlobString(image,
1700 "%%DocumentNeededResources: font Times-Roman\n");
1701 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1702 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1703 if (LocaleCompare(image_info->magick,"PS") != 0)
1704 (void) WriteBlobString(image,"%%Pages: 1\n");
1708 Compute the number of pages.
1710 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1711 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1712 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Pages: %.20g\n",
1713 image_info->adjoin != MagickFalse ? (double)
1714 GetImageListLength(image) : 1.0);
1715 (void) WriteBlobString(image,buffer);
1717 (void) WriteBlobString(image,"%%EndComments\n");
1718 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1719 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1720 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1721 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1722 (LocaleCompare(image_info->magick,"EPT") == 0))
1737 Create preview image.
1739 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1740 if (preview_image == (Image *) NULL)
1741 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1743 Dump image as bitmap.
1745 (void) FormatLocaleString(buffer,MagickPathExtent,
1746 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1747 preview_image->columns,(double) preview_image->rows,1.0,
1748 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1750 (void) WriteBlobString(image,buffer);
1752 for (y=0; y < (ssize_t) image->rows; y++)
1754 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1756 if (p == (const Quantum *) NULL)
1760 for (x=0; x < (ssize_t) preview_image->columns; x++)
1763 pixel=ClampToQuantum(GetPixelLuma(preview_image,p));
1764 if (pixel >= (Quantum) (QuantumRange/2))
1769 q=PopHexPixel(hex_digits,byte,q);
1770 if ((q-pixels+8) >= 80)
1773 (void) WriteBlob(image,q-pixels,pixels);
1775 (void) WriteBlobString(image,"% ");
1784 q=PopHexPixel(hex_digits,byte,q);
1785 if ((q-pixels+8) >= 80)
1788 (void) WriteBlob(image,q-pixels,pixels);
1790 (void) WriteBlobString(image,"% ");
1797 (void) WriteBlob(image,q-pixels,pixels);
1799 (void) WriteBlobString(image,"\n%%EndPreview\n");
1800 preview_image=DestroyImage(preview_image);
1803 Output Postscript commands.
1805 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1807 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s);
1808 (void) WriteBlobString(image,buffer);
1810 value=GetImageProperty(image,"label",exception);
1811 if (value != (const char *) NULL)
1813 (void) WriteBlobString(image,
1814 " /Times-Roman findfont pointsize scalefont setfont\n");
1815 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1817 (void) WriteBlobString(image," /label 512 string def\n");
1818 (void) WriteBlobString(image,
1819 " currentfile label readline pop\n");
1820 (void) FormatLocaleString(buffer,MagickPathExtent,
1821 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1822 (void) WriteBlobString(image,buffer);
1825 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1827 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s);
1828 (void) WriteBlobString(image,buffer);
1830 if (LocaleCompare(image_info->magick,"PS") == 0)
1831 (void) WriteBlobString(image," showpage\n");
1832 (void) WriteBlobString(image,"} bind def\n");
1833 (void) WriteBlobString(image,"%%EndProlog\n");
1835 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
1837 (void) WriteBlobString(image,buffer);
1838 (void) FormatLocaleString(buffer,MagickPathExtent,
1839 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1840 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1841 (geometry.height+text_size));
1842 (void) WriteBlobString(image,buffer);
1843 if ((double) geometry.x < bounds.x1)
1844 bounds.x1=(double) geometry.x;
1845 if ((double) geometry.y < bounds.y1)
1846 bounds.y1=(double) geometry.y;
1847 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1848 bounds.x2=(double) geometry.x+geometry.width-1;
1849 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1850 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1851 value=GetImageProperty(image,"label",exception);
1852 if (value != (const char *) NULL)
1853 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1854 if (LocaleCompare(image_info->magick,"PS") != 0)
1855 (void) WriteBlobString(image,"userdict begin\n");
1856 (void) WriteBlobString(image,"DisplayImage\n");
1860 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
1861 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1862 (void) WriteBlobString(image,buffer);
1863 labels=(char **) NULL;
1864 value=GetImageProperty(image,"label",exception);
1865 if (value != (const char *) NULL)
1866 labels=StringToList(value);
1867 if (labels != (char **) NULL)
1869 for (i=0; labels[i] != (char *) NULL; i++)
1871 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",
1873 (void) WriteBlobString(image,buffer);
1874 labels[i]=DestroyString(labels[i]);
1876 labels=(char **) RelinquishMagickMemory(labels);
1878 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1879 pixel.alpha=(MagickRealType) TransparentAlpha;
1882 if ((image_info->type != TrueColorType) &&
1883 (SetImageGray(image,exception) != MagickFalse))
1885 if (SetImageMonochrome(image,exception) == MagickFalse)
1891 Dump image as grayscale.
1893 (void) FormatLocaleString(buffer,MagickPathExtent,
1894 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1896 (void) WriteBlobString(image,buffer);
1898 for (y=0; y < (ssize_t) image->rows; y++)
1900 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1901 if (p == (const Quantum *) NULL)
1903 for (x=0; x < (ssize_t) image->columns; x++)
1905 pixel=(Quantum) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
1907 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1908 if ((q-pixels+8) >= 80)
1911 (void) WriteBlob(image,q-pixels,pixels);
1914 p+=GetPixelChannels(image);
1916 if (image->previous == (Image *) NULL)
1918 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1920 if (status == MagickFalse)
1927 (void) WriteBlob(image,q-pixels,pixels);
1939 Dump image as bitmap.
1941 (void) FormatLocaleString(buffer,MagickPathExtent,
1942 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1944 (void) WriteBlobString(image,buffer);
1946 for (y=0; y < (ssize_t) image->rows; y++)
1948 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1949 if (p == (const Quantum *) NULL)
1953 for (x=0; x < (ssize_t) image->columns; x++)
1956 pixel=ClampToQuantum(GetPixelLuma(image,p));
1957 if (pixel >= (Quantum) (QuantumRange/2))
1962 q=PopHexPixel(hex_digits,byte,q);
1963 if ((q-pixels+2) >= 80)
1966 (void) WriteBlob(image,q-pixels,pixels);
1972 p+=GetPixelChannels(image);
1977 q=PopHexPixel(hex_digits,byte,q);
1978 if ((q-pixels+2) >= 80)
1981 (void) WriteBlob(image,q-pixels,pixels);
1985 if (image->previous == (Image *) NULL)
1987 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1989 if (status == MagickFalse)
1996 (void) WriteBlob(image,q-pixels,pixels);
2001 if ((image->storage_class == DirectClass) ||
2002 (image->colors > 256) || (image->alpha_trait != UndefinedPixelTrait))
2005 Dump DirectClass image.
2007 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n0\n%d\n",
2008 (double) image->columns,(double) image->rows,
2009 compression == RLECompression ? 1 : 0);
2010 (void) WriteBlobString(image,buffer);
2011 switch (compression)
2013 case RLECompression:
2016 Dump runlength-encoded DirectColor packets.
2019 for (y=0; y < (ssize_t) image->rows; y++)
2021 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2022 if (p == (const Quantum *) NULL)
2024 GetPixelInfoPixel(image,p,&pixel);
2026 for (x=0; x < (ssize_t) image->columns; x++)
2028 if ((GetPixelRed(image,p) == ClampToQuantum(pixel.red)) &&
2029 (GetPixelGreen(image,p) == ClampToQuantum(pixel.green)) &&
2030 (GetPixelBlue(image,p) == ClampToQuantum(pixel.blue)) &&
2031 (GetPixelAlpha(image,p) == ClampToQuantum(pixel.alpha)) &&
2032 (length < 255) && (x < (ssize_t) (image->columns-1)))
2038 WriteRunlengthPacket(image,pixel,length,p);
2039 if ((q-pixels+10) >= 80)
2042 (void) WriteBlob(image,q-pixels,pixels);
2048 GetPixelInfoPixel(image,p,&pixel);
2049 p+=GetPixelChannels(image);
2051 WriteRunlengthPacket(image,pixel,length,p);
2052 if ((q-pixels+10) >= 80)
2055 (void) WriteBlob(image,q-pixels,pixels);
2058 if (image->previous == (Image *) NULL)
2060 status=SetImageProgress(image,SaveImageTag,
2061 (MagickOffsetType) y,image->rows);
2062 if (status == MagickFalse)
2069 (void) WriteBlob(image,q-pixels,pixels);
2077 Dump uncompressed DirectColor packets.
2080 for (y=0; y < (ssize_t) image->rows; y++)
2082 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2083 if (p == (const Quantum *) NULL)
2085 for (x=0; x < (ssize_t) image->columns; x++)
2087 if ((image->alpha_trait != UndefinedPixelTrait) &&
2088 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
2090 q=PopHexPixel(hex_digits,0xff,q);
2091 q=PopHexPixel(hex_digits,0xff,q);
2092 q=PopHexPixel(hex_digits,0xff,q);
2096 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2097 GetPixelRed(image,p)),q);
2098 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2099 GetPixelGreen(image,p)),q);
2100 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2101 GetPixelBlue(image,p)),q);
2103 if ((q-pixels+6) >= 80)
2106 (void) WriteBlob(image,q-pixels,pixels);
2109 p+=GetPixelChannels(image);
2111 if (image->previous == (Image *) NULL)
2113 status=SetImageProgress(image,SaveImageTag,
2114 (MagickOffsetType) y,image->rows);
2115 if (status == MagickFalse)
2122 (void) WriteBlob(image,q-pixels,pixels);
2127 (void) WriteBlobByte(image,'\n');
2132 Dump PseudoClass image.
2134 (void) FormatLocaleString(buffer,MagickPathExtent,
2135 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2136 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2137 compression == RLECompression ? 1 : 0);
2138 (void) WriteBlobString(image,buffer);
2140 Dump number of colors and colormap.
2142 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2144 (void) WriteBlobString(image,buffer);
2145 for (i=0; i < (ssize_t) image->colors; i++)
2147 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n",
2148 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)),
2149 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)),
2150 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue)));
2151 (void) WriteBlobString(image,buffer);
2153 switch (compression)
2155 case RLECompression:
2158 Dump runlength-encoded PseudoColor packets.
2161 for (y=0; y < (ssize_t) image->rows; y++)
2163 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2164 if (p == (const Quantum *) NULL)
2166 index=GetPixelIndex(image,p);
2168 for (x=0; x < (ssize_t) image->columns; x++)
2170 if ((index == GetPixelIndex(image,p)) &&
2171 (length < 255) && (x < ((ssize_t) image->columns-1)))
2177 q=PopHexPixel(hex_digits,(size_t) index,q);
2178 q=PopHexPixel(hex_digits,(size_t)
2179 MagickMin(length,0xff),q);
2181 if ((q-pixels+6) >= 80)
2184 (void) WriteBlob(image,q-pixels,pixels);
2190 index=GetPixelIndex(image,p);
2191 pixel.red=(MagickRealType) GetPixelRed(image,p);
2192 pixel.green=(MagickRealType) GetPixelGreen(image,p);
2193 pixel.blue=(MagickRealType) GetPixelBlue(image,p);
2194 pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
2195 p+=GetPixelChannels(image);
2197 q=PopHexPixel(hex_digits,(size_t) index,q);
2198 q=PopHexPixel(hex_digits,(size_t)
2199 MagickMin(length,0xff),q);
2200 if (image->previous == (Image *) NULL)
2202 status=SetImageProgress(image,SaveImageTag,
2203 (MagickOffsetType) y,image->rows);
2204 if (status == MagickFalse)
2211 (void) WriteBlob(image,q-pixels,pixels);
2219 Dump uncompressed PseudoColor packets.
2222 for (y=0; y < (ssize_t) image->rows; y++)
2224 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2225 if (p == (const Quantum *) NULL)
2227 for (x=0; x < (ssize_t) image->columns; x++)
2229 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2230 if ((q-pixels+4) >= 80)
2233 (void) WriteBlob(image,q-pixels,pixels);
2236 p+=GetPixelChannels(image);
2238 if (image->previous == (Image *) NULL)
2240 status=SetImageProgress(image,SaveImageTag,
2241 (MagickOffsetType) y,image->rows);
2242 if (status == MagickFalse)
2249 (void) WriteBlob(image,q-pixels,pixels);
2254 (void) WriteBlobByte(image,'\n');
2256 if (LocaleCompare(image_info->magick,"PS") != 0)
2257 (void) WriteBlobString(image,"end\n");
2258 (void) WriteBlobString(image,"%%PageTrailer\n");
2259 if (GetNextImageInList(image) == (Image *) NULL)
2261 image=SyncNextImageInList(image);
2262 status=SetImageProgress(image,SaveImagesTag,scene++,
2263 GetImageListLength(image));
2264 if (status == MagickFalse)
2266 } while (image_info->adjoin != MagickFalse);
2267 (void) WriteBlobString(image,"%%Trailer\n");
2270 (void) FormatLocaleString(buffer,MagickPathExtent,
2271 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2272 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5));
2273 (void) WriteBlobString(image,buffer);
2274 (void) FormatLocaleString(buffer,MagickPathExtent,
2275 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2277 (void) WriteBlobString(image,buffer);
2279 (void) WriteBlobString(image,"%%EOF\n");
2280 (void) CloseBlob(image);