2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2012 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/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/delegate-private.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/magick.h"
62 #include "MagickCore/memory_.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/resource_.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum-private.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/token.h"
75 #include "MagickCore/transform.h"
76 #include "MagickCore/utility.h"
81 static MagickBooleanType
82 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *);
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 % I n v o k e P o s t s r i p t D e l e g a t e %
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 % InvokePostscriptDelegate() executes the Postscript interpreter with the
98 % The format of the InvokePostscriptDelegate method is:
100 % MagickBooleanType InvokePostscriptDelegate(
101 % const MagickBooleanType verbose,const char *command,
102 % ExceptionInfo *exception)
104 % A description of each parameter follows:
106 % o verbose: A value other than zero displays the command prior to
109 % o command: the address of a character string containing the command to
112 % o exception: return any errors or warnings in this structure.
115 static MagickBooleanType InvokePostscriptDelegate(
116 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
121 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
138 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
139 ghost_info=NTGhostscriptDLLVectors();
144 ghost_info=(&ghost_info_struct);
145 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
146 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
148 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
149 gsapi_init_with_args;
150 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
151 int *)) gsapi_run_string;
152 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
153 gsapi_delete_instance;
154 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
156 if (ghost_info == (GhostInfo *) NULL)
158 status=SystemCommand(MagickFalse,verbose,command,exception);
159 return(status == 0 ? MagickTrue : MagickFalse);
161 if (verbose != MagickFalse)
163 (void) fputs("[ghostscript library]",stdout);
164 (void) fputs(strchr(command,' '),stdout);
166 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
169 status=SystemCommand(MagickFalse,verbose,command,exception);
170 return(status == 0 ? MagickTrue : MagickFalse);
173 argv=StringToArgv(command,&argc);
174 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
176 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
178 (ghost_info->exit)(interpreter);
179 (ghost_info->delete_instance)(interpreter);
180 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
181 NTGhostscriptUnLoadDLL();
183 for (i=0; i < (ssize_t) argc; i++)
184 argv[i]=DestroyString(argv[i]);
185 argv=(char **) RelinquishMagickMemory(argv);
186 if ((status != 0) && (status != -101))
191 message=GetExceptionMessage(errno);
192 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
193 "`%s': %s",command,message);
194 message=DestroyString(message);
195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
196 "Ghostscript returns status %d, exit code %d",status,code);
201 status=SystemCommand(MagickFalse,verbose,command,exception);
202 return(status == 0 ? MagickTrue : MagickFalse);
207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % IsPS() returns MagickTrue if the image format type, identified by the
218 % magick string, is PS.
220 % The format of the IsPS method is:
222 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
224 % A description of each parameter follows:
226 % o magick: compare image format pattern against these bytes.
228 % o length: Specifies the length of the magick string.
231 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
235 if (memcmp(magick,"%!",2) == 0)
237 if (memcmp(magick,"\004%!",3) == 0)
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 % R e a d P S I m a g e %
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 % ReadPSImage() reads a Postscript image file and returns it. It allocates
254 % the memory necessary for the new Image structure and returns a pointer
257 % The format of the ReadPSImage method is:
259 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
261 % A description of each parameter follows:
263 % o image_info: the image info.
265 % o exception: return any errors or warnings in this structure.
269 static MagickBooleanType IsPostscriptRendered(const char *path)
277 if ((path == (const char *) NULL) || (*path == '\0'))
279 status=GetPathAttributes(path,&attributes);
280 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
281 (attributes.st_size > 0))
286 static inline int ProfileInteger(Image *image,short int *hex_digits)
300 c=ReadBlobByte(image);
301 if ((c == EOF) || ((c == '%') && (l == '%')))
308 if (isxdigit(c) == MagickFalse)
310 value=(int) ((size_t) value << 4)+hex_digits[c];
316 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
318 #define BoundingBox "BoundingBox:"
319 #define BeginDocument "BeginDocument:"
320 #define BeginXMPPacket "<?xpacket begin="
321 #define EndXMPPacket "<?xpacket end="
322 #define ICCProfile "BeginICCProfile:"
323 #define CMYKCustomColor "CMYKCustomColor:"
324 #define CMYKProcessColor "CMYKProcessColor:"
325 #define DocumentMedia "DocumentMedia:"
326 #define DocumentCustomColors "DocumentCustomColors:"
327 #define DocumentProcessColors "DocumentProcessColors:"
328 #define EndDocument "EndDocument:"
329 #define HiResBoundingBox "HiResBoundingBox:"
330 #define ImageData "ImageData:"
331 #define PageBoundingBox "PageBoundingBox:"
332 #define LanguageLevel "LanguageLevel:"
333 #define PageMedia "PageMedia:"
334 #define Pages "Pages:"
335 #define PhotoshopProfile "BeginPhotoshop:"
336 #define PostscriptLevel "!PS-"
337 #define RenderPostscriptText " Rendering Postscript... "
338 #define SpotColor "+ "
341 command[MaxTextExtent],
342 density[MaxTextExtent],
343 filename[MaxTextExtent],
344 geometry[MaxTextExtent],
345 input_filename[MaxTextExtent],
346 options[MaxTextExtent],
347 postscript_filename[MaxTextExtent];
417 assert(image_info != (const ImageInfo *) NULL);
418 assert(image_info->signature == MagickSignature);
419 if (image_info->debug != MagickFalse)
420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
421 image_info->filename);
422 assert(exception != (ExceptionInfo *) NULL);
423 assert(exception->signature == MagickSignature);
424 image=AcquireImage(image_info,exception);
425 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
426 if (status == MagickFalse)
428 image=DestroyImageList(image);
429 return((Image *) NULL);
431 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
432 if (status == MagickFalse)
434 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
435 image_info->filename);
436 image=DestroyImageList(image);
437 return((Image *) NULL);
440 Initialize hex values.
442 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
443 hex_digits[(int) '0']=0;
444 hex_digits[(int) '1']=1;
445 hex_digits[(int) '2']=2;
446 hex_digits[(int) '3']=3;
447 hex_digits[(int) '4']=4;
448 hex_digits[(int) '5']=5;
449 hex_digits[(int) '6']=6;
450 hex_digits[(int) '7']=7;
451 hex_digits[(int) '8']=8;
452 hex_digits[(int) '9']=9;
453 hex_digits[(int) 'a']=10;
454 hex_digits[(int) 'b']=11;
455 hex_digits[(int) 'c']=12;
456 hex_digits[(int) 'd']=13;
457 hex_digits[(int) 'e']=14;
458 hex_digits[(int) 'f']=15;
459 hex_digits[(int) 'A']=10;
460 hex_digits[(int) 'B']=11;
461 hex_digits[(int) 'C']=12;
462 hex_digits[(int) 'D']=13;
463 hex_digits[(int) 'E']=14;
464 hex_digits[(int) 'F']=15;
466 Set the page density.
468 delta.x=DefaultResolution;
469 delta.y=DefaultResolution;
470 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
472 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
473 image->resolution.x=geometry_info.rho;
474 image->resolution.y=geometry_info.sigma;
475 if ((flags & SigmaValue) == 0)
476 image->resolution.y=image->resolution.x;
478 if (image_info->density != (char *) NULL)
480 flags=ParseGeometry(image_info->density,&geometry_info);
481 image->resolution.x=geometry_info.rho;
482 image->resolution.y=geometry_info.sigma;
483 if ((flags & SigmaValue) == 0)
484 image->resolution.y=image->resolution.x;
486 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
487 if (image_info->page != (char *) NULL)
488 (void) ParseAbsoluteGeometry(image_info->page,&page);
489 resolution=image->resolution;
490 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5);
491 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5);
493 Determine page geometry from the Postscript bounding box.
495 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
496 (void) ResetMagickMemory(command,0,sizeof(command));
497 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
498 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
507 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
510 Note document structuring comments.
513 if ((strchr("\n\r%",c) == (char *) NULL) &&
514 ((size_t) (p-command) < (MaxTextExtent-1)))
519 Skip %%BeginDocument thru %%EndDocument.
521 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
523 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
525 if (skip != MagickFalse)
527 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
529 (void) SetImageProperty(image,"ps:Level",command+4,exception);
530 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
533 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
534 (void) sscanf(command,LanguageLevel " %lu",&language_level);
535 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
536 (void) sscanf(command,Pages " %lu",&pages);
537 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
538 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
539 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
547 profile=AcquireStringInfo(65536);
548 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
550 SetStringInfoLength(profile,(size_t) i+1);
551 datum=GetStringInfoDatum(profile);
552 datum[i]=(unsigned char) c;
554 (void) SetImageProfile(image,"icc",profile,exception);
555 profile=DestroyStringInfo(profile);
558 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
564 Read Photoshop profile.
566 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
570 profile=BlobToStringInfo((const void *) NULL,length);
571 p=GetStringInfoDatum(profile);
572 for (i=0; i < (ssize_t) length; i++)
573 *p++=(unsigned char) ProfileInteger(image,hex_digits);
574 (void) SetImageProfile(image,"8bim",profile,exception);
575 profile=DestroyStringInfo(profile);
578 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
587 profile=StringToStringInfo(command);
588 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
590 SetStringInfoLength(profile,i+1);
591 c=ReadBlobByte(image);
592 GetStringInfoDatum(profile)[i]=(unsigned char) c;
594 if ((strchr("\n\r%",c) == (char *) NULL) &&
595 ((size_t) (p-command) < (MaxTextExtent-1)))
599 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
602 SetStringInfoLength(profile,i);
603 (void) SetImageProfile(image,"xmp",profile,exception);
604 profile=DestroyStringInfo(profile);
608 Is this a CMYK document?
610 length=strlen(DocumentProcessColors);
611 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
613 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
614 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
615 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
618 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
620 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
622 length=strlen(DocumentCustomColors);
623 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
624 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
625 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
628 property[MaxTextExtent],
637 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
638 (double) (spotcolor++));
639 for (p=command; *p != '\0'; p++)
640 if (isspace((int) (unsigned char) *p) != 0)
642 value=AcquireString(p);
643 (void) SubstituteString(&value,"(","");
644 (void) SubstituteString(&value,")","");
645 (void) StripString(value);
646 (void) SetImageProperty(image,property,value,exception);
647 value=DestroyString(value);
650 if (image_info->page != (char *) NULL)
653 Note region defined by bounding box.
657 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
659 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
660 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
663 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
665 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
666 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
669 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
671 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
672 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
675 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
677 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
678 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
681 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
683 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
684 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
687 if ((count != 4) || (i < (ssize_t) priority))
689 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
690 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
695 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
696 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
699 Set Postscript render geometry.
701 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
702 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
703 hires_bounds.x1,hires_bounds.y1);
704 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
705 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
706 resolution.x/delta.x)-0.5);
707 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
708 resolution.y/delta.y)-0.5);
710 (void) CloseBlob(image);
711 if (IssRGBColorspace(image_info->colorspace) != MagickFalse)
714 Create Ghostscript control file.
716 file=AcquireUniqueFileResource(postscript_filename);
719 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
720 image_info->filename);
721 image=DestroyImageList(image);
722 return((Image *) NULL);
724 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
725 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
726 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
727 count=write(file,command,(unsigned int) strlen(command));
728 if (image_info->page == (char *) NULL)
731 translate_geometry[MaxTextExtent];
733 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
734 "%g %g translate\n",-bounds.x1,-bounds.y1);
735 count=write(file,translate_geometry,(unsigned int)
736 strlen(translate_geometry));
740 Render Postscript with the Ghostscript delegate.
742 if (image_info->monochrome != MagickFalse)
743 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
745 if (cmyk != MagickFalse)
746 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
748 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
749 if (delegate_info == (const DelegateInfo *) NULL)
751 (void) RelinquishUniqueFileResource(postscript_filename);
752 image=DestroyImageList(image);
753 return((Image *) NULL);
756 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",resolution.x,
758 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
759 page.width,(double) page.height);
760 read_info=CloneImageInfo(image_info);
761 *read_info->magick='\0';
762 if (read_info->number_scenes != 0)
765 pages[MaxTextExtent];
767 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
768 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
769 (read_info->scene+read_info->number_scenes));
770 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
771 read_info->number_scenes=0;
772 if (read_info->scenes != (char *) NULL)
773 *read_info->scenes='\0';
775 if (IfMagickTrue(IsStringTrue(GetImageOption(image_info,"ps:use-cropbox"))))
776 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
777 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
778 (void) AcquireUniqueFilename(filename);
779 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
780 (void) FormatLocaleString(command,MaxTextExtent,
781 GetDelegateCommands(delegate_info),
782 read_info->antialias != MagickFalse ? 4 : 1,
783 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
784 postscript_filename,input_filename);
785 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
786 (void) InterpretImageFilename(image_info,image,filename,1,
787 read_info->filename,exception);
788 if ((status == MagickFalse) ||
789 (IsPostscriptRendered(read_info->filename) == MagickFalse))
791 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
792 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
794 (void) RelinquishUniqueFileResource(postscript_filename);
795 (void) RelinquishUniqueFileResource(input_filename);
796 postscript_image=(Image *) NULL;
797 if (status == MagickFalse)
800 (void) InterpretImageFilename(image_info,image,filename,(int) i,
801 read_info->filename,exception);
802 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
804 (void) RelinquishUniqueFileResource(read_info->filename);
809 (void) InterpretImageFilename(image_info,image,filename,(int) i,
810 read_info->filename,exception);
811 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
813 read_info->blob=NULL;
815 next=ReadImage(read_info,exception);
816 (void) RelinquishUniqueFileResource(read_info->filename);
817 if (next == (Image *) NULL)
819 AppendImageToList(&postscript_image,next);
821 (void) RelinquishUniqueFileResource(read_info->filename);
822 read_info=DestroyImageInfo(read_info);
823 if (postscript_image == (Image *) NULL)
825 image=DestroyImageList(image);
826 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
827 image_info->filename);
828 return((Image *) NULL);
830 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
835 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
836 if (cmyk_image != (Image *) NULL)
838 postscript_image=DestroyImageList(postscript_image);
839 postscript_image=cmyk_image;
842 if (image_info->number_scenes != 0)
851 Add place holder images to meet the subimage specification requirement.
853 for (i=0; i < (ssize_t) image_info->scene; i++)
855 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
856 if (clone_image != (Image *) NULL)
857 PrependImageToList(&postscript_image,clone_image);
862 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
864 postscript_image->magick_columns=columns;
866 postscript_image->magick_rows=rows;
867 postscript_image->page=page;
868 (void) CloneImageProfiles(postscript_image,image);
869 (void) CloneImageProperties(postscript_image,image);
870 next=SyncNextImageInList(postscript_image);
871 if (next != (Image *) NULL)
872 postscript_image=next;
873 } while (next != (Image *) NULL);
874 image=DestroyImageList(image);
876 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
879 next=GetNextImageInList(next);
881 return(GetFirstImageInList(postscript_image));
885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 % R e g i s t e r P S I m a g e %
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895 % RegisterPSImage() adds properties for the PS image format to
896 % the list of supported formats. The properties include the image format
897 % tag, a method to read and/or write the format, whether the format
898 % supports the saving of more than one frame to the same file or blob,
899 % whether the format supports native in-memory I/O, and a brief
900 % description of the format.
902 % The format of the RegisterPSImage method is:
904 % size_t RegisterPSImage(void)
907 ModuleExport size_t RegisterPSImage(void)
912 entry=SetMagickInfo("EPI");
913 entry->decoder=(DecodeImageHandler *) ReadPSImage;
914 entry->encoder=(EncodeImageHandler *) WritePSImage;
915 entry->magick=(IsImageFormatHandler *) IsPS;
916 entry->adjoin=MagickFalse;
917 entry->blob_support=MagickFalse;
918 entry->seekable_stream=MagickTrue;
919 entry->thread_support=EncoderThreadSupport;
920 entry->description=ConstantString(
921 "Encapsulated PostScript Interchange format");
922 entry->module=ConstantString("PS");
923 (void) RegisterMagickInfo(entry);
924 entry=SetMagickInfo("EPS");
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->thread_support=EncoderThreadSupport;
932 entry->description=ConstantString("Encapsulated PostScript");
933 entry->module=ConstantString("PS");
934 (void) RegisterMagickInfo(entry);
935 entry=SetMagickInfo("EPSF");
936 entry->decoder=(DecodeImageHandler *) ReadPSImage;
937 entry->encoder=(EncodeImageHandler *) WritePSImage;
938 entry->magick=(IsImageFormatHandler *) IsPS;
939 entry->adjoin=MagickFalse;
940 entry->blob_support=MagickFalse;
941 entry->seekable_stream=MagickTrue;
942 entry->description=ConstantString("Encapsulated PostScript");
943 entry->module=ConstantString("PS");
944 (void) RegisterMagickInfo(entry);
945 entry=SetMagickInfo("EPSI");
946 entry->decoder=(DecodeImageHandler *) ReadPSImage;
947 entry->encoder=(EncodeImageHandler *) WritePSImage;
948 entry->magick=(IsImageFormatHandler *) IsPS;
949 entry->adjoin=MagickFalse;
950 entry->blob_support=MagickFalse;
951 entry->seekable_stream=MagickTrue;
952 entry->thread_support=EncoderThreadSupport;
953 entry->description=ConstantString(
954 "Encapsulated PostScript Interchange format");
955 entry->module=ConstantString("PS");
956 (void) RegisterMagickInfo(entry);
957 entry=SetMagickInfo("PS");
958 entry->decoder=(DecodeImageHandler *) ReadPSImage;
959 entry->encoder=(EncodeImageHandler *) WritePSImage;
960 entry->magick=(IsImageFormatHandler *) IsPS;
961 entry->module=ConstantString("PS");
962 entry->blob_support=MagickFalse;
963 entry->seekable_stream=MagickTrue;
964 entry->thread_support=EncoderThreadSupport;
965 entry->description=ConstantString("PostScript");
966 (void) RegisterMagickInfo(entry);
967 return(MagickImageCoderSignature);
971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 % U n r e g i s t e r P S I m a g e %
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981 % UnregisterPSImage() removes format registrations made by the
982 % PS module from the list of supported formats.
984 % The format of the UnregisterPSImage method is:
986 % UnregisterPSImage(void)
989 ModuleExport void UnregisterPSImage(void)
991 (void) UnregisterMagickInfo("EPI");
992 (void) UnregisterMagickInfo("EPS");
993 (void) UnregisterMagickInfo("EPSF");
994 (void) UnregisterMagickInfo("EPSI");
995 (void) UnregisterMagickInfo("PS");
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1003 % W r i t e P S I m a g e %
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 % WritePSImage translates an image to encapsulated Postscript
1010 % Level I for printing. If the supplied geometry is null, the image is
1011 % centered on the Postscript page. Otherwise, the image is positioned as
1012 % specified by the geometry.
1014 % The format of the WritePSImage method is:
1016 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
1017 % Image *image,ExceptionInfo *exception)
1019 % A description of each parameter follows:
1021 % o image_info: the image info.
1023 % o image: the image.
1025 % o exception: return any errors or warnings in this structure.
1029 static inline size_t MagickMin(const size_t x,const size_t y)
1036 static inline unsigned char *PopHexPixel(const char **hex_digits,
1037 const size_t pixel,unsigned char *pixels)
1042 hex=hex_digits[pixel];
1043 *pixels++=(unsigned char) (*hex++);
1044 *pixels++=(unsigned char) (*hex);
1048 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1049 ExceptionInfo *exception)
1051 #define WriteRunlengthPacket(image,pixel,length,p) \
1053 if ((image->matte != MagickFalse) && \
1054 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1056 q=PopHexPixel(hex_digits,0xff,q); \
1057 q=PopHexPixel(hex_digits,0xff,q); \
1058 q=PopHexPixel(hex_digits,0xff,q); \
1062 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1063 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1064 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1066 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1072 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1073 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1074 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1075 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1076 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1077 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1078 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1079 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1080 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1081 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1082 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1083 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1084 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1085 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1086 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1087 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1088 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1089 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1090 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1091 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1092 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1093 "FC", "FD", "FE", "FF", (char *) NULL
1095 *PostscriptProlog[]=
1099 "% Display a color image. The image is displayed in color on",
1100 "% Postscript viewers or printers that support color, otherwise",
1101 "% it is displayed as grayscale.",
1103 "/DirectClassPacket",
1106 " % Get a DirectClass packet.",
1112 " % length: number of pixels minus one of this color (optional).",
1114 " currentfile color_packet readhexstring pop pop",
1115 " compression 0 eq",
1117 " /number_pixels 3 def",
1120 " currentfile byte readhexstring pop 0 get",
1121 " /number_pixels exch 1 add 3 mul def",
1123 " 0 3 number_pixels 1 sub",
1125 " pixels exch color_packet putinterval",
1127 " pixels 0 number_pixels getinterval",
1130 "/DirectClassImage",
1133 " % Display a DirectClass image.",
1135 " systemdict /colorimage known",
1142 " { DirectClassPacket } false 3 colorimage",
1146 " % No colorimage operator; convert to grayscale.",
1153 " { GrayDirectClassPacket } image",
1157 "/GrayDirectClassPacket",
1160 " % Get a DirectClass packet; convert to grayscale.",
1166 " % length: number of pixels minus one of this color (optional).",
1168 " currentfile color_packet readhexstring pop pop",
1169 " color_packet 0 get 0.299 mul",
1170 " color_packet 1 get 0.587 mul add",
1171 " color_packet 2 get 0.114 mul add",
1173 " /gray_packet exch def",
1174 " compression 0 eq",
1176 " /number_pixels 1 def",
1179 " currentfile byte readhexstring pop 0 get",
1180 " /number_pixels exch 1 add def",
1182 " 0 1 number_pixels 1 sub",
1184 " pixels exch gray_packet put",
1186 " pixels 0 number_pixels getinterval",
1189 "/GrayPseudoClassPacket",
1192 " % Get a PseudoClass packet; convert to grayscale.",
1195 " % index: index into the colormap.",
1196 " % length: number of pixels minus one of this color (optional).",
1198 " currentfile byte readhexstring pop 0 get",
1199 " /offset exch 3 mul def",
1200 " /color_packet colormap offset 3 getinterval def",
1201 " color_packet 0 get 0.299 mul",
1202 " color_packet 1 get 0.587 mul add",
1203 " color_packet 2 get 0.114 mul add",
1205 " /gray_packet exch def",
1206 " compression 0 eq",
1208 " /number_pixels 1 def",
1211 " currentfile byte readhexstring pop 0 get",
1212 " /number_pixels exch 1 add def",
1214 " 0 1 number_pixels 1 sub",
1216 " pixels exch gray_packet put",
1218 " pixels 0 number_pixels getinterval",
1221 "/PseudoClassPacket",
1224 " % Get a PseudoClass packet.",
1227 " % index: index into the colormap.",
1228 " % length: number of pixels minus one of this color (optional).",
1230 " currentfile byte readhexstring pop 0 get",
1231 " /offset exch 3 mul def",
1232 " /color_packet colormap offset 3 getinterval def",
1233 " compression 0 eq",
1235 " /number_pixels 3 def",
1238 " currentfile byte readhexstring pop 0 get",
1239 " /number_pixels exch 1 add 3 mul def",
1241 " 0 3 number_pixels 1 sub",
1243 " pixels exch color_packet putinterval",
1245 " pixels 0 number_pixels getinterval",
1248 "/PseudoClassImage",
1251 " % Display a PseudoClass image.",
1254 " % class: 0-PseudoClass or 1-Grayscale.",
1256 " currentfile buffer readline pop",
1257 " token pop /class exch def pop",
1260 " currentfile buffer readline pop",
1261 " token pop /depth exch def pop",
1262 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1263 " columns rows depth",
1268 " { currentfile grays readhexstring pop } image",
1273 " % colors: number of colors in the colormap.",
1274 " % colormap: red, green, blue color packets.",
1276 " currentfile buffer readline pop",
1277 " token pop /colors exch def pop",
1278 " /colors colors 3 mul def",
1279 " /colormap colors string def",
1280 " currentfile colormap readhexstring pop pop",
1281 " systemdict /colorimage known",
1288 " { PseudoClassPacket } false 3 colorimage",
1292 " % No colorimage operator; convert to grayscale.",
1299 " { GrayPseudoClassPacket } image",
1307 " % Display a DirectClass or PseudoClass image.",
1310 " % x & y translation.",
1312 " % label pointsize.",
1314 " % image columns & rows.",
1315 " % class: 0-DirectClass or 1-PseudoClass.",
1316 " % compression: 0-none or 1-RunlengthEncoded.",
1317 " % hex color packets.",
1320 " /buffer 512 string def",
1321 " /byte 1 string def",
1322 " /color_packet 3 string def",
1323 " /pixels 768 string def",
1325 " currentfile buffer readline pop",
1326 " token pop /x exch def",
1327 " token pop /y exch def pop",
1329 " currentfile buffer readline pop",
1330 " token pop /x exch def",
1331 " token pop /y exch def pop",
1332 " currentfile buffer readline pop",
1333 " token pop /pointsize exch def pop",
1334 " /Times-Roman findfont pointsize scalefont setfont",
1337 *PostscriptEpilog[]=
1340 " currentfile buffer readline pop",
1341 " token pop /columns exch def",
1342 " token pop /rows exch def pop",
1343 " currentfile buffer readline pop",
1344 " token pop /class exch def pop",
1345 " currentfile buffer readline pop",
1346 " token pop /compression exch def pop",
1347 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1353 buffer[MaxTextExtent],
1354 date[MaxTextExtent],
1356 page_geometry[MaxTextExtent];
1396 register const Quantum
1403 register unsigned char
1427 Open output image file.
1429 assert(image_info != (const ImageInfo *) NULL);
1430 assert(image_info->signature == MagickSignature);
1431 assert(image != (Image *) NULL);
1432 assert(image->signature == MagickSignature);
1433 if (image->debug != MagickFalse)
1434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1435 assert(exception != (ExceptionInfo *) NULL);
1436 assert(exception->signature == MagickSignature);
1437 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1438 if (status == MagickFalse)
1440 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1446 Scale relative to dots-per-inch.
1448 if ((IssRGBColorspace(image->colorspace) == MagickFalse) &&
1449 (IsImageGray(image,exception) == MagickFalse) &&
1450 (image->colorspace != CMYKColorspace))
1451 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1452 delta.x=DefaultResolution;
1453 delta.y=DefaultResolution;
1454 resolution.x=image->resolution.x;
1455 resolution.y=image->resolution.y;
1456 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1458 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1459 resolution.x=geometry_info.rho;
1460 resolution.y=geometry_info.sigma;
1461 if ((flags & SigmaValue) == 0)
1462 resolution.y=resolution.x;
1464 if (image_info->density != (char *) NULL)
1466 flags=ParseGeometry(image_info->density,&geometry_info);
1467 resolution.x=geometry_info.rho;
1468 resolution.y=geometry_info.sigma;
1469 if ((flags & SigmaValue) == 0)
1470 resolution.y=resolution.x;
1472 if (image->units == PixelsPerCentimeterResolution)
1474 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1475 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1477 SetGeometry(image,&geometry);
1478 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1479 (double) image->columns,(double) image->rows);
1480 if (image_info->page != (char *) NULL)
1481 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1483 if ((image->page.width != 0) && (image->page.height != 0))
1484 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1485 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1486 image->page.height,(double) image->page.x,(double) image->page.y);
1488 if ((image->gravity != UndefinedGravity) &&
1489 (LocaleCompare(image_info->magick,"PS") == 0))
1490 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1491 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1492 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1493 &geometry.width,&geometry.height);
1494 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1495 geometry.width=(size_t) floor(scale.x+0.5);
1496 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1497 geometry.height=(size_t) floor(scale.y+0.5);
1498 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1499 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1500 if (image->gravity != UndefinedGravity)
1502 geometry.x=(-page_info.x);
1503 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1506 if (image_info->pointsize != 0.0)
1507 pointsize=image_info->pointsize;
1509 value=GetImageProperty(image,"label",exception);
1510 if (value != (const char *) NULL)
1511 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1515 Output Postscript header.
1517 if (LocaleCompare(image_info->magick,"PS") == 0)
1518 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1520 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1522 (void) WriteBlobString(image,buffer);
1523 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1524 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1526 (void) WriteBlobString(image,buffer);
1527 timer=time((time_t *) NULL);
1528 (void) FormatMagickTime(timer,MaxTextExtent,date);
1529 (void) FormatLocaleString(buffer,MaxTextExtent,
1530 "%%%%CreationDate: (%s)\n",date);
1531 (void) WriteBlobString(image,buffer);
1532 bounds.x1=(double) geometry.x;
1533 bounds.y1=(double) geometry.y;
1534 bounds.x2=(double) geometry.x+scale.x;
1535 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1536 if ((image_info->adjoin != MagickFalse) &&
1537 (GetNextImageInList(image) != (Image *) NULL))
1538 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1542 (void) FormatLocaleString(buffer,MaxTextExtent,
1543 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1544 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1545 (void) WriteBlobString(image,buffer);
1546 (void) FormatLocaleString(buffer,MaxTextExtent,
1547 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1548 bounds.y1,bounds.x2,bounds.y2);
1550 (void) WriteBlobString(image,buffer);
1551 profile=GetImageProfile(image,"8bim");
1552 if (profile != (StringInfo *) NULL)
1555 Embed Photoshop profile.
1557 (void) FormatLocaleString(buffer,MaxTextExtent,
1558 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1559 (void) WriteBlobString(image,buffer);
1560 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1563 (void) WriteBlobString(image,"\n% ");
1564 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1565 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1566 (void) WriteBlobString(image,buffer);
1568 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1570 profile=GetImageProfile(image,"xmp");
1571 if (0 && (profile != (StringInfo *) NULL))
1576 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1577 (void) FormatLocaleString(buffer,MaxTextExtent,
1578 "\n%%begin_xml_packet: %.20g\n",(double)
1579 GetStringInfoLength(profile));
1580 (void) WriteBlobString(image,buffer);
1581 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1582 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1583 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1585 value=GetImageProperty(image,"label",exception);
1586 if (value != (const char *) NULL)
1587 (void) WriteBlobString(image,
1588 "%%DocumentNeededResources: font Times-Roman\n");
1589 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1590 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1591 if (LocaleCompare(image_info->magick,"PS") != 0)
1592 (void) WriteBlobString(image,"%%Pages: 1\n");
1596 Compute the number of pages.
1598 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1599 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1600 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1601 image_info->adjoin != MagickFalse ? (double)
1602 GetImageListLength(image) : 1.0);
1603 (void) WriteBlobString(image,buffer);
1605 (void) WriteBlobString(image,"%%EndComments\n");
1606 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1607 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1608 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1609 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1610 (LocaleCompare(image_info->magick,"EPT") == 0))
1625 Create preview image.
1627 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1628 if (preview_image == (Image *) NULL)
1629 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1631 Dump image as bitmap.
1633 (void) FormatLocaleString(buffer,MaxTextExtent,
1634 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1635 preview_image->columns,(double) preview_image->rows,1.0,
1636 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1638 (void) WriteBlobString(image,buffer);
1640 for (y=0; y < (ssize_t) image->rows; y++)
1642 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1644 if (p == (const Quantum *) NULL)
1648 for (x=0; x < (ssize_t) preview_image->columns; x++)
1651 pixel=GetPixelIntensity(preview_image,p);
1652 if (pixel >= (Quantum) (QuantumRange/2))
1657 q=PopHexPixel(hex_digits,byte,q);
1658 if ((q-pixels+8) >= 80)
1661 (void) WriteBlob(image,q-pixels,pixels);
1663 (void) WriteBlobString(image,"% ");
1672 q=PopHexPixel(hex_digits,byte,q);
1673 if ((q-pixels+8) >= 80)
1676 (void) WriteBlob(image,q-pixels,pixels);
1678 (void) WriteBlobString(image,"% ");
1685 (void) WriteBlob(image,q-pixels,pixels);
1687 (void) WriteBlobString(image,"\n%%EndPreview\n");
1688 preview_image=DestroyImage(preview_image);
1691 Output Postscript commands.
1693 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1695 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1696 (void) WriteBlobString(image,buffer);
1698 value=GetImageProperty(image,"label",exception);
1699 if (value != (const char *) NULL)
1700 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1702 (void) WriteBlobString(image," /label 512 string def\n");
1703 (void) WriteBlobString(image," currentfile label readline pop\n");
1704 (void) FormatLocaleString(buffer,MaxTextExtent,
1705 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1706 (void) WriteBlobString(image,buffer);
1708 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1710 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1711 (void) WriteBlobString(image,buffer);
1713 if (LocaleCompare(image_info->magick,"PS") == 0)
1714 (void) WriteBlobString(image," showpage\n");
1715 (void) WriteBlobString(image,"} bind def\n");
1716 (void) WriteBlobString(image,"%%EndProlog\n");
1718 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1720 (void) WriteBlobString(image,buffer);
1721 (void) FormatLocaleString(buffer,MaxTextExtent,
1722 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1723 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1724 (geometry.height+text_size));
1725 (void) WriteBlobString(image,buffer);
1726 if ((double) geometry.x < bounds.x1)
1727 bounds.x1=(double) geometry.x;
1728 if ((double) geometry.y < bounds.y1)
1729 bounds.y1=(double) geometry.y;
1730 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1731 bounds.x2=(double) geometry.x+geometry.width-1;
1732 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1733 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1734 value=GetImageProperty(image,"label",exception);
1735 if (value != (const char *) NULL)
1736 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1737 if (LocaleCompare(image_info->magick,"PS") != 0)
1738 (void) WriteBlobString(image,"userdict begin\n");
1739 (void) WriteBlobString(image,"DisplayImage\n");
1743 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1744 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1745 (void) WriteBlobString(image,buffer);
1746 labels=(char **) NULL;
1747 value=GetImageProperty(image,"label",exception);
1748 if (value != (const char *) NULL)
1749 labels=StringToList(value);
1750 if (labels != (char **) NULL)
1752 for (i=0; labels[i] != (char *) NULL; i++)
1754 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1756 (void) WriteBlobString(image,buffer);
1757 labels[i]=DestroyString(labels[i]);
1759 labels=(char **) RelinquishMagickMemory(labels);
1761 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1762 pixel.alpha=(Quantum) TransparentAlpha;
1765 if ((image_info->type != TrueColorType) &&
1766 (IsImageGray(image,exception) != MagickFalse))
1768 if (IsImageMonochrome(image,exception) == MagickFalse)
1774 Dump image as grayscale.
1776 (void) FormatLocaleString(buffer,MaxTextExtent,
1777 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1779 (void) WriteBlobString(image,buffer);
1781 for (y=0; y < (ssize_t) image->rows; y++)
1783 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1784 if (p == (const Quantum *) NULL)
1786 for (x=0; x < (ssize_t) image->columns; x++)
1788 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
1789 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1791 if ((q-pixels+8) >= 80)
1794 (void) WriteBlob(image,q-pixels,pixels);
1797 p+=GetPixelChannels(image);
1799 if (image->previous == (Image *) NULL)
1801 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1803 if (status == MagickFalse)
1810 (void) WriteBlob(image,q-pixels,pixels);
1822 Dump image as bitmap.
1824 (void) FormatLocaleString(buffer,MaxTextExtent,
1825 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1827 (void) WriteBlobString(image,buffer);
1829 for (y=0; y < (ssize_t) image->rows; y++)
1831 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1832 if (p == (const Quantum *) NULL)
1836 for (x=0; x < (ssize_t) image->columns; x++)
1839 pixel=GetPixelIntensity(image,p);
1840 if (pixel >= (Quantum) (QuantumRange/2))
1845 q=PopHexPixel(hex_digits,byte,q);
1846 if ((q-pixels+2) >= 80)
1849 (void) WriteBlob(image,q-pixels,pixels);
1855 p+=GetPixelChannels(image);
1860 q=PopHexPixel(hex_digits,byte,q);
1861 if ((q-pixels+2) >= 80)
1864 (void) WriteBlob(image,q-pixels,pixels);
1868 if (image->previous == (Image *) NULL)
1870 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1872 if (status == MagickFalse)
1879 (void) WriteBlob(image,q-pixels,pixels);
1884 if ((image->storage_class == DirectClass) ||
1885 (image->colors > 256) || (image->matte != MagickFalse))
1888 Dump DirectClass image.
1890 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1891 (double) image->columns,(double) image->rows,
1892 image_info->compression == RLECompression ? 1 : 0);
1893 (void) WriteBlobString(image,buffer);
1894 switch (image_info->compression)
1896 case RLECompression:
1899 Dump runlength-encoded DirectColor packets.
1902 for (y=0; y < (ssize_t) image->rows; y++)
1904 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1905 if (p == (const Quantum *) NULL)
1907 GetPixelInfoPixel(image,p,&pixel);
1909 for (x=0; x < (ssize_t) image->columns; x++)
1911 if ((GetPixelRed(image,p) == pixel.red) &&
1912 (GetPixelGreen(image,p) == pixel.green) &&
1913 (GetPixelBlue(image,p) == pixel.blue) &&
1914 (GetPixelAlpha(image,p) == pixel.alpha) &&
1915 (length < 255) && (x < (ssize_t) (image->columns-1)))
1921 WriteRunlengthPacket(image,pixel,length,p);
1922 if ((q-pixels+10) >= 80)
1925 (void) WriteBlob(image,q-pixels,pixels);
1931 GetPixelInfoPixel(image,p,&pixel);
1932 p+=GetPixelChannels(image);
1934 WriteRunlengthPacket(image,pixel,length,p);
1935 if ((q-pixels+10) >= 80)
1938 (void) WriteBlob(image,q-pixels,pixels);
1941 if (image->previous == (Image *) NULL)
1943 status=SetImageProgress(image,SaveImageTag,
1944 (MagickOffsetType) y,image->rows);
1945 if (status == MagickFalse)
1952 (void) WriteBlob(image,q-pixels,pixels);
1960 Dump uncompressed DirectColor packets.
1963 for (y=0; y < (ssize_t) image->rows; y++)
1965 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1966 if (p == (const Quantum *) NULL)
1968 for (x=0; x < (ssize_t) image->columns; x++)
1970 if ((image->matte != MagickFalse) &&
1971 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1973 q=PopHexPixel(hex_digits,0xff,q);
1974 q=PopHexPixel(hex_digits,0xff,q);
1975 q=PopHexPixel(hex_digits,0xff,q);
1979 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1980 GetPixelRed(image,p)),q);
1981 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1982 GetPixelGreen(image,p)),q);
1983 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1984 GetPixelBlue(image,p)),q);
1986 if ((q-pixels+6) >= 80)
1989 (void) WriteBlob(image,q-pixels,pixels);
1992 p+=GetPixelChannels(image);
1994 if (image->previous == (Image *) NULL)
1996 status=SetImageProgress(image,SaveImageTag,
1997 (MagickOffsetType) y,image->rows);
1998 if (status == MagickFalse)
2005 (void) WriteBlob(image,q-pixels,pixels);
2010 (void) WriteBlobByte(image,'\n');
2015 Dump PseudoClass image.
2017 (void) FormatLocaleString(buffer,MaxTextExtent,
2018 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2019 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2020 image_info->compression == RLECompression ? 1 : 0);
2021 (void) WriteBlobString(image,buffer);
2023 Dump number of colors and colormap.
2025 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2027 (void) WriteBlobString(image,buffer);
2028 for (i=0; i < (ssize_t) image->colors; i++)
2030 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2031 ScaleQuantumToChar(image->colormap[i].red),
2032 ScaleQuantumToChar(image->colormap[i].green),
2033 ScaleQuantumToChar(image->colormap[i].blue));
2034 (void) WriteBlobString(image,buffer);
2036 switch (image_info->compression)
2038 case RLECompression:
2041 Dump runlength-encoded PseudoColor packets.
2044 for (y=0; y < (ssize_t) image->rows; y++)
2046 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2047 if (p == (const Quantum *) NULL)
2049 index=GetPixelIndex(image,p);
2051 for (x=0; x < (ssize_t) image->columns; x++)
2053 if ((index == GetPixelIndex(image,p)) &&
2054 (length < 255) && (x < ((ssize_t) image->columns-1)))
2060 q=PopHexPixel(hex_digits,(size_t) index,q);
2061 q=PopHexPixel(hex_digits,(size_t)
2062 MagickMin(length,0xff),q);
2064 if ((q-pixels+6) >= 80)
2067 (void) WriteBlob(image,q-pixels,pixels);
2073 index=GetPixelIndex(image,p);
2074 pixel.red=GetPixelRed(image,p);
2075 pixel.green=GetPixelGreen(image,p);
2076 pixel.blue=GetPixelBlue(image,p);
2077 pixel.alpha=GetPixelAlpha(image,p);
2078 p+=GetPixelChannels(image);
2080 q=PopHexPixel(hex_digits,(size_t) index,q);
2081 q=PopHexPixel(hex_digits,(size_t)
2082 MagickMin(length,0xff),q);
2083 if (image->previous == (Image *) NULL)
2085 status=SetImageProgress(image,SaveImageTag,
2086 (MagickOffsetType) y,image->rows);
2087 if (status == MagickFalse)
2094 (void) WriteBlob(image,q-pixels,pixels);
2102 Dump uncompressed PseudoColor packets.
2105 for (y=0; y < (ssize_t) image->rows; y++)
2107 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2108 if (p == (const Quantum *) NULL)
2110 for (x=0; x < (ssize_t) image->columns; x++)
2112 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2113 if ((q-pixels+4) >= 80)
2116 (void) WriteBlob(image,q-pixels,pixels);
2119 p+=GetPixelChannels(image);
2121 if (image->previous == (Image *) NULL)
2123 status=SetImageProgress(image,SaveImageTag,
2124 (MagickOffsetType) y,image->rows);
2125 if (status == MagickFalse)
2132 (void) WriteBlob(image,q-pixels,pixels);
2137 (void) WriteBlobByte(image,'\n');
2139 if (LocaleCompare(image_info->magick,"PS") != 0)
2140 (void) WriteBlobString(image,"end\n");
2141 (void) WriteBlobString(image,"%%PageTrailer\n");
2142 if (GetNextImageInList(image) == (Image *) NULL)
2144 image=SyncNextImageInList(image);
2145 status=SetImageProgress(image,SaveImagesTag,scene++,
2146 GetImageListLength(image));
2147 if (status == MagickFalse)
2149 } while (image_info->adjoin != MagickFalse);
2150 (void) WriteBlobString(image,"%%Trailer\n");
2153 (void) FormatLocaleString(buffer,MaxTextExtent,
2154 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2155 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
2156 (void) WriteBlobString(image,buffer);
2157 (void) FormatLocaleString(buffer,MaxTextExtent,
2158 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2159 bounds.x2,bounds.y2);
2160 (void) WriteBlobString(image,buffer);
2162 (void) WriteBlobString(image,"%%EOF\n");
2163 (void) CloseBlob(image);