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];
419 assert(image_info != (const ImageInfo *) NULL);
420 assert(image_info->signature == MagickSignature);
421 if (image_info->debug != MagickFalse)
422 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
423 image_info->filename);
424 assert(exception != (ExceptionInfo *) NULL);
425 assert(exception->signature == MagickSignature);
426 image=AcquireImage(image_info,exception);
427 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
428 if (status == MagickFalse)
430 image=DestroyImageList(image);
431 return((Image *) NULL);
433 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
434 if (status == MagickFalse)
436 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
437 image_info->filename);
438 image=DestroyImageList(image);
439 return((Image *) NULL);
442 Initialize hex values.
444 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
445 hex_digits[(int) '0']=0;
446 hex_digits[(int) '1']=1;
447 hex_digits[(int) '2']=2;
448 hex_digits[(int) '3']=3;
449 hex_digits[(int) '4']=4;
450 hex_digits[(int) '5']=5;
451 hex_digits[(int) '6']=6;
452 hex_digits[(int) '7']=7;
453 hex_digits[(int) '8']=8;
454 hex_digits[(int) '9']=9;
455 hex_digits[(int) 'a']=10;
456 hex_digits[(int) 'b']=11;
457 hex_digits[(int) 'c']=12;
458 hex_digits[(int) 'd']=13;
459 hex_digits[(int) 'e']=14;
460 hex_digits[(int) 'f']=15;
461 hex_digits[(int) 'A']=10;
462 hex_digits[(int) 'B']=11;
463 hex_digits[(int) 'C']=12;
464 hex_digits[(int) 'D']=13;
465 hex_digits[(int) 'E']=14;
466 hex_digits[(int) 'F']=15;
468 Set the page density.
470 delta.x=DefaultResolution;
471 delta.y=DefaultResolution;
472 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
474 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
475 image->resolution.x=geometry_info.rho;
476 image->resolution.y=geometry_info.sigma;
477 if ((flags & SigmaValue) == 0)
478 image->resolution.y=image->resolution.x;
480 if (image_info->density != (char *) NULL)
482 flags=ParseGeometry(image_info->density,&geometry_info);
483 image->resolution.x=geometry_info.rho;
484 image->resolution.y=geometry_info.sigma;
485 if ((flags & SigmaValue) == 0)
486 image->resolution.y=image->resolution.x;
488 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
489 if (image_info->page != (char *) NULL)
490 (void) ParseAbsoluteGeometry(image_info->page,&page);
491 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)-
493 page.height=(size_t) ceil((double) (page.height*image->resolution.y/delta.y)-
496 Determine page geometry from the Postscript bounding box.
498 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
499 (void) ResetMagickMemory(command,0,sizeof(command));
500 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
501 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
510 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
513 Note document structuring comments.
516 if ((strchr("\n\r%",c) == (char *) NULL) &&
517 ((size_t) (p-command) < (MaxTextExtent-1)))
522 Skip %%BeginDocument thru %%EndDocument.
524 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
526 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
528 if (skip != MagickFalse)
530 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
532 (void) SetImageProperty(image,"ps:Level",command+4,exception);
533 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
536 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
537 (void) sscanf(command,LanguageLevel " %lu",&language_level);
538 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
539 (void) sscanf(command,Pages " %lu",&pages);
540 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
541 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
542 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
550 profile=AcquireStringInfo(65536);
551 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
553 SetStringInfoLength(profile,(size_t) i+1);
554 datum=GetStringInfoDatum(profile);
555 datum[i]=(unsigned char) c;
557 (void) SetImageProfile(image,"icc",profile,exception);
558 profile=DestroyStringInfo(profile);
561 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
567 Read Photoshop profile.
569 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
573 profile=BlobToStringInfo((const void *) NULL,length);
574 p=GetStringInfoDatum(profile);
575 for (i=0; i < (ssize_t) length; i++)
576 *p++=(unsigned char) ProfileInteger(image,hex_digits);
577 (void) SetImageProfile(image,"8bim",profile,exception);
578 profile=DestroyStringInfo(profile);
581 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
590 profile=StringToStringInfo(command);
591 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
593 SetStringInfoLength(profile,i+1);
594 c=ReadBlobByte(image);
595 GetStringInfoDatum(profile)[i]=(unsigned char) c;
597 if ((strchr("\n\r%",c) == (char *) NULL) &&
598 ((size_t) (p-command) < (MaxTextExtent-1)))
602 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
605 SetStringInfoLength(profile,i);
606 (void) SetImageProfile(image,"xmp",profile,exception);
607 profile=DestroyStringInfo(profile);
611 Is this a CMYK document?
613 length=strlen(DocumentProcessColors);
614 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
616 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
617 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
618 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
621 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
623 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
625 length=strlen(DocumentCustomColors);
626 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
627 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
628 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
631 property[MaxTextExtent],
640 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
641 (double) (spotcolor++));
642 for (p=command; *p != '\0'; p++)
643 if (isspace((int) (unsigned char) *p) != 0)
645 value=AcquireString(p);
646 (void) SubstituteString(&value,"(","");
647 (void) SubstituteString(&value,")","");
648 (void) StripString(value);
649 (void) SetImageProperty(image,property,value,exception);
650 value=DestroyString(value);
653 if (image_info->page != (char *) NULL)
656 Note region defined by bounding box.
660 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
662 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
663 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
666 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
668 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
669 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
672 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
674 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
675 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
678 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
680 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
681 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
684 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
686 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
687 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
690 if ((count != 4) || (i < (ssize_t) priority))
692 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
693 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
698 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
699 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
702 Set Postscript render geometry.
704 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
705 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
706 hires_bounds.x1,hires_bounds.y1);
707 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
708 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
709 image->resolution.x/delta.x)-0.5);
710 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
711 image->resolution.y/delta.y)-0.5);
713 (void) CloseBlob(image);
714 if (IsRGBColorspace(image_info->colorspace) != MagickFalse)
717 Create Ghostscript control file.
719 file=AcquireUniqueFileResource(postscript_filename);
722 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
723 image_info->filename);
724 image=DestroyImageList(image);
725 return((Image *) NULL);
727 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
728 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
729 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
730 count=write(file,command,(unsigned int) strlen(command));
731 if (image_info->page == (char *) NULL)
734 translate_geometry[MaxTextExtent];
736 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
737 "%g %g translate\n",-bounds.x1,-bounds.y1);
738 count=write(file,translate_geometry,(unsigned int)
739 strlen(translate_geometry));
743 Render Postscript with the Ghostscript delegate.
745 if (image_info->monochrome != MagickFalse)
746 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
748 if (cmyk != MagickFalse)
749 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
751 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
752 if (delegate_info == (const DelegateInfo *) NULL)
754 (void) RelinquishUniqueFileResource(postscript_filename);
755 image=DestroyImageList(image);
756 return((Image *) NULL);
759 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
760 image->resolution.x,image->resolution.y);
761 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
762 page.width,(double) page.height);
763 read_info=CloneImageInfo(image_info);
764 *read_info->magick='\0';
765 if (read_info->number_scenes != 0)
768 pages[MaxTextExtent];
770 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
771 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
772 (read_info->scene+read_info->number_scenes));
773 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
774 read_info->number_scenes=0;
775 if (read_info->scenes != (char *) NULL)
776 *read_info->scenes='\0';
778 option=GetImageOption(image_info,"ps:use-cropbox");
779 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
780 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
781 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
782 (void) AcquireUniqueFilename(filename);
783 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
784 (void) FormatLocaleString(command,MaxTextExtent,
785 GetDelegateCommands(delegate_info),
786 read_info->antialias != MagickFalse ? 4 : 1,
787 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
788 postscript_filename,input_filename);
789 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
790 (void) InterpretImageFilename(image_info,image,filename,1,
791 read_info->filename,exception);
792 if ((status == MagickFalse) ||
793 (IsPostscriptRendered(read_info->filename) == MagickFalse))
795 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
796 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
798 (void) RelinquishUniqueFileResource(postscript_filename);
799 (void) RelinquishUniqueFileResource(input_filename);
800 postscript_image=(Image *) NULL;
801 if (status == MagickFalse)
804 (void) InterpretImageFilename(image_info,image,filename,(int) i,
805 read_info->filename,exception);
806 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
808 (void) RelinquishUniqueFileResource(read_info->filename);
813 (void) InterpretImageFilename(image_info,image,filename,(int) i,
814 read_info->filename,exception);
815 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
817 next=ReadImage(read_info,exception);
818 (void) RelinquishUniqueFileResource(read_info->filename);
819 if (next == (Image *) NULL)
821 AppendImageToList(&postscript_image,next);
823 (void) RelinquishUniqueFileResource(read_info->filename);
824 read_info=DestroyImageInfo(read_info);
825 if (postscript_image == (Image *) NULL)
827 image=DestroyImageList(image);
828 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
829 image_info->filename);
830 return((Image *) NULL);
832 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
837 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
838 if (cmyk_image != (Image *) NULL)
840 postscript_image=DestroyImageList(postscript_image);
841 postscript_image=cmyk_image;
844 if (image_info->number_scenes != 0)
853 Add place holder images to meet the subimage specification requirement.
855 for (i=0; i < (ssize_t) image_info->scene; i++)
857 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
858 if (clone_image != (Image *) NULL)
859 PrependImageToList(&postscript_image,clone_image);
864 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
866 postscript_image->magick_columns=columns;
868 postscript_image->magick_rows=rows;
869 postscript_image->page=page;
870 (void) CloneImageProfiles(postscript_image,image);
871 (void) CloneImageProperties(postscript_image,image);
872 next=SyncNextImageInList(postscript_image);
873 if (next != (Image *) NULL)
874 postscript_image=next;
875 } while (next != (Image *) NULL);
876 image=DestroyImageList(image);
878 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
881 next=GetNextImageInList(next);
883 return(GetFirstImageInList(postscript_image));
887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891 % R e g i s t e r P S I m a g e %
895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897 % RegisterPSImage() adds properties for the PS image format to
898 % the list of supported formats. The properties include the image format
899 % tag, a method to read and/or write the format, whether the format
900 % supports the saving of more than one frame to the same file or blob,
901 % whether the format supports native in-memory I/O, and a brief
902 % description of the format.
904 % The format of the RegisterPSImage method is:
906 % size_t RegisterPSImage(void)
909 ModuleExport size_t RegisterPSImage(void)
914 entry=SetMagickInfo("EPI");
915 entry->decoder=(DecodeImageHandler *) ReadPSImage;
916 entry->encoder=(EncodeImageHandler *) WritePSImage;
917 entry->magick=(IsImageFormatHandler *) IsPS;
918 entry->adjoin=MagickFalse;
919 entry->blob_support=MagickFalse;
920 entry->seekable_stream=MagickTrue;
921 entry->thread_support=EncoderThreadSupport;
922 entry->description=ConstantString(
923 "Encapsulated PostScript Interchange format");
924 entry->module=ConstantString("PS");
925 (void) RegisterMagickInfo(entry);
926 entry=SetMagickInfo("EPS");
927 entry->decoder=(DecodeImageHandler *) ReadPSImage;
928 entry->encoder=(EncodeImageHandler *) WritePSImage;
929 entry->magick=(IsImageFormatHandler *) IsPS;
930 entry->adjoin=MagickFalse;
931 entry->blob_support=MagickFalse;
932 entry->seekable_stream=MagickTrue;
933 entry->thread_support=EncoderThreadSupport;
934 entry->description=ConstantString("Encapsulated PostScript");
935 entry->module=ConstantString("PS");
936 (void) RegisterMagickInfo(entry);
937 entry=SetMagickInfo("EPSF");
938 entry->decoder=(DecodeImageHandler *) ReadPSImage;
939 entry->encoder=(EncodeImageHandler *) WritePSImage;
940 entry->magick=(IsImageFormatHandler *) IsPS;
941 entry->adjoin=MagickFalse;
942 entry->blob_support=MagickFalse;
943 entry->seekable_stream=MagickTrue;
944 entry->description=ConstantString("Encapsulated PostScript");
945 entry->module=ConstantString("PS");
946 (void) RegisterMagickInfo(entry);
947 entry=SetMagickInfo("EPSI");
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->thread_support=EncoderThreadSupport;
955 entry->description=ConstantString(
956 "Encapsulated PostScript Interchange format");
957 entry->module=ConstantString("PS");
958 (void) RegisterMagickInfo(entry);
959 entry=SetMagickInfo("PS");
960 entry->decoder=(DecodeImageHandler *) ReadPSImage;
961 entry->encoder=(EncodeImageHandler *) WritePSImage;
962 entry->magick=(IsImageFormatHandler *) IsPS;
963 entry->module=ConstantString("PS");
964 entry->blob_support=MagickFalse;
965 entry->seekable_stream=MagickTrue;
966 entry->thread_support=EncoderThreadSupport;
967 entry->description=ConstantString("PostScript");
968 (void) RegisterMagickInfo(entry);
969 return(MagickImageCoderSignature);
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
977 % U n r e g i s t e r P S I m a g e %
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983 % UnregisterPSImage() removes format registrations made by the
984 % PS module from the list of supported formats.
986 % The format of the UnregisterPSImage method is:
988 % UnregisterPSImage(void)
991 ModuleExport void UnregisterPSImage(void)
993 (void) UnregisterMagickInfo("EPI");
994 (void) UnregisterMagickInfo("EPS");
995 (void) UnregisterMagickInfo("EPSF");
996 (void) UnregisterMagickInfo("EPSI");
997 (void) UnregisterMagickInfo("PS");
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005 % W r i t e P S I m a g e %
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011 % WritePSImage translates an image to encapsulated Postscript
1012 % Level I for printing. If the supplied geometry is null, the image is
1013 % centered on the Postscript page. Otherwise, the image is positioned as
1014 % specified by the geometry.
1016 % The format of the WritePSImage method is:
1018 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
1019 % Image *image,ExceptionInfo *exception)
1021 % A description of each parameter follows:
1023 % o image_info: the image info.
1025 % o image: the image.
1027 % o exception: return any errors or warnings in this structure.
1031 static inline size_t MagickMin(const size_t x,const size_t y)
1038 static inline unsigned char *PopHexPixel(const char **hex_digits,
1039 const size_t pixel,unsigned char *pixels)
1044 hex=hex_digits[pixel];
1045 *pixels++=(unsigned char) (*hex++);
1046 *pixels++=(unsigned char) (*hex);
1050 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1051 ExceptionInfo *exception)
1053 #define WriteRunlengthPacket(image,pixel,length,p) \
1055 if ((image->matte != MagickFalse) && \
1056 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1058 q=PopHexPixel(hex_digits,0xff,q); \
1059 q=PopHexPixel(hex_digits,0xff,q); \
1060 q=PopHexPixel(hex_digits,0xff,q); \
1064 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1065 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1066 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1068 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1074 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1075 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1076 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1077 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1078 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1079 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1080 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1081 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1082 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1083 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1084 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1085 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1086 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1087 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1088 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1089 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1090 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1091 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1092 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1093 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1094 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1095 "FC", "FD", "FE", "FF", (char *) NULL
1097 *PostscriptProlog[]=
1101 "% Display a color image. The image is displayed in color on",
1102 "% Postscript viewers or printers that support color, otherwise",
1103 "% it is displayed as grayscale.",
1105 "/DirectClassPacket",
1108 " % Get a DirectClass packet.",
1114 " % length: number of pixels minus one of this color (optional).",
1116 " currentfile color_packet readhexstring pop pop",
1117 " compression 0 eq",
1119 " /number_pixels 3 def",
1122 " currentfile byte readhexstring pop 0 get",
1123 " /number_pixels exch 1 add 3 mul def",
1125 " 0 3 number_pixels 1 sub",
1127 " pixels exch color_packet putinterval",
1129 " pixels 0 number_pixels getinterval",
1132 "/DirectClassImage",
1135 " % Display a DirectClass image.",
1137 " systemdict /colorimage known",
1144 " { DirectClassPacket } false 3 colorimage",
1148 " % No colorimage operator; convert to grayscale.",
1155 " { GrayDirectClassPacket } image",
1159 "/GrayDirectClassPacket",
1162 " % Get a DirectClass packet; convert to grayscale.",
1168 " % length: number of pixels minus one of this color (optional).",
1170 " currentfile color_packet readhexstring pop pop",
1171 " color_packet 0 get 0.299 mul",
1172 " color_packet 1 get 0.587 mul add",
1173 " color_packet 2 get 0.114 mul add",
1175 " /gray_packet exch def",
1176 " compression 0 eq",
1178 " /number_pixels 1 def",
1181 " currentfile byte readhexstring pop 0 get",
1182 " /number_pixels exch 1 add def",
1184 " 0 1 number_pixels 1 sub",
1186 " pixels exch gray_packet put",
1188 " pixels 0 number_pixels getinterval",
1191 "/GrayPseudoClassPacket",
1194 " % Get a PseudoClass packet; convert to grayscale.",
1197 " % index: index into the colormap.",
1198 " % length: number of pixels minus one of this color (optional).",
1200 " currentfile byte readhexstring pop 0 get",
1201 " /offset exch 3 mul def",
1202 " /color_packet colormap offset 3 getinterval def",
1203 " color_packet 0 get 0.299 mul",
1204 " color_packet 1 get 0.587 mul add",
1205 " color_packet 2 get 0.114 mul add",
1207 " /gray_packet exch def",
1208 " compression 0 eq",
1210 " /number_pixels 1 def",
1213 " currentfile byte readhexstring pop 0 get",
1214 " /number_pixels exch 1 add def",
1216 " 0 1 number_pixels 1 sub",
1218 " pixels exch gray_packet put",
1220 " pixels 0 number_pixels getinterval",
1223 "/PseudoClassPacket",
1226 " % Get a PseudoClass packet.",
1229 " % index: index into the colormap.",
1230 " % length: number of pixels minus one of this color (optional).",
1232 " currentfile byte readhexstring pop 0 get",
1233 " /offset exch 3 mul def",
1234 " /color_packet colormap offset 3 getinterval def",
1235 " compression 0 eq",
1237 " /number_pixels 3 def",
1240 " currentfile byte readhexstring pop 0 get",
1241 " /number_pixels exch 1 add 3 mul def",
1243 " 0 3 number_pixels 1 sub",
1245 " pixels exch color_packet putinterval",
1247 " pixels 0 number_pixels getinterval",
1250 "/PseudoClassImage",
1253 " % Display a PseudoClass image.",
1256 " % class: 0-PseudoClass or 1-Grayscale.",
1258 " currentfile buffer readline pop",
1259 " token pop /class exch def pop",
1262 " currentfile buffer readline pop",
1263 " token pop /depth exch def pop",
1264 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1265 " columns rows depth",
1270 " { currentfile grays readhexstring pop } image",
1275 " % colors: number of colors in the colormap.",
1276 " % colormap: red, green, blue color packets.",
1278 " currentfile buffer readline pop",
1279 " token pop /colors exch def pop",
1280 " /colors colors 3 mul def",
1281 " /colormap colors string def",
1282 " currentfile colormap readhexstring pop pop",
1283 " systemdict /colorimage known",
1290 " { PseudoClassPacket } false 3 colorimage",
1294 " % No colorimage operator; convert to grayscale.",
1301 " { GrayPseudoClassPacket } image",
1309 " % Display a DirectClass or PseudoClass image.",
1312 " % x & y translation.",
1314 " % label pointsize.",
1316 " % image columns & rows.",
1317 " % class: 0-DirectClass or 1-PseudoClass.",
1318 " % compression: 0-none or 1-RunlengthEncoded.",
1319 " % hex color packets.",
1322 " /buffer 512 string def",
1323 " /byte 1 string def",
1324 " /color_packet 3 string def",
1325 " /pixels 768 string def",
1327 " currentfile buffer readline pop",
1328 " token pop /x exch def",
1329 " token pop /y exch def pop",
1331 " currentfile buffer readline pop",
1332 " token pop /x exch def",
1333 " token pop /y exch def pop",
1334 " currentfile buffer readline pop",
1335 " token pop /pointsize exch def pop",
1336 " /Times-Roman findfont pointsize scalefont setfont",
1339 *PostscriptEpilog[]=
1342 " currentfile buffer readline pop",
1343 " token pop /columns exch def",
1344 " token pop /rows exch def pop",
1345 " currentfile buffer readline pop",
1346 " token pop /class exch def pop",
1347 " currentfile buffer readline pop",
1348 " token pop /compression exch def pop",
1349 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1355 buffer[MaxTextExtent],
1356 date[MaxTextExtent],
1358 page_geometry[MaxTextExtent];
1398 register const Quantum
1405 register unsigned char
1429 Open output image file.
1431 assert(image_info != (const ImageInfo *) NULL);
1432 assert(image_info->signature == MagickSignature);
1433 assert(image != (Image *) NULL);
1434 assert(image->signature == MagickSignature);
1435 if (image->debug != MagickFalse)
1436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1437 assert(exception != (ExceptionInfo *) NULL);
1438 assert(exception->signature == MagickSignature);
1439 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1440 if (status == MagickFalse)
1442 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1448 Scale relative to dots-per-inch.
1450 if ((IsRGBColorspace(image->colorspace) == MagickFalse) &&
1451 (image->colorspace != CMYKColorspace))
1452 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1453 delta.x=DefaultResolution;
1454 delta.y=DefaultResolution;
1455 resolution.x=image->resolution.x;
1456 resolution.y=image->resolution.y;
1457 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1459 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1460 resolution.x=geometry_info.rho;
1461 resolution.y=geometry_info.sigma;
1462 if ((flags & SigmaValue) == 0)
1463 resolution.y=resolution.x;
1465 if (image_info->density != (char *) NULL)
1467 flags=ParseGeometry(image_info->density,&geometry_info);
1468 resolution.x=geometry_info.rho;
1469 resolution.y=geometry_info.sigma;
1470 if ((flags & SigmaValue) == 0)
1471 resolution.y=resolution.x;
1473 if (image->units == PixelsPerCentimeterResolution)
1475 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1476 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1478 SetGeometry(image,&geometry);
1479 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1480 (double) image->columns,(double) image->rows);
1481 if (image_info->page != (char *) NULL)
1482 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1484 if ((image->page.width != 0) && (image->page.height != 0))
1485 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1486 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1487 image->page.height,(double) image->page.x,(double) image->page.y);
1489 if ((image->gravity != UndefinedGravity) &&
1490 (LocaleCompare(image_info->magick,"PS") == 0))
1491 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1492 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1493 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1494 &geometry.width,&geometry.height);
1495 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1496 geometry.width=(size_t) floor(scale.x+0.5);
1497 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1498 geometry.height=(size_t) floor(scale.y+0.5);
1499 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1500 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1501 if (image->gravity != UndefinedGravity)
1503 geometry.x=(-page_info.x);
1504 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1507 if (image_info->pointsize != 0.0)
1508 pointsize=image_info->pointsize;
1510 value=GetImageProperty(image,"label",exception);
1511 if (value != (const char *) NULL)
1512 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1516 Output Postscript header.
1518 if (LocaleCompare(image_info->magick,"PS") == 0)
1519 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1521 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1523 (void) WriteBlobString(image,buffer);
1524 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1525 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1527 (void) WriteBlobString(image,buffer);
1528 timer=time((time_t *) NULL);
1529 (void) FormatMagickTime(timer,MaxTextExtent,date);
1530 (void) FormatLocaleString(buffer,MaxTextExtent,
1531 "%%%%CreationDate: (%s)\n",date);
1532 (void) WriteBlobString(image,buffer);
1533 bounds.x1=(double) geometry.x;
1534 bounds.y1=(double) geometry.y;
1535 bounds.x2=(double) geometry.x+scale.x;
1536 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1537 if ((image_info->adjoin != MagickFalse) &&
1538 (GetNextImageInList(image) != (Image *) NULL))
1539 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1543 (void) FormatLocaleString(buffer,MaxTextExtent,
1544 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1545 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1546 (void) WriteBlobString(image,buffer);
1547 (void) FormatLocaleString(buffer,MaxTextExtent,
1548 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1549 bounds.y1,bounds.x2,bounds.y2);
1551 (void) WriteBlobString(image,buffer);
1552 profile=GetImageProfile(image,"8bim");
1553 if (profile != (StringInfo *) NULL)
1556 Embed Photoshop profile.
1558 (void) FormatLocaleString(buffer,MaxTextExtent,
1559 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1560 (void) WriteBlobString(image,buffer);
1561 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1564 (void) WriteBlobString(image,"\n% ");
1565 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1566 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1567 (void) WriteBlobString(image,buffer);
1569 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1571 profile=GetImageProfile(image,"xmp");
1572 if (0 && (profile != (StringInfo *) NULL))
1577 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1578 (void) FormatLocaleString(buffer,MaxTextExtent,
1579 "\n%%begin_xml_packet: %.20g\n",(double)
1580 GetStringInfoLength(profile));
1581 (void) WriteBlobString(image,buffer);
1582 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1583 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1584 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1586 value=GetImageProperty(image,"label",exception);
1587 if (value != (const char *) NULL)
1588 (void) WriteBlobString(image,
1589 "%%DocumentNeededResources: font Times-Roman\n");
1590 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1591 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1592 if (LocaleCompare(image_info->magick,"PS") != 0)
1593 (void) WriteBlobString(image,"%%Pages: 1\n");
1597 Compute the number of pages.
1599 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1600 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1601 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1602 image_info->adjoin != MagickFalse ? (double)
1603 GetImageListLength(image) : 1.0);
1604 (void) WriteBlobString(image,buffer);
1606 (void) WriteBlobString(image,"%%EndComments\n");
1607 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1608 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1609 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1610 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1611 (LocaleCompare(image_info->magick,"EPT") == 0))
1626 Create preview image.
1628 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1629 if (preview_image == (Image *) NULL)
1630 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1632 Dump image as bitmap.
1634 (void) FormatLocaleString(buffer,MaxTextExtent,
1635 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1636 preview_image->columns,(double) preview_image->rows,1.0,
1637 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1639 (void) WriteBlobString(image,buffer);
1641 for (y=0; y < (ssize_t) image->rows; y++)
1643 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1645 if (p == (const Quantum *) NULL)
1649 for (x=0; x < (ssize_t) preview_image->columns; x++)
1652 pixel=GetPixelIntensity(preview_image,p);
1653 if (pixel >= (Quantum) (QuantumRange/2))
1658 q=PopHexPixel(hex_digits,byte,q);
1659 if ((q-pixels+8) >= 80)
1662 (void) WriteBlob(image,q-pixels,pixels);
1664 (void) WriteBlobString(image,"% ");
1673 q=PopHexPixel(hex_digits,byte,q);
1674 if ((q-pixels+8) >= 80)
1677 (void) WriteBlob(image,q-pixels,pixels);
1679 (void) WriteBlobString(image,"% ");
1686 (void) WriteBlob(image,q-pixels,pixels);
1688 (void) WriteBlobString(image,"\n%%EndPreview\n");
1689 preview_image=DestroyImage(preview_image);
1692 Output Postscript commands.
1694 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1696 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1697 (void) WriteBlobString(image,buffer);
1699 value=GetImageProperty(image,"label",exception);
1700 if (value != (const char *) NULL)
1701 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1703 (void) WriteBlobString(image," /label 512 string def\n");
1704 (void) WriteBlobString(image," currentfile label readline pop\n");
1705 (void) FormatLocaleString(buffer,MaxTextExtent,
1706 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1707 (void) WriteBlobString(image,buffer);
1709 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1711 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1712 (void) WriteBlobString(image,buffer);
1714 if (LocaleCompare(image_info->magick,"PS") == 0)
1715 (void) WriteBlobString(image," showpage\n");
1716 (void) WriteBlobString(image,"} bind def\n");
1717 (void) WriteBlobString(image,"%%EndProlog\n");
1719 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1721 (void) WriteBlobString(image,buffer);
1722 (void) FormatLocaleString(buffer,MaxTextExtent,
1723 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1724 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1725 (geometry.height+text_size));
1726 (void) WriteBlobString(image,buffer);
1727 if ((double) geometry.x < bounds.x1)
1728 bounds.x1=(double) geometry.x;
1729 if ((double) geometry.y < bounds.y1)
1730 bounds.y1=(double) geometry.y;
1731 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1732 bounds.x2=(double) geometry.x+geometry.width-1;
1733 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1734 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1735 value=GetImageProperty(image,"label",exception);
1736 if (value != (const char *) NULL)
1737 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1738 if (LocaleCompare(image_info->magick,"PS") != 0)
1739 (void) WriteBlobString(image,"userdict begin\n");
1740 (void) WriteBlobString(image,"DisplayImage\n");
1744 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1745 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1746 (void) WriteBlobString(image,buffer);
1747 labels=(char **) NULL;
1748 value=GetImageProperty(image,"label",exception);
1749 if (value != (const char *) NULL)
1750 labels=StringToList(value);
1751 if (labels != (char **) NULL)
1753 for (i=0; labels[i] != (char *) NULL; i++)
1755 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1757 (void) WriteBlobString(image,buffer);
1758 labels[i]=DestroyString(labels[i]);
1760 labels=(char **) RelinquishMagickMemory(labels);
1762 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1763 pixel.alpha=(Quantum) TransparentAlpha;
1766 if ((image_info->type != TrueColorType) &&
1767 (IsImageGray(image,exception) != MagickFalse))
1769 if (IsImageMonochrome(image,exception) == MagickFalse)
1775 Dump image as grayscale.
1777 (void) FormatLocaleString(buffer,MaxTextExtent,
1778 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1780 (void) WriteBlobString(image,buffer);
1782 for (y=0; y < (ssize_t) image->rows; y++)
1784 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1785 if (p == (const Quantum *) NULL)
1787 for (x=0; x < (ssize_t) image->columns; x++)
1789 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
1790 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1792 if ((q-pixels+8) >= 80)
1795 (void) WriteBlob(image,q-pixels,pixels);
1798 p+=GetPixelChannels(image);
1800 if (image->previous == (Image *) NULL)
1802 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1804 if (status == MagickFalse)
1811 (void) WriteBlob(image,q-pixels,pixels);
1823 Dump image as bitmap.
1825 (void) FormatLocaleString(buffer,MaxTextExtent,
1826 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1828 (void) WriteBlobString(image,buffer);
1830 for (y=0; y < (ssize_t) image->rows; y++)
1832 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1833 if (p == (const Quantum *) NULL)
1837 for (x=0; x < (ssize_t) image->columns; x++)
1840 pixel=GetPixelIntensity(image,p);
1841 if (pixel >= (Quantum) (QuantumRange/2))
1846 q=PopHexPixel(hex_digits,byte,q);
1847 if ((q-pixels+2) >= 80)
1850 (void) WriteBlob(image,q-pixels,pixels);
1856 p+=GetPixelChannels(image);
1861 q=PopHexPixel(hex_digits,byte,q);
1862 if ((q-pixels+2) >= 80)
1865 (void) WriteBlob(image,q-pixels,pixels);
1869 if (image->previous == (Image *) NULL)
1871 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1873 if (status == MagickFalse)
1880 (void) WriteBlob(image,q-pixels,pixels);
1885 if ((image->storage_class == DirectClass) ||
1886 (image->colors > 256) || (image->matte != MagickFalse))
1889 Dump DirectClass image.
1891 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1892 (double) image->columns,(double) image->rows,
1893 image_info->compression == RLECompression ? 1 : 0);
1894 (void) WriteBlobString(image,buffer);
1895 switch (image_info->compression)
1897 case RLECompression:
1900 Dump runlength-encoded DirectColor packets.
1903 for (y=0; y < (ssize_t) image->rows; y++)
1905 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1906 if (p == (const Quantum *) NULL)
1908 GetPixelInfoPixel(image,p,&pixel);
1910 for (x=0; x < (ssize_t) image->columns; x++)
1912 if ((GetPixelRed(image,p) == pixel.red) &&
1913 (GetPixelGreen(image,p) == pixel.green) &&
1914 (GetPixelBlue(image,p) == pixel.blue) &&
1915 (GetPixelAlpha(image,p) == pixel.alpha) &&
1916 (length < 255) && (x < (ssize_t) (image->columns-1)))
1922 WriteRunlengthPacket(image,pixel,length,p);
1923 if ((q-pixels+10) >= 80)
1926 (void) WriteBlob(image,q-pixels,pixels);
1932 GetPixelInfoPixel(image,p,&pixel);
1933 p+=GetPixelChannels(image);
1935 WriteRunlengthPacket(image,pixel,length,p);
1936 if ((q-pixels+10) >= 80)
1939 (void) WriteBlob(image,q-pixels,pixels);
1942 if (image->previous == (Image *) NULL)
1944 status=SetImageProgress(image,SaveImageTag,
1945 (MagickOffsetType) y,image->rows);
1946 if (status == MagickFalse)
1953 (void) WriteBlob(image,q-pixels,pixels);
1961 Dump uncompressed DirectColor packets.
1964 for (y=0; y < (ssize_t) image->rows; y++)
1966 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1967 if (p == (const Quantum *) NULL)
1969 for (x=0; x < (ssize_t) image->columns; x++)
1971 if ((image->matte != MagickFalse) &&
1972 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1974 q=PopHexPixel(hex_digits,0xff,q);
1975 q=PopHexPixel(hex_digits,0xff,q);
1976 q=PopHexPixel(hex_digits,0xff,q);
1980 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1981 GetPixelRed(image,p)),q);
1982 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1983 GetPixelGreen(image,p)),q);
1984 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1985 GetPixelBlue(image,p)),q);
1987 if ((q-pixels+6) >= 80)
1990 (void) WriteBlob(image,q-pixels,pixels);
1993 p+=GetPixelChannels(image);
1995 if (image->previous == (Image *) NULL)
1997 status=SetImageProgress(image,SaveImageTag,
1998 (MagickOffsetType) y,image->rows);
1999 if (status == MagickFalse)
2006 (void) WriteBlob(image,q-pixels,pixels);
2011 (void) WriteBlobByte(image,'\n');
2016 Dump PseudoClass image.
2018 (void) FormatLocaleString(buffer,MaxTextExtent,
2019 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
2020 image->rows,image->storage_class == PseudoClass ? 1 : 0,
2021 image_info->compression == RLECompression ? 1 : 0);
2022 (void) WriteBlobString(image,buffer);
2024 Dump number of colors and colormap.
2026 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2028 (void) WriteBlobString(image,buffer);
2029 for (i=0; i < (ssize_t) image->colors; i++)
2031 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2032 ScaleQuantumToChar(image->colormap[i].red),
2033 ScaleQuantumToChar(image->colormap[i].green),
2034 ScaleQuantumToChar(image->colormap[i].blue));
2035 (void) WriteBlobString(image,buffer);
2037 switch (image_info->compression)
2039 case RLECompression:
2042 Dump runlength-encoded PseudoColor packets.
2045 for (y=0; y < (ssize_t) image->rows; y++)
2047 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2048 if (p == (const Quantum *) NULL)
2050 index=GetPixelIndex(image,p);
2052 for (x=0; x < (ssize_t) image->columns; x++)
2054 if ((index == GetPixelIndex(image,p)) &&
2055 (length < 255) && (x < ((ssize_t) image->columns-1)))
2061 q=PopHexPixel(hex_digits,(size_t) index,q);
2062 q=PopHexPixel(hex_digits,(size_t)
2063 MagickMin(length,0xff),q);
2065 if ((q-pixels+6) >= 80)
2068 (void) WriteBlob(image,q-pixels,pixels);
2074 index=GetPixelIndex(image,p);
2075 pixel.red=GetPixelRed(image,p);
2076 pixel.green=GetPixelGreen(image,p);
2077 pixel.blue=GetPixelBlue(image,p);
2078 pixel.alpha=GetPixelAlpha(image,p);
2079 p+=GetPixelChannels(image);
2081 q=PopHexPixel(hex_digits,(size_t) index,q);
2082 q=PopHexPixel(hex_digits,(size_t)
2083 MagickMin(length,0xff),q);
2084 if (image->previous == (Image *) NULL)
2086 status=SetImageProgress(image,SaveImageTag,
2087 (MagickOffsetType) y,image->rows);
2088 if (status == MagickFalse)
2095 (void) WriteBlob(image,q-pixels,pixels);
2103 Dump uncompressed PseudoColor packets.
2106 for (y=0; y < (ssize_t) image->rows; y++)
2108 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2109 if (p == (const Quantum *) NULL)
2111 for (x=0; x < (ssize_t) image->columns; x++)
2113 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2114 if ((q-pixels+4) >= 80)
2117 (void) WriteBlob(image,q-pixels,pixels);
2120 p+=GetPixelChannels(image);
2122 if (image->previous == (Image *) NULL)
2124 status=SetImageProgress(image,SaveImageTag,
2125 (MagickOffsetType) y,image->rows);
2126 if (status == MagickFalse)
2133 (void) WriteBlob(image,q-pixels,pixels);
2138 (void) WriteBlobByte(image,'\n');
2140 if (LocaleCompare(image_info->magick,"PS") != 0)
2141 (void) WriteBlobString(image,"end\n");
2142 (void) WriteBlobString(image,"%%PageTrailer\n");
2143 if (GetNextImageInList(image) == (Image *) NULL)
2145 image=SyncNextImageInList(image);
2146 status=SetImageProgress(image,SaveImagesTag,scene++,
2147 GetImageListLength(image));
2148 if (status == MagickFalse)
2150 } while (image_info->adjoin != MagickFalse);
2151 (void) WriteBlobString(image,"%%Trailer\n");
2154 (void) FormatLocaleString(buffer,MaxTextExtent,
2155 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2156 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
2157 (void) WriteBlobString(image,buffer);
2158 (void) FormatLocaleString(buffer,MaxTextExtent,
2159 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2160 bounds.x2,bounds.y2);
2161 (void) WriteBlobString(image,buffer);
2163 (void) WriteBlobString(image,"%%EOF\n");
2164 (void) CloseBlob(image);