2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2011 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/constitute.h"
51 #include "MagickCore/delegate.h"
52 #include "MagickCore/delegate-private.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/geometry.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/monitor.h"
63 #include "MagickCore/monitor-private.h"
64 #include "MagickCore/option.h"
65 #include "MagickCore/profile.h"
66 #include "MagickCore/resource_.h"
67 #include "MagickCore/pixel-accessor.h"
68 #include "MagickCore/property.h"
69 #include "MagickCore/quantum-private.h"
70 #include "MagickCore/static.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/module.h"
73 #include "MagickCore/token.h"
74 #include "MagickCore/transform.h"
75 #include "MagickCore/utility.h"
80 static MagickBooleanType
81 WritePSImage(const ImageInfo *,Image *);
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88 % I n v o k e P o s t s r i p t D e l e g a t e %
92 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 % InvokePostscriptDelegate() executes the Postscript interpreter with the
97 % The format of the InvokePostscriptDelegate method is:
99 % MagickBooleanType InvokePostscriptDelegate(
100 % const MagickBooleanType verbose,const char *command,
101 % ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o verbose: A value other than zero displays the command prior to
108 % o command: the address of a character string containing the command to
111 % o exception: return any errors or warnings in this structure.
114 static MagickBooleanType InvokePostscriptDelegate(
115 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
120 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
137 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
138 ghost_info=NTGhostscriptDLLVectors();
143 ghost_info=(&ghost_info_struct);
144 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
145 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
147 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
148 gsapi_init_with_args;
149 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
150 int *)) gsapi_run_string;
151 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
152 gsapi_delete_instance;
153 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
155 if (ghost_info == (GhostInfo *) NULL)
157 status=SystemCommand(MagickFalse,verbose,command,exception);
158 return(status == 0 ? MagickTrue : MagickFalse);
160 if (verbose != MagickFalse)
162 (void) fputs("[ghostscript library]",stdout);
163 (void) fputs(strchr(command,' '),stdout);
165 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
168 status=SystemCommand(MagickFalse,verbose,command,exception);
169 return(status == 0 ? MagickTrue : MagickFalse);
172 argv=StringToArgv(command,&argc);
173 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
175 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
177 (ghost_info->exit)(interpreter);
178 (ghost_info->delete_instance)(interpreter);
179 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
180 NTGhostscriptUnLoadDLL();
182 for (i=0; i < (ssize_t) argc; i++)
183 argv[i]=DestroyString(argv[i]);
184 argv=(char **) RelinquishMagickMemory(argv);
185 if ((status != 0) && (status != -101))
190 message=GetExceptionMessage(errno);
191 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
192 "`%s': %s",command,message);
193 message=DestroyString(message);
194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
195 "Ghostscript returns status %d, exit code %d",status,code);
200 status=SystemCommand(MagickFalse,verbose,command,exception);
201 return(status == 0 ? MagickTrue : MagickFalse);
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 % IsPS() returns MagickTrue if the image format type, identified by the
217 % magick string, is PS.
219 % The format of the IsPS method is:
221 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
223 % A description of each parameter follows:
225 % o magick: compare image format pattern against these bytes.
227 % o length: Specifies the length of the magick string.
230 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
234 if (memcmp(magick,"%!",2) == 0)
236 if (memcmp(magick,"\004%!",3) == 0)
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 % R e a d P S I m a g e %
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 % ReadPSImage() reads a Postscript image file and returns it. It allocates
253 % the memory necessary for the new Image structure and returns a pointer
256 % The format of the ReadPSImage method is:
258 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
260 % A description of each parameter follows:
262 % o image_info: the image info.
264 % o exception: return any errors or warnings in this structure.
268 static MagickBooleanType IsPostscriptRendered(const char *path)
276 if ((path == (const char *) NULL) || (*path == '\0'))
278 status=GetPathAttributes(path,&attributes);
279 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
280 (attributes.st_size > 0))
285 static inline int ProfileInteger(Image *image,short int *hex_digits)
299 c=ReadBlobByte(image);
300 if ((c == EOF) || ((c == '%') && (l == '%')))
307 if (isxdigit(c) == MagickFalse)
309 value=(int) ((size_t) value << 4)+hex_digits[c];
315 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
317 #define BoundingBox "BoundingBox:"
318 #define BeginDocument "BeginDocument:"
319 #define BeginXMPPacket "<?xpacket begin="
320 #define EndXMPPacket "<?xpacket end="
321 #define ICCProfile "BeginICCProfile:"
322 #define CMYKCustomColor "CMYKCustomColor:"
323 #define CMYKProcessColor "CMYKProcessColor:"
324 #define DocumentMedia "DocumentMedia:"
325 #define DocumentCustomColors "DocumentCustomColors:"
326 #define DocumentProcessColors "DocumentProcessColors:"
327 #define EndDocument "EndDocument:"
328 #define HiResBoundingBox "HiResBoundingBox:"
329 #define ImageData "ImageData:"
330 #define PageBoundingBox "PageBoundingBox:"
331 #define LanguageLevel "LanguageLevel:"
332 #define PageMedia "PageMedia:"
333 #define Pages "Pages:"
334 #define PhotoshopProfile "BeginPhotoshop:"
335 #define PostscriptLevel "!PS-"
336 #define RenderPostscriptText " Rendering Postscript... "
337 #define SpotColor "+ "
340 command[MaxTextExtent],
341 density[MaxTextExtent],
342 filename[MaxTextExtent],
343 geometry[MaxTextExtent],
344 input_filename[MaxTextExtent],
345 options[MaxTextExtent],
346 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);
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->x_resolution == 0.0) || (image->y_resolution == 0.0))
472 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
473 image->x_resolution=geometry_info.rho;
474 image->y_resolution=geometry_info.sigma;
475 if ((flags & SigmaValue) == 0)
476 image->y_resolution=image->x_resolution;
479 Determine page geometry from the Postscript bounding box.
481 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
482 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
483 (void) ResetMagickMemory(&page,0,sizeof(page));
484 (void) ResetMagickMemory(command,0,sizeof(command));
493 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
496 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
499 Note document structuring comments.
502 if ((strchr("\n\r%",c) == (char *) NULL) &&
503 ((size_t) (p-command) < (MaxTextExtent-1)))
508 Skip %%BeginDocument thru %%EndDocument.
510 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
512 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
514 if (skip != MagickFalse)
516 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
518 (void) SetImageProperty(image,"ps:Level",command+4);
519 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
522 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
523 (void) sscanf(command,LanguageLevel " %lu",&language_level);
524 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
525 (void) sscanf(command,Pages " %lu",&pages);
526 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
527 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
528 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
536 profile=AcquireStringInfo(65536);
537 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
539 SetStringInfoLength(profile,(size_t) i+1);
540 datum=GetStringInfoDatum(profile);
541 datum[i]=(unsigned char) c;
543 (void) SetImageProfile(image,"icc",profile);
544 profile=DestroyStringInfo(profile);
547 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
553 Read Photoshop profile.
555 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
559 profile=AcquireStringInfo(length);
560 p=GetStringInfoDatum(profile);
561 for (i=0; i < (ssize_t) length; i++)
562 *p++=(unsigned char) ProfileInteger(image,hex_digits);
563 (void) SetImageProfile(image,"8bim",profile);
564 profile=DestroyStringInfo(profile);
567 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
576 profile=StringToStringInfo(command);
577 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
579 SetStringInfoLength(profile,i+1);
580 c=ReadBlobByte(image);
581 GetStringInfoDatum(profile)[i]=(unsigned char) c;
583 if ((strchr("\n\r%",c) == (char *) NULL) &&
584 ((size_t) (p-command) < (MaxTextExtent-1)))
588 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
591 SetStringInfoLength(profile,i);
592 (void) SetImageProfile(image,"xmp",profile);
593 profile=DestroyStringInfo(profile);
597 Is this a CMYK document?
599 length=strlen(DocumentProcessColors);
600 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
602 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
603 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
604 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
607 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
609 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
611 length=strlen(DocumentCustomColors);
612 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
613 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
614 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
617 property[MaxTextExtent],
626 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
627 (double) (spotcolor++));
628 for (p=command; *p != '\0'; p++)
629 if (isspace((int) (unsigned char) *p) != 0)
631 value=AcquireString(p);
632 (void) SubstituteString(&value,"(","");
633 (void) SubstituteString(&value,")","");
634 (void) StripString(value);
635 (void) SetImageProperty(image,property,value);
636 value=DestroyString(value);
640 Note region defined by bounding box.
643 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
644 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
645 &bounds.y1,&bounds.x2,&bounds.y2);
646 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
647 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
649 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
650 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
651 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
652 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
653 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
654 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
655 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
656 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
660 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
661 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
664 Set Postscript render geometry.
666 (void) FormatLocaleString(geometry,MaxTextExtent,
667 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
668 bounds.x1,bounds.y1);
669 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
670 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
671 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
675 (void) CloseBlob(image);
676 if (image_info->colorspace == RGBColorspace)
679 Create Ghostscript control file.
681 file=AcquireUniqueFileResource(postscript_filename);
684 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
685 image_info->filename);
686 image=DestroyImageList(image);
687 return((Image *) NULL);
689 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
690 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
691 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
692 count=write(file,command,(unsigned int) strlen(command));
693 if (image_info->page == (char *) NULL)
696 translate_geometry[MaxTextExtent];
698 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
699 "%g %g translate\n",-bounds.x1,-bounds.y1);
700 count=write(file,translate_geometry,(unsigned int)
701 strlen(translate_geometry));
705 Render Postscript with the Ghostscript delegate.
707 if (image_info->monochrome != MagickFalse)
708 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
710 if (cmyk != MagickFalse)
711 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
713 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
714 if (delegate_info == (const DelegateInfo *) NULL)
716 (void) RelinquishUniqueFileResource(postscript_filename);
717 image=DestroyImageList(image);
718 return((Image *) NULL);
721 if ((page.width == 0) || (page.height == 0))
722 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
723 if (image_info->density != (char *) NULL)
725 flags=ParseGeometry(image_info->density,&geometry_info);
726 image->x_resolution=geometry_info.rho;
727 image->y_resolution=geometry_info.sigma;
728 if ((flags & SigmaValue) == 0)
729 image->y_resolution=image->x_resolution;
731 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
732 image->x_resolution,image->y_resolution);
733 if (image_info->page != (char *) NULL)
734 (void) ParseAbsoluteGeometry(image_info->page,&page);
735 page.width=(size_t) floor((double) (page.width*image->x_resolution/delta.x)+
737 page.height=(size_t) floor((double) (page.height*image->y_resolution/delta.y)+
739 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
740 page.width,(double) page.height);
741 read_info=CloneImageInfo(image_info);
742 *read_info->magick='\0';
743 if (read_info->number_scenes != 0)
746 pages[MaxTextExtent];
748 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
749 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
750 (read_info->scene+read_info->number_scenes));
751 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
752 read_info->number_scenes=0;
753 if (read_info->scenes != (char *) NULL)
754 *read_info->scenes='\0';
756 option=GetImageOption(image_info,"ps:use-cropbox");
757 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
758 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
759 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
760 (void) AcquireUniqueFilename(filename);
761 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
762 (void) FormatLocaleString(command,MaxTextExtent,
763 GetDelegateCommands(delegate_info),
764 read_info->antialias != MagickFalse ? 4 : 1,
765 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
766 postscript_filename,input_filename);
767 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
768 (void) InterpretImageFilename(image_info,image,filename,1,
769 read_info->filename);
770 if ((status == MagickFalse) ||
771 (IsPostscriptRendered(read_info->filename) == MagickFalse))
773 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
774 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
776 (void) RelinquishUniqueFileResource(postscript_filename);
777 (void) RelinquishUniqueFileResource(input_filename);
778 postscript_image=(Image *) NULL;
779 if (status == MagickFalse)
782 (void) InterpretImageFilename(image_info,image,filename,(int) i,
783 read_info->filename);
784 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
786 (void) RelinquishUniqueFileResource(read_info->filename);
791 (void) InterpretImageFilename(image_info,image,filename,(int) i,
792 read_info->filename);
793 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
795 next=ReadImage(read_info,exception);
796 (void) RelinquishUniqueFileResource(read_info->filename);
797 if (next == (Image *) NULL)
799 AppendImageToList(&postscript_image,next);
801 (void) RelinquishUniqueFileResource(read_info->filename);
802 read_info=DestroyImageInfo(read_info);
803 if (postscript_image == (Image *) NULL)
805 image=DestroyImageList(image);
806 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
807 image_info->filename);
808 return((Image *) NULL);
810 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
815 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
816 if (cmyk_image != (Image *) NULL)
818 postscript_image=DestroyImageList(postscript_image);
819 postscript_image=cmyk_image;
822 if (image_info->number_scenes != 0)
831 Add place holder images to meet the subimage specification requirement.
833 for (i=0; i < (ssize_t) image_info->scene; i++)
835 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
836 if (clone_image != (Image *) NULL)
837 PrependImageToList(&postscript_image,clone_image);
842 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
844 postscript_image->magick_columns=columns;
846 postscript_image->magick_rows=rows;
847 postscript_image->page=page;
848 (void) CloneImageProfiles(postscript_image,image);
849 (void) CloneImageProperties(postscript_image,image);
850 next=SyncNextImageInList(postscript_image);
851 if (next != (Image *) NULL)
852 postscript_image=next;
853 } while (next != (Image *) NULL);
854 image=DestroyImageList(image);
856 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
859 next=GetNextImageInList(next);
861 return(GetFirstImageInList(postscript_image));
865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
869 % R e g i s t e r P S I m a g e %
873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875 % RegisterPSImage() adds properties for the PS image format to
876 % the list of supported formats. The properties include the image format
877 % tag, a method to read and/or write the format, whether the format
878 % supports the saving of more than one frame to the same file or blob,
879 % whether the format supports native in-memory I/O, and a brief
880 % description of the format.
882 % The format of the RegisterPSImage method is:
884 % size_t RegisterPSImage(void)
887 ModuleExport size_t RegisterPSImage(void)
892 entry=SetMagickInfo("EPI");
893 entry->decoder=(DecodeImageHandler *) ReadPSImage;
894 entry->encoder=(EncodeImageHandler *) WritePSImage;
895 entry->magick=(IsImageFormatHandler *) IsPS;
896 entry->adjoin=MagickFalse;
897 entry->blob_support=MagickFalse;
898 entry->seekable_stream=MagickTrue;
899 entry->thread_support=EncoderThreadSupport;
900 entry->description=ConstantString(
901 "Encapsulated PostScript Interchange format");
902 entry->module=ConstantString("PS");
903 (void) RegisterMagickInfo(entry);
904 entry=SetMagickInfo("EPS");
905 entry->decoder=(DecodeImageHandler *) ReadPSImage;
906 entry->encoder=(EncodeImageHandler *) WritePSImage;
907 entry->magick=(IsImageFormatHandler *) IsPS;
908 entry->adjoin=MagickFalse;
909 entry->blob_support=MagickFalse;
910 entry->seekable_stream=MagickTrue;
911 entry->thread_support=EncoderThreadSupport;
912 entry->description=ConstantString("Encapsulated PostScript");
913 entry->module=ConstantString("PS");
914 (void) RegisterMagickInfo(entry);
915 entry=SetMagickInfo("EPSF");
916 entry->decoder=(DecodeImageHandler *) ReadPSImage;
917 entry->encoder=(EncodeImageHandler *) WritePSImage;
918 entry->magick=(IsImageFormatHandler *) IsPS;
919 entry->adjoin=MagickFalse;
920 entry->blob_support=MagickFalse;
921 entry->seekable_stream=MagickTrue;
922 entry->description=ConstantString("Encapsulated PostScript");
923 entry->module=ConstantString("PS");
924 (void) RegisterMagickInfo(entry);
925 entry=SetMagickInfo("EPSI");
926 entry->decoder=(DecodeImageHandler *) ReadPSImage;
927 entry->encoder=(EncodeImageHandler *) WritePSImage;
928 entry->magick=(IsImageFormatHandler *) IsPS;
929 entry->adjoin=MagickFalse;
930 entry->blob_support=MagickFalse;
931 entry->seekable_stream=MagickTrue;
932 entry->thread_support=EncoderThreadSupport;
933 entry->description=ConstantString(
934 "Encapsulated PostScript Interchange format");
935 entry->module=ConstantString("PS");
936 (void) RegisterMagickInfo(entry);
937 entry=SetMagickInfo("PS");
938 entry->decoder=(DecodeImageHandler *) ReadPSImage;
939 entry->encoder=(EncodeImageHandler *) WritePSImage;
940 entry->magick=(IsImageFormatHandler *) IsPS;
941 entry->module=ConstantString("PS");
942 entry->blob_support=MagickFalse;
943 entry->seekable_stream=MagickTrue;
944 entry->thread_support=EncoderThreadSupport;
945 entry->description=ConstantString("PostScript");
946 (void) RegisterMagickInfo(entry);
947 return(MagickImageCoderSignature);
951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955 % U n r e g i s t e r P S I m a g e %
959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 % UnregisterPSImage() removes format registrations made by the
962 % PS module from the list of supported formats.
964 % The format of the UnregisterPSImage method is:
966 % UnregisterPSImage(void)
969 ModuleExport void UnregisterPSImage(void)
971 (void) UnregisterMagickInfo("EPI");
972 (void) UnregisterMagickInfo("EPS");
973 (void) UnregisterMagickInfo("EPSF");
974 (void) UnregisterMagickInfo("EPSI");
975 (void) UnregisterMagickInfo("PS");
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983 % W r i t e P S I m a g e %
987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
989 % WritePSImage translates an image to encapsulated Postscript
990 % Level I for printing. If the supplied geometry is null, the image is
991 % centered on the Postscript page. Otherwise, the image is positioned as
992 % specified by the geometry.
994 % The format of the WritePSImage method is:
996 % MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
998 % A description of each parameter follows:
1000 % o image_info: the image info.
1002 % o image: the image.
1006 static inline size_t MagickMin(const size_t x,const size_t y)
1013 static inline unsigned char *PopHexPixel(const char **hex_digits,
1014 const size_t pixel,unsigned char *pixels)
1019 hex=hex_digits[pixel];
1020 *pixels++=(unsigned char) (*hex++);
1021 *pixels++=(unsigned char) (*hex);
1025 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
1027 #define WriteRunlengthPacket(image,pixel,length,p) \
1029 if ((image->matte != MagickFalse) && \
1030 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1032 q=PopHexPixel(hex_digits,0xff,q); \
1033 q=PopHexPixel(hex_digits,0xff,q); \
1034 q=PopHexPixel(hex_digits,0xff,q); \
1038 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1039 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1040 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1042 q=PopHexPixel(hex_digits,(const size_t) MagickMin(length,0xff),q); \
1048 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1049 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1050 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1051 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1052 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1053 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1054 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1055 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1056 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1057 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1058 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1059 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1060 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1061 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1062 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1063 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1064 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1065 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1066 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1067 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1068 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1069 "FC", "FD", "FE", "FF", (char *) NULL
1071 *PostscriptProlog[]=
1075 "% Display a color image. The image is displayed in color on",
1076 "% Postscript viewers or printers that support color, otherwise",
1077 "% it is displayed as grayscale.",
1079 "/DirectClassPacket",
1082 " % Get a DirectClass packet.",
1088 " % length: number of pixels minus one of this color (optional).",
1090 " currentfile color_packet readhexstring pop pop",
1091 " compression 0 eq",
1093 " /number_pixels 3 def",
1096 " currentfile byte readhexstring pop 0 get",
1097 " /number_pixels exch 1 add 3 mul def",
1099 " 0 3 number_pixels 1 sub",
1101 " pixels exch color_packet putinterval",
1103 " pixels 0 number_pixels getinterval",
1106 "/DirectClassImage",
1109 " % Display a DirectClass image.",
1111 " systemdict /colorimage known",
1118 " { DirectClassPacket } false 3 colorimage",
1122 " % No colorimage operator; convert to grayscale.",
1129 " { GrayDirectClassPacket } image",
1133 "/GrayDirectClassPacket",
1136 " % Get a DirectClass packet; convert to grayscale.",
1142 " % length: number of pixels minus one of this color (optional).",
1144 " currentfile color_packet readhexstring pop pop",
1145 " color_packet 0 get 0.299 mul",
1146 " color_packet 1 get 0.587 mul add",
1147 " color_packet 2 get 0.114 mul add",
1149 " /gray_packet exch def",
1150 " compression 0 eq",
1152 " /number_pixels 1 def",
1155 " currentfile byte readhexstring pop 0 get",
1156 " /number_pixels exch 1 add def",
1158 " 0 1 number_pixels 1 sub",
1160 " pixels exch gray_packet put",
1162 " pixels 0 number_pixels getinterval",
1165 "/GrayPseudoClassPacket",
1168 " % Get a PseudoClass packet; convert to grayscale.",
1171 " % index: index into the colormap.",
1172 " % length: number of pixels minus one of this color (optional).",
1174 " currentfile byte readhexstring pop 0 get",
1175 " /offset exch 3 mul def",
1176 " /color_packet colormap offset 3 getinterval def",
1177 " color_packet 0 get 0.299 mul",
1178 " color_packet 1 get 0.587 mul add",
1179 " color_packet 2 get 0.114 mul add",
1181 " /gray_packet exch def",
1182 " compression 0 eq",
1184 " /number_pixels 1 def",
1187 " currentfile byte readhexstring pop 0 get",
1188 " /number_pixels exch 1 add def",
1190 " 0 1 number_pixels 1 sub",
1192 " pixels exch gray_packet put",
1194 " pixels 0 number_pixels getinterval",
1197 "/PseudoClassPacket",
1200 " % Get a PseudoClass packet.",
1203 " % index: index into the colormap.",
1204 " % length: number of pixels minus one of this color (optional).",
1206 " currentfile byte readhexstring pop 0 get",
1207 " /offset exch 3 mul def",
1208 " /color_packet colormap offset 3 getinterval def",
1209 " compression 0 eq",
1211 " /number_pixels 3 def",
1214 " currentfile byte readhexstring pop 0 get",
1215 " /number_pixels exch 1 add 3 mul def",
1217 " 0 3 number_pixels 1 sub",
1219 " pixels exch color_packet putinterval",
1221 " pixels 0 number_pixels getinterval",
1224 "/PseudoClassImage",
1227 " % Display a PseudoClass image.",
1230 " % class: 0-PseudoClass or 1-Grayscale.",
1232 " currentfile buffer readline pop",
1233 " token pop /class exch def pop",
1236 " currentfile buffer readline pop",
1237 " token pop /depth exch def pop",
1238 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1239 " columns rows depth",
1244 " { currentfile grays readhexstring pop } image",
1249 " % colors: number of colors in the colormap.",
1250 " % colormap: red, green, blue color packets.",
1252 " currentfile buffer readline pop",
1253 " token pop /colors exch def pop",
1254 " /colors colors 3 mul def",
1255 " /colormap colors string def",
1256 " currentfile colormap readhexstring pop pop",
1257 " systemdict /colorimage known",
1264 " { PseudoClassPacket } false 3 colorimage",
1268 " % No colorimage operator; convert to grayscale.",
1275 " { GrayPseudoClassPacket } image",
1283 " % Display a DirectClass or PseudoClass image.",
1286 " % x & y translation.",
1288 " % label pointsize.",
1290 " % image columns & rows.",
1291 " % class: 0-DirectClass or 1-PseudoClass.",
1292 " % compression: 0-none or 1-RunlengthEncoded.",
1293 " % hex color packets.",
1296 " /buffer 512 string def",
1297 " /byte 1 string def",
1298 " /color_packet 3 string def",
1299 " /pixels 768 string def",
1301 " currentfile buffer readline pop",
1302 " token pop /x exch def",
1303 " token pop /y exch def pop",
1305 " currentfile buffer readline pop",
1306 " token pop /x exch def",
1307 " token pop /y exch def pop",
1308 " currentfile buffer readline pop",
1309 " token pop /pointsize exch def pop",
1310 " /Times-Roman findfont pointsize scalefont setfont",
1313 *PostscriptEpilog[]=
1316 " currentfile buffer readline pop",
1317 " token pop /columns exch def",
1318 " token pop /rows exch def pop",
1319 " currentfile buffer readline pop",
1320 " token pop /class exch def pop",
1321 " currentfile buffer readline pop",
1322 " token pop /compression exch def pop",
1323 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1328 buffer[MaxTextExtent],
1329 date[MaxTextExtent],
1331 page_geometry[MaxTextExtent];
1371 register const Quantum
1378 register unsigned char
1402 Open output image file.
1404 assert(image_info != (const ImageInfo *) NULL);
1405 assert(image_info->signature == MagickSignature);
1406 assert(image != (Image *) NULL);
1407 assert(image->signature == MagickSignature);
1408 if (image->debug != MagickFalse)
1409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1410 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1411 if (status == MagickFalse)
1413 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1419 Scale relative to dots-per-inch.
1421 if ((image->colorspace != RGBColorspace) &&
1422 (image->colorspace != CMYKColorspace))
1423 (void) TransformImageColorspace(image,RGBColorspace);
1424 delta.x=DefaultResolution;
1425 delta.y=DefaultResolution;
1426 resolution.x=image->x_resolution;
1427 resolution.y=image->y_resolution;
1428 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1430 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1431 resolution.x=geometry_info.rho;
1432 resolution.y=geometry_info.sigma;
1433 if ((flags & SigmaValue) == 0)
1434 resolution.y=resolution.x;
1436 if (image_info->density != (char *) NULL)
1438 flags=ParseGeometry(image_info->density,&geometry_info);
1439 resolution.x=geometry_info.rho;
1440 resolution.y=geometry_info.sigma;
1441 if ((flags & SigmaValue) == 0)
1442 resolution.y=resolution.x;
1444 if (image->units == PixelsPerCentimeterResolution)
1446 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1447 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1449 SetGeometry(image,&geometry);
1450 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1451 (double) image->columns,(double) image->rows);
1452 if (image_info->page != (char *) NULL)
1453 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1455 if ((image->page.width != 0) && (image->page.height != 0))
1456 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1457 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1458 image->page.height,(double) image->page.x,(double) image->page.y);
1460 if ((image->gravity != UndefinedGravity) &&
1461 (LocaleCompare(image_info->magick,"PS") == 0))
1462 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1463 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1464 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1465 &geometry.width,&geometry.height);
1466 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1467 geometry.width=(size_t) floor(scale.x+0.5);
1468 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1469 geometry.height=(size_t) floor(scale.y+0.5);
1470 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1471 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1473 if (image->gravity != UndefinedGravity)
1475 geometry.x=(-page_info.x);
1476 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1479 if (image_info->pointsize != 0.0)
1480 pointsize=image_info->pointsize;
1482 value=GetImageProperty(image,"label");
1483 if (value != (const char *) NULL)
1484 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1488 Output Postscript header.
1490 if (LocaleCompare(image_info->magick,"PS") == 0)
1491 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1493 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1495 (void) WriteBlobString(image,buffer);
1496 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1497 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1499 (void) WriteBlobString(image,buffer);
1500 timer=time((time_t *) NULL);
1501 (void) FormatMagickTime(timer,MaxTextExtent,date);
1502 (void) FormatLocaleString(buffer,MaxTextExtent,
1503 "%%%%CreationDate: (%s)\n",date);
1504 (void) WriteBlobString(image,buffer);
1505 bounds.x1=(double) geometry.x;
1506 bounds.y1=(double) geometry.y;
1507 bounds.x2=(double) geometry.x+scale.x;
1508 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1509 if ((image_info->adjoin != MagickFalse) &&
1510 (GetNextImageInList(image) != (Image *) NULL))
1511 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1515 (void) FormatLocaleString(buffer,MaxTextExtent,
1516 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1517 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1518 (void) WriteBlobString(image,buffer);
1519 (void) FormatLocaleString(buffer,MaxTextExtent,
1520 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1521 bounds.y1,bounds.x2,bounds.y2);
1523 (void) WriteBlobString(image,buffer);
1524 profile=GetImageProfile(image,"8bim");
1525 if (profile != (StringInfo *) NULL)
1528 Embed Photoshop profile.
1530 (void) FormatLocaleString(buffer,MaxTextExtent,
1531 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1532 (void) WriteBlobString(image,buffer);
1533 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1536 (void) WriteBlobString(image,"\n% ");
1537 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1538 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1539 (void) WriteBlobString(image,buffer);
1541 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1543 profile=GetImageProfile(image,"xmp");
1544 if (0 && (profile != (StringInfo *) NULL))
1549 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1550 (void) FormatLocaleString(buffer,MaxTextExtent,
1551 "\n%%begin_xml_packet: %.20g\n",(double)
1552 GetStringInfoLength(profile));
1553 (void) WriteBlobString(image,buffer);
1554 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1555 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1556 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1558 value=GetImageProperty(image,"label");
1559 if (value != (const char *) NULL)
1560 (void) WriteBlobString(image,
1561 "%%DocumentNeededResources: font Times-Roman\n");
1562 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1563 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1564 if (LocaleCompare(image_info->magick,"PS") != 0)
1565 (void) WriteBlobString(image,"%%Pages: 1\n");
1569 Compute the number of pages.
1571 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1572 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1573 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1574 image_info->adjoin != MagickFalse ? (double)
1575 GetImageListLength(image) : 1.0);
1576 (void) WriteBlobString(image,buffer);
1578 (void) WriteBlobString(image,"%%EndComments\n");
1579 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1580 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1581 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1582 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1583 (LocaleCompare(image_info->magick,"EPT") == 0))
1598 Create preview image.
1600 preview_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1601 if (preview_image == (Image *) NULL)
1602 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1604 Dump image as bitmap.
1606 (void) FormatLocaleString(buffer,MaxTextExtent,
1607 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1608 preview_image->columns,(double) preview_image->rows,1.0,
1609 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1611 (void) WriteBlobString(image,buffer);
1613 for (y=0; y < (ssize_t) image->rows; y++)
1615 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1616 &preview_image->exception);
1617 if (p == (const Quantum *) NULL)
1621 for (x=0; x < (ssize_t) preview_image->columns; x++)
1624 pixel=GetPixelIntensity(preview_image,p);
1625 if (pixel >= (Quantum) (QuantumRange/2))
1630 q=PopHexPixel(hex_digits,byte,q);
1631 if ((q-pixels+8) >= 80)
1634 (void) WriteBlob(image,q-pixels,pixels);
1636 (void) WriteBlobString(image,"% ");
1645 q=PopHexPixel(hex_digits,byte,q);
1646 if ((q-pixels+8) >= 80)
1649 (void) WriteBlob(image,q-pixels,pixels);
1651 (void) WriteBlobString(image,"% ");
1658 (void) WriteBlob(image,q-pixels,pixels);
1660 (void) WriteBlobString(image,"\n%%EndPreview\n");
1661 preview_image=DestroyImage(preview_image);
1664 Output Postscript commands.
1666 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1668 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1669 (void) WriteBlobString(image,buffer);
1671 value=GetImageProperty(image,"label");
1672 if (value != (const char *) NULL)
1673 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1675 (void) WriteBlobString(image," /label 512 string def\n");
1676 (void) WriteBlobString(image," currentfile label readline pop\n");
1677 (void) FormatLocaleString(buffer,MaxTextExtent,
1678 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1679 (void) WriteBlobString(image,buffer);
1681 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1683 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1684 (void) WriteBlobString(image,buffer);
1686 if (LocaleCompare(image_info->magick,"PS") == 0)
1687 (void) WriteBlobString(image," showpage\n");
1688 (void) WriteBlobString(image,"} bind def\n");
1689 (void) WriteBlobString(image,"%%EndProlog\n");
1691 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1693 (void) WriteBlobString(image,buffer);
1694 (void) FormatLocaleString(buffer,MaxTextExtent,
1695 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1696 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1697 (geometry.height+text_size));
1698 (void) WriteBlobString(image,buffer);
1699 if ((double) geometry.x < bounds.x1)
1700 bounds.x1=(double) geometry.x;
1701 if ((double) geometry.y < bounds.y1)
1702 bounds.y1=(double) geometry.y;
1703 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1704 bounds.x2=(double) geometry.x+geometry.width-1;
1705 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1706 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1707 value=GetImageProperty(image,"label");
1708 if (value != (const char *) NULL)
1709 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1710 if (LocaleCompare(image_info->magick,"PS") != 0)
1711 (void) WriteBlobString(image,"userdict begin\n");
1712 (void) WriteBlobString(image,"DisplayImage\n");
1716 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1717 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1718 (void) WriteBlobString(image,buffer);
1719 labels=(char **) NULL;
1720 value=GetImageProperty(image,"label");
1721 if (value != (const char *) NULL)
1722 labels=StringToList(value);
1723 if (labels != (char **) NULL)
1725 for (i=0; labels[i] != (char *) NULL; i++)
1727 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1729 (void) WriteBlobString(image,buffer);
1730 labels[i]=DestroyString(labels[i]);
1732 labels=(char **) RelinquishMagickMemory(labels);
1734 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1735 pixel.alpha=(Quantum) TransparentAlpha;
1738 if ((image_info->type != TrueColorType) &&
1739 (IsImageGray(image,&image->exception) != MagickFalse))
1741 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
1747 Dump image as grayscale.
1749 (void) FormatLocaleString(buffer,MaxTextExtent,
1750 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1752 (void) WriteBlobString(image,buffer);
1754 for (y=0; y < (ssize_t) image->rows; y++)
1756 p=GetVirtualPixels(image,0,y,image->columns,1,
1758 if (p == (const Quantum *) NULL)
1760 for (x=0; x < (ssize_t) image->columns; x++)
1762 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
1763 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1765 if ((q-pixels+8) >= 80)
1768 (void) WriteBlob(image,q-pixels,pixels);
1771 p+=GetPixelChannels(image);
1773 if (image->previous == (Image *) NULL)
1775 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1777 if (status == MagickFalse)
1784 (void) WriteBlob(image,q-pixels,pixels);
1796 Dump image as bitmap.
1798 (void) FormatLocaleString(buffer,MaxTextExtent,
1799 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1801 (void) WriteBlobString(image,buffer);
1803 for (y=0; y < (ssize_t) image->rows; y++)
1805 p=GetVirtualPixels(image,0,y,image->columns,1,
1807 if (p == (const Quantum *) NULL)
1811 for (x=0; x < (ssize_t) image->columns; x++)
1814 pixel=GetPixelIntensity(image,p);
1815 if (pixel >= (Quantum) (QuantumRange/2))
1820 q=PopHexPixel(hex_digits,byte,q);
1821 if ((q-pixels+2) >= 80)
1824 (void) WriteBlob(image,q-pixels,pixels);
1830 p+=GetPixelChannels(image);
1835 q=PopHexPixel(hex_digits,byte,q);
1836 if ((q-pixels+2) >= 80)
1839 (void) WriteBlob(image,q-pixels,pixels);
1843 if (image->previous == (Image *) NULL)
1845 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1847 if (status == MagickFalse)
1854 (void) WriteBlob(image,q-pixels,pixels);
1859 if ((image->storage_class == DirectClass) ||
1860 (image->colors > 256) || (image->matte != MagickFalse))
1863 Dump DirectClass image.
1865 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1866 (double) image->columns,(double) image->rows,
1867 image_info->compression == RLECompression ? 1 : 0);
1868 (void) WriteBlobString(image,buffer);
1869 switch (image_info->compression)
1871 case RLECompression:
1874 Dump runlength-encoded DirectColor packets.
1877 for (y=0; y < (ssize_t) image->rows; y++)
1879 p=GetVirtualPixels(image,0,y,image->columns,1,
1881 if (p == (const Quantum *) NULL)
1883 GetPixelPacket(image,p,&pixel);
1885 for (x=0; x < (ssize_t) image->columns; x++)
1887 if ((GetPixelRed(image,p) == pixel.red) &&
1888 (GetPixelGreen(image,p) == pixel.green) &&
1889 (GetPixelBlue(image,p) == pixel.blue) &&
1890 (GetPixelAlpha(image,p) == pixel.alpha) &&
1891 (length < 255) && (x < (ssize_t) (image->columns-1)))
1897 WriteRunlengthPacket(image,pixel,length,p);
1898 if ((q-pixels+10) >= 80)
1901 (void) WriteBlob(image,q-pixels,pixels);
1907 GetPixelPacket(image,p,&pixel);
1908 p+=GetPixelChannels(image);
1910 WriteRunlengthPacket(image,pixel,length,p);
1911 if ((q-pixels+10) >= 80)
1914 (void) WriteBlob(image,q-pixels,pixels);
1917 if (image->previous == (Image *) NULL)
1919 status=SetImageProgress(image,SaveImageTag,
1920 (MagickOffsetType) y,image->rows);
1921 if (status == MagickFalse)
1928 (void) WriteBlob(image,q-pixels,pixels);
1936 Dump uncompressed DirectColor packets.
1939 for (y=0; y < (ssize_t) image->rows; y++)
1941 p=GetVirtualPixels(image,0,y,image->columns,1,
1943 if (p == (const Quantum *) NULL)
1945 for (x=0; x < (ssize_t) image->columns; x++)
1947 if ((image->matte != MagickFalse) &&
1948 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1950 q=PopHexPixel(hex_digits,0xff,q);
1951 q=PopHexPixel(hex_digits,0xff,q);
1952 q=PopHexPixel(hex_digits,0xff,q);
1956 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1957 GetPixelRed(image,p)),q);
1958 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1959 GetPixelGreen(image,p)),q);
1960 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1961 GetPixelBlue(image,p)),q);
1963 if ((q-pixels+6) >= 80)
1966 (void) WriteBlob(image,q-pixels,pixels);
1969 p+=GetPixelChannels(image);
1971 if (image->previous == (Image *) NULL)
1973 status=SetImageProgress(image,SaveImageTag,
1974 (MagickOffsetType) y,image->rows);
1975 if (status == MagickFalse)
1982 (void) WriteBlob(image,q-pixels,pixels);
1987 (void) WriteBlobByte(image,'\n');
1992 Dump PseudoClass image.
1994 (void) FormatLocaleString(buffer,MaxTextExtent,
1995 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1996 image->rows,image->storage_class == PseudoClass ? 1 : 0,
1997 image_info->compression == RLECompression ? 1 : 0);
1998 (void) WriteBlobString(image,buffer);
2000 Dump number of colors and colormap.
2002 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2004 (void) WriteBlobString(image,buffer);
2005 for (i=0; i < (ssize_t) image->colors; i++)
2007 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2008 ScaleQuantumToChar(image->colormap[i].red),
2009 ScaleQuantumToChar(image->colormap[i].green),
2010 ScaleQuantumToChar(image->colormap[i].blue));
2011 (void) WriteBlobString(image,buffer);
2013 switch (image_info->compression)
2015 case RLECompression:
2018 Dump runlength-encoded PseudoColor packets.
2021 for (y=0; y < (ssize_t) image->rows; y++)
2023 p=GetVirtualPixels(image,0,y,image->columns,1,
2025 if (p == (const Quantum *) NULL)
2027 index=GetPixelIndex(image,p);
2029 for (x=0; x < (ssize_t) image->columns; x++)
2031 if ((index == GetPixelIndex(image,p)) &&
2032 (length < 255) && (x < ((ssize_t) image->columns-1)))
2038 q=PopHexPixel(hex_digits,(size_t) index,q);
2039 q=PopHexPixel(hex_digits,(size_t)
2040 MagickMin(length,0xff),q);
2042 if ((q-pixels+6) >= 80)
2045 (void) WriteBlob(image,q-pixels,pixels);
2051 index=GetPixelIndex(image,p);
2052 pixel.red=GetPixelRed(image,p);
2053 pixel.green=GetPixelGreen(image,p);
2054 pixel.blue=GetPixelBlue(image,p);
2055 pixel.alpha=GetPixelAlpha(image,p);
2056 p+=GetPixelChannels(image);
2058 q=PopHexPixel(hex_digits,(size_t) index,q);
2059 q=PopHexPixel(hex_digits,(size_t)
2060 MagickMin(length,0xff),q);
2061 if (image->previous == (Image *) NULL)
2063 status=SetImageProgress(image,SaveImageTag,
2064 (MagickOffsetType) y,image->rows);
2065 if (status == MagickFalse)
2072 (void) WriteBlob(image,q-pixels,pixels);
2080 Dump uncompressed PseudoColor packets.
2083 for (y=0; y < (ssize_t) image->rows; y++)
2085 p=GetVirtualPixels(image,0,y,image->columns,1,
2087 if (p == (const Quantum *) NULL)
2089 for (x=0; x < (ssize_t) image->columns; x++)
2091 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
2092 if ((q-pixels+4) >= 80)
2095 (void) WriteBlob(image,q-pixels,pixels);
2098 p+=GetPixelChannels(image);
2100 if (image->previous == (Image *) NULL)
2102 status=SetImageProgress(image,SaveImageTag,
2103 (MagickOffsetType) y,image->rows);
2104 if (status == MagickFalse)
2111 (void) WriteBlob(image,q-pixels,pixels);
2116 (void) WriteBlobByte(image,'\n');
2118 if (LocaleCompare(image_info->magick,"PS") != 0)
2119 (void) WriteBlobString(image,"end\n");
2120 (void) WriteBlobString(image,"%%PageTrailer\n");
2121 if (GetNextImageInList(image) == (Image *) NULL)
2123 image=SyncNextImageInList(image);
2124 status=SetImageProgress(image,SaveImagesTag,scene++,
2125 GetImageListLength(image));
2126 if (status == MagickFalse)
2128 } while (image_info->adjoin != MagickFalse);
2129 (void) WriteBlobString(image,"%%Trailer\n");
2132 (void) FormatLocaleString(buffer,MaxTextExtent,
2133 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2134 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
2135 (void) WriteBlobString(image,buffer);
2136 (void) FormatLocaleString(buffer,MaxTextExtent,
2137 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2138 bounds.x2,bounds.y2);
2139 (void) WriteBlobString(image,buffer);
2141 (void) WriteBlobString(image,"%%EOF\n");
2142 (void) CloseBlob(image);