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],
345 translate_geometry[MaxTextExtent];
416 assert(image_info != (const ImageInfo *) NULL);
417 assert(image_info->signature == MagickSignature);
418 if (image_info->debug != MagickFalse)
419 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
420 image_info->filename);
421 assert(exception != (ExceptionInfo *) NULL);
422 assert(exception->signature == MagickSignature);
423 image=AcquireImage(image_info);
424 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
425 if (status == MagickFalse)
427 image=DestroyImageList(image);
428 return((Image *) NULL);
430 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
431 if (status == MagickFalse)
433 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
434 image_info->filename);
435 image=DestroyImageList(image);
436 return((Image *) NULL);
439 Initialize hex values.
441 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
442 hex_digits[(int) '0']=0;
443 hex_digits[(int) '1']=1;
444 hex_digits[(int) '2']=2;
445 hex_digits[(int) '3']=3;
446 hex_digits[(int) '4']=4;
447 hex_digits[(int) '5']=5;
448 hex_digits[(int) '6']=6;
449 hex_digits[(int) '7']=7;
450 hex_digits[(int) '8']=8;
451 hex_digits[(int) '9']=9;
452 hex_digits[(int) 'a']=10;
453 hex_digits[(int) 'b']=11;
454 hex_digits[(int) 'c']=12;
455 hex_digits[(int) 'd']=13;
456 hex_digits[(int) 'e']=14;
457 hex_digits[(int) 'f']=15;
458 hex_digits[(int) 'A']=10;
459 hex_digits[(int) 'B']=11;
460 hex_digits[(int) 'C']=12;
461 hex_digits[(int) 'D']=13;
462 hex_digits[(int) 'E']=14;
463 hex_digits[(int) 'F']=15;
465 Set the page density.
467 delta.x=DefaultResolution;
468 delta.y=DefaultResolution;
469 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
471 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
472 image->x_resolution=geometry_info.rho;
473 image->y_resolution=geometry_info.sigma;
474 if ((flags & SigmaValue) == 0)
475 image->y_resolution=image->x_resolution;
478 Determine page geometry from the Postscript bounding box.
480 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
481 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
482 (void) ResetMagickMemory(&page,0,sizeof(page));
483 (void) ResetMagickMemory(command,0,sizeof(command));
492 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
495 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
498 Note document structuring comments.
501 if ((strchr("\n\r%",c) == (char *) NULL) &&
502 ((size_t) (p-command) < (MaxTextExtent-1)))
507 Skip %%BeginDocument thru %%EndDocument.
509 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
511 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
513 if (skip != MagickFalse)
515 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
517 (void) SetImageProperty(image,"ps:Level",command+4);
518 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
521 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
522 (void) sscanf(command,LanguageLevel " %lu",&language_level);
523 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
524 (void) sscanf(command,Pages " %lu",&pages);
525 if (LocaleNCompare(ImageData,command,strlen(Pages)) == 0)
526 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
527 if (LocaleNCompare(ICCProfile,command,strlen(PhotoshopProfile)) == 0)
535 profile=AcquireStringInfo(65536);
536 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
538 SetStringInfoLength(profile,(size_t) i+1);
539 datum=GetStringInfoDatum(profile);
540 datum[i]=(unsigned char) c;
542 (void) SetImageProfile(image,"icc",profile);
543 profile=DestroyStringInfo(profile);
546 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
552 Read Photoshop profile.
554 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
558 profile=AcquireStringInfo(length);
559 p=GetStringInfoDatum(profile);
560 for (i=0; i < (ssize_t) length; i++)
561 *p++=(unsigned char) ProfileInteger(image,hex_digits);
562 (void) SetImageProfile(image,"8bim",profile);
563 profile=DestroyStringInfo(profile);
566 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
575 profile=StringToStringInfo(command);
576 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
578 SetStringInfoLength(profile,i+1);
579 c=ReadBlobByte(image);
580 GetStringInfoDatum(profile)[i]=(unsigned char) c;
582 if ((strchr("\n\r%",c) == (char *) NULL) &&
583 ((size_t) (p-command) < (MaxTextExtent-1)))
587 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
590 SetStringInfoLength(profile,i);
591 (void) SetImageProfile(image,"xmp",profile);
592 profile=DestroyStringInfo(profile);
596 Is this a CMYK document?
598 length=strlen(DocumentProcessColors);
599 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
601 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
602 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
603 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
606 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
608 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
610 length=strlen(DocumentCustomColors);
611 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
612 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
613 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
616 property[MaxTextExtent],
625 (void) FormatMagickString(property,MaxTextExtent,"ps:SpotColor-%.20g",
626 (double) (spotcolor++));
627 for (p=command; *p != '\0'; p++)
628 if (isspace((int) (unsigned char) *p) != 0)
630 value=AcquireString(p);
631 (void) SubstituteString(&value,"(","");
632 (void) SubstituteString(&value,")","");
633 (void) StripString(value);
634 (void) SetImageProperty(image,property,value);
635 value=DestroyString(value);
639 Note region defined by bounding box.
642 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
643 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
644 &bounds.y1,&bounds.x2,&bounds.y2);
645 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
646 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
648 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
649 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
650 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
651 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
652 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
653 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
654 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
655 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
659 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
660 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
663 Set Postscript render geometry.
665 (void) FormatMagickString(geometry,MaxTextExtent,
666 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
667 bounds.x1,bounds.y1);
668 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
669 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
670 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
674 (void) CloseBlob(image);
675 if (image_info->colorspace == RGBColorspace)
678 Create Ghostscript control file.
680 file=AcquireUniqueFileResource(postscript_filename);
683 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
684 image_info->filename);
685 image=DestroyImageList(image);
686 return((Image *) NULL);
688 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
689 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
690 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
691 count=write(file,command,(unsigned int) strlen(command));
692 (void) FormatMagickString(translate_geometry,MaxTextExtent,
693 "%g %g translate\n",-bounds.x1,-bounds.y1);
694 count=write(file,translate_geometry,(unsigned int)
695 strlen(translate_geometry));
698 Render Postscript with the Ghostscript delegate.
700 if (image_info->monochrome != MagickFalse)
701 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
703 if (cmyk != MagickFalse)
704 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
707 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
709 delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception);
710 if (delegate_info == (const DelegateInfo *) NULL)
712 (void) RelinquishUniqueFileResource(postscript_filename);
713 image=DestroyImageList(image);
714 return((Image *) NULL);
717 if ((page.width == 0) || (page.height == 0))
718 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
719 if (image_info->density != (char *) NULL)
721 flags=ParseGeometry(image_info->density,&geometry_info);
722 image->x_resolution=geometry_info.rho;
723 image->y_resolution=geometry_info.sigma;
724 if ((flags & SigmaValue) == 0)
725 image->y_resolution=image->x_resolution;
727 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",
728 image->x_resolution,image->y_resolution);
729 if (image_info->page != (char *) NULL)
730 (void) ParseAbsoluteGeometry(image_info->page,&page);
731 page.width=(size_t) floor(page.width*image->x_resolution/delta.x+0.5);
732 page.height=(size_t) floor(page.height*image->y_resolution/delta.y+
734 (void) FormatMagickString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
735 page.width,(double) page.height);
736 read_info=CloneImageInfo(image_info);
737 *read_info->magick='\0';
738 if (read_info->number_scenes != 0)
741 pages[MaxTextExtent];
743 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%.20g "
744 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
745 (read_info->scene+read_info->number_scenes));
746 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
747 read_info->number_scenes=0;
748 if (read_info->scenes != (char *) NULL)
749 *read_info->scenes='\0';
751 option=GetImageOption(image_info,"ps:use-cropbox");
752 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
753 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
754 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
755 (void) AcquireUniqueFilename(read_info->filename);
756 (void) FormatMagickString(command,MaxTextExtent,
757 GetDelegateCommands(delegate_info),
758 read_info->antialias != MagickFalse ? 4 : 1,
759 read_info->antialias != MagickFalse ? 4 : 1,density,options,
760 read_info->filename,postscript_filename,input_filename);
761 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
762 if ((status == MagickFalse) ||
763 (IsPostscriptRendered(read_info->filename) == MagickFalse))
765 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
766 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
768 postscript_image=(Image *) NULL;
769 if (status != MagickFalse)
770 postscript_image=ReadImage(read_info,exception);
771 (void) RelinquishUniqueFileResource(postscript_filename);
772 (void) RelinquishUniqueFileResource(read_info->filename);
773 (void) RelinquishUniqueFileResource(input_filename);
774 read_info=DestroyImageInfo(read_info);
775 if (postscript_image == (Image *) NULL)
777 image=DestroyImageList(image);
778 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
779 image_info->filename);
780 return((Image *) NULL);
782 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
787 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
788 if (cmyk_image != (Image *) NULL)
790 postscript_image=DestroyImageList(postscript_image);
791 postscript_image=cmyk_image;
794 if (image_info->number_scenes != 0)
803 Add place holder images to meet the subimage specification requirement.
805 for (i=0; i < (ssize_t) image_info->scene; i++)
807 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
808 if (clone_image != (Image *) NULL)
809 PrependImageToList(&postscript_image,clone_image);
814 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
816 postscript_image->magick_columns=columns;
818 postscript_image->magick_rows=rows;
819 postscript_image->page=page;
820 (void) CloneImageProfiles(postscript_image,image);
821 (void) CloneImageProperties(postscript_image,image);
822 next=SyncNextImageInList(postscript_image);
823 if (next != (Image *) NULL)
824 postscript_image=next;
825 } while (next != (Image *) NULL);
826 image=DestroyImageList(image);
828 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
831 next=GetNextImageInList(next);
833 return(GetFirstImageInList(postscript_image));
837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
841 % R e g i s t e r P S I m a g e %
845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847 % RegisterPSImage() adds properties for the PS image format to
848 % the list of supported formats. The properties include the image format
849 % tag, a method to read and/or write the format, whether the format
850 % supports the saving of more than one frame to the same file or blob,
851 % whether the format supports native in-memory I/O, and a brief
852 % description of the format.
854 % The format of the RegisterPSImage method is:
856 % size_t RegisterPSImage(void)
859 ModuleExport size_t RegisterPSImage(void)
864 entry=SetMagickInfo("EPI");
865 entry->decoder=(DecodeImageHandler *) ReadPSImage;
866 entry->encoder=(EncodeImageHandler *) WritePSImage;
867 entry->magick=(IsImageFormatHandler *) IsPS;
868 entry->adjoin=MagickFalse;
869 entry->blob_support=MagickFalse;
870 entry->seekable_stream=MagickTrue;
871 entry->thread_support=EncoderThreadSupport;
872 entry->description=ConstantString(
873 "Encapsulated PostScript Interchange format");
874 entry->module=ConstantString("PS");
875 (void) RegisterMagickInfo(entry);
876 entry=SetMagickInfo("EPS");
877 entry->decoder=(DecodeImageHandler *) ReadPSImage;
878 entry->encoder=(EncodeImageHandler *) WritePSImage;
879 entry->magick=(IsImageFormatHandler *) IsPS;
880 entry->adjoin=MagickFalse;
881 entry->blob_support=MagickFalse;
882 entry->seekable_stream=MagickTrue;
883 entry->thread_support=EncoderThreadSupport;
884 entry->description=ConstantString("Encapsulated PostScript");
885 entry->module=ConstantString("PS");
886 (void) RegisterMagickInfo(entry);
887 entry=SetMagickInfo("EPSF");
888 entry->decoder=(DecodeImageHandler *) ReadPSImage;
889 entry->encoder=(EncodeImageHandler *) WritePSImage;
890 entry->magick=(IsImageFormatHandler *) IsPS;
891 entry->adjoin=MagickFalse;
892 entry->blob_support=MagickFalse;
893 entry->seekable_stream=MagickTrue;
894 entry->description=ConstantString("Encapsulated PostScript");
895 entry->module=ConstantString("PS");
896 (void) RegisterMagickInfo(entry);
897 entry=SetMagickInfo("EPSI");
898 entry->decoder=(DecodeImageHandler *) ReadPSImage;
899 entry->encoder=(EncodeImageHandler *) WritePSImage;
900 entry->magick=(IsImageFormatHandler *) IsPS;
901 entry->adjoin=MagickFalse;
902 entry->blob_support=MagickFalse;
903 entry->seekable_stream=MagickTrue;
904 entry->thread_support=EncoderThreadSupport;
905 entry->description=ConstantString(
906 "Encapsulated PostScript Interchange format");
907 entry->module=ConstantString("PS");
908 (void) RegisterMagickInfo(entry);
909 entry=SetMagickInfo("PS");
910 entry->decoder=(DecodeImageHandler *) ReadPSImage;
911 entry->encoder=(EncodeImageHandler *) WritePSImage;
912 entry->magick=(IsImageFormatHandler *) IsPS;
913 entry->module=ConstantString("PS");
914 entry->blob_support=MagickFalse;
915 entry->seekable_stream=MagickTrue;
916 entry->thread_support=EncoderThreadSupport;
917 entry->description=ConstantString("PostScript");
918 (void) RegisterMagickInfo(entry);
919 return(MagickImageCoderSignature);
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927 % U n r e g i s t e r P S I m a g e %
931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933 % UnregisterPSImage() removes format registrations made by the
934 % PS module from the list of supported formats.
936 % The format of the UnregisterPSImage method is:
938 % UnregisterPSImage(void)
941 ModuleExport void UnregisterPSImage(void)
943 (void) UnregisterMagickInfo("EPI");
944 (void) UnregisterMagickInfo("EPS");
945 (void) UnregisterMagickInfo("EPSF");
946 (void) UnregisterMagickInfo("EPSI");
947 (void) UnregisterMagickInfo("PS");
951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955 % W r i t e P S I m a g e %
959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 % WritePSImage translates an image to encapsulated Postscript
962 % Level I for printing. If the supplied geometry is null, the image is
963 % centered on the Postscript page. Otherwise, the image is positioned as
964 % specified by the geometry.
966 % The format of the WritePSImage method is:
968 % MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
970 % A description of each parameter follows:
972 % o image_info: the image info.
974 % o image: the image.
978 static inline size_t MagickMin(const size_t x,const size_t y)
985 static inline unsigned char *PopHexPixel(const char **hex_digits,
986 const size_t pixel,unsigned char *pixels)
991 hex=hex_digits[pixel];
992 *pixels++=(unsigned char) (*hex++);
993 *pixels++=(unsigned char) (*hex);
997 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
999 #define WriteRunlengthPacket(image,pixel,length,p) \
1001 if ((image->matte != MagickFalse) && \
1002 (p->opacity == (Quantum) TransparentOpacity)) \
1004 q=PopHexPixel(hex_digits,0xff,q); \
1005 q=PopHexPixel(hex_digits,0xff,q); \
1006 q=PopHexPixel(hex_digits,0xff,q); \
1010 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1011 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1012 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1014 q=PopHexPixel(hex_digits,(const size_t) MagickMin(length,0xff),q); \
1020 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1021 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1022 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1023 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1024 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1025 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1026 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1027 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1028 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1029 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1030 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1031 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1032 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1033 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1034 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1035 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1036 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1037 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1038 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1039 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1040 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1041 "FC", "FD", "FE", "FF", (char *) NULL
1043 *PostscriptProlog[]=
1047 "% Display a color image. The image is displayed in color on",
1048 "% Postscript viewers or printers that support color, otherwise",
1049 "% it is displayed as grayscale.",
1051 "/DirectClassPacket",
1054 " % Get a DirectClass packet.",
1060 " % length: number of pixels minus one of this color (optional).",
1062 " currentfile color_packet readhexstring pop pop",
1063 " compression 0 eq",
1065 " /number_pixels 3 def",
1068 " currentfile byte readhexstring pop 0 get",
1069 " /number_pixels exch 1 add 3 mul def",
1071 " 0 3 number_pixels 1 sub",
1073 " pixels exch color_packet putinterval",
1075 " pixels 0 number_pixels getinterval",
1078 "/DirectClassImage",
1081 " % Display a DirectClass image.",
1083 " systemdict /colorimage known",
1090 " { DirectClassPacket } false 3 colorimage",
1094 " % No colorimage operator; convert to grayscale.",
1101 " { GrayDirectClassPacket } image",
1105 "/GrayDirectClassPacket",
1108 " % Get a DirectClass packet; convert to grayscale.",
1114 " % length: number of pixels minus one of this color (optional).",
1116 " currentfile color_packet readhexstring pop pop",
1117 " color_packet 0 get 0.299 mul",
1118 " color_packet 1 get 0.587 mul add",
1119 " color_packet 2 get 0.114 mul add",
1121 " /gray_packet exch def",
1122 " compression 0 eq",
1124 " /number_pixels 1 def",
1127 " currentfile byte readhexstring pop 0 get",
1128 " /number_pixels exch 1 add def",
1130 " 0 1 number_pixels 1 sub",
1132 " pixels exch gray_packet put",
1134 " pixels 0 number_pixels getinterval",
1137 "/GrayPseudoClassPacket",
1140 " % Get a PseudoClass packet; convert to grayscale.",
1143 " % index: index into the colormap.",
1144 " % length: number of pixels minus one of this color (optional).",
1146 " currentfile byte readhexstring pop 0 get",
1147 " /offset exch 3 mul def",
1148 " /color_packet colormap offset 3 getinterval def",
1149 " color_packet 0 get 0.299 mul",
1150 " color_packet 1 get 0.587 mul add",
1151 " color_packet 2 get 0.114 mul add",
1153 " /gray_packet exch def",
1154 " compression 0 eq",
1156 " /number_pixels 1 def",
1159 " currentfile byte readhexstring pop 0 get",
1160 " /number_pixels exch 1 add def",
1162 " 0 1 number_pixels 1 sub",
1164 " pixels exch gray_packet put",
1166 " pixels 0 number_pixels getinterval",
1169 "/PseudoClassPacket",
1172 " % Get a PseudoClass packet.",
1175 " % index: index into the colormap.",
1176 " % length: number of pixels minus one of this color (optional).",
1178 " currentfile byte readhexstring pop 0 get",
1179 " /offset exch 3 mul def",
1180 " /color_packet colormap offset 3 getinterval def",
1181 " compression 0 eq",
1183 " /number_pixels 3 def",
1186 " currentfile byte readhexstring pop 0 get",
1187 " /number_pixels exch 1 add 3 mul def",
1189 " 0 3 number_pixels 1 sub",
1191 " pixels exch color_packet putinterval",
1193 " pixels 0 number_pixels getinterval",
1196 "/PseudoClassImage",
1199 " % Display a PseudoClass image.",
1202 " % class: 0-PseudoClass or 1-Grayscale.",
1204 " currentfile buffer readline pop",
1205 " token pop /class exch def pop",
1208 " currentfile buffer readline pop",
1209 " token pop /depth exch def pop",
1210 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1211 " columns rows depth",
1216 " { currentfile grays readhexstring pop } image",
1221 " % colors: number of colors in the colormap.",
1222 " % colormap: red, green, blue color packets.",
1224 " currentfile buffer readline pop",
1225 " token pop /colors exch def pop",
1226 " /colors colors 3 mul def",
1227 " /colormap colors string def",
1228 " currentfile colormap readhexstring pop pop",
1229 " systemdict /colorimage known",
1236 " { PseudoClassPacket } false 3 colorimage",
1240 " % No colorimage operator; convert to grayscale.",
1247 " { GrayPseudoClassPacket } image",
1255 " % Display a DirectClass or PseudoClass image.",
1258 " % x & y translation.",
1260 " % label pointsize.",
1262 " % image columns & rows.",
1263 " % class: 0-DirectClass or 1-PseudoClass.",
1264 " % compression: 0-none or 1-RunlengthEncoded.",
1265 " % hex color packets.",
1268 " /buffer 512 string def",
1269 " /byte 1 string def",
1270 " /color_packet 3 string def",
1271 " /pixels 768 string def",
1273 " currentfile buffer readline pop",
1274 " token pop /x exch def",
1275 " token pop /y exch def pop",
1277 " currentfile buffer readline pop",
1278 " token pop /x exch def",
1279 " token pop /y exch def pop",
1280 " currentfile buffer readline pop",
1281 " token pop /pointsize exch def pop",
1282 " /Times-Roman findfont pointsize scalefont setfont",
1285 *PostscriptEpilog[]=
1288 " currentfile buffer readline pop",
1289 " token pop /columns exch def",
1290 " token pop /rows exch def pop",
1291 " currentfile buffer readline pop",
1292 " token pop /class exch def pop",
1293 " currentfile buffer readline pop",
1294 " token pop /compression exch def pop",
1295 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1300 buffer[MaxTextExtent],
1301 date[MaxTextExtent],
1303 page_geometry[MaxTextExtent];
1347 register const IndexPacket
1350 register const PixelPacket
1357 register unsigned char
1379 Open output image file.
1381 assert(image_info != (const ImageInfo *) NULL);
1382 assert(image_info->signature == MagickSignature);
1383 assert(image != (Image *) NULL);
1384 assert(image->signature == MagickSignature);
1385 if (image->debug != MagickFalse)
1386 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1387 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1388 if (status == MagickFalse)
1390 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1396 Scale relative to dots-per-inch.
1398 if ((image->colorspace != RGBColorspace) &&
1399 (image->colorspace != CMYKColorspace))
1400 (void) TransformImageColorspace(image,RGBColorspace);
1401 delta.x=DefaultResolution;
1402 delta.y=DefaultResolution;
1403 resolution.x=image->x_resolution;
1404 resolution.y=image->y_resolution;
1405 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1407 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1408 resolution.x=geometry_info.rho;
1409 resolution.y=geometry_info.sigma;
1410 if ((flags & SigmaValue) == 0)
1411 resolution.y=resolution.x;
1413 if (image_info->density != (char *) NULL)
1415 flags=ParseGeometry(image_info->density,&geometry_info);
1416 resolution.x=geometry_info.rho;
1417 resolution.y=geometry_info.sigma;
1418 if ((flags & SigmaValue) == 0)
1419 resolution.y=resolution.x;
1421 if (image->units == PixelsPerCentimeterResolution)
1423 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
1424 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
1426 SetGeometry(image,&geometry);
1427 (void) FormatMagickString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1428 (double) image->columns,(double) image->rows);
1429 if (image_info->page != (char *) NULL)
1430 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1432 if ((image->page.width != 0) && (image->page.height != 0))
1433 (void) FormatMagickString(page_geometry,MaxTextExtent,
1434 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1435 image->page.height,(double) image->page.x,(double) image->page.y);
1437 if ((image->gravity != UndefinedGravity) &&
1438 (LocaleCompare(image_info->magick,"PS") == 0))
1439 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1440 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1441 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1442 &geometry.width,&geometry.height);
1443 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1444 geometry.width=(size_t) floor(scale.x+0.5);
1445 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1446 geometry.height=(size_t) floor(scale.y+0.5);
1447 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1448 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1450 if (image->gravity != UndefinedGravity)
1452 geometry.x=(-page_info.x);
1453 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1456 if (image_info->pointsize != 0.0)
1457 pointsize=image_info->pointsize;
1459 value=GetImageProperty(image,"label");
1460 if (value != (const char *) NULL)
1461 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1465 Output Postscript header.
1467 if (LocaleCompare(image_info->magick,"PS") == 0)
1468 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1470 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1472 (void) WriteBlobString(image,buffer);
1473 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1474 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1476 (void) WriteBlobString(image,buffer);
1477 timer=time((time_t *) NULL);
1478 (void) FormatMagickTime(timer,MaxTextExtent,date);
1479 (void) FormatMagickString(buffer,MaxTextExtent,
1480 "%%%%CreationDate: (%s)\n",date);
1481 (void) WriteBlobString(image,buffer);
1482 bounds.x1=(double) geometry.x;
1483 bounds.y1=(double) geometry.y;
1484 bounds.x2=(double) geometry.x+scale.x;
1485 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1486 if ((image_info->adjoin != MagickFalse) &&
1487 (GetNextImageInList(image) != (Image *) NULL))
1488 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1492 (void) FormatMagickString(buffer,MaxTextExtent,
1493 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1494 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1495 (void) WriteBlobString(image,buffer);
1496 (void) FormatMagickString(buffer,MaxTextExtent,
1497 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1498 bounds.y1,bounds.x2,bounds.y2);
1500 (void) WriteBlobString(image,buffer);
1501 profile=GetImageProfile(image,"8bim");
1502 if (profile != (StringInfo *) NULL)
1505 Embed Photoshop profile.
1507 (void) FormatMagickString(buffer,MaxTextExtent,
1508 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1509 (void) WriteBlobString(image,buffer);
1510 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1513 (void) WriteBlobString(image,"\n% ");
1514 (void) FormatMagickString(buffer,MaxTextExtent,"%02X",
1515 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1516 (void) WriteBlobString(image,buffer);
1518 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1520 profile=GetImageProfile(image,"xmp");
1521 if (0 && (profile != (StringInfo *) NULL))
1526 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1527 (void) FormatMagickString(buffer,MaxTextExtent,
1528 "\n%%begin_xml_packet: %.20g\n",(double)
1529 GetStringInfoLength(profile));
1530 (void) WriteBlobString(image,buffer);
1531 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1532 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1533 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1535 value=GetImageProperty(image,"label");
1536 if (value != (const char *) NULL)
1537 (void) WriteBlobString(image,
1538 "%%DocumentNeededResources: font Times-Roman\n");
1539 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1540 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1541 if (LocaleCompare(image_info->magick,"PS") != 0)
1542 (void) WriteBlobString(image,"%%Pages: 1\n");
1546 Compute the number of pages.
1548 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1549 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1550 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1551 image_info->adjoin != MagickFalse ? (double)
1552 GetImageListLength(image) : 1.0);
1553 (void) WriteBlobString(image,buffer);
1555 (void) WriteBlobString(image,"%%EndComments\n");
1556 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1557 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1558 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1559 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1560 (LocaleCompare(image_info->magick,"EPT") == 0))
1575 Create preview image.
1577 preview_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1578 if (preview_image == (Image *) NULL)
1579 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1581 Dump image as bitmap.
1583 (void) FormatMagickString(buffer,MaxTextExtent,
1584 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1585 preview_image->columns,(double) preview_image->rows,1.0,
1586 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1588 (void) WriteBlobString(image,buffer);
1590 for (y=0; y < (ssize_t) image->rows; y++)
1592 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1593 &preview_image->exception);
1594 if (p == (const PixelPacket *) NULL)
1596 indexes=GetVirtualIndexQueue(preview_image);
1599 for (x=0; x < (ssize_t) preview_image->columns; x++)
1602 pixel=PixelIntensityToQuantum(p);
1603 if (pixel >= (Quantum) (QuantumRange/2))
1608 q=PopHexPixel(hex_digits,byte,q);
1609 if ((q-pixels+8) >= 80)
1612 (void) WriteBlob(image,q-pixels,pixels);
1614 (void) WriteBlobString(image,"% ");
1623 q=PopHexPixel(hex_digits,byte,q);
1624 if ((q-pixels+8) >= 80)
1627 (void) WriteBlob(image,q-pixels,pixels);
1629 (void) WriteBlobString(image,"% ");
1636 (void) WriteBlob(image,q-pixels,pixels);
1638 (void) WriteBlobString(image,"\n%%EndPreview\n");
1639 preview_image=DestroyImage(preview_image);
1642 Output Postscript commands.
1644 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1646 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1647 (void) WriteBlobString(image,buffer);
1649 value=GetImageProperty(image,"label");
1650 if (value != (const char *) NULL)
1651 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1653 (void) WriteBlobString(image," /label 512 string def\n");
1654 (void) WriteBlobString(image," currentfile label readline pop\n");
1655 (void) FormatMagickString(buffer,MaxTextExtent,
1656 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1657 (void) WriteBlobString(image,buffer);
1659 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1661 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1662 (void) WriteBlobString(image,buffer);
1664 if (LocaleCompare(image_info->magick,"PS") == 0)
1665 (void) WriteBlobString(image," showpage\n");
1666 (void) WriteBlobString(image,"} bind def\n");
1667 (void) WriteBlobString(image,"%%EndProlog\n");
1669 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1671 (void) WriteBlobString(image,buffer);
1672 (void) FormatMagickString(buffer,MaxTextExtent,
1673 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1674 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1675 (geometry.height+text_size));
1676 (void) WriteBlobString(image,buffer);
1677 if ((double) geometry.x < bounds.x1)
1678 bounds.x1=(double) geometry.x;
1679 if ((double) geometry.y < bounds.y1)
1680 bounds.y1=(double) geometry.y;
1681 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1682 bounds.x2=(double) geometry.x+geometry.width-1;
1683 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1684 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1685 value=GetImageProperty(image,"label");
1686 if (value != (const char *) NULL)
1687 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1688 if (LocaleCompare(image_info->magick,"PS") != 0)
1689 (void) WriteBlobString(image,"userdict begin\n");
1690 (void) WriteBlobString(image,"DisplayImage\n");
1694 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1695 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1696 (void) WriteBlobString(image,buffer);
1697 labels=(char **) NULL;
1698 value=GetImageProperty(image,"label");
1699 if (value != (const char *) NULL)
1700 labels=StringToList(value);
1701 if (labels != (char **) NULL)
1703 for (i=0; labels[i] != (char *) NULL; i++)
1705 (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
1707 (void) WriteBlobString(image,buffer);
1708 labels[i]=DestroyString(labels[i]);
1710 labels=(char **) RelinquishMagickMemory(labels);
1712 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1713 pixel.opacity=(Quantum) TransparentOpacity;
1714 index=(IndexPacket) 0;
1716 if ((image_info->type != TrueColorType) &&
1717 (IsGrayImage(image,&image->exception) != MagickFalse))
1719 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
1725 Dump image as grayscale.
1727 (void) FormatMagickString(buffer,MaxTextExtent,
1728 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1730 (void) WriteBlobString(image,buffer);
1732 for (y=0; y < (ssize_t) image->rows; y++)
1734 p=GetVirtualPixels(image,0,y,image->columns,1,
1736 if (p == (const PixelPacket *) NULL)
1738 for (x=0; x < (ssize_t) image->columns; x++)
1740 pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1741 q=PopHexPixel(hex_digits,pixel,q);
1743 if ((q-pixels+8) >= 80)
1746 (void) WriteBlob(image,q-pixels,pixels);
1751 if (image->previous == (Image *) NULL)
1753 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1755 if (status == MagickFalse)
1762 (void) WriteBlob(image,q-pixels,pixels);
1774 Dump image as bitmap.
1776 (void) FormatMagickString(buffer,MaxTextExtent,
1777 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1779 (void) WriteBlobString(image,buffer);
1781 for (y=0; y < (ssize_t) image->rows; y++)
1783 p=GetVirtualPixels(image,0,y,image->columns,1,
1785 if (p == (const PixelPacket *) NULL)
1787 indexes=GetVirtualIndexQueue(image);
1790 for (x=0; x < (ssize_t) image->columns; x++)
1793 pixel=PixelIntensityToQuantum(p);
1794 if (pixel >= (Quantum) (QuantumRange/2))
1799 q=PopHexPixel(hex_digits,byte,q);
1800 if ((q-pixels+2) >= 80)
1803 (void) WriteBlob(image,q-pixels,pixels);
1814 q=PopHexPixel(hex_digits,byte,q);
1815 if ((q-pixels+2) >= 80)
1818 (void) WriteBlob(image,q-pixels,pixels);
1822 if (image->previous == (Image *) NULL)
1824 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1826 if (status == MagickFalse)
1833 (void) WriteBlob(image,q-pixels,pixels);
1838 if ((image->storage_class == DirectClass) ||
1839 (image->colors > 256) || (image->matte != MagickFalse))
1842 Dump DirectClass image.
1844 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1845 (double) image->columns,(double) image->rows,
1846 image_info->compression == RLECompression ? 1 : 0);
1847 (void) WriteBlobString(image,buffer);
1848 switch (image_info->compression)
1850 case RLECompression:
1853 Dump runlength-encoded DirectColor packets.
1856 for (y=0; y < (ssize_t) image->rows; y++)
1858 p=GetVirtualPixels(image,0,y,image->columns,1,
1860 if (p == (const PixelPacket *) NULL)
1864 for (x=0; x < (ssize_t) image->columns; x++)
1866 if ((p->red == pixel.red) && (p->green == pixel.green) &&
1867 (p->blue == pixel.blue) &&
1868 (p->opacity == pixel.opacity) && (length < 255) &&
1869 (x < (ssize_t) (image->columns-1)))
1875 WriteRunlengthPacket(image,pixel,length,p);
1876 if ((q-pixels+10) >= 80)
1879 (void) WriteBlob(image,q-pixels,pixels);
1888 WriteRunlengthPacket(image,pixel,length,p);
1889 if ((q-pixels+10) >= 80)
1892 (void) WriteBlob(image,q-pixels,pixels);
1895 if (image->previous == (Image *) NULL)
1897 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1899 if (status == MagickFalse)
1906 (void) WriteBlob(image,q-pixels,pixels);
1914 Dump uncompressed DirectColor packets.
1917 for (y=0; y < (ssize_t) image->rows; y++)
1919 p=GetVirtualPixels(image,0,y,image->columns,1,
1921 if (p == (const PixelPacket *) NULL)
1923 for (x=0; x < (ssize_t) image->columns; x++)
1925 if ((image->matte != MagickFalse) &&
1926 (p->opacity == (Quantum) TransparentOpacity))
1928 q=PopHexPixel(hex_digits,0xff,q);
1929 q=PopHexPixel(hex_digits,0xff,q);
1930 q=PopHexPixel(hex_digits,0xff,q);
1934 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetRedPixelComponent(p)),q);
1935 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetGreenPixelComponent(p)),q);
1936 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetBluePixelComponent(p)),q);
1938 if ((q-pixels+6) >= 80)
1941 (void) WriteBlob(image,q-pixels,pixels);
1946 if (image->previous == (Image *) NULL)
1948 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1950 if (status == MagickFalse)
1957 (void) WriteBlob(image,q-pixels,pixels);
1962 (void) WriteBlobByte(image,'\n');
1967 Dump PseudoClass image.
1969 (void) FormatMagickString(buffer,MaxTextExtent,
1970 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1971 image->rows,image->storage_class == PseudoClass ? 1 : 0,
1972 image_info->compression == RLECompression ? 1 : 0);
1973 (void) WriteBlobString(image,buffer);
1975 Dump number of colors and colormap.
1977 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double)
1979 (void) WriteBlobString(image,buffer);
1980 for (i=0; i < (ssize_t) image->colors; i++)
1982 (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1983 ScaleQuantumToChar(image->colormap[i].red),
1984 ScaleQuantumToChar(image->colormap[i].green),
1985 ScaleQuantumToChar(image->colormap[i].blue));
1986 (void) WriteBlobString(image,buffer);
1988 switch (image_info->compression)
1990 case RLECompression:
1993 Dump runlength-encoded PseudoColor packets.
1996 for (y=0; y < (ssize_t) image->rows; y++)
1998 p=GetVirtualPixels(image,0,y,image->columns,1,
2000 if (p == (const PixelPacket *) NULL)
2002 indexes=GetVirtualIndexQueue(image);
2005 for (x=0; x < (ssize_t) image->columns; x++)
2007 if ((index == indexes[x]) && (length < 255) &&
2008 (x < ((ssize_t) image->columns-1)))
2014 q=PopHexPixel(hex_digits,index,q);
2015 q=PopHexPixel(hex_digits,(size_t)
2016 MagickMin(length,0xff),q);
2018 if ((q-pixels+6) >= 80)
2021 (void) WriteBlob(image,q-pixels,pixels);
2031 q=PopHexPixel(hex_digits,index,q);
2032 q=PopHexPixel(hex_digits,(size_t)
2033 MagickMin(length,0xff),q);
2034 if (image->previous == (Image *) NULL)
2036 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2038 if (status == MagickFalse)
2045 (void) WriteBlob(image,q-pixels,pixels);
2053 Dump uncompressed PseudoColor packets.
2056 for (y=0; y < (ssize_t) image->rows; y++)
2058 p=GetVirtualPixels(image,0,y,image->columns,1,
2060 if (p == (const PixelPacket *) NULL)
2062 indexes=GetVirtualIndexQueue(image);
2063 for (x=0; x < (ssize_t) image->columns; x++)
2065 q=PopHexPixel(hex_digits,indexes[x],q);
2066 if ((q-pixels+4) >= 80)
2069 (void) WriteBlob(image,q-pixels,pixels);
2074 if (image->previous == (Image *) NULL)
2076 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2078 if (status == MagickFalse)
2085 (void) WriteBlob(image,q-pixels,pixels);
2090 (void) WriteBlobByte(image,'\n');
2092 if (LocaleCompare(image_info->magick,"PS") != 0)
2093 (void) WriteBlobString(image,"end\n");
2094 (void) WriteBlobString(image,"%%PageTrailer\n");
2095 if (GetNextImageInList(image) == (Image *) NULL)
2097 image=SyncNextImageInList(image);
2098 status=SetImageProgress(image,SaveImagesTag,scene++,
2099 GetImageListLength(image));
2100 if (status == MagickFalse)
2102 } while (image_info->adjoin != MagickFalse);
2103 (void) WriteBlobString(image,"%%Trailer\n");
2106 (void) FormatMagickString(buffer,MaxTextExtent,
2107 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2108 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
2109 (void) WriteBlobString(image,buffer);
2110 (void) FormatMagickString(buffer,MaxTextExtent,
2111 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2112 bounds.x2,bounds.y2);
2113 (void) WriteBlobString(image,buffer);
2115 (void) WriteBlobString(image,"%%EOF\n");
2116 (void) CloseBlob(image);