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/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];
418 assert(image_info != (const ImageInfo *) NULL);
419 assert(image_info->signature == MagickSignature);
420 if (image_info->debug != MagickFalse)
421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
422 image_info->filename);
423 assert(exception != (ExceptionInfo *) NULL);
424 assert(exception->signature == MagickSignature);
425 image=AcquireImage(image_info,exception);
426 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
427 if (status == MagickFalse)
429 image=DestroyImageList(image);
430 return((Image *) NULL);
432 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
433 if (status == MagickFalse)
435 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
436 image_info->filename);
437 image=DestroyImageList(image);
438 return((Image *) NULL);
441 Initialize hex values.
443 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
444 hex_digits[(int) '0']=0;
445 hex_digits[(int) '1']=1;
446 hex_digits[(int) '2']=2;
447 hex_digits[(int) '3']=3;
448 hex_digits[(int) '4']=4;
449 hex_digits[(int) '5']=5;
450 hex_digits[(int) '6']=6;
451 hex_digits[(int) '7']=7;
452 hex_digits[(int) '8']=8;
453 hex_digits[(int) '9']=9;
454 hex_digits[(int) 'a']=10;
455 hex_digits[(int) 'b']=11;
456 hex_digits[(int) 'c']=12;
457 hex_digits[(int) 'd']=13;
458 hex_digits[(int) 'e']=14;
459 hex_digits[(int) 'f']=15;
460 hex_digits[(int) 'A']=10;
461 hex_digits[(int) 'B']=11;
462 hex_digits[(int) 'C']=12;
463 hex_digits[(int) 'D']=13;
464 hex_digits[(int) 'E']=14;
465 hex_digits[(int) 'F']=15;
467 Set the page density.
469 delta.x=DefaultResolution;
470 delta.y=DefaultResolution;
471 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
473 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
474 image->x_resolution=geometry_info.rho;
475 image->y_resolution=geometry_info.sigma;
476 if ((flags & SigmaValue) == 0)
477 image->y_resolution=image->x_resolution;
480 Determine page geometry from the Postscript bounding box.
482 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
483 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
484 (void) ResetMagickMemory(&page,0,sizeof(page));
485 (void) ResetMagickMemory(command,0,sizeof(command));
494 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
497 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
500 Note document structuring comments.
503 if ((strchr("\n\r%",c) == (char *) NULL) &&
504 ((size_t) (p-command) < (MaxTextExtent-1)))
509 Skip %%BeginDocument thru %%EndDocument.
511 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
513 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
515 if (skip != MagickFalse)
517 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
519 (void) SetImageProperty(image,"ps:Level",command+4,exception);
520 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
523 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
524 (void) sscanf(command,LanguageLevel " %lu",&language_level);
525 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
526 (void) sscanf(command,Pages " %lu",&pages);
527 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
528 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
529 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
537 profile=AcquireStringInfo(65536);
538 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
540 SetStringInfoLength(profile,(size_t) i+1);
541 datum=GetStringInfoDatum(profile);
542 datum[i]=(unsigned char) c;
544 (void) SetImageProfile(image,"icc",profile,exception);
545 profile=DestroyStringInfo(profile);
548 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
554 Read Photoshop profile.
556 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
560 profile=BlobToStringInfo((const void *) NULL,length);
561 p=GetStringInfoDatum(profile);
562 for (i=0; i < (ssize_t) length; i++)
563 *p++=(unsigned char) ProfileInteger(image,hex_digits);
564 (void) SetImageProfile(image,"8bim",profile,exception);
565 profile=DestroyStringInfo(profile);
568 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
577 profile=StringToStringInfo(command);
578 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
580 SetStringInfoLength(profile,i+1);
581 c=ReadBlobByte(image);
582 GetStringInfoDatum(profile)[i]=(unsigned char) c;
584 if ((strchr("\n\r%",c) == (char *) NULL) &&
585 ((size_t) (p-command) < (MaxTextExtent-1)))
589 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
592 SetStringInfoLength(profile,i);
593 (void) SetImageProfile(image,"xmp",profile,exception);
594 profile=DestroyStringInfo(profile);
598 Is this a CMYK document?
600 length=strlen(DocumentProcessColors);
601 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
603 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
604 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
605 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
608 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
610 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
612 length=strlen(DocumentCustomColors);
613 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
614 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
615 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
618 property[MaxTextExtent],
627 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
628 (double) (spotcolor++));
629 for (p=command; *p != '\0'; p++)
630 if (isspace((int) (unsigned char) *p) != 0)
632 value=AcquireString(p);
633 (void) SubstituteString(&value,"(","");
634 (void) SubstituteString(&value,")","");
635 (void) StripString(value);
636 (void) SetImageProperty(image,property,value,exception);
637 value=DestroyString(value);
641 Note region defined by bounding box.
644 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
645 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
646 &bounds.y1,&bounds.x2,&bounds.y2);
647 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
648 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
650 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
651 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
652 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
653 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
654 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
655 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
656 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
657 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
661 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
662 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
665 Set Postscript render geometry.
667 (void) FormatLocaleString(geometry,MaxTextExtent,
668 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
669 bounds.x1,bounds.y1);
670 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
671 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
672 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
676 (void) CloseBlob(image);
677 if (IsRGBColorspace(image_info->colorspace) != MagickFalse)
680 Create Ghostscript control file.
682 file=AcquireUniqueFileResource(postscript_filename);
685 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
686 image_info->filename);
687 image=DestroyImageList(image);
688 return((Image *) NULL);
690 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
691 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
692 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
693 count=write(file,command,(unsigned int) strlen(command));
694 if (image_info->page == (char *) NULL)
697 translate_geometry[MaxTextExtent];
699 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
700 "%g %g translate\n",-bounds.x1,-bounds.y1);
701 count=write(file,translate_geometry,(unsigned int)
702 strlen(translate_geometry));
706 Render Postscript with the Ghostscript delegate.
708 if (image_info->monochrome != MagickFalse)
709 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
711 if (cmyk != MagickFalse)
712 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
714 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
715 if (delegate_info == (const DelegateInfo *) NULL)
717 (void) RelinquishUniqueFileResource(postscript_filename);
718 image=DestroyImageList(image);
719 return((Image *) NULL);
722 if ((page.width == 0) || (page.height == 0))
723 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
724 if (image_info->density != (char *) NULL)
726 flags=ParseGeometry(image_info->density,&geometry_info);
727 image->x_resolution=geometry_info.rho;
728 image->y_resolution=geometry_info.sigma;
729 if ((flags & SigmaValue) == 0)
730 image->y_resolution=image->x_resolution;
732 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
733 image->x_resolution,image->y_resolution);
734 if (image_info->page != (char *) NULL)
735 (void) ParseAbsoluteGeometry(image_info->page,&page);
736 page.width=(size_t) floor((double) (page.width*image->x_resolution/delta.x)+
738 page.height=(size_t) floor((double) (page.height*image->y_resolution/delta.y)+
740 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
741 page.width,(double) page.height);
742 read_info=CloneImageInfo(image_info);
743 *read_info->magick='\0';
744 if (read_info->number_scenes != 0)
747 pages[MaxTextExtent];
749 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
750 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
751 (read_info->scene+read_info->number_scenes));
752 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
753 read_info->number_scenes=0;
754 if (read_info->scenes != (char *) NULL)
755 *read_info->scenes='\0';
757 option=GetImageOption(image_info,"ps:use-cropbox");
758 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
759 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
760 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
761 (void) AcquireUniqueFilename(filename);
762 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
763 (void) FormatLocaleString(command,MaxTextExtent,
764 GetDelegateCommands(delegate_info),
765 read_info->antialias != MagickFalse ? 4 : 1,
766 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
767 postscript_filename,input_filename);
768 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
769 (void) InterpretImageFilename(image_info,image,filename,1,
770 read_info->filename,exception);
771 if ((status == MagickFalse) ||
772 (IsPostscriptRendered(read_info->filename) == MagickFalse))
774 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
775 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
777 (void) RelinquishUniqueFileResource(postscript_filename);
778 (void) RelinquishUniqueFileResource(input_filename);
779 postscript_image=(Image *) NULL;
780 if (status == MagickFalse)
783 (void) InterpretImageFilename(image_info,image,filename,(int) i,
784 read_info->filename,exception);
785 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
787 (void) RelinquishUniqueFileResource(read_info->filename);
792 (void) InterpretImageFilename(image_info,image,filename,(int) i,
793 read_info->filename,exception);
794 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
796 next=ReadImage(read_info,exception);
797 (void) RelinquishUniqueFileResource(read_info->filename);
798 if (next == (Image *) NULL)
800 AppendImageToList(&postscript_image,next);
802 (void) RelinquishUniqueFileResource(read_info->filename);
803 read_info=DestroyImageInfo(read_info);
804 if (postscript_image == (Image *) NULL)
806 image=DestroyImageList(image);
807 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
808 image_info->filename);
809 return((Image *) NULL);
811 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
816 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
817 if (cmyk_image != (Image *) NULL)
819 postscript_image=DestroyImageList(postscript_image);
820 postscript_image=cmyk_image;
823 if (image_info->number_scenes != 0)
832 Add place holder images to meet the subimage specification requirement.
834 for (i=0; i < (ssize_t) image_info->scene; i++)
836 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
837 if (clone_image != (Image *) NULL)
838 PrependImageToList(&postscript_image,clone_image);
843 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
845 postscript_image->magick_columns=columns;
847 postscript_image->magick_rows=rows;
848 postscript_image->page=page;
849 (void) CloneImageProfiles(postscript_image,image);
850 (void) CloneImageProperties(postscript_image,image);
851 next=SyncNextImageInList(postscript_image);
852 if (next != (Image *) NULL)
853 postscript_image=next;
854 } while (next != (Image *) NULL);
855 image=DestroyImageList(image);
857 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
860 next=GetNextImageInList(next);
862 return(GetFirstImageInList(postscript_image));
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870 % R e g i s t e r P S I m a g e %
874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
876 % RegisterPSImage() adds properties for the PS image format to
877 % the list of supported formats. The properties include the image format
878 % tag, a method to read and/or write the format, whether the format
879 % supports the saving of more than one frame to the same file or blob,
880 % whether the format supports native in-memory I/O, and a brief
881 % description of the format.
883 % The format of the RegisterPSImage method is:
885 % size_t RegisterPSImage(void)
888 ModuleExport size_t RegisterPSImage(void)
893 entry=SetMagickInfo("EPI");
894 entry->decoder=(DecodeImageHandler *) ReadPSImage;
895 entry->encoder=(EncodeImageHandler *) WritePSImage;
896 entry->magick=(IsImageFormatHandler *) IsPS;
897 entry->adjoin=MagickFalse;
898 entry->blob_support=MagickFalse;
899 entry->seekable_stream=MagickTrue;
900 entry->thread_support=EncoderThreadSupport;
901 entry->description=ConstantString(
902 "Encapsulated PostScript Interchange format");
903 entry->module=ConstantString("PS");
904 (void) RegisterMagickInfo(entry);
905 entry=SetMagickInfo("EPS");
906 entry->decoder=(DecodeImageHandler *) ReadPSImage;
907 entry->encoder=(EncodeImageHandler *) WritePSImage;
908 entry->magick=(IsImageFormatHandler *) IsPS;
909 entry->adjoin=MagickFalse;
910 entry->blob_support=MagickFalse;
911 entry->seekable_stream=MagickTrue;
912 entry->thread_support=EncoderThreadSupport;
913 entry->description=ConstantString("Encapsulated PostScript");
914 entry->module=ConstantString("PS");
915 (void) RegisterMagickInfo(entry);
916 entry=SetMagickInfo("EPSF");
917 entry->decoder=(DecodeImageHandler *) ReadPSImage;
918 entry->encoder=(EncodeImageHandler *) WritePSImage;
919 entry->magick=(IsImageFormatHandler *) IsPS;
920 entry->adjoin=MagickFalse;
921 entry->blob_support=MagickFalse;
922 entry->seekable_stream=MagickTrue;
923 entry->description=ConstantString("Encapsulated PostScript");
924 entry->module=ConstantString("PS");
925 (void) RegisterMagickInfo(entry);
926 entry=SetMagickInfo("EPSI");
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(
935 "Encapsulated PostScript Interchange format");
936 entry->module=ConstantString("PS");
937 (void) RegisterMagickInfo(entry);
938 entry=SetMagickInfo("PS");
939 entry->decoder=(DecodeImageHandler *) ReadPSImage;
940 entry->encoder=(EncodeImageHandler *) WritePSImage;
941 entry->magick=(IsImageFormatHandler *) IsPS;
942 entry->module=ConstantString("PS");
943 entry->blob_support=MagickFalse;
944 entry->seekable_stream=MagickTrue;
945 entry->thread_support=EncoderThreadSupport;
946 entry->description=ConstantString("PostScript");
947 (void) RegisterMagickInfo(entry);
948 return(MagickImageCoderSignature);
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
956 % U n r e g i s t e r P S I m a g e %
960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 % UnregisterPSImage() removes format registrations made by the
963 % PS module from the list of supported formats.
965 % The format of the UnregisterPSImage method is:
967 % UnregisterPSImage(void)
970 ModuleExport void UnregisterPSImage(void)
972 (void) UnregisterMagickInfo("EPI");
973 (void) UnregisterMagickInfo("EPS");
974 (void) UnregisterMagickInfo("EPSF");
975 (void) UnregisterMagickInfo("EPSI");
976 (void) UnregisterMagickInfo("PS");
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % W r i t e P S I m a g e %
988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990 % WritePSImage translates an image to encapsulated Postscript
991 % Level I for printing. If the supplied geometry is null, the image is
992 % centered on the Postscript page. Otherwise, the image is positioned as
993 % specified by the geometry.
995 % The format of the WritePSImage method is:
997 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
998 % Image *image,ExceptionInfo *exception)
1000 % A description of each parameter follows:
1002 % o image_info: the image info.
1004 % o image: the image.
1006 % o exception: return any errors or warnings in this structure.
1010 static inline size_t MagickMin(const size_t x,const size_t y)
1017 static inline unsigned char *PopHexPixel(const char **hex_digits,
1018 const size_t pixel,unsigned char *pixels)
1023 hex=hex_digits[pixel];
1024 *pixels++=(unsigned char) (*hex++);
1025 *pixels++=(unsigned char) (*hex);
1029 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1030 ExceptionInfo *exception)
1032 #define WriteRunlengthPacket(image,pixel,length,p) \
1034 if ((image->matte != MagickFalse) && \
1035 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
1037 q=PopHexPixel(hex_digits,0xff,q); \
1038 q=PopHexPixel(hex_digits,0xff,q); \
1039 q=PopHexPixel(hex_digits,0xff,q); \
1043 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1044 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1045 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1047 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
1053 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1054 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1055 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1056 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1057 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1058 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1059 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1060 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1061 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1062 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1063 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1064 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1065 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1066 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1067 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1068 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1069 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1070 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1071 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1072 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1073 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1074 "FC", "FD", "FE", "FF", (char *) NULL
1076 *PostscriptProlog[]=
1080 "% Display a color image. The image is displayed in color on",
1081 "% Postscript viewers or printers that support color, otherwise",
1082 "% it is displayed as grayscale.",
1084 "/DirectClassPacket",
1087 " % Get a DirectClass packet.",
1093 " % length: number of pixels minus one of this color (optional).",
1095 " currentfile color_packet readhexstring pop pop",
1096 " compression 0 eq",
1098 " /number_pixels 3 def",
1101 " currentfile byte readhexstring pop 0 get",
1102 " /number_pixels exch 1 add 3 mul def",
1104 " 0 3 number_pixels 1 sub",
1106 " pixels exch color_packet putinterval",
1108 " pixels 0 number_pixels getinterval",
1111 "/DirectClassImage",
1114 " % Display a DirectClass image.",
1116 " systemdict /colorimage known",
1123 " { DirectClassPacket } false 3 colorimage",
1127 " % No colorimage operator; convert to grayscale.",
1134 " { GrayDirectClassPacket } image",
1138 "/GrayDirectClassPacket",
1141 " % Get a DirectClass packet; convert to grayscale.",
1147 " % length: number of pixels minus one of this color (optional).",
1149 " currentfile color_packet readhexstring pop pop",
1150 " color_packet 0 get 0.299 mul",
1151 " color_packet 1 get 0.587 mul add",
1152 " color_packet 2 get 0.114 mul add",
1154 " /gray_packet exch def",
1155 " compression 0 eq",
1157 " /number_pixels 1 def",
1160 " currentfile byte readhexstring pop 0 get",
1161 " /number_pixels exch 1 add def",
1163 " 0 1 number_pixels 1 sub",
1165 " pixels exch gray_packet put",
1167 " pixels 0 number_pixels getinterval",
1170 "/GrayPseudoClassPacket",
1173 " % Get a PseudoClass packet; convert to grayscale.",
1176 " % index: index into the colormap.",
1177 " % length: number of pixels minus one of this color (optional).",
1179 " currentfile byte readhexstring pop 0 get",
1180 " /offset exch 3 mul def",
1181 " /color_packet colormap offset 3 getinterval def",
1182 " color_packet 0 get 0.299 mul",
1183 " color_packet 1 get 0.587 mul add",
1184 " color_packet 2 get 0.114 mul add",
1186 " /gray_packet exch def",
1187 " compression 0 eq",
1189 " /number_pixels 1 def",
1192 " currentfile byte readhexstring pop 0 get",
1193 " /number_pixels exch 1 add def",
1195 " 0 1 number_pixels 1 sub",
1197 " pixels exch gray_packet put",
1199 " pixels 0 number_pixels getinterval",
1202 "/PseudoClassPacket",
1205 " % Get a PseudoClass packet.",
1208 " % index: index into the colormap.",
1209 " % length: number of pixels minus one of this color (optional).",
1211 " currentfile byte readhexstring pop 0 get",
1212 " /offset exch 3 mul def",
1213 " /color_packet colormap offset 3 getinterval def",
1214 " compression 0 eq",
1216 " /number_pixels 3 def",
1219 " currentfile byte readhexstring pop 0 get",
1220 " /number_pixels exch 1 add 3 mul def",
1222 " 0 3 number_pixels 1 sub",
1224 " pixels exch color_packet putinterval",
1226 " pixels 0 number_pixels getinterval",
1229 "/PseudoClassImage",
1232 " % Display a PseudoClass image.",
1235 " % class: 0-PseudoClass or 1-Grayscale.",
1237 " currentfile buffer readline pop",
1238 " token pop /class exch def pop",
1241 " currentfile buffer readline pop",
1242 " token pop /depth exch def pop",
1243 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1244 " columns rows depth",
1249 " { currentfile grays readhexstring pop } image",
1254 " % colors: number of colors in the colormap.",
1255 " % colormap: red, green, blue color packets.",
1257 " currentfile buffer readline pop",
1258 " token pop /colors exch def pop",
1259 " /colors colors 3 mul def",
1260 " /colormap colors string def",
1261 " currentfile colormap readhexstring pop pop",
1262 " systemdict /colorimage known",
1269 " { PseudoClassPacket } false 3 colorimage",
1273 " % No colorimage operator; convert to grayscale.",
1280 " { GrayPseudoClassPacket } image",
1288 " % Display a DirectClass or PseudoClass image.",
1291 " % x & y translation.",
1293 " % label pointsize.",
1295 " % image columns & rows.",
1296 " % class: 0-DirectClass or 1-PseudoClass.",
1297 " % compression: 0-none or 1-RunlengthEncoded.",
1298 " % hex color packets.",
1301 " /buffer 512 string def",
1302 " /byte 1 string def",
1303 " /color_packet 3 string def",
1304 " /pixels 768 string def",
1306 " currentfile buffer readline pop",
1307 " token pop /x exch def",
1308 " token pop /y exch def pop",
1310 " currentfile buffer readline pop",
1311 " token pop /x exch def",
1312 " token pop /y exch def pop",
1313 " currentfile buffer readline pop",
1314 " token pop /pointsize exch def pop",
1315 " /Times-Roman findfont pointsize scalefont setfont",
1318 *PostscriptEpilog[]=
1321 " currentfile buffer readline pop",
1322 " token pop /columns exch def",
1323 " token pop /rows exch def pop",
1324 " currentfile buffer readline pop",
1325 " token pop /class exch def pop",
1326 " currentfile buffer readline pop",
1327 " token pop /compression exch def pop",
1328 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1333 buffer[MaxTextExtent],
1334 date[MaxTextExtent],
1336 page_geometry[MaxTextExtent];
1376 register const Quantum
1383 register unsigned char
1407 Open output image file.
1409 assert(image_info != (const ImageInfo *) NULL);
1410 assert(image_info->signature == MagickSignature);
1411 assert(image != (Image *) NULL);
1412 assert(image->signature == MagickSignature);
1413 if (image->debug != MagickFalse)
1414 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1415 assert(exception != (ExceptionInfo *) NULL);
1416 assert(exception->signature == MagickSignature);
1417 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1418 if (status == MagickFalse)
1420 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1426 Scale relative to dots-per-inch.
1428 if ((IsRGBColorspace(image->colorspace) == MagickFalse) &&
1429 (image->colorspace != CMYKColorspace))
1430 (void) TransformImageColorspace(image,RGBColorspace,exception);
1431 delta.x=DefaultResolution;
1432 delta.y=DefaultResolution;
1433 resolution.x=image->x_resolution;
1434 resolution.y=image->y_resolution;
1435 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1437 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1438 resolution.x=geometry_info.rho;
1439 resolution.y=geometry_info.sigma;
1440 if ((flags & SigmaValue) == 0)
1441 resolution.y=resolution.x;
1443 if (image_info->density != (char *) NULL)
1445 flags=ParseGeometry(image_info->density,&geometry_info);
1446 resolution.x=geometry_info.rho;
1447 resolution.y=geometry_info.sigma;
1448 if ((flags & SigmaValue) == 0)
1449 resolution.y=resolution.x;
1451 if (image->units == PixelsPerCentimeterResolution)
1453 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1454 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1456 SetGeometry(image,&geometry);
1457 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1458 (double) image->columns,(double) image->rows);
1459 if (image_info->page != (char *) NULL)
1460 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1462 if ((image->page.width != 0) && (image->page.height != 0))
1463 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1464 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1465 image->page.height,(double) image->page.x,(double) image->page.y);
1467 if ((image->gravity != UndefinedGravity) &&
1468 (LocaleCompare(image_info->magick,"PS") == 0))
1469 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1470 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1471 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1472 &geometry.width,&geometry.height);
1473 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1474 geometry.width=(size_t) floor(scale.x+0.5);
1475 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1476 geometry.height=(size_t) floor(scale.y+0.5);
1477 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1478 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1479 if (image->gravity != UndefinedGravity)
1481 geometry.x=(-page_info.x);
1482 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1485 if (image_info->pointsize != 0.0)
1486 pointsize=image_info->pointsize;
1488 value=GetImageProperty(image,"label",exception);
1489 if (value != (const char *) NULL)
1490 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1494 Output Postscript header.
1496 if (LocaleCompare(image_info->magick,"PS") == 0)
1497 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1499 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1501 (void) WriteBlobString(image,buffer);
1502 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1503 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1505 (void) WriteBlobString(image,buffer);
1506 timer=time((time_t *) NULL);
1507 (void) FormatMagickTime(timer,MaxTextExtent,date);
1508 (void) FormatLocaleString(buffer,MaxTextExtent,
1509 "%%%%CreationDate: (%s)\n",date);
1510 (void) WriteBlobString(image,buffer);
1511 bounds.x1=(double) geometry.x;
1512 bounds.y1=(double) geometry.y;
1513 bounds.x2=(double) geometry.x+scale.x;
1514 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1515 if ((image_info->adjoin != MagickFalse) &&
1516 (GetNextImageInList(image) != (Image *) NULL))
1517 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1521 (void) FormatLocaleString(buffer,MaxTextExtent,
1522 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1523 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1524 (void) WriteBlobString(image,buffer);
1525 (void) FormatLocaleString(buffer,MaxTextExtent,
1526 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1527 bounds.y1,bounds.x2,bounds.y2);
1529 (void) WriteBlobString(image,buffer);
1530 profile=GetImageProfile(image,"8bim");
1531 if (profile != (StringInfo *) NULL)
1534 Embed Photoshop profile.
1536 (void) FormatLocaleString(buffer,MaxTextExtent,
1537 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1538 (void) WriteBlobString(image,buffer);
1539 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1542 (void) WriteBlobString(image,"\n% ");
1543 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1544 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1545 (void) WriteBlobString(image,buffer);
1547 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1549 profile=GetImageProfile(image,"xmp");
1550 if (0 && (profile != (StringInfo *) NULL))
1555 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1556 (void) FormatLocaleString(buffer,MaxTextExtent,
1557 "\n%%begin_xml_packet: %.20g\n",(double)
1558 GetStringInfoLength(profile));
1559 (void) WriteBlobString(image,buffer);
1560 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1561 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1562 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1564 value=GetImageProperty(image,"label",exception);
1565 if (value != (const char *) NULL)
1566 (void) WriteBlobString(image,
1567 "%%DocumentNeededResources: font Times-Roman\n");
1568 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1569 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1570 if (LocaleCompare(image_info->magick,"PS") != 0)
1571 (void) WriteBlobString(image,"%%Pages: 1\n");
1575 Compute the number of pages.
1577 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1578 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1579 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1580 image_info->adjoin != MagickFalse ? (double)
1581 GetImageListLength(image) : 1.0);
1582 (void) WriteBlobString(image,buffer);
1584 (void) WriteBlobString(image,"%%EndComments\n");
1585 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1586 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1587 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1588 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1589 (LocaleCompare(image_info->magick,"EPT") == 0))
1604 Create preview image.
1606 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1607 if (preview_image == (Image *) NULL)
1608 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1610 Dump image as bitmap.
1612 (void) FormatLocaleString(buffer,MaxTextExtent,
1613 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1614 preview_image->columns,(double) preview_image->rows,1.0,
1615 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1617 (void) WriteBlobString(image,buffer);
1619 for (y=0; y < (ssize_t) image->rows; y++)
1621 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1623 if (p == (const Quantum *) NULL)
1627 for (x=0; x < (ssize_t) preview_image->columns; x++)
1630 pixel=GetPixelIntensity(preview_image,p);
1631 if (pixel >= (Quantum) (QuantumRange/2))
1636 q=PopHexPixel(hex_digits,byte,q);
1637 if ((q-pixels+8) >= 80)
1640 (void) WriteBlob(image,q-pixels,pixels);
1642 (void) WriteBlobString(image,"% ");
1651 q=PopHexPixel(hex_digits,byte,q);
1652 if ((q-pixels+8) >= 80)
1655 (void) WriteBlob(image,q-pixels,pixels);
1657 (void) WriteBlobString(image,"% ");
1664 (void) WriteBlob(image,q-pixels,pixels);
1666 (void) WriteBlobString(image,"\n%%EndPreview\n");
1667 preview_image=DestroyImage(preview_image);
1670 Output Postscript commands.
1672 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1674 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1675 (void) WriteBlobString(image,buffer);
1677 value=GetImageProperty(image,"label",exception);
1678 if (value != (const char *) NULL)
1679 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1681 (void) WriteBlobString(image," /label 512 string def\n");
1682 (void) WriteBlobString(image," currentfile label readline pop\n");
1683 (void) FormatLocaleString(buffer,MaxTextExtent,
1684 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1685 (void) WriteBlobString(image,buffer);
1687 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1689 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1690 (void) WriteBlobString(image,buffer);
1692 if (LocaleCompare(image_info->magick,"PS") == 0)
1693 (void) WriteBlobString(image," showpage\n");
1694 (void) WriteBlobString(image,"} bind def\n");
1695 (void) WriteBlobString(image,"%%EndProlog\n");
1697 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1699 (void) WriteBlobString(image,buffer);
1700 (void) FormatLocaleString(buffer,MaxTextExtent,
1701 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1702 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1703 (geometry.height+text_size));
1704 (void) WriteBlobString(image,buffer);
1705 if ((double) geometry.x < bounds.x1)
1706 bounds.x1=(double) geometry.x;
1707 if ((double) geometry.y < bounds.y1)
1708 bounds.y1=(double) geometry.y;
1709 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1710 bounds.x2=(double) geometry.x+geometry.width-1;
1711 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1712 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1713 value=GetImageProperty(image,"label",exception);
1714 if (value != (const char *) NULL)
1715 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1716 if (LocaleCompare(image_info->magick,"PS") != 0)
1717 (void) WriteBlobString(image,"userdict begin\n");
1718 (void) WriteBlobString(image,"DisplayImage\n");
1722 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1723 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1724 (void) WriteBlobString(image,buffer);
1725 labels=(char **) NULL;
1726 value=GetImageProperty(image,"label",exception);
1727 if (value != (const char *) NULL)
1728 labels=StringToList(value);
1729 if (labels != (char **) NULL)
1731 for (i=0; labels[i] != (char *) NULL; i++)
1733 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1735 (void) WriteBlobString(image,buffer);
1736 labels[i]=DestroyString(labels[i]);
1738 labels=(char **) RelinquishMagickMemory(labels);
1740 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1741 pixel.alpha=(Quantum) TransparentAlpha;
1744 if ((image_info->type != TrueColorType) &&
1745 (IsImageGray(image,exception) != MagickFalse))
1747 if (IsImageMonochrome(image,exception) == MagickFalse)
1753 Dump image as grayscale.
1755 (void) FormatLocaleString(buffer,MaxTextExtent,
1756 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1758 (void) WriteBlobString(image,buffer);
1760 for (y=0; y < (ssize_t) image->rows; y++)
1762 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1763 if (p == (const Quantum *) NULL)
1765 for (x=0; x < (ssize_t) image->columns; x++)
1767 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
1768 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1770 if ((q-pixels+8) >= 80)
1773 (void) WriteBlob(image,q-pixels,pixels);
1776 p+=GetPixelChannels(image);
1778 if (image->previous == (Image *) NULL)
1780 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1782 if (status == MagickFalse)
1789 (void) WriteBlob(image,q-pixels,pixels);
1801 Dump image as bitmap.
1803 (void) FormatLocaleString(buffer,MaxTextExtent,
1804 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1806 (void) WriteBlobString(image,buffer);
1808 for (y=0; y < (ssize_t) image->rows; y++)
1810 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1811 if (p == (const Quantum *) NULL)
1815 for (x=0; x < (ssize_t) image->columns; x++)
1818 pixel=GetPixelIntensity(image,p);
1819 if (pixel >= (Quantum) (QuantumRange/2))
1824 q=PopHexPixel(hex_digits,byte,q);
1825 if ((q-pixels+2) >= 80)
1828 (void) WriteBlob(image,q-pixels,pixels);
1834 p+=GetPixelChannels(image);
1839 q=PopHexPixel(hex_digits,byte,q);
1840 if ((q-pixels+2) >= 80)
1843 (void) WriteBlob(image,q-pixels,pixels);
1847 if (image->previous == (Image *) NULL)
1849 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1851 if (status == MagickFalse)
1858 (void) WriteBlob(image,q-pixels,pixels);
1863 if ((image->storage_class == DirectClass) ||
1864 (image->colors > 256) || (image->matte != MagickFalse))
1867 Dump DirectClass image.
1869 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1870 (double) image->columns,(double) image->rows,
1871 image_info->compression == RLECompression ? 1 : 0);
1872 (void) WriteBlobString(image,buffer);
1873 switch (image_info->compression)
1875 case RLECompression:
1878 Dump runlength-encoded DirectColor packets.
1881 for (y=0; y < (ssize_t) image->rows; y++)
1883 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1884 if (p == (const Quantum *) NULL)
1886 GetPixelInfoPixel(image,p,&pixel);
1888 for (x=0; x < (ssize_t) image->columns; x++)
1890 if ((GetPixelRed(image,p) == pixel.red) &&
1891 (GetPixelGreen(image,p) == pixel.green) &&
1892 (GetPixelBlue(image,p) == pixel.blue) &&
1893 (GetPixelAlpha(image,p) == pixel.alpha) &&
1894 (length < 255) && (x < (ssize_t) (image->columns-1)))
1900 WriteRunlengthPacket(image,pixel,length,p);
1901 if ((q-pixels+10) >= 80)
1904 (void) WriteBlob(image,q-pixels,pixels);
1910 GetPixelInfoPixel(image,p,&pixel);
1911 p+=GetPixelChannels(image);
1913 WriteRunlengthPacket(image,pixel,length,p);
1914 if ((q-pixels+10) >= 80)
1917 (void) WriteBlob(image,q-pixels,pixels);
1920 if (image->previous == (Image *) NULL)
1922 status=SetImageProgress(image,SaveImageTag,
1923 (MagickOffsetType) y,image->rows);
1924 if (status == MagickFalse)
1931 (void) WriteBlob(image,q-pixels,pixels);
1939 Dump uncompressed DirectColor packets.
1942 for (y=0; y < (ssize_t) image->rows; y++)
1944 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1945 if (p == (const Quantum *) NULL)
1947 for (x=0; x < (ssize_t) image->columns; x++)
1949 if ((image->matte != MagickFalse) &&
1950 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1952 q=PopHexPixel(hex_digits,0xff,q);
1953 q=PopHexPixel(hex_digits,0xff,q);
1954 q=PopHexPixel(hex_digits,0xff,q);
1958 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1959 GetPixelRed(image,p)),q);
1960 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1961 GetPixelGreen(image,p)),q);
1962 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1963 GetPixelBlue(image,p)),q);
1965 if ((q-pixels+6) >= 80)
1968 (void) WriteBlob(image,q-pixels,pixels);
1971 p+=GetPixelChannels(image);
1973 if (image->previous == (Image *) NULL)
1975 status=SetImageProgress(image,SaveImageTag,
1976 (MagickOffsetType) y,image->rows);
1977 if (status == MagickFalse)
1984 (void) WriteBlob(image,q-pixels,pixels);
1989 (void) WriteBlobByte(image,'\n');
1994 Dump PseudoClass image.
1996 (void) FormatLocaleString(buffer,MaxTextExtent,
1997 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1998 image->rows,image->storage_class == PseudoClass ? 1 : 0,
1999 image_info->compression == RLECompression ? 1 : 0);
2000 (void) WriteBlobString(image,buffer);
2002 Dump number of colors and colormap.
2004 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2006 (void) WriteBlobString(image,buffer);
2007 for (i=0; i < (ssize_t) image->colors; i++)
2009 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
2010 ScaleQuantumToChar(image->colormap[i].red),
2011 ScaleQuantumToChar(image->colormap[i].green),
2012 ScaleQuantumToChar(image->colormap[i].blue));
2013 (void) WriteBlobString(image,buffer);
2015 switch (image_info->compression)
2017 case RLECompression:
2020 Dump runlength-encoded PseudoColor packets.
2023 for (y=0; y < (ssize_t) image->rows; y++)
2025 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2026 if (p == (const Quantum *) NULL)
2028 index=GetPixelIndex(image,p);
2030 for (x=0; x < (ssize_t) image->columns; x++)
2032 if ((index == GetPixelIndex(image,p)) &&
2033 (length < 255) && (x < ((ssize_t) image->columns-1)))
2039 q=PopHexPixel(hex_digits,(size_t) index,q);
2040 q=PopHexPixel(hex_digits,(size_t)
2041 MagickMin(length,0xff),q);
2043 if ((q-pixels+6) >= 80)
2046 (void) WriteBlob(image,q-pixels,pixels);
2052 index=GetPixelIndex(image,p);
2053 pixel.red=GetPixelRed(image,p);
2054 pixel.green=GetPixelGreen(image,p);
2055 pixel.blue=GetPixelBlue(image,p);
2056 pixel.alpha=GetPixelAlpha(image,p);
2057 p+=GetPixelChannels(image);
2059 q=PopHexPixel(hex_digits,(size_t) index,q);
2060 q=PopHexPixel(hex_digits,(size_t)
2061 MagickMin(length,0xff),q);
2062 if (image->previous == (Image *) NULL)
2064 status=SetImageProgress(image,SaveImageTag,
2065 (MagickOffsetType) y,image->rows);
2066 if (status == MagickFalse)
2073 (void) WriteBlob(image,q-pixels,pixels);
2081 Dump uncompressed PseudoColor packets.
2084 for (y=0; y < (ssize_t) image->rows; y++)
2086 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
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);