2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2014 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 static MagickBooleanType InvokePostscriptDelegate(
118 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
123 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
140 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
141 ghost_info=NTGhostscriptDLLVectors();
146 ghost_info=(&ghost_info_struct);
147 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
148 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
150 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
151 gsapi_init_with_args;
152 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
153 int *)) gsapi_run_string;
154 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
155 gsapi_delete_instance;
156 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
158 if (ghost_info == (GhostInfo *) NULL)
160 status=SystemCommand(MagickFalse,verbose,command,exception);
161 return(status == 0 ? MagickTrue : MagickFalse);
163 if (verbose != MagickFalse)
165 (void) fputs("[ghostscript library]",stdout);
166 (void) fputs(strchr(command,' '),stdout);
168 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
171 status=SystemCommand(MagickFalse,verbose,command,exception);
172 return(status == 0 ? MagickTrue : MagickFalse);
175 argv=StringToArgv(command,&argc);
176 if (argv == (char **) NULL)
178 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
180 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
182 (ghost_info->exit)(interpreter);
183 (ghost_info->delete_instance)(interpreter);
184 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
185 NTGhostscriptUnLoadDLL();
187 for (i=0; i < (ssize_t) argc; i++)
188 argv[i]=DestroyString(argv[i]);
189 argv=(char **) RelinquishMagickMemory(argv);
190 if ((status != 0) && (status != -101))
195 message=GetExceptionMessage(errno);
196 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
197 "`%s': %s",command,message);
198 message=DestroyString(message);
199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
200 "Ghostscript returns status %d, exit code %d",status,code);
205 status=SystemCommand(MagickFalse,verbose,command,exception);
206 return(status == 0 ? MagickTrue : MagickFalse);
211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221 % IsPS() returns MagickTrue if the image format type, identified by the
222 % magick string, is PS.
224 % The format of the IsPS method is:
226 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
228 % A description of each parameter follows:
230 % o magick: compare image format pattern against these bytes.
232 % o length: Specifies the length of the magick string.
235 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
239 if (memcmp(magick,"%!",2) == 0)
241 if (memcmp(magick,"\004%!",3) == 0)
247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 % R e a d P S I m a g e %
255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257 % ReadPSImage() reads a Postscript image file and returns it. It allocates
258 % the memory necessary for the new Image structure and returns a pointer
261 % The format of the ReadPSImage method is:
263 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
265 % A description of each parameter follows:
267 % o image_info: the image info.
269 % o exception: return any errors or warnings in this structure.
273 static MagickBooleanType IsPostscriptRendered(const char *path)
281 if ((path == (const char *) NULL) || (*path == '\0'))
283 status=GetPathAttributes(path,&attributes);
284 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
285 (attributes.st_size > 0))
290 static inline int ProfileInteger(Image *image,short int *hex_digits)
304 c=ReadBlobByte(image);
305 if ((c == EOF) || ((c == '%') && (l == '%')))
312 if (isxdigit(c) == MagickFalse)
314 value=(int) ((size_t) value << 4)+hex_digits[c];
320 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
322 #define BoundingBox "BoundingBox:"
323 #define BeginDocument "BeginDocument:"
324 #define BeginXMPPacket "<?xpacket begin="
325 #define EndXMPPacket "<?xpacket end="
326 #define ICCProfile "BeginICCProfile:"
327 #define CMYKCustomColor "CMYKCustomColor:"
328 #define CMYKProcessColor "CMYKProcessColor:"
329 #define DocumentMedia "DocumentMedia:"
330 #define DocumentCustomColors "DocumentCustomColors:"
331 #define DocumentProcessColors "DocumentProcessColors:"
332 #define EndDocument "EndDocument:"
333 #define HiResBoundingBox "HiResBoundingBox:"
334 #define ImageData "ImageData:"
335 #define PageBoundingBox "PageBoundingBox:"
336 #define LanguageLevel "LanguageLevel:"
337 #define PageMedia "PageMedia:"
338 #define Pages "Pages:"
339 #define PhotoshopProfile "BeginPhotoshop:"
340 #define PostscriptLevel "!PS-"
341 #define RenderPostscriptText " Rendering Postscript... "
342 #define SpotColor "+ "
345 command[MaxTextExtent],
346 density[MaxTextExtent],
347 filename[MaxTextExtent],
348 geometry[MaxTextExtent],
349 input_filename[MaxTextExtent],
350 options[MaxTextExtent],
351 postscript_filename[MaxTextExtent];
424 assert(image_info != (const ImageInfo *) NULL);
425 assert(image_info->signature == MagickSignature);
426 if (image_info->debug != MagickFalse)
427 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
428 image_info->filename);
429 assert(exception != (ExceptionInfo *) NULL);
430 assert(exception->signature == MagickSignature);
431 image=AcquireImage(image_info,exception);
432 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
433 if (status == MagickFalse)
435 image=DestroyImageList(image);
436 return((Image *) NULL);
438 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
439 if (status == MagickFalse)
441 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
442 image_info->filename);
443 image=DestroyImageList(image);
444 return((Image *) NULL);
447 Initialize hex values.
449 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
450 hex_digits[(int) '0']=0;
451 hex_digits[(int) '1']=1;
452 hex_digits[(int) '2']=2;
453 hex_digits[(int) '3']=3;
454 hex_digits[(int) '4']=4;
455 hex_digits[(int) '5']=5;
456 hex_digits[(int) '6']=6;
457 hex_digits[(int) '7']=7;
458 hex_digits[(int) '8']=8;
459 hex_digits[(int) '9']=9;
460 hex_digits[(int) 'a']=10;
461 hex_digits[(int) 'b']=11;
462 hex_digits[(int) 'c']=12;
463 hex_digits[(int) 'd']=13;
464 hex_digits[(int) 'e']=14;
465 hex_digits[(int) 'f']=15;
466 hex_digits[(int) 'A']=10;
467 hex_digits[(int) 'B']=11;
468 hex_digits[(int) 'C']=12;
469 hex_digits[(int) 'D']=13;
470 hex_digits[(int) 'E']=14;
471 hex_digits[(int) 'F']=15;
473 Set the page density.
475 delta.x=DefaultResolution;
476 delta.y=DefaultResolution;
477 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
479 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
480 image->resolution.x=geometry_info.rho;
481 image->resolution.y=geometry_info.sigma;
482 if ((flags & SigmaValue) == 0)
483 image->resolution.y=image->resolution.x;
485 if (image_info->density != (char *) NULL)
487 flags=ParseGeometry(image_info->density,&geometry_info);
488 image->resolution.x=geometry_info.rho;
489 image->resolution.y=geometry_info.sigma;
490 if ((flags & SigmaValue) == 0)
491 image->resolution.y=image->resolution.x;
493 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
494 if (image_info->page != (char *) NULL)
495 (void) ParseAbsoluteGeometry(image_info->page,&page);
496 resolution=image->resolution;
497 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5);
498 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5);
500 Determine page geometry from the Postscript bounding box.
502 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
503 (void) ResetMagickMemory(command,0,sizeof(command));
504 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
505 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
516 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
519 Note document structuring comments.
522 if ((strchr("\n\r%",c) == (char *) NULL) &&
523 ((size_t) (p-command) < (MaxTextExtent-1)))
528 Skip %%BeginDocument thru %%EndDocument.
530 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
532 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
534 if (skip != MagickFalse)
536 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
538 (void) SetImageProperty(image,"ps:Level",command+4,exception);
539 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
542 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
543 (void) sscanf(command,LanguageLevel " %lu",&language_level);
544 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
545 (void) sscanf(command,Pages " %lu",&pages);
546 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
547 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
548 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
556 profile=AcquireStringInfo(65536);
557 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
559 SetStringInfoLength(profile,(size_t) i+1);
560 datum=GetStringInfoDatum(profile);
561 datum[i]=(unsigned char) c;
563 (void) SetImageProfile(image,"icc",profile,exception);
564 profile=DestroyStringInfo(profile);
567 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
573 Read Photoshop profile.
575 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
579 profile=BlobToStringInfo((const void *) NULL,length);
580 p=GetStringInfoDatum(profile);
581 for (i=0; i < (ssize_t) length; i++)
582 *p++=(unsigned char) ProfileInteger(image,hex_digits);
583 (void) SetImageProfile(image,"8bim",profile,exception);
584 profile=DestroyStringInfo(profile);
587 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
596 profile=StringToStringInfo(command);
597 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
599 SetStringInfoLength(profile,i+1);
600 c=ReadBlobByte(image);
601 GetStringInfoDatum(profile)[i]=(unsigned char) c;
603 if ((strchr("\n\r%",c) == (char *) NULL) &&
604 ((size_t) (p-command) < (MaxTextExtent-1)))
608 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
611 SetStringInfoLength(profile,i);
612 (void) SetImageProfile(image,"xmp",profile,exception);
613 profile=DestroyStringInfo(profile);
617 Is this a CMYK document?
619 length=strlen(DocumentProcessColors);
620 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
622 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
623 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
624 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
627 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
629 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
631 length=strlen(DocumentCustomColors);
632 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
633 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
634 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
637 property[MaxTextExtent],
646 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
647 (double) (spotcolor++));
648 for (p=command; *p != '\0'; p++)
649 if (isspace((int) (unsigned char) *p) != 0)
651 value=AcquireString(p);
652 (void) SubstituteString(&value,"(","");
653 (void) SubstituteString(&value,")","");
654 (void) StripString(value);
655 (void) SetImageProperty(image,property,value,exception);
656 value=DestroyString(value);
659 if (image_info->page != (char *) NULL)
662 Note region defined by bounding box.
666 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
668 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
669 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
672 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
674 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
675 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
678 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
680 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
681 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
684 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
686 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
687 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
690 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
692 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
693 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
696 if ((count != 4) || (i < (ssize_t) priority))
698 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
699 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
700 if (i == (ssize_t) priority)
705 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
706 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
709 Set Postscript render geometry.
711 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
712 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
713 hires_bounds.x1,hires_bounds.y1);
714 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
715 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
716 resolution.x/delta.x)-0.5);
717 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
718 resolution.y/delta.y)-0.5);
720 (void) CloseBlob(image);
721 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
724 Create Ghostscript control file.
726 file=AcquireUniqueFileResource(postscript_filename);
729 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
730 image_info->filename);
731 image=DestroyImageList(image);
732 return((Image *) NULL);
734 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
735 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
736 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
737 count=write(file,command,(unsigned int) strlen(command));
738 if (image_info->page == (char *) NULL)
741 translate_geometry[MaxTextExtent];
743 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
744 "%g %g translate\n",-bounds.x1,-bounds.y1);
745 count=write(file,translate_geometry,(unsigned int)
746 strlen(translate_geometry));
750 Render Postscript with the Ghostscript delegate.
752 if (image_info->monochrome != MagickFalse)
753 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
755 if (cmyk != MagickFalse)
756 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
758 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
759 if (delegate_info == (const DelegateInfo *) NULL)
761 (void) RelinquishUniqueFileResource(postscript_filename);
762 image=DestroyImageList(image);
763 return((Image *) NULL);
766 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",resolution.x,
768 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
769 page.width,(double) page.height);
770 read_info=CloneImageInfo(image_info);
771 *read_info->magick='\0';
772 if (read_info->number_scenes != 0)
775 pages[MaxTextExtent];
777 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
778 "-dLastPage=%.20g ",(double) read_info->scene+1,(double)
779 (read_info->scene+read_info->number_scenes));
780 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
781 read_info->number_scenes=0;
782 if (read_info->scenes != (char *) NULL)
783 *read_info->scenes='\0';
785 option=GetImageOption(image_info,"eps:use-cropbox");
786 if ((*image_info->magick == 'E') && ((option == (const char *) NULL) ||
787 (IsStringTrue(option) != MagickFalse)))
788 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
789 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
790 (void) AcquireUniqueFilename(filename);
791 (void) ConcatenateMagickString(filename,"%d",MaxTextExtent);
792 (void) FormatLocaleString(command,MaxTextExtent,
793 GetDelegateCommands(delegate_info),
794 read_info->antialias != MagickFalse ? 4 : 1,
795 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
796 postscript_filename,input_filename);
797 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
798 (void) InterpretImageFilename(image_info,image,filename,1,
799 read_info->filename,exception);
800 if ((status == MagickFalse) ||
801 (IsPostscriptRendered(read_info->filename) == MagickFalse))
803 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
804 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
806 (void) RelinquishUniqueFileResource(postscript_filename);
807 (void) RelinquishUniqueFileResource(input_filename);
808 postscript_image=(Image *) NULL;
809 if (status == MagickFalse)
812 (void) InterpretImageFilename(image_info,image,filename,(int) i,
813 read_info->filename,exception);
814 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
816 (void) RelinquishUniqueFileResource(read_info->filename);
821 (void) InterpretImageFilename(image_info,image,filename,(int) i,
822 read_info->filename,exception);
823 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
825 read_info->blob=NULL;
827 next=ReadImage(read_info,exception);
828 (void) RelinquishUniqueFileResource(read_info->filename);
829 if (next == (Image *) NULL)
831 AppendImageToList(&postscript_image,next);
833 (void) RelinquishUniqueFileResource(read_info->filename);
834 read_info=DestroyImageInfo(read_info);
835 if (postscript_image == (Image *) NULL)
837 image=DestroyImageList(image);
838 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
839 image_info->filename);
840 return((Image *) NULL);
842 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
847 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
848 if (cmyk_image != (Image *) NULL)
850 postscript_image=DestroyImageList(postscript_image);
851 postscript_image=cmyk_image;
854 if (image_info->number_scenes != 0)
863 Add place holder images to meet the subimage specification requirement.
865 for (i=0; i < (ssize_t) image_info->scene; i++)
867 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
868 if (clone_image != (Image *) NULL)
869 PrependImageToList(&postscript_image,clone_image);
874 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
876 postscript_image->magick_columns=columns;
878 postscript_image->magick_rows=rows;
879 postscript_image->page=page;
880 (void) CloneImageProfiles(postscript_image,image);
881 (void) CloneImageProperties(postscript_image,image);
882 next=SyncNextImageInList(postscript_image);
883 if (next != (Image *) NULL)
884 postscript_image=next;
885 } while (next != (Image *) NULL);
886 image=DestroyImageList(image);
888 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
891 next=GetNextImageInList(next);
893 return(GetFirstImageInList(postscript_image));
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 % R e g i s t e r P S I m a g e %
905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907 % RegisterPSImage() adds properties for the PS image format to
908 % the list of supported formats. The properties include the image format
909 % tag, a method to read and/or write the format, whether the format
910 % supports the saving of more than one frame to the same file or blob,
911 % whether the format supports native in-memory I/O, and a brief
912 % description of the format.
914 % The format of the RegisterPSImage method is:
916 % size_t RegisterPSImage(void)
919 ModuleExport size_t RegisterPSImage(void)
924 entry=SetMagickInfo("EPI");
925 entry->decoder=(DecodeImageHandler *) ReadPSImage;
926 entry->encoder=(EncodeImageHandler *) WritePSImage;
927 entry->magick=(IsImageFormatHandler *) IsPS;
928 entry->adjoin=MagickFalse;
929 entry->blob_support=MagickFalse;
930 entry->seekable_stream=MagickTrue;
931 entry->description=ConstantString(
932 "Encapsulated PostScript Interchange format");
933 entry->mime_type=ConstantString("application/postscript");
934 entry->module=ConstantString("PS");
935 (void) RegisterMagickInfo(entry);
936 entry=SetMagickInfo("EPS");
937 entry->decoder=(DecodeImageHandler *) ReadPSImage;
938 entry->encoder=(EncodeImageHandler *) WritePSImage;
939 entry->magick=(IsImageFormatHandler *) IsPS;
940 entry->adjoin=MagickFalse;
941 entry->blob_support=MagickFalse;
942 entry->seekable_stream=MagickTrue;
943 entry->description=ConstantString("Encapsulated PostScript");
944 entry->mime_type=ConstantString("application/postscript");
945 entry->module=ConstantString("PS");
946 (void) RegisterMagickInfo(entry);
947 entry=SetMagickInfo("EPSF");
948 entry->decoder=(DecodeImageHandler *) ReadPSImage;
949 entry->encoder=(EncodeImageHandler *) WritePSImage;
950 entry->magick=(IsImageFormatHandler *) IsPS;
951 entry->adjoin=MagickFalse;
952 entry->blob_support=MagickFalse;
953 entry->seekable_stream=MagickTrue;
954 entry->description=ConstantString("Encapsulated PostScript");
955 entry->mime_type=ConstantString("application/postscript");
956 entry->module=ConstantString("PS");
957 (void) RegisterMagickInfo(entry);
958 entry=SetMagickInfo("EPSI");
959 entry->decoder=(DecodeImageHandler *) ReadPSImage;
960 entry->encoder=(EncodeImageHandler *) WritePSImage;
961 entry->magick=(IsImageFormatHandler *) IsPS;
962 entry->adjoin=MagickFalse;
963 entry->blob_support=MagickFalse;
964 entry->seekable_stream=MagickTrue;
965 entry->description=ConstantString(
966 "Encapsulated PostScript Interchange format");
967 entry->mime_type=ConstantString("application/postscript");
968 entry->module=ConstantString("PS");
969 (void) RegisterMagickInfo(entry);
970 entry=SetMagickInfo("PS");
971 entry->decoder=(DecodeImageHandler *) ReadPSImage;
972 entry->encoder=(EncodeImageHandler *) WritePSImage;
973 entry->magick=(IsImageFormatHandler *) IsPS;
974 entry->mime_type=ConstantString("application/postscript");
975 entry->module=ConstantString("PS");
976 entry->blob_support=MagickFalse;
977 entry->seekable_stream=MagickTrue;
978 entry->description=ConstantString("PostScript");
979 (void) RegisterMagickInfo(entry);
980 return(MagickImageCoderSignature);
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % U n r e g i s t e r P S I m a g e %
992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994 % UnregisterPSImage() removes format registrations made by the
995 % PS module from the list of supported formats.
997 % The format of the UnregisterPSImage method is:
999 % UnregisterPSImage(void)
1002 ModuleExport void UnregisterPSImage(void)
1004 (void) UnregisterMagickInfo("EPI");
1005 (void) UnregisterMagickInfo("EPS");
1006 (void) UnregisterMagickInfo("EPSF");
1007 (void) UnregisterMagickInfo("EPSI");
1008 (void) UnregisterMagickInfo("PS");
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % W r i t e P S I m a g e %
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 % WritePSImage translates an image to encapsulated Postscript
1023 % Level I for printing. If the supplied geometry is null, the image is
1024 % centered on the Postscript page. Otherwise, the image is positioned as
1025 % specified by the geometry.
1027 % The format of the WritePSImage method is:
1029 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
1030 % Image *image,ExceptionInfo *exception)
1032 % A description of each parameter follows:
1034 % o image_info: the image info.
1036 % o image: the image.
1038 % o exception: return any errors or warnings in this structure.
1042 static inline size_t MagickMin(const size_t x,const size_t y)
1049 static inline unsigned char *PopHexPixel(const char **hex_digits,
1050 const size_t pixel,unsigned char *pixels)
1055 hex=hex_digits[pixel];
1056 *pixels++=(unsigned char) (*hex++);
1057 *pixels++=(unsigned char) (*hex);
1061 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1062 ExceptionInfo *exception)
1064 #define WriteRunlengthPacket(image,pixel,length,p) \
1066 if ((image->alpha_trait == BlendPixelTrait) && \
1067 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1069 q=PopHexPixel(hex_digits,0xff,q); \
1070 q=PopHexPixel(hex_digits,0xff,q); \
1071 q=PopHexPixel(hex_digits,0xff,q); \
1075 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.red)),q); \
1076 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.green)),q); \
1077 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.blue)),q); \
1079 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1085 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1086 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1087 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1088 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1089 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1090 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1091 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1092 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1093 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1094 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1095 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1096 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1097 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1098 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1099 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1100 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1101 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1102 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1103 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1104 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1105 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1106 "FC", "FD", "FE", "FF", (char *) NULL
1108 *PostscriptProlog[]=
1112 "% Display a color image. The image is displayed in color on",
1113 "% Postscript viewers or printers that support color, otherwise",
1114 "% it is displayed as grayscale.",
1116 "/DirectClassPacket",
1119 " % Get a DirectClass packet.",
1125 " % length: number of pixels minus one of this color (optional).",
1127 " currentfile color_packet readhexstring pop pop",
1128 " compression 0 eq",
1130 " /number_pixels 3 def",
1133 " currentfile byte readhexstring pop 0 get",
1134 " /number_pixels exch 1 add 3 mul def",
1136 " 0 3 number_pixels 1 sub",
1138 " pixels exch color_packet putinterval",
1140 " pixels 0 number_pixels getinterval",
1143 "/DirectClassImage",
1146 " % Display a DirectClass image.",
1148 " systemdict /colorimage known",
1155 " { DirectClassPacket } false 3 colorimage",
1159 " % No colorimage operator; convert to grayscale.",
1166 " { GrayDirectClassPacket } image",
1170 "/GrayDirectClassPacket",
1173 " % Get a DirectClass packet; convert to grayscale.",
1179 " % length: number of pixels minus one of this color (optional).",
1181 " currentfile color_packet readhexstring pop pop",
1182 " color_packet 0 get 0.299 mul",
1183 " color_packet 1 get 0.587 mul add",
1184 " color_packet 2 get 0.114 mul add",
1186 " /gray_packet exch def",
1187 " compression 0 eq",
1189 " /number_pixels 1 def",
1192 " currentfile byte readhexstring pop 0 get",
1193 " /number_pixels exch 1 add def",
1195 " 0 1 number_pixels 1 sub",
1197 " pixels exch gray_packet put",
1199 " pixels 0 number_pixels getinterval",
1202 "/GrayPseudoClassPacket",
1205 " % Get a PseudoClass packet; convert to grayscale.",
1208 " % index: index into the colormap.",
1209 " % length: number of pixels minus one of this color (optional).",
1211 " currentfile byte readhexstring pop 0 get",
1212 " /offset exch 3 mul def",
1213 " /color_packet colormap offset 3 getinterval def",
1214 " color_packet 0 get 0.299 mul",
1215 " color_packet 1 get 0.587 mul add",
1216 " color_packet 2 get 0.114 mul add",
1218 " /gray_packet exch def",
1219 " compression 0 eq",
1221 " /number_pixels 1 def",
1224 " currentfile byte readhexstring pop 0 get",
1225 " /number_pixels exch 1 add def",
1227 " 0 1 number_pixels 1 sub",
1229 " pixels exch gray_packet put",
1231 " pixels 0 number_pixels getinterval",
1234 "/PseudoClassPacket",
1237 " % Get a PseudoClass packet.",
1240 " % index: index into the colormap.",
1241 " % length: number of pixels minus one of this color (optional).",
1243 " currentfile byte readhexstring pop 0 get",
1244 " /offset exch 3 mul def",
1245 " /color_packet colormap offset 3 getinterval def",
1246 " compression 0 eq",
1248 " /number_pixels 3 def",
1251 " currentfile byte readhexstring pop 0 get",
1252 " /number_pixels exch 1 add 3 mul def",
1254 " 0 3 number_pixels 1 sub",
1256 " pixels exch color_packet putinterval",
1258 " pixels 0 number_pixels getinterval",
1261 "/PseudoClassImage",
1264 " % Display a PseudoClass image.",
1267 " % class: 0-PseudoClass or 1-Grayscale.",
1269 " currentfile buffer readline pop",
1270 " token pop /class exch def pop",
1273 " currentfile buffer readline pop",
1274 " token pop /depth exch def pop",
1275 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1276 " columns rows depth",
1281 " { currentfile grays readhexstring pop } image",
1286 " % colors: number of colors in the colormap.",
1287 " % colormap: red, green, blue color packets.",
1289 " currentfile buffer readline pop",
1290 " token pop /colors exch def pop",
1291 " /colors colors 3 mul def",
1292 " /colormap colors string def",
1293 " currentfile colormap readhexstring pop pop",
1294 " systemdict /colorimage known",
1301 " { PseudoClassPacket } false 3 colorimage",
1305 " % No colorimage operator; convert to grayscale.",
1312 " { GrayPseudoClassPacket } image",
1320 " % Display a DirectClass or PseudoClass image.",
1323 " % x & y translation.",
1325 " % label pointsize.",
1327 " % image columns & rows.",
1328 " % class: 0-DirectClass or 1-PseudoClass.",
1329 " % compression: 0-none or 1-RunlengthEncoded.",
1330 " % hex color packets.",
1333 " /buffer 512 string def",
1334 " /byte 1 string def",
1335 " /color_packet 3 string def",
1336 " /pixels 768 string def",
1338 " currentfile buffer readline pop",
1339 " token pop /x exch def",
1340 " token pop /y exch def pop",
1342 " currentfile buffer readline pop",
1343 " token pop /x exch def",
1344 " token pop /y exch def pop",
1345 " currentfile buffer readline pop",
1346 " token pop /pointsize exch def pop",
1347 " /Times-Roman findfont pointsize scalefont setfont",
1350 *PostscriptEpilog[]=
1353 " currentfile buffer readline pop",
1354 " token pop /columns exch def",
1355 " token pop /rows exch def pop",
1356 " currentfile buffer readline pop",
1357 " token pop /class exch def pop",
1358 " currentfile buffer readline pop",
1359 " token pop /compression exch def pop",
1360 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1366 buffer[MaxTextExtent],
1367 date[MaxTextExtent],
1369 page_geometry[MaxTextExtent];
1412 register const Quantum
1419 register unsigned char
1443 Open output image file.
1445 assert(image_info != (const ImageInfo *) NULL);
1446 assert(image_info->signature == MagickSignature);
1447 assert(image != (Image *) NULL);
1448 assert(image->signature == MagickSignature);
1449 if (image->debug != MagickFalse)
1450 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1451 assert(exception != (ExceptionInfo *) NULL);
1452 assert(exception->signature == MagickSignature);
1453 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1454 if (status == MagickFalse)
1456 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1457 compression=image->compression;
1458 if (image_info->compression != UndefinedCompression)
1459 compression=image_info->compression;
1465 Scale relative to dots-per-inch.
1467 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1468 delta.x=DefaultResolution;
1469 delta.y=DefaultResolution;
1470 resolution.x=image->resolution.x;
1471 resolution.y=image->resolution.y;
1472 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1474 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1475 resolution.x=geometry_info.rho;
1476 resolution.y=geometry_info.sigma;
1477 if ((flags & SigmaValue) == 0)
1478 resolution.y=resolution.x;
1480 if (image_info->density != (char *) NULL)
1482 flags=ParseGeometry(image_info->density,&geometry_info);
1483 resolution.x=geometry_info.rho;
1484 resolution.y=geometry_info.sigma;
1485 if ((flags & SigmaValue) == 0)
1486 resolution.y=resolution.x;
1488 if (image->units == PixelsPerCentimeterResolution)
1490 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1491 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1493 SetGeometry(image,&geometry);
1494 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1495 (double) image->columns,(double) image->rows);
1496 if (image_info->page != (char *) NULL)
1497 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1499 if ((image->page.width != 0) && (image->page.height != 0))
1500 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1501 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1502 image->page.height,(double) image->page.x,(double) image->page.y);
1504 if ((image->gravity != UndefinedGravity) &&
1505 (LocaleCompare(image_info->magick,"PS") == 0))
1506 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1507 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1508 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1509 &geometry.width,&geometry.height);
1510 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1511 geometry.width=(size_t) floor(scale.x+0.5);
1512 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1513 geometry.height=(size_t) floor(scale.y+0.5);
1514 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1515 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1516 if (image->gravity != UndefinedGravity)
1518 geometry.x=(-page_info.x);
1519 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1522 if (image_info->pointsize != 0.0)
1523 pointsize=image_info->pointsize;
1525 value=GetImageProperty(image,"label",exception);
1526 if (value != (const char *) NULL)
1527 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1531 Output Postscript header.
1533 if (LocaleCompare(image_info->magick,"PS") == 0)
1534 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1536 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1538 (void) WriteBlobString(image,buffer);
1539 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1540 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1542 (void) WriteBlobString(image,buffer);
1543 timer=time((time_t *) NULL);
1544 (void) FormatMagickTime(timer,MaxTextExtent,date);
1545 (void) FormatLocaleString(buffer,MaxTextExtent,
1546 "%%%%CreationDate: (%s)\n",date);
1547 (void) WriteBlobString(image,buffer);
1548 bounds.x1=(double) geometry.x;
1549 bounds.y1=(double) geometry.y;
1550 bounds.x2=(double) geometry.x+scale.x;
1551 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1552 if ((image_info->adjoin != MagickFalse) &&
1553 (GetNextImageInList(image) != (Image *) NULL))
1554 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1558 (void) FormatLocaleString(buffer,MaxTextExtent,
1559 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1560 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1561 (void) WriteBlobString(image,buffer);
1562 (void) FormatLocaleString(buffer,MaxTextExtent,
1563 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1564 bounds.y1,bounds.x2,bounds.y2);
1566 (void) WriteBlobString(image,buffer);
1567 profile=GetImageProfile(image,"8bim");
1568 if (profile != (StringInfo *) NULL)
1571 Embed Photoshop profile.
1573 (void) FormatLocaleString(buffer,MaxTextExtent,
1574 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1575 (void) WriteBlobString(image,buffer);
1576 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1579 (void) WriteBlobString(image,"\n% ");
1580 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1581 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1582 (void) WriteBlobString(image,buffer);
1584 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1586 profile=GetImageProfile(image,"xmp");
1587 DisableMSCWarning(4127)
1588 if (0 && (profile != (StringInfo *) NULL))
1594 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1595 (void) FormatLocaleString(buffer,MaxTextExtent,
1596 "\n%%begin_xml_packet: %.20g\n",(double)
1597 GetStringInfoLength(profile));
1598 (void) WriteBlobString(image,buffer);
1599 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1600 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1601 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1603 value=GetImageProperty(image,"label",exception);
1604 if (value != (const char *) NULL)
1605 (void) WriteBlobString(image,
1606 "%%DocumentNeededResources: font Times-Roman\n");
1607 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1608 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1609 if (LocaleCompare(image_info->magick,"PS") != 0)
1610 (void) WriteBlobString(image,"%%Pages: 1\n");
1614 Compute the number of pages.
1616 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1617 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1618 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1619 image_info->adjoin != MagickFalse ? (double)
1620 GetImageListLength(image) : 1.0);
1621 (void) WriteBlobString(image,buffer);
1623 (void) WriteBlobString(image,"%%EndComments\n");
1624 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1625 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1626 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1627 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1628 (LocaleCompare(image_info->magick,"EPT") == 0))
1643 Create preview image.
1645 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1646 if (preview_image == (Image *) NULL)
1647 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1649 Dump image as bitmap.
1651 (void) FormatLocaleString(buffer,MaxTextExtent,
1652 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1653 preview_image->columns,(double) preview_image->rows,1.0,
1654 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1656 (void) WriteBlobString(image,buffer);
1658 for (y=0; y < (ssize_t) image->rows; y++)
1660 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1662 if (p == (const Quantum *) NULL)
1666 for (x=0; x < (ssize_t) preview_image->columns; x++)
1669 pixel=ClampToQuantum(GetPixelLuma(preview_image,p));
1670 if (pixel >= (Quantum) (QuantumRange/2))
1675 q=PopHexPixel(hex_digits,byte,q);
1676 if ((q-pixels+8) >= 80)
1679 (void) WriteBlob(image,q-pixels,pixels);
1681 (void) WriteBlobString(image,"% ");
1690 q=PopHexPixel(hex_digits,byte,q);
1691 if ((q-pixels+8) >= 80)
1694 (void) WriteBlob(image,q-pixels,pixels);
1696 (void) WriteBlobString(image,"% ");
1703 (void) WriteBlob(image,q-pixels,pixels);
1705 (void) WriteBlobString(image,"\n%%EndPreview\n");
1706 preview_image=DestroyImage(preview_image);
1709 Output Postscript commands.
1711 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1713 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1714 (void) WriteBlobString(image,buffer);
1716 value=GetImageProperty(image,"label",exception);
1717 if (value != (const char *) NULL)
1718 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1720 (void) WriteBlobString(image," /label 512 string def\n");
1721 (void) WriteBlobString(image," currentfile label readline pop\n");
1722 (void) FormatLocaleString(buffer,MaxTextExtent,
1723 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1724 (void) WriteBlobString(image,buffer);
1726 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1728 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1729 (void) WriteBlobString(image,buffer);
1731 if (LocaleCompare(image_info->magick,"PS") == 0)
1732 (void) WriteBlobString(image," showpage\n");
1733 (void) WriteBlobString(image,"} bind def\n");
1734 (void) WriteBlobString(image,"%%EndProlog\n");
1736 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1738 (void) WriteBlobString(image,buffer);
1739 (void) FormatLocaleString(buffer,MaxTextExtent,
1740 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1741 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1742 (geometry.height+text_size));
1743 (void) WriteBlobString(image,buffer);
1744 if ((double) geometry.x < bounds.x1)
1745 bounds.x1=(double) geometry.x;
1746 if ((double) geometry.y < bounds.y1)
1747 bounds.y1=(double) geometry.y;
1748 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1749 bounds.x2=(double) geometry.x+geometry.width-1;
1750 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1751 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1752 value=GetImageProperty(image,"label",exception);
1753 if (value != (const char *) NULL)
1754 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1755 if (LocaleCompare(image_info->magick,"PS") != 0)
1756 (void) WriteBlobString(image,"userdict begin\n");
1757 (void) WriteBlobString(image,"DisplayImage\n");
1761 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1762 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1763 (void) WriteBlobString(image,buffer);
1764 labels=(char **) NULL;
1765 value=GetImageProperty(image,"label",exception);
1766 if (value != (const char *) NULL)
1767 labels=StringToList(value);
1768 if (labels != (char **) NULL)
1770 for (i=0; labels[i] != (char *) NULL; i++)
1772 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1774 (void) WriteBlobString(image,buffer);
1775 labels[i]=DestroyString(labels[i]);
1777 labels=(char **) RelinquishMagickMemory(labels);
1779 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1780 pixel.alpha=(MagickRealType) TransparentAlpha;
1783 if ((image_info->type != TrueColorType) &&
1784 (IsImageGray(image,exception) != MagickFalse))
1786 if (IsImageMonochrome(image,exception) == MagickFalse)
1792 Dump image as grayscale.
1794 (void) FormatLocaleString(buffer,MaxTextExtent,
1795 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1797 (void) WriteBlobString(image,buffer);
1799 for (y=0; y < (ssize_t) image->rows; y++)
1801 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1802 if (p == (const Quantum *) NULL)
1804 for (x=0; x < (ssize_t) image->columns; x++)
1806 pixel=(Quantum) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
1808 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1810 if ((q-pixels+8) >= 80)
1813 (void) WriteBlob(image,q-pixels,pixels);
1816 p+=GetPixelChannels(image);
1818 if (image->previous == (Image *) NULL)
1820 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1822 if (status == MagickFalse)
1829 (void) WriteBlob(image,q-pixels,pixels);
1841 Dump image as bitmap.
1843 (void) FormatLocaleString(buffer,MaxTextExtent,
1844 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1846 (void) WriteBlobString(image,buffer);
1848 for (y=0; y < (ssize_t) image->rows; y++)
1850 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1851 if (p == (const Quantum *) NULL)
1855 for (x=0; x < (ssize_t) image->columns; x++)
1858 pixel=ClampToQuantum(GetPixelLuma(image,p));
1859 if (pixel >= (Quantum) (QuantumRange/2))
1864 q=PopHexPixel(hex_digits,byte,q);
1865 if ((q-pixels+2) >= 80)
1868 (void) WriteBlob(image,q-pixels,pixels);
1874 p+=GetPixelChannels(image);
1879 q=PopHexPixel(hex_digits,byte,q);
1880 if ((q-pixels+2) >= 80)
1883 (void) WriteBlob(image,q-pixels,pixels);
1887 if (image->previous == (Image *) NULL)
1889 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1891 if (status == MagickFalse)
1898 (void) WriteBlob(image,q-pixels,pixels);
1903 if ((image->storage_class == DirectClass) ||
1904 (image->colors > 256) || (image->alpha_trait == BlendPixelTrait))
1907 Dump DirectClass image.
1909 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1910 (double) image->columns,(double) image->rows,
1911 compression == RLECompression ? 1 : 0);
1912 (void) WriteBlobString(image,buffer);
1913 switch (compression)
1915 case RLECompression:
1918 Dump runlength-encoded DirectColor packets.
1921 for (y=0; y < (ssize_t) image->rows; y++)
1923 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1924 if (p == (const Quantum *) NULL)
1926 GetPixelInfoPixel(image,p,&pixel);
1928 for (x=0; x < (ssize_t) image->columns; x++)
1930 if ((GetPixelRed(image,p) == ClampToQuantum(pixel.red)) &&
1931 (GetPixelGreen(image,p) == ClampToQuantum(pixel.green)) &&
1932 (GetPixelBlue(image,p) == ClampToQuantum(pixel.blue)) &&
1933 (GetPixelAlpha(image,p) == ClampToQuantum(pixel.alpha)) &&
1934 (length < 255) && (x < (ssize_t) (image->columns-1)))
1940 WriteRunlengthPacket(image,pixel,length,p);
1941 if ((q-pixels+10) >= 80)
1944 (void) WriteBlob(image,q-pixels,pixels);
1950 GetPixelInfoPixel(image,p,&pixel);
1951 p+=GetPixelChannels(image);
1953 WriteRunlengthPacket(image,pixel,length,p);
1954 if ((q-pixels+10) >= 80)
1957 (void) WriteBlob(image,q-pixels,pixels);
1960 if (image->previous == (Image *) NULL)
1962 status=SetImageProgress(image,SaveImageTag,
1963 (MagickOffsetType) y,image->rows);
1964 if (status == MagickFalse)
1971 (void) WriteBlob(image,q-pixels,pixels);
1979 Dump uncompressed DirectColor packets.
1982 for (y=0; y < (ssize_t) image->rows; y++)
1984 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1985 if (p == (const Quantum *) NULL)
1987 for (x=0; x < (ssize_t) image->columns; x++)
1989 if ((image->alpha_trait == BlendPixelTrait) &&
1990 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1992 q=PopHexPixel(hex_digits,0xff,q);
1993 q=PopHexPixel(hex_digits,0xff,q);
1994 q=PopHexPixel(hex_digits,0xff,q);
1998 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1999 GetPixelRed(image,p)),q);
2000 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2001 GetPixelGreen(image,p)),q);
2002 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
2003 GetPixelBlue(image,p)),q);
2005 if ((q-pixels+6) >= 80)
2008 (void) WriteBlob(image,q-pixels,pixels);
2011 p+=GetPixelChannels(image);
2013 if (image->previous == (Image *) NULL)
2015 status=SetImageProgress(image,SaveImageTag,
2016 (MagickOffsetType) y,image->rows);
2017 if (status == MagickFalse)
2024 (void) WriteBlob(image,q-pixels,pixels);
2029 (void) WriteBlobByte(image,'\n');
2034 Dump PseudoClass image.
2036 (void) FormatLocaleString(buffer,MaxTextExtent,
2037 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2038 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2039 compression == RLECompression ? 1 : 0);
2040 (void) WriteBlobString(image,buffer);
2042 Dump number of colors and colormap.
2044 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2046 (void) WriteBlobString(image,buffer);
2047 for (i=0; i < (ssize_t) image->colors; i++)
2049 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2050 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)),
2051 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)),
2052 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue)));
2053 (void) WriteBlobString(image,buffer);
2055 switch (compression)
2057 case RLECompression:
2060 Dump runlength-encoded PseudoColor packets.
2063 for (y=0; y < (ssize_t) image->rows; y++)
2065 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2066 if (p == (const Quantum *) NULL)
2068 index=GetPixelIndex(image,p);
2070 for (x=0; x < (ssize_t) image->columns; x++)
2072 if ((index == GetPixelIndex(image,p)) &&
2073 (length < 255) && (x < ((ssize_t) image->columns-1)))
2079 q=PopHexPixel(hex_digits,(size_t) index,q);
2080 q=PopHexPixel(hex_digits,(size_t)
2081 MagickMin(length,0xff),q);
2083 if ((q-pixels+6) >= 80)
2086 (void) WriteBlob(image,q-pixels,pixels);
2092 index=GetPixelIndex(image,p);
2093 pixel.red=(MagickRealType) GetPixelRed(image,p);
2094 pixel.green=(MagickRealType) GetPixelGreen(image,p);
2095 pixel.blue=(MagickRealType) GetPixelBlue(image,p);
2096 pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
2097 p+=GetPixelChannels(image);
2099 q=PopHexPixel(hex_digits,(size_t) index,q);
2100 q=PopHexPixel(hex_digits,(size_t)
2101 MagickMin(length,0xff),q);
2102 if (image->previous == (Image *) NULL)
2104 status=SetImageProgress(image,SaveImageTag,
2105 (MagickOffsetType) y,image->rows);
2106 if (status == MagickFalse)
2113 (void) WriteBlob(image,q-pixels,pixels);
2121 Dump uncompressed PseudoColor packets.
2124 for (y=0; y < (ssize_t) image->rows; y++)
2126 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2127 if (p == (const Quantum *) NULL)
2129 for (x=0; x < (ssize_t) image->columns; x++)
2131 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2132 if ((q-pixels+4) >= 80)
2135 (void) WriteBlob(image,q-pixels,pixels);
2138 p+=GetPixelChannels(image);
2140 if (image->previous == (Image *) NULL)
2142 status=SetImageProgress(image,SaveImageTag,
2143 (MagickOffsetType) y,image->rows);
2144 if (status == MagickFalse)
2151 (void) WriteBlob(image,q-pixels,pixels);
2156 (void) WriteBlobByte(image,'\n');
2158 if (LocaleCompare(image_info->magick,"PS") != 0)
2159 (void) WriteBlobString(image,"end\n");
2160 (void) WriteBlobString(image,"%%PageTrailer\n");
2161 if (GetNextImageInList(image) == (Image *) NULL)
2163 image=SyncNextImageInList(image);
2164 status=SetImageProgress(image,SaveImagesTag,scene++,
2165 GetImageListLength(image));
2166 if (status == MagickFalse)
2168 } while (image_info->adjoin != MagickFalse);
2169 (void) WriteBlobString(image,"%%Trailer\n");
2172 (void) FormatLocaleString(buffer,MaxTextExtent,
2173 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2174 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5));
2175 (void) WriteBlobString(image,buffer);
2176 (void) FormatLocaleString(buffer,MaxTextExtent,
2177 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2179 (void) WriteBlobString(image,buffer);
2181 (void) WriteBlobString(image,"%%EOF\n");
2182 (void) CloseBlob(image);