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(MAGICKCORE_WINDOWS_SUPPORT)
136 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
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(MagickFalse,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(MagickFalse,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(MAGICKCORE_WINDOWS_SUPPORT)
178 NTGhostscriptUnLoadDLL();
180 for (i=0; i < (ssize_t) 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(MagickFalse,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) ((size_t) 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 CMYKProcessColor "CMYKProcessColor:"
322 #define DocumentMedia "DocumentMedia:"
323 #define DocumentCustomColors "DocumentCustomColors:"
324 #define DocumentProcessColors "DocumentProcessColors:"
325 #define EndDocument "EndDocument:"
326 #define HiResBoundingBox "HiResBoundingBox:"
327 #define ImageData "ImageData:"
328 #define PageBoundingBox "PageBoundingBox:"
329 #define LanguageLevel "LanguageLevel:"
330 #define PageMedia "PageMedia:"
331 #define Pages "Pages:"
332 #define PhotoshopProfile "BeginPhotoshop:"
333 #define PostscriptLevel "!PS-"
334 #define RenderPostscriptText " Rendering Postscript... "
335 #define SpotColor "+ "
338 command[MaxTextExtent],
339 density[MaxTextExtent],
340 filename[MaxTextExtent],
341 geometry[MaxTextExtent],
342 input_filename[MaxTextExtent],
343 options[MaxTextExtent],
344 postscript_filename[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(ImageData)) == 0)
525 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
526 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 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 < (ssize_t) 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 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
609 length=strlen(DocumentCustomColors);
610 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
611 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
612 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
615 property[MaxTextExtent],
624 (void) FormatMagickString(property,MaxTextExtent,"ps:SpotColor-%.20g",
625 (double) (spotcolor++));
626 for (p=command; *p != '\0'; p++)
627 if (isspace((int) (unsigned char) *p) != 0)
629 value=AcquireString(p);
630 (void) SubstituteString(&value,"(","");
631 (void) SubstituteString(&value,")","");
632 (void) StripString(value);
633 (void) SetImageProperty(image,property,value);
634 value=DestroyString(value);
638 Note region defined by bounding box.
641 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
642 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
643 &bounds.y1,&bounds.x2,&bounds.y2);
644 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
645 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
647 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
648 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
649 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
650 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
651 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
652 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
653 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
654 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
658 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
659 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
662 Set Postscript render geometry.
664 (void) FormatMagickString(geometry,MaxTextExtent,
665 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
666 bounds.x1,bounds.y1);
667 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
668 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
669 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
673 (void) CloseBlob(image);
674 if (image_info->colorspace == RGBColorspace)
677 Create Ghostscript control file.
679 file=AcquireUniqueFileResource(postscript_filename);
682 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
683 image_info->filename);
684 image=DestroyImageList(image);
685 return((Image *) NULL);
687 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
688 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
689 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
690 count=write(file,command,(unsigned int) strlen(command));
691 if (image_info->page == (char *) NULL)
694 translate_geometry[MaxTextExtent];
696 (void) FormatMagickString(translate_geometry,MaxTextExtent,
697 "%g %g translate\n",-bounds.x1,-bounds.y1);
698 count=write(file,translate_geometry,(unsigned int)
699 strlen(translate_geometry));
703 Render Postscript with the Ghostscript delegate.
705 if (image_info->monochrome != MagickFalse)
706 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
708 if (cmyk != MagickFalse)
709 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
712 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
714 delegate_info=GetDelegateInfo("ps:color",(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) FormatMagickString(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(page.width*image->x_resolution/delta.x+0.5);
737 page.height=(size_t) floor(page.height*image->y_resolution/delta.y+
739 (void) FormatMagickString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
740 page.width,(double) page.height);
741 read_info=CloneImageInfo(image_info);
742 *read_info->magick='\0';
743 if (read_info->number_scenes != 0)
746 pages[MaxTextExtent];
748 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%.20g "
749 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
750 (read_info->scene+read_info->number_scenes));
751 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
752 read_info->number_scenes=0;
753 if (read_info->scenes != (char *) NULL)
754 *read_info->scenes='\0';
756 option=GetImageOption(image_info,"ps:use-cropbox");
757 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
758 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
759 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
760 (void) AcquireUniqueFilename(read_info->filename);
761 (void) FormatMagickString(command,MaxTextExtent,
762 GetDelegateCommands(delegate_info),
763 read_info->antialias != MagickFalse ? 4 : 1,
764 read_info->antialias != MagickFalse ? 4 : 1,density,options,
765 read_info->filename,postscript_filename,input_filename);
766 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
767 if ((status == MagickFalse) ||
768 (IsPostscriptRendered(read_info->filename) == MagickFalse))
770 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
771 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
773 postscript_image=(Image *) NULL;
774 if (status != MagickFalse)
775 postscript_image=ReadImage(read_info,exception);
776 (void) RelinquishUniqueFileResource(postscript_filename);
777 (void) RelinquishUniqueFileResource(read_info->filename);
778 (void) RelinquishUniqueFileResource(input_filename);
779 read_info=DestroyImageInfo(read_info);
780 if (postscript_image == (Image *) NULL)
782 image=DestroyImageList(image);
783 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
784 image_info->filename);
785 return((Image *) NULL);
787 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
792 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
793 if (cmyk_image != (Image *) NULL)
795 postscript_image=DestroyImageList(postscript_image);
796 postscript_image=cmyk_image;
799 if (image_info->number_scenes != 0)
808 Add place holder images to meet the subimage specification requirement.
810 for (i=0; i < (ssize_t) image_info->scene; i++)
812 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
813 if (clone_image != (Image *) NULL)
814 PrependImageToList(&postscript_image,clone_image);
819 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
821 postscript_image->magick_columns=columns;
823 postscript_image->magick_rows=rows;
824 postscript_image->page=page;
825 (void) CloneImageProfiles(postscript_image,image);
826 (void) CloneImageProperties(postscript_image,image);
827 next=SyncNextImageInList(postscript_image);
828 if (next != (Image *) NULL)
829 postscript_image=next;
830 } while (next != (Image *) NULL);
831 image=DestroyImageList(image);
833 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
836 next=GetNextImageInList(next);
838 return(GetFirstImageInList(postscript_image));
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
846 % R e g i s t e r P S I m a g e %
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852 % RegisterPSImage() adds properties for the PS image format to
853 % the list of supported formats. The properties include the image format
854 % tag, a method to read and/or write the format, whether the format
855 % supports the saving of more than one frame to the same file or blob,
856 % whether the format supports native in-memory I/O, and a brief
857 % description of the format.
859 % The format of the RegisterPSImage method is:
861 % size_t RegisterPSImage(void)
864 ModuleExport size_t RegisterPSImage(void)
869 entry=SetMagickInfo("EPI");
870 entry->decoder=(DecodeImageHandler *) ReadPSImage;
871 entry->encoder=(EncodeImageHandler *) WritePSImage;
872 entry->magick=(IsImageFormatHandler *) IsPS;
873 entry->adjoin=MagickFalse;
874 entry->blob_support=MagickFalse;
875 entry->seekable_stream=MagickTrue;
876 entry->thread_support=EncoderThreadSupport;
877 entry->description=ConstantString(
878 "Encapsulated PostScript Interchange format");
879 entry->module=ConstantString("PS");
880 (void) RegisterMagickInfo(entry);
881 entry=SetMagickInfo("EPS");
882 entry->decoder=(DecodeImageHandler *) ReadPSImage;
883 entry->encoder=(EncodeImageHandler *) WritePSImage;
884 entry->magick=(IsImageFormatHandler *) IsPS;
885 entry->adjoin=MagickFalse;
886 entry->blob_support=MagickFalse;
887 entry->seekable_stream=MagickTrue;
888 entry->thread_support=EncoderThreadSupport;
889 entry->description=ConstantString("Encapsulated PostScript");
890 entry->module=ConstantString("PS");
891 (void) RegisterMagickInfo(entry);
892 entry=SetMagickInfo("EPSF");
893 entry->decoder=(DecodeImageHandler *) ReadPSImage;
894 entry->encoder=(EncodeImageHandler *) WritePSImage;
895 entry->magick=(IsImageFormatHandler *) IsPS;
896 entry->adjoin=MagickFalse;
897 entry->blob_support=MagickFalse;
898 entry->seekable_stream=MagickTrue;
899 entry->description=ConstantString("Encapsulated PostScript");
900 entry->module=ConstantString("PS");
901 (void) RegisterMagickInfo(entry);
902 entry=SetMagickInfo("EPSI");
903 entry->decoder=(DecodeImageHandler *) ReadPSImage;
904 entry->encoder=(EncodeImageHandler *) WritePSImage;
905 entry->magick=(IsImageFormatHandler *) IsPS;
906 entry->adjoin=MagickFalse;
907 entry->blob_support=MagickFalse;
908 entry->seekable_stream=MagickTrue;
909 entry->thread_support=EncoderThreadSupport;
910 entry->description=ConstantString(
911 "Encapsulated PostScript Interchange format");
912 entry->module=ConstantString("PS");
913 (void) RegisterMagickInfo(entry);
914 entry=SetMagickInfo("PS");
915 entry->decoder=(DecodeImageHandler *) ReadPSImage;
916 entry->encoder=(EncodeImageHandler *) WritePSImage;
917 entry->magick=(IsImageFormatHandler *) IsPS;
918 entry->module=ConstantString("PS");
919 entry->blob_support=MagickFalse;
920 entry->seekable_stream=MagickTrue;
921 entry->thread_support=EncoderThreadSupport;
922 entry->description=ConstantString("PostScript");
923 (void) RegisterMagickInfo(entry);
924 return(MagickImageCoderSignature);
928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932 % U n r e g i s t e r P S I m a g e %
936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
938 % UnregisterPSImage() removes format registrations made by the
939 % PS module from the list of supported formats.
941 % The format of the UnregisterPSImage method is:
943 % UnregisterPSImage(void)
946 ModuleExport void UnregisterPSImage(void)
948 (void) UnregisterMagickInfo("EPI");
949 (void) UnregisterMagickInfo("EPS");
950 (void) UnregisterMagickInfo("EPSF");
951 (void) UnregisterMagickInfo("EPSI");
952 (void) UnregisterMagickInfo("PS");
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960 % W r i t e P S I m a g e %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % WritePSImage translates an image to encapsulated Postscript
967 % Level I for printing. If the supplied geometry is null, the image is
968 % centered on the Postscript page. Otherwise, the image is positioned as
969 % specified by the geometry.
971 % The format of the WritePSImage method is:
973 % MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
975 % A description of each parameter follows:
977 % o image_info: the image info.
979 % o image: the image.
983 static inline size_t MagickMin(const size_t x,const size_t y)
990 static inline unsigned char *PopHexPixel(const char **hex_digits,
991 const size_t pixel,unsigned char *pixels)
996 hex=hex_digits[pixel];
997 *pixels++=(unsigned char) (*hex++);
998 *pixels++=(unsigned char) (*hex);
1002 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
1004 #define WriteRunlengthPacket(image,pixel,length,p) \
1006 if ((image->matte != MagickFalse) && \
1007 (p->opacity == (Quantum) TransparentOpacity)) \
1009 q=PopHexPixel(hex_digits,0xff,q); \
1010 q=PopHexPixel(hex_digits,0xff,q); \
1011 q=PopHexPixel(hex_digits,0xff,q); \
1015 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1016 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1017 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1019 q=PopHexPixel(hex_digits,(const size_t) MagickMin(length,0xff),q); \
1025 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1026 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1027 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1028 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1029 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1030 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1031 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1032 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1033 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1034 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1035 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1036 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1037 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1038 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1039 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1040 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1041 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1042 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1043 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1044 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1045 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1046 "FC", "FD", "FE", "FF", (char *) NULL
1048 *PostscriptProlog[]=
1052 "% Display a color image. The image is displayed in color on",
1053 "% Postscript viewers or printers that support color, otherwise",
1054 "% it is displayed as grayscale.",
1056 "/DirectClassPacket",
1059 " % Get a DirectClass packet.",
1065 " % length: number of pixels minus one of this color (optional).",
1067 " currentfile color_packet readhexstring pop pop",
1068 " compression 0 eq",
1070 " /number_pixels 3 def",
1073 " currentfile byte readhexstring pop 0 get",
1074 " /number_pixels exch 1 add 3 mul def",
1076 " 0 3 number_pixels 1 sub",
1078 " pixels exch color_packet putinterval",
1080 " pixels 0 number_pixels getinterval",
1083 "/DirectClassImage",
1086 " % Display a DirectClass image.",
1088 " systemdict /colorimage known",
1095 " { DirectClassPacket } false 3 colorimage",
1099 " % No colorimage operator; convert to grayscale.",
1106 " { GrayDirectClassPacket } image",
1110 "/GrayDirectClassPacket",
1113 " % Get a DirectClass packet; convert to grayscale.",
1119 " % length: number of pixels minus one of this color (optional).",
1121 " currentfile color_packet readhexstring pop pop",
1122 " color_packet 0 get 0.299 mul",
1123 " color_packet 1 get 0.587 mul add",
1124 " color_packet 2 get 0.114 mul add",
1126 " /gray_packet exch def",
1127 " compression 0 eq",
1129 " /number_pixels 1 def",
1132 " currentfile byte readhexstring pop 0 get",
1133 " /number_pixels exch 1 add def",
1135 " 0 1 number_pixels 1 sub",
1137 " pixels exch gray_packet put",
1139 " pixels 0 number_pixels getinterval",
1142 "/GrayPseudoClassPacket",
1145 " % Get a PseudoClass packet; convert to grayscale.",
1148 " % index: index into the colormap.",
1149 " % length: number of pixels minus one of this color (optional).",
1151 " currentfile byte readhexstring pop 0 get",
1152 " /offset exch 3 mul def",
1153 " /color_packet colormap offset 3 getinterval def",
1154 " color_packet 0 get 0.299 mul",
1155 " color_packet 1 get 0.587 mul add",
1156 " color_packet 2 get 0.114 mul add",
1158 " /gray_packet exch def",
1159 " compression 0 eq",
1161 " /number_pixels 1 def",
1164 " currentfile byte readhexstring pop 0 get",
1165 " /number_pixels exch 1 add def",
1167 " 0 1 number_pixels 1 sub",
1169 " pixels exch gray_packet put",
1171 " pixels 0 number_pixels getinterval",
1174 "/PseudoClassPacket",
1177 " % Get a PseudoClass packet.",
1180 " % index: index into the colormap.",
1181 " % length: number of pixels minus one of this color (optional).",
1183 " currentfile byte readhexstring pop 0 get",
1184 " /offset exch 3 mul def",
1185 " /color_packet colormap offset 3 getinterval def",
1186 " compression 0 eq",
1188 " /number_pixels 3 def",
1191 " currentfile byte readhexstring pop 0 get",
1192 " /number_pixels exch 1 add 3 mul def",
1194 " 0 3 number_pixels 1 sub",
1196 " pixels exch color_packet putinterval",
1198 " pixels 0 number_pixels getinterval",
1201 "/PseudoClassImage",
1204 " % Display a PseudoClass image.",
1207 " % class: 0-PseudoClass or 1-Grayscale.",
1209 " currentfile buffer readline pop",
1210 " token pop /class exch def pop",
1213 " currentfile buffer readline pop",
1214 " token pop /depth exch def pop",
1215 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1216 " columns rows depth",
1221 " { currentfile grays readhexstring pop } image",
1226 " % colors: number of colors in the colormap.",
1227 " % colormap: red, green, blue color packets.",
1229 " currentfile buffer readline pop",
1230 " token pop /colors exch def pop",
1231 " /colors colors 3 mul def",
1232 " /colormap colors string def",
1233 " currentfile colormap readhexstring pop pop",
1234 " systemdict /colorimage known",
1241 " { PseudoClassPacket } false 3 colorimage",
1245 " % No colorimage operator; convert to grayscale.",
1252 " { GrayPseudoClassPacket } image",
1260 " % Display a DirectClass or PseudoClass image.",
1263 " % x & y translation.",
1265 " % label pointsize.",
1267 " % image columns & rows.",
1268 " % class: 0-DirectClass or 1-PseudoClass.",
1269 " % compression: 0-none or 1-RunlengthEncoded.",
1270 " % hex color packets.",
1273 " /buffer 512 string def",
1274 " /byte 1 string def",
1275 " /color_packet 3 string def",
1276 " /pixels 768 string def",
1278 " currentfile buffer readline pop",
1279 " token pop /x exch def",
1280 " token pop /y exch def pop",
1282 " currentfile buffer readline pop",
1283 " token pop /x exch def",
1284 " token pop /y exch def pop",
1285 " currentfile buffer readline pop",
1286 " token pop /pointsize exch def pop",
1287 " /Times-Roman findfont pointsize scalefont setfont",
1290 *PostscriptEpilog[]=
1293 " currentfile buffer readline pop",
1294 " token pop /columns exch def",
1295 " token pop /rows exch def pop",
1296 " currentfile buffer readline pop",
1297 " token pop /class exch def pop",
1298 " currentfile buffer readline pop",
1299 " token pop /compression exch def pop",
1300 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1305 buffer[MaxTextExtent],
1306 date[MaxTextExtent],
1308 page_geometry[MaxTextExtent];
1352 register const IndexPacket
1355 register const PixelPacket
1362 register unsigned char
1384 Open output image file.
1386 assert(image_info != (const ImageInfo *) NULL);
1387 assert(image_info->signature == MagickSignature);
1388 assert(image != (Image *) NULL);
1389 assert(image->signature == MagickSignature);
1390 if (image->debug != MagickFalse)
1391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1392 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1393 if (status == MagickFalse)
1395 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1401 Scale relative to dots-per-inch.
1403 if ((image->colorspace != RGBColorspace) &&
1404 (image->colorspace != CMYKColorspace))
1405 (void) TransformImageColorspace(image,RGBColorspace);
1406 delta.x=DefaultResolution;
1407 delta.y=DefaultResolution;
1408 resolution.x=image->x_resolution;
1409 resolution.y=image->y_resolution;
1410 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1412 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1413 resolution.x=geometry_info.rho;
1414 resolution.y=geometry_info.sigma;
1415 if ((flags & SigmaValue) == 0)
1416 resolution.y=resolution.x;
1418 if (image_info->density != (char *) NULL)
1420 flags=ParseGeometry(image_info->density,&geometry_info);
1421 resolution.x=geometry_info.rho;
1422 resolution.y=geometry_info.sigma;
1423 if ((flags & SigmaValue) == 0)
1424 resolution.y=resolution.x;
1426 if (image->units == PixelsPerCentimeterResolution)
1428 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
1429 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
1431 SetGeometry(image,&geometry);
1432 (void) FormatMagickString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1433 (double) image->columns,(double) image->rows);
1434 if (image_info->page != (char *) NULL)
1435 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1437 if ((image->page.width != 0) && (image->page.height != 0))
1438 (void) FormatMagickString(page_geometry,MaxTextExtent,
1439 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1440 image->page.height,(double) image->page.x,(double) image->page.y);
1442 if ((image->gravity != UndefinedGravity) &&
1443 (LocaleCompare(image_info->magick,"PS") == 0))
1444 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1445 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1446 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1447 &geometry.width,&geometry.height);
1448 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1449 geometry.width=(size_t) floor(scale.x+0.5);
1450 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1451 geometry.height=(size_t) floor(scale.y+0.5);
1452 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1453 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1455 if (image->gravity != UndefinedGravity)
1457 geometry.x=(-page_info.x);
1458 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1461 if (image_info->pointsize != 0.0)
1462 pointsize=image_info->pointsize;
1464 value=GetImageProperty(image,"label");
1465 if (value != (const char *) NULL)
1466 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1470 Output Postscript header.
1472 if (LocaleCompare(image_info->magick,"PS") == 0)
1473 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1475 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1477 (void) WriteBlobString(image,buffer);
1478 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1479 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1481 (void) WriteBlobString(image,buffer);
1482 timer=time((time_t *) NULL);
1483 (void) FormatMagickTime(timer,MaxTextExtent,date);
1484 (void) FormatMagickString(buffer,MaxTextExtent,
1485 "%%%%CreationDate: (%s)\n",date);
1486 (void) WriteBlobString(image,buffer);
1487 bounds.x1=(double) geometry.x;
1488 bounds.y1=(double) geometry.y;
1489 bounds.x2=(double) geometry.x+scale.x;
1490 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1491 if ((image_info->adjoin != MagickFalse) &&
1492 (GetNextImageInList(image) != (Image *) NULL))
1493 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1497 (void) FormatMagickString(buffer,MaxTextExtent,
1498 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1499 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1500 (void) WriteBlobString(image,buffer);
1501 (void) FormatMagickString(buffer,MaxTextExtent,
1502 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1503 bounds.y1,bounds.x2,bounds.y2);
1505 (void) WriteBlobString(image,buffer);
1506 profile=GetImageProfile(image,"8bim");
1507 if (profile != (StringInfo *) NULL)
1510 Embed Photoshop profile.
1512 (void) FormatMagickString(buffer,MaxTextExtent,
1513 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1514 (void) WriteBlobString(image,buffer);
1515 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1518 (void) WriteBlobString(image,"\n% ");
1519 (void) FormatMagickString(buffer,MaxTextExtent,"%02X",
1520 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1521 (void) WriteBlobString(image,buffer);
1523 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1525 profile=GetImageProfile(image,"xmp");
1526 if (0 && (profile != (StringInfo *) NULL))
1531 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1532 (void) FormatMagickString(buffer,MaxTextExtent,
1533 "\n%%begin_xml_packet: %.20g\n",(double)
1534 GetStringInfoLength(profile));
1535 (void) WriteBlobString(image,buffer);
1536 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1537 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1538 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1540 value=GetImageProperty(image,"label");
1541 if (value != (const char *) NULL)
1542 (void) WriteBlobString(image,
1543 "%%DocumentNeededResources: font Times-Roman\n");
1544 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1545 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1546 if (LocaleCompare(image_info->magick,"PS") != 0)
1547 (void) WriteBlobString(image,"%%Pages: 1\n");
1551 Compute the number of pages.
1553 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1554 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1555 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1556 image_info->adjoin != MagickFalse ? (double)
1557 GetImageListLength(image) : 1.0);
1558 (void) WriteBlobString(image,buffer);
1560 (void) WriteBlobString(image,"%%EndComments\n");
1561 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1562 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1563 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1564 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1565 (LocaleCompare(image_info->magick,"EPT") == 0))
1580 Create preview image.
1582 preview_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1583 if (preview_image == (Image *) NULL)
1584 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1586 Dump image as bitmap.
1588 (void) FormatMagickString(buffer,MaxTextExtent,
1589 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1590 preview_image->columns,(double) preview_image->rows,1.0,
1591 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1593 (void) WriteBlobString(image,buffer);
1595 for (y=0; y < (ssize_t) image->rows; y++)
1597 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1598 &preview_image->exception);
1599 if (p == (const PixelPacket *) NULL)
1601 indexes=GetVirtualIndexQueue(preview_image);
1604 for (x=0; x < (ssize_t) preview_image->columns; x++)
1607 pixel=PixelIntensityToQuantum(p);
1608 if (pixel >= (Quantum) (QuantumRange/2))
1613 q=PopHexPixel(hex_digits,byte,q);
1614 if ((q-pixels+8) >= 80)
1617 (void) WriteBlob(image,q-pixels,pixels);
1619 (void) WriteBlobString(image,"% ");
1628 q=PopHexPixel(hex_digits,byte,q);
1629 if ((q-pixels+8) >= 80)
1632 (void) WriteBlob(image,q-pixels,pixels);
1634 (void) WriteBlobString(image,"% ");
1641 (void) WriteBlob(image,q-pixels,pixels);
1643 (void) WriteBlobString(image,"\n%%EndPreview\n");
1644 preview_image=DestroyImage(preview_image);
1647 Output Postscript commands.
1649 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1651 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1652 (void) WriteBlobString(image,buffer);
1654 value=GetImageProperty(image,"label");
1655 if (value != (const char *) NULL)
1656 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1658 (void) WriteBlobString(image," /label 512 string def\n");
1659 (void) WriteBlobString(image," currentfile label readline pop\n");
1660 (void) FormatMagickString(buffer,MaxTextExtent,
1661 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1662 (void) WriteBlobString(image,buffer);
1664 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1666 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1667 (void) WriteBlobString(image,buffer);
1669 if (LocaleCompare(image_info->magick,"PS") == 0)
1670 (void) WriteBlobString(image," showpage\n");
1671 (void) WriteBlobString(image,"} bind def\n");
1672 (void) WriteBlobString(image,"%%EndProlog\n");
1674 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1676 (void) WriteBlobString(image,buffer);
1677 (void) FormatMagickString(buffer,MaxTextExtent,
1678 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1679 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1680 (geometry.height+text_size));
1681 (void) WriteBlobString(image,buffer);
1682 if ((double) geometry.x < bounds.x1)
1683 bounds.x1=(double) geometry.x;
1684 if ((double) geometry.y < bounds.y1)
1685 bounds.y1=(double) geometry.y;
1686 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1687 bounds.x2=(double) geometry.x+geometry.width-1;
1688 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1689 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1690 value=GetImageProperty(image,"label");
1691 if (value != (const char *) NULL)
1692 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1693 if (LocaleCompare(image_info->magick,"PS") != 0)
1694 (void) WriteBlobString(image,"userdict begin\n");
1695 (void) WriteBlobString(image,"DisplayImage\n");
1699 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1700 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1701 (void) WriteBlobString(image,buffer);
1702 labels=(char **) NULL;
1703 value=GetImageProperty(image,"label");
1704 if (value != (const char *) NULL)
1705 labels=StringToList(value);
1706 if (labels != (char **) NULL)
1708 for (i=0; labels[i] != (char *) NULL; i++)
1710 (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
1712 (void) WriteBlobString(image,buffer);
1713 labels[i]=DestroyString(labels[i]);
1715 labels=(char **) RelinquishMagickMemory(labels);
1717 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1718 pixel.opacity=(Quantum) TransparentOpacity;
1719 index=(IndexPacket) 0;
1721 if ((image_info->type != TrueColorType) &&
1722 (IsGrayImage(image,&image->exception) != MagickFalse))
1724 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
1730 Dump image as grayscale.
1732 (void) FormatMagickString(buffer,MaxTextExtent,
1733 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1735 (void) WriteBlobString(image,buffer);
1737 for (y=0; y < (ssize_t) image->rows; y++)
1739 p=GetVirtualPixels(image,0,y,image->columns,1,
1741 if (p == (const PixelPacket *) NULL)
1743 for (x=0; x < (ssize_t) image->columns; x++)
1745 pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1746 q=PopHexPixel(hex_digits,pixel,q);
1748 if ((q-pixels+8) >= 80)
1751 (void) WriteBlob(image,q-pixels,pixels);
1756 if (image->previous == (Image *) NULL)
1758 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1760 if (status == MagickFalse)
1767 (void) WriteBlob(image,q-pixels,pixels);
1779 Dump image as bitmap.
1781 (void) FormatMagickString(buffer,MaxTextExtent,
1782 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1784 (void) WriteBlobString(image,buffer);
1786 for (y=0; y < (ssize_t) image->rows; y++)
1788 p=GetVirtualPixels(image,0,y,image->columns,1,
1790 if (p == (const PixelPacket *) NULL)
1792 indexes=GetVirtualIndexQueue(image);
1795 for (x=0; x < (ssize_t) image->columns; x++)
1798 pixel=PixelIntensityToQuantum(p);
1799 if (pixel >= (Quantum) (QuantumRange/2))
1804 q=PopHexPixel(hex_digits,byte,q);
1805 if ((q-pixels+2) >= 80)
1808 (void) WriteBlob(image,q-pixels,pixels);
1819 q=PopHexPixel(hex_digits,byte,q);
1820 if ((q-pixels+2) >= 80)
1823 (void) WriteBlob(image,q-pixels,pixels);
1827 if (image->previous == (Image *) NULL)
1829 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1831 if (status == MagickFalse)
1838 (void) WriteBlob(image,q-pixels,pixels);
1843 if ((image->storage_class == DirectClass) ||
1844 (image->colors > 256) || (image->matte != MagickFalse))
1847 Dump DirectClass image.
1849 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1850 (double) image->columns,(double) image->rows,
1851 image_info->compression == RLECompression ? 1 : 0);
1852 (void) WriteBlobString(image,buffer);
1853 switch (image_info->compression)
1855 case RLECompression:
1858 Dump runlength-encoded DirectColor packets.
1861 for (y=0; y < (ssize_t) image->rows; y++)
1863 p=GetVirtualPixels(image,0,y,image->columns,1,
1865 if (p == (const PixelPacket *) NULL)
1869 for (x=0; x < (ssize_t) image->columns; x++)
1871 if ((p->red == pixel.red) && (p->green == pixel.green) &&
1872 (p->blue == pixel.blue) &&
1873 (p->opacity == pixel.opacity) && (length < 255) &&
1874 (x < (ssize_t) (image->columns-1)))
1880 WriteRunlengthPacket(image,pixel,length,p);
1881 if ((q-pixels+10) >= 80)
1884 (void) WriteBlob(image,q-pixels,pixels);
1893 WriteRunlengthPacket(image,pixel,length,p);
1894 if ((q-pixels+10) >= 80)
1897 (void) WriteBlob(image,q-pixels,pixels);
1900 if (image->previous == (Image *) NULL)
1902 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1904 if (status == MagickFalse)
1911 (void) WriteBlob(image,q-pixels,pixels);
1919 Dump uncompressed DirectColor packets.
1922 for (y=0; y < (ssize_t) image->rows; y++)
1924 p=GetVirtualPixels(image,0,y,image->columns,1,
1926 if (p == (const PixelPacket *) NULL)
1928 for (x=0; x < (ssize_t) image->columns; x++)
1930 if ((image->matte != MagickFalse) &&
1931 (p->opacity == (Quantum) TransparentOpacity))
1933 q=PopHexPixel(hex_digits,0xff,q);
1934 q=PopHexPixel(hex_digits,0xff,q);
1935 q=PopHexPixel(hex_digits,0xff,q);
1939 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetRedPixelComponent(p)),q);
1940 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetGreenPixelComponent(p)),q);
1941 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetBluePixelComponent(p)),q);
1943 if ((q-pixels+6) >= 80)
1946 (void) WriteBlob(image,q-pixels,pixels);
1951 if (image->previous == (Image *) NULL)
1953 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1955 if (status == MagickFalse)
1962 (void) WriteBlob(image,q-pixels,pixels);
1967 (void) WriteBlobByte(image,'\n');
1972 Dump PseudoClass image.
1974 (void) FormatMagickString(buffer,MaxTextExtent,
1975 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1976 image->rows,image->storage_class == PseudoClass ? 1 : 0,
1977 image_info->compression == RLECompression ? 1 : 0);
1978 (void) WriteBlobString(image,buffer);
1980 Dump number of colors and colormap.
1982 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double)
1984 (void) WriteBlobString(image,buffer);
1985 for (i=0; i < (ssize_t) image->colors; i++)
1987 (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1988 ScaleQuantumToChar(image->colormap[i].red),
1989 ScaleQuantumToChar(image->colormap[i].green),
1990 ScaleQuantumToChar(image->colormap[i].blue));
1991 (void) WriteBlobString(image,buffer);
1993 switch (image_info->compression)
1995 case RLECompression:
1998 Dump runlength-encoded PseudoColor packets.
2001 for (y=0; y < (ssize_t) image->rows; y++)
2003 p=GetVirtualPixels(image,0,y,image->columns,1,
2005 if (p == (const PixelPacket *) NULL)
2007 indexes=GetVirtualIndexQueue(image);
2010 for (x=0; x < (ssize_t) image->columns; x++)
2012 if ((index == indexes[x]) && (length < 255) &&
2013 (x < ((ssize_t) image->columns-1)))
2019 q=PopHexPixel(hex_digits,index,q);
2020 q=PopHexPixel(hex_digits,(size_t)
2021 MagickMin(length,0xff),q);
2023 if ((q-pixels+6) >= 80)
2026 (void) WriteBlob(image,q-pixels,pixels);
2036 q=PopHexPixel(hex_digits,index,q);
2037 q=PopHexPixel(hex_digits,(size_t)
2038 MagickMin(length,0xff),q);
2039 if (image->previous == (Image *) NULL)
2041 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2043 if (status == MagickFalse)
2050 (void) WriteBlob(image,q-pixels,pixels);
2058 Dump uncompressed PseudoColor packets.
2061 for (y=0; y < (ssize_t) image->rows; y++)
2063 p=GetVirtualPixels(image,0,y,image->columns,1,
2065 if (p == (const PixelPacket *) NULL)
2067 indexes=GetVirtualIndexQueue(image);
2068 for (x=0; x < (ssize_t) image->columns; x++)
2070 q=PopHexPixel(hex_digits,indexes[x],q);
2071 if ((q-pixels+4) >= 80)
2074 (void) WriteBlob(image,q-pixels,pixels);
2079 if (image->previous == (Image *) NULL)
2081 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2083 if (status == MagickFalse)
2090 (void) WriteBlob(image,q-pixels,pixels);
2095 (void) WriteBlobByte(image,'\n');
2097 if (LocaleCompare(image_info->magick,"PS") != 0)
2098 (void) WriteBlobString(image,"end\n");
2099 (void) WriteBlobString(image,"%%PageTrailer\n");
2100 if (GetNextImageInList(image) == (Image *) NULL)
2102 image=SyncNextImageInList(image);
2103 status=SetImageProgress(image,SaveImagesTag,scene++,
2104 GetImageListLength(image));
2105 if (status == MagickFalse)
2107 } while (image_info->adjoin != MagickFalse);
2108 (void) WriteBlobString(image,"%%Trailer\n");
2111 (void) FormatMagickString(buffer,MaxTextExtent,
2112 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2113 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
2114 (void) WriteBlobString(image,buffer);
2115 (void) FormatMagickString(buffer,MaxTextExtent,
2116 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2117 bounds.x2,bounds.y2);
2118 (void) WriteBlobString(image,buffer);
2120 (void) WriteBlobString(image,"%%EOF\n");
2121 (void) CloseBlob(image);