2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2010 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 "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colorspace.h"
49 #include "magick/constitute.h"
50 #include "magick/delegate.h"
51 #include "magick/delegate-private.h"
52 #include "magick/draw.h"
53 #include "magick/exception.h"
54 #include "magick/exception-private.h"
55 #include "magick/geometry.h"
56 #include "magick/image.h"
57 #include "magick/image-private.h"
58 #include "magick/list.h"
59 #include "magick/magick.h"
60 #include "magick/memory_.h"
61 #include "magick/monitor.h"
62 #include "magick/monitor-private.h"
63 #include "magick/option.h"
64 #include "magick/profile.h"
65 #include "magick/resource_.h"
66 #include "magick/pixel-private.h"
67 #include "magick/property.h"
68 #include "magick/quantum-private.h"
69 #include "magick/static.h"
70 #include "magick/string_.h"
71 #include "magick/module.h"
72 #include "magick/token.h"
73 #include "magick/transform.h"
74 #include "magick/utility.h"
79 static MagickBooleanType
80 WritePSImage(const ImageInfo *,Image *);
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % I n v o k e P o s t s r i p t D e l e g a t e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % InvokePostscriptDelegate() executes the Postscript interpreter with the
96 % The format of the InvokePostscriptDelegate method is:
98 % MagickBooleanType InvokePostscriptDelegate(
99 % const MagickBooleanType verbose,const char *command,
100 % ExceptionInfo *exception)
102 % A description of each parameter follows:
104 % o verbose: A value other than zero displays the command prior to
107 % o command: the address of a character string containing the command to
110 % o exception: return any errors or warnings in this structure.
113 static MagickBooleanType InvokePostscriptDelegate(
114 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
119 #if defined(MAGICKCORE_GS_DELEGATE) || defined(__WINDOWS__)
136 #if defined(__WINDOWS__)
137 ghost_info=NTGhostscriptDLLVectors();
142 ghost_info=(&ghost_info_struct);
143 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
144 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
146 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
147 gsapi_init_with_args;
148 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
149 int *)) gsapi_run_string;
150 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
151 gsapi_delete_instance;
152 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
154 if (ghost_info == (GhostInfo *) NULL)
156 status=SystemCommand(verbose,command,exception);
157 return(status == 0 ? MagickTrue : MagickFalse);
159 if (verbose != MagickFalse)
161 (void) fputs("[ghostscript library]",stdout);
162 (void) fputs(strchr(command,' '),stdout);
164 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
167 status=SystemCommand(verbose,command,exception);
168 return(status == 0 ? MagickTrue : MagickFalse);
170 argv=StringToArgv(command,&argc);
171 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
173 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
175 (ghost_info->exit)(interpreter);
176 (ghost_info->delete_instance)(interpreter);
177 #if defined(__WINDOWS__)
178 NTGhostscriptUnLoadDLL();
180 for (i=0; i < (long) argc; i++)
181 argv[i]=DestroyString(argv[i]);
182 argv=(char **) RelinquishMagickMemory(argv);
183 if ((status != 0) && (status != -101))
188 message=GetExceptionMessage(errno);
189 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
190 "`%s': %s",command,message);
191 message=DestroyString(message);
192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
193 "Ghostscript returns status %d, exit code %d",status,code);
198 status=SystemCommand(verbose,command,exception);
199 return(status == 0 ? MagickTrue : MagickFalse);
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 % IsPS() returns MagickTrue if the image format type, identified by the
215 % magick string, is PS.
217 % The format of the IsPS method is:
219 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
221 % A description of each parameter follows:
223 % o magick: compare image format pattern against these bytes.
225 % o length: Specifies the length of the magick string.
228 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
232 if (memcmp(magick,"%!",2) == 0)
234 if (memcmp(magick,"\004%!",3) == 0)
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 % R e a d P S I m a g e %
248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 % ReadPSImage() reads a Postscript image file and returns it. It allocates
251 % the memory necessary for the new Image structure and returns a pointer
254 % The format of the ReadPSImage method is:
256 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
258 % A description of each parameter follows:
260 % o image_info: the image info.
262 % o exception: return any errors or warnings in this structure.
266 static MagickBooleanType IsPostscriptRendered(const char *path)
274 if ((path == (const char *) NULL) || (*path == '\0'))
276 status=GetPathAttributes(path,&attributes);
277 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
278 (attributes.st_size > 0))
283 static inline int ProfileInteger(Image *image,short int *hex_digits)
297 c=ReadBlobByte(image);
298 if ((c == EOF) || ((c == '%') && (l == '%')))
305 if (isxdigit(c) == MagickFalse)
307 value=(int) ((unsigned long) value << 4)+hex_digits[c];
313 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
315 #define BoundingBox "BoundingBox:"
316 #define BeginDocument "BeginDocument:"
317 #define BeginXMPPacket "<?xpacket begin="
318 #define EndXMPPacket "<?xpacket end="
319 #define ICCProfile "BeginICCProfile:"
320 #define CMYKCustomColor "CMYKCustomColor:"
321 #define DocumentMedia "DocumentMedia:"
322 #define DocumentCustomColors "DocumentCustomColors:"
323 #define DocumentProcessColors "DocumentProcessColors:"
324 #define EndDocument "EndDocument:"
325 #define HiResBoundingBox "HiResBoundingBox:"
326 #define ImageData "ImageData:"
327 #define PageBoundingBox "PageBoundingBox:"
328 #define LanguageLevel "LanguageLevel:"
329 #define PageMedia "PageMedia:"
330 #define Pages "Pages:"
331 #define PhotoshopProfile "BeginPhotoshop:"
332 #define PostscriptLevel "!PS-"
333 #define RenderPostscriptText " Rendering Postscript... "
334 #define SpotColor "+ "
337 command[MaxTextExtent],
338 density[MaxTextExtent],
339 filename[MaxTextExtent],
340 geometry[MaxTextExtent],
341 input_filename[MaxTextExtent],
342 options[MaxTextExtent],
343 postscript_filename[MaxTextExtent],
344 translate_geometry[MaxTextExtent];
415 assert(image_info != (const ImageInfo *) NULL);
416 assert(image_info->signature == MagickSignature);
417 if (image_info->debug != MagickFalse)
418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
419 image_info->filename);
420 assert(exception != (ExceptionInfo *) NULL);
421 assert(exception->signature == MagickSignature);
422 image=AcquireImage(image_info);
423 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
424 if (status == MagickFalse)
426 image=DestroyImageList(image);
427 return((Image *) NULL);
429 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
430 if (status == MagickFalse)
432 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
433 image_info->filename);
434 image=DestroyImageList(image);
435 return((Image *) NULL);
438 Initialize hex values.
440 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
441 hex_digits[(int) '0']=0;
442 hex_digits[(int) '1']=1;
443 hex_digits[(int) '2']=2;
444 hex_digits[(int) '3']=3;
445 hex_digits[(int) '4']=4;
446 hex_digits[(int) '5']=5;
447 hex_digits[(int) '6']=6;
448 hex_digits[(int) '7']=7;
449 hex_digits[(int) '8']=8;
450 hex_digits[(int) '9']=9;
451 hex_digits[(int) 'a']=10;
452 hex_digits[(int) 'b']=11;
453 hex_digits[(int) 'c']=12;
454 hex_digits[(int) 'd']=13;
455 hex_digits[(int) 'e']=14;
456 hex_digits[(int) 'f']=15;
457 hex_digits[(int) 'A']=10;
458 hex_digits[(int) 'B']=11;
459 hex_digits[(int) 'C']=12;
460 hex_digits[(int) 'D']=13;
461 hex_digits[(int) 'E']=14;
462 hex_digits[(int) 'F']=15;
464 Set the page density.
466 delta.x=DefaultResolution;
467 delta.y=DefaultResolution;
468 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
470 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
471 image->x_resolution=geometry_info.rho;
472 image->y_resolution=geometry_info.sigma;
473 if ((flags & SigmaValue) == 0)
474 image->y_resolution=image->x_resolution;
477 Determine page geometry from the Postscript bounding box.
479 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
480 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
481 (void) ResetMagickMemory(&page,0,sizeof(page));
482 (void) ResetMagickMemory(command,0,sizeof(command));
491 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
494 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
497 Note document structuring comments.
500 if ((strchr("\n\r%",c) == (char *) NULL) &&
501 ((size_t) (p-command) < (MaxTextExtent-1)))
506 Skip %%BeginDocument thru %%EndDocument.
508 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
510 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
512 if (skip != MagickFalse)
514 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
516 (void) SetImageProperty(image,"ps:Level",command+4);
517 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
520 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
521 (void) sscanf(command,LanguageLevel " %lu",&language_level);
522 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
523 (void) sscanf(command,Pages " %lu",&pages);
524 if (LocaleNCompare(ImageData,command,strlen(Pages)) == 0)
525 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
526 if (LocaleNCompare(ICCProfile,command,strlen(PhotoshopProfile)) == 0)
534 profile=AcquireStringInfo(65536);
535 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
537 SetStringInfoLength(profile,(size_t) i+1);
538 datum=GetStringInfoDatum(profile);
539 datum[i]=(unsigned char) c;
541 (void) SetImageProfile(image,"icc",profile);
542 profile=DestroyStringInfo(profile);
545 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
551 Read Photoshop profile.
553 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
557 profile=AcquireStringInfo(length);
558 p=GetStringInfoDatum(profile);
559 for (i=0; i < (long) length; i++)
560 *p++=(unsigned char) ProfileInteger(image,hex_digits);
561 (void) SetImageProfile(image,"8bim",profile);
562 profile=DestroyStringInfo(profile);
565 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
574 profile=StringToStringInfo(command);
575 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
577 SetStringInfoLength(profile,i+1);
578 c=ReadBlobByte(image);
579 GetStringInfoDatum(profile)[i]=(unsigned char) c;
581 if ((strchr("\n\r%",c) == (char *) NULL) &&
582 ((size_t) (p-command) < (MaxTextExtent-1)))
586 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
589 SetStringInfoLength(profile,i);
590 (void) SetImageProfile(image,"xmp",profile);
591 profile=DestroyStringInfo(profile);
595 Is this a CMYK document?
597 length=strlen(DocumentProcessColors);
598 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
600 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
601 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
602 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
605 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
607 length=strlen(DocumentCustomColors);
608 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
609 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
610 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
613 property[MaxTextExtent],
622 (void) FormatMagickString(property,MaxTextExtent,"ps:SpotColor-%lu",
624 for (p=command; *p != '\0'; p++)
625 if (isspace((int) (unsigned char) *p) != 0)
627 value=AcquireString(p);
628 (void) SubstituteString(&value,"(","");
629 (void) SubstituteString(&value,")","");
630 (void) StripString(value);
631 (void) SetImageProperty(image,property,value);
632 value=DestroyString(value);
636 Note region defined by bounding box.
639 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
640 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
641 &bounds.y1,&bounds.x2,&bounds.y2);
642 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
643 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
645 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
646 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
647 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
648 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
649 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
650 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
651 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
652 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
656 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
657 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
660 Set Postscript render geometry.
662 (void) FormatMagickString(geometry,MaxTextExtent,"%gx%g%+g%+g",
663 bounds.x2-bounds.x1,bounds.y2-bounds.y1,bounds.x1,bounds.y1);
664 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
665 page.width=(unsigned long) (bounds.x2-bounds.x1+0.5);
666 page.height=(unsigned long) (bounds.y2-bounds.y1+0.5);
670 (void) CloseBlob(image);
671 if (image_info->colorspace == RGBColorspace)
674 Create Ghostscript control file.
676 file=AcquireUniqueFileResource(postscript_filename);
679 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
680 image_info->filename);
681 image=DestroyImageList(image);
682 return((Image *) NULL);
684 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
685 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
686 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
687 count=write(file,command,(unsigned int) strlen(command));
688 (void) FormatMagickString(translate_geometry,MaxTextExtent,
689 "%g %g translate\n",-bounds.x1,-bounds.y1);
690 count=write(file,translate_geometry,strlen(translate_geometry));
693 Render Postscript with the Ghostscript delegate.
695 if (image_info->monochrome != MagickFalse)
696 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
698 if (cmyk != MagickFalse)
699 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
702 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
704 delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception);
705 if (delegate_info == (const DelegateInfo *) NULL)
707 (void) RelinquishUniqueFileResource(postscript_filename);
708 image=DestroyImageList(image);
709 return((Image *) NULL);
712 if ((page.width == 0) || (page.height == 0))
713 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
714 if (image_info->page != (char *) NULL)
715 (void) ParseAbsoluteGeometry(image_info->page,&page);
716 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",image->x_resolution,
717 image->y_resolution);
718 page.width=(unsigned long) (page.width*image->x_resolution/delta.x+0.5);
719 page.height=(unsigned long) (page.height*image->y_resolution/delta.y+0.5);
720 (void) FormatMagickString(options,MaxTextExtent,"-g%lux%lu ",
721 page.width,page.height);
722 read_info=CloneImageInfo(image_info);
723 *read_info->magick='\0';
724 if (read_info->number_scenes != 0)
727 pages[MaxTextExtent];
729 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%lu "
730 "-dLastPage=%lu",read_info->scene+1,read_info->scene+
731 read_info->number_scenes);
732 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
733 read_info->number_scenes=0;
734 if (read_info->scenes != (char *) NULL)
735 *read_info->scenes='\0';
737 option=GetImageOption(image_info,"ps:use-cropbox");
738 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
739 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
740 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
741 (void) AcquireUniqueFilename(read_info->filename);
742 (void) FormatMagickString(command,MaxTextExtent,
743 GetDelegateCommands(delegate_info),
744 read_info->antialias != MagickFalse ? 4 : 1,
745 read_info->antialias != MagickFalse ? 4 : 1,density,options,
746 read_info->filename,postscript_filename,input_filename);
747 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
748 if ((status == MagickFalse) ||
749 (IsPostscriptRendered(read_info->filename) == MagickFalse))
751 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
752 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
754 postscript_image=(Image *) NULL;
755 if (status != MagickFalse)
756 postscript_image=ReadImage(read_info,exception);
757 (void) RelinquishUniqueFileResource(postscript_filename);
758 (void) RelinquishUniqueFileResource(read_info->filename);
759 (void) RelinquishUniqueFileResource(input_filename);
760 read_info=DestroyImageInfo(read_info);
761 if (postscript_image == (Image *) NULL)
763 image=DestroyImageList(image);
764 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
765 image_info->filename);
766 return((Image *) NULL);
768 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
773 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
774 if (cmyk_image != (Image *) NULL)
776 postscript_image=DestroyImageList(postscript_image);
777 postscript_image=cmyk_image;
780 if (image_info->number_scenes != 0)
789 Add place holder images to meet the subimage specification requirement.
791 for (i=0; i < (long) image_info->scene; i++)
793 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
794 if (clone_image != (Image *) NULL)
795 PrependImageToList(&postscript_image,clone_image);
800 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
802 postscript_image->magick_columns=columns;
804 postscript_image->magick_rows=rows;
805 postscript_image->page=page;
806 (void) CloneImageProfiles(postscript_image,image);
807 (void) CloneImageProperties(postscript_image,image);
808 next=SyncNextImageInList(postscript_image);
809 if (next != (Image *) NULL)
810 postscript_image=next;
811 } while (next != (Image *) NULL);
812 image=DestroyImageList(image);
814 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
817 next=GetNextImageInList(next);
819 return(GetFirstImageInList(postscript_image));
823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827 % R e g i s t e r P S I m a g e %
831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833 % RegisterPSImage() adds properties for the PS image format to
834 % the list of supported formats. The properties include the image format
835 % tag, a method to read and/or write the format, whether the format
836 % supports the saving of more than one frame to the same file or blob,
837 % whether the format supports native in-memory I/O, and a brief
838 % description of the format.
840 % The format of the RegisterPSImage method is:
842 % unsigned long RegisterPSImage(void)
845 ModuleExport unsigned long RegisterPSImage(void)
850 entry=SetMagickInfo("EPI");
851 entry->decoder=(DecodeImageHandler *) ReadPSImage;
852 entry->encoder=(EncodeImageHandler *) WritePSImage;
853 entry->magick=(IsImageFormatHandler *) IsPS;
854 entry->adjoin=MagickFalse;
855 entry->blob_support=MagickFalse;
856 entry->seekable_stream=MagickTrue;
857 entry->thread_support=EncoderThreadSupport;
858 entry->description=ConstantString(
859 "Encapsulated PostScript Interchange format");
860 entry->module=ConstantString("PS");
861 (void) RegisterMagickInfo(entry);
862 entry=SetMagickInfo("EPS");
863 entry->decoder=(DecodeImageHandler *) ReadPSImage;
864 entry->encoder=(EncodeImageHandler *) WritePSImage;
865 entry->magick=(IsImageFormatHandler *) IsPS;
866 entry->adjoin=MagickFalse;
867 entry->blob_support=MagickFalse;
868 entry->seekable_stream=MagickTrue;
869 entry->thread_support=EncoderThreadSupport;
870 entry->description=ConstantString("Encapsulated PostScript");
871 entry->module=ConstantString("PS");
872 (void) RegisterMagickInfo(entry);
873 entry=SetMagickInfo("EPSF");
874 entry->decoder=(DecodeImageHandler *) ReadPSImage;
875 entry->encoder=(EncodeImageHandler *) WritePSImage;
876 entry->magick=(IsImageFormatHandler *) IsPS;
877 entry->adjoin=MagickFalse;
878 entry->blob_support=MagickFalse;
879 entry->seekable_stream=MagickTrue;
880 entry->description=ConstantString("Encapsulated PostScript");
881 entry->module=ConstantString("PS");
882 (void) RegisterMagickInfo(entry);
883 entry=SetMagickInfo("EPSI");
884 entry->decoder=(DecodeImageHandler *) ReadPSImage;
885 entry->encoder=(EncodeImageHandler *) WritePSImage;
886 entry->magick=(IsImageFormatHandler *) IsPS;
887 entry->adjoin=MagickFalse;
888 entry->blob_support=MagickFalse;
889 entry->seekable_stream=MagickTrue;
890 entry->thread_support=EncoderThreadSupport;
891 entry->description=ConstantString(
892 "Encapsulated PostScript Interchange format");
893 entry->module=ConstantString("PS");
894 (void) RegisterMagickInfo(entry);
895 entry=SetMagickInfo("PS");
896 entry->decoder=(DecodeImageHandler *) ReadPSImage;
897 entry->encoder=(EncodeImageHandler *) WritePSImage;
898 entry->magick=(IsImageFormatHandler *) IsPS;
899 entry->module=ConstantString("PS");
900 entry->blob_support=MagickFalse;
901 entry->seekable_stream=MagickTrue;
902 entry->thread_support=EncoderThreadSupport;
903 entry->description=ConstantString("PostScript");
904 (void) RegisterMagickInfo(entry);
905 return(MagickImageCoderSignature);
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
913 % U n r e g i s t e r P S I m a g e %
917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919 % UnregisterPSImage() removes format registrations made by the
920 % PS module from the list of supported formats.
922 % The format of the UnregisterPSImage method is:
924 % UnregisterPSImage(void)
927 ModuleExport void UnregisterPSImage(void)
929 (void) UnregisterMagickInfo("EPI");
930 (void) UnregisterMagickInfo("EPS");
931 (void) UnregisterMagickInfo("EPSF");
932 (void) UnregisterMagickInfo("EPSI");
933 (void) UnregisterMagickInfo("PS");
937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 % W r i t e P S I m a g e %
945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947 % WritePSImage translates an image to encapsulated Postscript
948 % Level I for printing. If the supplied geometry is null, the image is
949 % centered on the Postscript page. Otherwise, the image is positioned as
950 % specified by the geometry.
952 % The format of the WritePSImage method is:
954 % MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
956 % A description of each parameter follows:
958 % o image_info: the image info.
960 % o image: the image.
964 static inline size_t MagickMin(const size_t x,const size_t y)
971 static inline unsigned char *PopHexPixel(const char **hex_digits,
972 const unsigned long pixel,unsigned char *pixels)
977 hex=hex_digits[pixel];
978 *pixels++=(unsigned char) (*hex++);
979 *pixels++=(unsigned char) (*hex);
983 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
985 #define WriteRunlengthPacket(image,pixel,length,p) \
987 if ((image->matte != MagickFalse) && \
988 (p->opacity == (Quantum) TransparentOpacity)) \
990 q=PopHexPixel(hex_digits,0xff,q); \
991 q=PopHexPixel(hex_digits,0xff,q); \
992 q=PopHexPixel(hex_digits,0xff,q); \
996 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
997 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
998 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1000 q=PopHexPixel(hex_digits,(const unsigned long) MagickMin(length,0xff),q); \
1006 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1007 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1008 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1009 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1010 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1011 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1012 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1013 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1014 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1015 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1016 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1017 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1018 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1019 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1020 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1021 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1022 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1023 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1024 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1025 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1026 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1027 "FC", "FD", "FE", "FF", (char *) NULL
1029 *PostscriptProlog[]=
1033 "% Display a color image. The image is displayed in color on",
1034 "% Postscript viewers or printers that support color, otherwise",
1035 "% it is displayed as grayscale.",
1037 "/DirectClassPacket",
1040 " % Get a DirectClass packet.",
1046 " % length: number of pixels minus one of this color (optional).",
1048 " currentfile color_packet readhexstring pop pop",
1049 " compression 0 eq",
1051 " /number_pixels 3 def",
1054 " currentfile byte readhexstring pop 0 get",
1055 " /number_pixels exch 1 add 3 mul def",
1057 " 0 3 number_pixels 1 sub",
1059 " pixels exch color_packet putinterval",
1061 " pixels 0 number_pixels getinterval",
1064 "/DirectClassImage",
1067 " % Display a DirectClass image.",
1069 " systemdict /colorimage known",
1076 " { DirectClassPacket } false 3 colorimage",
1080 " % No colorimage operator; convert to grayscale.",
1087 " { GrayDirectClassPacket } image",
1091 "/GrayDirectClassPacket",
1094 " % Get a DirectClass packet; convert to grayscale.",
1100 " % length: number of pixels minus one of this color (optional).",
1102 " currentfile color_packet readhexstring pop pop",
1103 " color_packet 0 get 0.299 mul",
1104 " color_packet 1 get 0.587 mul add",
1105 " color_packet 2 get 0.114 mul add",
1107 " /gray_packet exch def",
1108 " compression 0 eq",
1110 " /number_pixels 1 def",
1113 " currentfile byte readhexstring pop 0 get",
1114 " /number_pixels exch 1 add def",
1116 " 0 1 number_pixels 1 sub",
1118 " pixels exch gray_packet put",
1120 " pixels 0 number_pixels getinterval",
1123 "/GrayPseudoClassPacket",
1126 " % Get a PseudoClass packet; convert to grayscale.",
1129 " % index: index into the colormap.",
1130 " % length: number of pixels minus one of this color (optional).",
1132 " currentfile byte readhexstring pop 0 get",
1133 " /offset exch 3 mul def",
1134 " /color_packet colormap offset 3 getinterval def",
1135 " color_packet 0 get 0.299 mul",
1136 " color_packet 1 get 0.587 mul add",
1137 " color_packet 2 get 0.114 mul add",
1139 " /gray_packet exch def",
1140 " compression 0 eq",
1142 " /number_pixels 1 def",
1145 " currentfile byte readhexstring pop 0 get",
1146 " /number_pixels exch 1 add def",
1148 " 0 1 number_pixels 1 sub",
1150 " pixels exch gray_packet put",
1152 " pixels 0 number_pixels getinterval",
1155 "/PseudoClassPacket",
1158 " % Get a PseudoClass packet.",
1161 " % index: index into the colormap.",
1162 " % length: number of pixels minus one of this color (optional).",
1164 " currentfile byte readhexstring pop 0 get",
1165 " /offset exch 3 mul def",
1166 " /color_packet colormap offset 3 getinterval def",
1167 " compression 0 eq",
1169 " /number_pixels 3 def",
1172 " currentfile byte readhexstring pop 0 get",
1173 " /number_pixels exch 1 add 3 mul def",
1175 " 0 3 number_pixels 1 sub",
1177 " pixels exch color_packet putinterval",
1179 " pixels 0 number_pixels getinterval",
1182 "/PseudoClassImage",
1185 " % Display a PseudoClass image.",
1188 " % class: 0-PseudoClass or 1-Grayscale.",
1190 " currentfile buffer readline pop",
1191 " token pop /class exch def pop",
1194 " currentfile buffer readline pop",
1195 " token pop /depth exch def pop",
1196 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1197 " columns rows depth",
1202 " { currentfile grays readhexstring pop } image",
1207 " % colors: number of colors in the colormap.",
1208 " % colormap: red, green, blue color packets.",
1210 " currentfile buffer readline pop",
1211 " token pop /colors exch def pop",
1212 " /colors colors 3 mul def",
1213 " /colormap colors string def",
1214 " currentfile colormap readhexstring pop pop",
1215 " systemdict /colorimage known",
1222 " { PseudoClassPacket } false 3 colorimage",
1226 " % No colorimage operator; convert to grayscale.",
1233 " { GrayPseudoClassPacket } image",
1241 " % Display a DirectClass or PseudoClass image.",
1244 " % x & y translation.",
1246 " % label pointsize.",
1248 " % image columns & rows.",
1249 " % class: 0-DirectClass or 1-PseudoClass.",
1250 " % compression: 0-none or 1-RunlengthEncoded.",
1251 " % hex color packets.",
1254 " /buffer 512 string def",
1255 " /byte 1 string def",
1256 " /color_packet 3 string def",
1257 " /pixels 768 string def",
1259 " currentfile buffer readline pop",
1260 " token pop /x exch def",
1261 " token pop /y exch def pop",
1263 " currentfile buffer readline pop",
1264 " token pop /x exch def",
1265 " token pop /y exch def pop",
1266 " currentfile buffer readline pop",
1267 " token pop /pointsize exch def pop",
1268 " /Times-Roman findfont pointsize scalefont setfont",
1271 *PostscriptEpilog[]=
1274 " currentfile buffer readline pop",
1275 " token pop /columns exch def",
1276 " token pop /rows exch def pop",
1277 " currentfile buffer readline pop",
1278 " token pop /class exch def pop",
1279 " currentfile buffer readline pop",
1280 " token pop /compression exch def pop",
1281 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1286 buffer[MaxTextExtent],
1287 date[MaxTextExtent],
1289 page_geometry[MaxTextExtent];
1333 register const IndexPacket
1336 register const PixelPacket
1343 register unsigned char
1365 Open output image file.
1367 assert(image_info != (const ImageInfo *) NULL);
1368 assert(image_info->signature == MagickSignature);
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1373 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1374 if (status == MagickFalse)
1376 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1382 Scale relative to dots-per-inch.
1384 if ((image->colorspace != RGBColorspace) &&
1385 (image->colorspace != CMYKColorspace))
1386 (void) TransformImageColorspace(image,RGBColorspace);
1387 delta.x=DefaultResolution;
1388 delta.y=DefaultResolution;
1389 resolution.x=image->x_resolution;
1390 resolution.y=image->y_resolution;
1391 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1393 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1394 resolution.x=geometry_info.rho;
1395 resolution.y=geometry_info.sigma;
1396 if ((flags & SigmaValue) == 0)
1397 resolution.y=resolution.x;
1399 if (image_info->density != (char *) NULL)
1401 flags=ParseGeometry(image_info->density,&geometry_info);
1402 resolution.x=geometry_info.rho;
1403 resolution.y=geometry_info.sigma;
1404 if ((flags & SigmaValue) == 0)
1405 resolution.y=resolution.x;
1407 if (image->units == PixelsPerCentimeterResolution)
1412 SetGeometry(image,&geometry);
1413 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
1414 image->columns,image->rows);
1415 if (image_info->page != (char *) NULL)
1416 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1418 if ((image->page.width != 0) && (image->page.height != 0))
1419 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
1420 image->page.width,image->page.height,image->page.x,image->page.y);
1422 if ((image->gravity != UndefinedGravity) &&
1423 (LocaleCompare(image_info->magick,"PS") == 0))
1424 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1425 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1426 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1427 &geometry.width,&geometry.height);
1428 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1429 geometry.width=(unsigned long) (scale.x+0.5);
1430 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1431 geometry.height=(unsigned long) (scale.y+0.5);
1432 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1433 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1435 if (image->gravity != UndefinedGravity)
1437 geometry.x=(-page_info.x);
1438 geometry.y=(long) (media_info.height+page_info.y-image->rows);
1441 if (image_info->pointsize != 0.0)
1442 pointsize=image_info->pointsize;
1444 value=GetImageProperty(image,"label");
1445 if (value != (const char *) NULL)
1446 text_size=(unsigned long) (MultilineCensus(value)*pointsize+12);
1450 Output Postscript header.
1452 if (LocaleCompare(image_info->magick,"PS") == 0)
1453 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1455 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1457 (void) WriteBlobString(image,buffer);
1458 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1459 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1461 (void) WriteBlobString(image,buffer);
1462 timer=time((time_t *) NULL);
1463 (void) FormatMagickTime(timer,MaxTextExtent,date);
1464 (void) FormatMagickString(buffer,MaxTextExtent,
1465 "%%%%CreationDate: (%s)\n",date);
1466 (void) WriteBlobString(image,buffer);
1467 bounds.x1=(double) geometry.x;
1468 bounds.y1=(double) geometry.y;
1469 bounds.x2=(double) geometry.x+scale.x;
1470 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1471 if ((image_info->adjoin != MagickFalse) &&
1472 (GetNextImageInList(image) != (Image *) NULL))
1473 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1477 (void) FormatMagickString(buffer,MaxTextExtent,
1478 "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
1479 (long) (bounds.y1+0.5),(long) (bounds.x2+0.5),
1480 (long) (bounds.y2+0.5));
1481 (void) WriteBlobString(image,buffer);
1482 (void) FormatMagickString(buffer,MaxTextExtent,
1483 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
1484 bounds.x2,bounds.y2);
1486 (void) WriteBlobString(image,buffer);
1487 profile=GetImageProfile(image,"8bim");
1488 if (profile != (StringInfo *) NULL)
1491 Embed Photoshop profile.
1493 (void) FormatMagickString(buffer,MaxTextExtent,
1494 "%%BeginPhotoshop: %lu",(unsigned long) GetStringInfoLength(
1496 (void) WriteBlobString(image,buffer);
1497 for (i=0; i < (long) GetStringInfoLength(profile); i++)
1500 (void) WriteBlobString(image,"\n% ");
1501 (void) FormatMagickString(buffer,MaxTextExtent,"%02X",
1502 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1503 (void) WriteBlobString(image,buffer);
1505 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1507 profile=GetImageProfile(image,"xmp");
1508 if (profile != (StringInfo *) NULL)
1513 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1514 for (i=0; i < (long) GetStringInfoLength(profile); i++)
1515 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1516 (void) WriteBlobString(image,"\n%end_xml_code\n");
1518 value=GetImageProperty(image,"label");
1519 if (value != (const char *) NULL)
1520 (void) WriteBlobString(image,
1521 "%%DocumentNeededResources: font Times-Roman\n");
1522 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1523 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1524 if (LocaleCompare(image_info->magick,"PS") != 0)
1525 (void) WriteBlobString(image,"%%Pages: 1\n");
1529 Compute the number of pages.
1531 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1532 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1533 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %lu\n",
1534 image_info->adjoin != MagickFalse ? (unsigned long)
1535 GetImageListLength(image) : 1UL);
1536 (void) WriteBlobString(image,buffer);
1538 (void) WriteBlobString(image,"%%EndComments\n");
1539 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1540 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1541 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1542 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1543 (LocaleCompare(image_info->magick,"EPT") == 0))
1558 Create preview image.
1560 preview_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1561 if (preview_image == (Image *) NULL)
1562 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1564 Dump image as bitmap.
1566 (void) FormatMagickString(buffer,MaxTextExtent,
1567 "%%%%BeginPreview: %lu %lu %lu %lu\n%% ",preview_image->columns,
1568 preview_image->rows,1L,(((preview_image->columns+7) >> 3)*
1569 preview_image->rows+35)/36);
1570 (void) WriteBlobString(image,buffer);
1572 for (y=0; y < (long) image->rows; y++)
1574 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1575 &preview_image->exception);
1576 if (p == (const PixelPacket *) NULL)
1578 indexes=GetVirtualIndexQueue(preview_image);
1581 for (x=0; x < (long) preview_image->columns; x++)
1584 pixel=PixelIntensityToQuantum(p);
1585 if (pixel >= (Quantum) (QuantumRange/2))
1590 q=PopHexPixel(hex_digits,byte,q);
1591 if ((q-pixels+8) >= 80)
1594 (void) WriteBlob(image,q-pixels,pixels);
1596 (void) WriteBlobString(image,"% ");
1605 q=PopHexPixel(hex_digits,byte,q);
1606 if ((q-pixels+8) >= 80)
1609 (void) WriteBlob(image,q-pixels,pixels);
1611 (void) WriteBlobString(image,"% ");
1618 (void) WriteBlob(image,q-pixels,pixels);
1620 (void) WriteBlobString(image,"\n%%EndPreview\n");
1621 preview_image=DestroyImage(preview_image);
1624 Output Postscript commands.
1626 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1628 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1629 (void) WriteBlobString(image,buffer);
1631 value=GetImageProperty(image,"label");
1632 if (value != (const char *) NULL)
1633 for (j=(long) MultilineCensus(value)-1; j >= 0; j--)
1635 (void) WriteBlobString(image," /label 512 string def\n");
1636 (void) WriteBlobString(image," currentfile label readline pop\n");
1637 (void) FormatMagickString(buffer,MaxTextExtent,
1638 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1639 (void) WriteBlobString(image,buffer);
1641 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1643 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1644 (void) WriteBlobString(image,buffer);
1646 if (LocaleCompare(image_info->magick,"PS") == 0)
1647 (void) WriteBlobString(image," showpage\n");
1648 (void) WriteBlobString(image,"} bind def\n");
1649 (void) WriteBlobString(image,"%%EndProlog\n");
1651 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page: 1 %lu\n",page++);
1652 (void) WriteBlobString(image,buffer);
1653 (void) FormatMagickString(buffer,MaxTextExtent,
1654 "%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,geometry.y,
1655 geometry.x+(long) geometry.width,geometry.y+(long) (geometry.height+
1657 (void) WriteBlobString(image,buffer);
1658 if ((double) geometry.x < bounds.x1)
1659 bounds.x1=(double) geometry.x;
1660 if ((double) geometry.y < bounds.y1)
1661 bounds.y1=(double) geometry.y;
1662 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1663 bounds.x2=(double) geometry.x+geometry.width-1;
1664 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1665 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1666 value=GetImageProperty(image,"label");
1667 if (value != (const char *) NULL)
1668 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1669 if (LocaleCompare(image_info->magick,"PS") != 0)
1670 (void) WriteBlobString(image,"userdict begin\n");
1671 (void) WriteBlobString(image,"DisplayImage\n");
1675 (void) FormatMagickString(buffer,MaxTextExtent,"%ld %ld\n%g %g\n%f\n",
1676 geometry.x,geometry.y,scale.x,scale.y,pointsize);
1677 (void) WriteBlobString(image,buffer);
1678 labels=(char **) NULL;
1679 value=GetImageProperty(image,"label");
1680 if (value != (const char *) NULL)
1681 labels=StringToList(value);
1682 if (labels != (char **) NULL)
1684 for (i=0; labels[i] != (char *) NULL; i++)
1686 (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
1688 (void) WriteBlobString(image,buffer);
1689 labels[i]=DestroyString(labels[i]);
1691 labels=(char **) RelinquishMagickMemory(labels);
1693 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1694 pixel.opacity=(Quantum) TransparentOpacity;
1695 index=(IndexPacket) 0;
1697 if ((image_info->type != TrueColorType) &&
1698 (IsGrayImage(image,&image->exception) != MagickFalse))
1700 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
1706 Dump image as grayscale.
1708 (void) FormatMagickString(buffer,MaxTextExtent,
1709 "%lu %lu\n1\n1\n1\n8\n",image->columns,image->rows);
1710 (void) WriteBlobString(image,buffer);
1712 for (y=0; y < (long) image->rows; y++)
1714 p=GetVirtualPixels(image,0,y,image->columns,1,
1716 if (p == (const PixelPacket *) NULL)
1718 for (x=0; x < (long) image->columns; x++)
1720 pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1721 q=PopHexPixel(hex_digits,pixel,q);
1723 if ((q-pixels+8) >= 80)
1726 (void) WriteBlob(image,q-pixels,pixels);
1731 if (image->previous == (Image *) NULL)
1733 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1734 if (status == MagickFalse)
1741 (void) WriteBlob(image,q-pixels,pixels);
1753 Dump image as bitmap.
1755 (void) FormatMagickString(buffer,MaxTextExtent,
1756 "%lu %lu\n1\n1\n1\n1\n",image->columns,image->rows);
1757 (void) WriteBlobString(image,buffer);
1759 for (y=0; y < (long) image->rows; y++)
1761 p=GetVirtualPixels(image,0,y,image->columns,1,
1763 if (p == (const PixelPacket *) NULL)
1765 indexes=GetVirtualIndexQueue(image);
1768 for (x=0; x < (long) image->columns; x++)
1771 pixel=PixelIntensityToQuantum(p);
1772 if (pixel >= (Quantum) (QuantumRange/2))
1777 q=PopHexPixel(hex_digits,byte,q);
1778 if ((q-pixels+2) >= 80)
1781 (void) WriteBlob(image,q-pixels,pixels);
1792 q=PopHexPixel(hex_digits,byte,q);
1793 if ((q-pixels+2) >= 80)
1796 (void) WriteBlob(image,q-pixels,pixels);
1800 if (image->previous == (Image *) NULL)
1802 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1803 if (status == MagickFalse)
1810 (void) WriteBlob(image,q-pixels,pixels);
1815 if ((image->storage_class == DirectClass) ||
1816 (image->colors > 256) || (image->matte != MagickFalse))
1819 Dump DirectClass image.
1821 (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n0\n%d\n",
1822 image->columns,image->rows,
1823 image_info->compression == RLECompression ? 1 : 0);
1824 (void) WriteBlobString(image,buffer);
1825 switch (image_info->compression)
1827 case RLECompression:
1830 Dump runlength-encoded DirectColor packets.
1833 for (y=0; y < (long) image->rows; y++)
1835 p=GetVirtualPixels(image,0,y,image->columns,1,
1837 if (p == (const PixelPacket *) NULL)
1841 for (x=0; x < (long) image->columns; x++)
1843 if ((p->red == pixel.red) && (p->green == pixel.green) &&
1844 (p->blue == pixel.blue) &&
1845 (p->opacity == pixel.opacity) && (length < 255) &&
1846 (x < (long) (image->columns-1)))
1852 WriteRunlengthPacket(image,pixel,length,p);
1853 if ((q-pixels+10) >= 80)
1856 (void) WriteBlob(image,q-pixels,pixels);
1865 WriteRunlengthPacket(image,pixel,length,p);
1866 if ((q-pixels+10) >= 80)
1869 (void) WriteBlob(image,q-pixels,pixels);
1872 if (image->previous == (Image *) NULL)
1874 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1875 if (status == MagickFalse)
1882 (void) WriteBlob(image,q-pixels,pixels);
1890 Dump uncompressed DirectColor packets.
1893 for (y=0; y < (long) image->rows; y++)
1895 p=GetVirtualPixels(image,0,y,image->columns,1,
1897 if (p == (const PixelPacket *) NULL)
1899 for (x=0; x < (long) image->columns; x++)
1901 if ((image->matte != MagickFalse) &&
1902 (p->opacity == (Quantum) TransparentOpacity))
1904 q=PopHexPixel(hex_digits,0xff,q);
1905 q=PopHexPixel(hex_digits,0xff,q);
1906 q=PopHexPixel(hex_digits,0xff,q);
1910 q=PopHexPixel(hex_digits,ScaleQuantumToChar(p->red),q);
1911 q=PopHexPixel(hex_digits,ScaleQuantumToChar(p->green),q);
1912 q=PopHexPixel(hex_digits,ScaleQuantumToChar(p->blue),q);
1914 if ((q-pixels+6) >= 80)
1917 (void) WriteBlob(image,q-pixels,pixels);
1922 if (image->previous == (Image *) NULL)
1924 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1925 if (status == MagickFalse)
1932 (void) WriteBlob(image,q-pixels,pixels);
1937 (void) WriteBlobByte(image,'\n');
1942 Dump PseudoClass image.
1944 (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n%d\n%d\n0\n",
1945 image->columns,image->rows,
1946 image->storage_class == PseudoClass ? 1 : 0,
1947 image_info->compression == RLECompression ? 1 : 0);
1948 (void) WriteBlobString(image,buffer);
1950 Dump number of colors and colormap.
1952 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",image->colors);
1953 (void) WriteBlobString(image,buffer);
1954 for (i=0; i < (long) image->colors; i++)
1956 (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1957 ScaleQuantumToChar(image->colormap[i].red),
1958 ScaleQuantumToChar(image->colormap[i].green),
1959 ScaleQuantumToChar(image->colormap[i].blue));
1960 (void) WriteBlobString(image,buffer);
1962 switch (image_info->compression)
1964 case RLECompression:
1967 Dump runlength-encoded PseudoColor packets.
1970 for (y=0; y < (long) image->rows; y++)
1972 p=GetVirtualPixels(image,0,y,image->columns,1,
1974 if (p == (const PixelPacket *) NULL)
1976 indexes=GetVirtualIndexQueue(image);
1979 for (x=0; x < (long) image->columns; x++)
1981 if ((index == indexes[x]) && (length < 255) &&
1982 (x < ((long) image->columns-1)))
1988 q=PopHexPixel(hex_digits,index,q);
1989 q=PopHexPixel(hex_digits,(unsigned long)
1990 MagickMin(length,0xff),q);
1992 if ((q-pixels+6) >= 80)
1995 (void) WriteBlob(image,q-pixels,pixels);
2005 q=PopHexPixel(hex_digits,index,q);
2006 q=PopHexPixel(hex_digits,(unsigned long)
2007 MagickMin(length,0xff),q);
2008 if (image->previous == (Image *) NULL)
2010 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2011 if (status == MagickFalse)
2018 (void) WriteBlob(image,q-pixels,pixels);
2026 Dump uncompressed PseudoColor packets.
2029 for (y=0; y < (long) image->rows; y++)
2031 p=GetVirtualPixels(image,0,y,image->columns,1,
2033 if (p == (const PixelPacket *) NULL)
2035 indexes=GetVirtualIndexQueue(image);
2036 for (x=0; x < (long) image->columns; x++)
2038 q=PopHexPixel(hex_digits,indexes[x],q);
2039 if ((q-pixels+4) >= 80)
2042 (void) WriteBlob(image,q-pixels,pixels);
2047 if (image->previous == (Image *) NULL)
2049 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2050 if (status == MagickFalse)
2057 (void) WriteBlob(image,q-pixels,pixels);
2062 (void) WriteBlobByte(image,'\n');
2064 if (LocaleCompare(image_info->magick,"PS") != 0)
2065 (void) WriteBlobString(image,"end\n");
2066 (void) WriteBlobString(image,"%%PageTrailer\n");
2067 if (GetNextImageInList(image) == (Image *) NULL)
2069 image=SyncNextImageInList(image);
2070 status=SetImageProgress(image,SaveImagesTag,scene++,
2071 GetImageListLength(image));
2072 if (status == MagickFalse)
2074 } while (image_info->adjoin != MagickFalse);
2075 (void) WriteBlobString(image,"%%Trailer\n");
2078 (void) FormatMagickString(buffer,MaxTextExtent,
2079 "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
2080 (long) (bounds.y1+0.5),(long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
2081 (void) WriteBlobString(image,buffer);
2082 (void) FormatMagickString(buffer,MaxTextExtent,
2083 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2085 (void) WriteBlobString(image,buffer);
2087 (void) WriteBlobString(image,"%%EOF\n");
2088 (void) CloseBlob(image);