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 < (long) argc; i++)
181 argv[i]=DestroyString(argv[i]);
182 argv=(char **) RelinquishMagickMemory(argv);
183 if ((status != 0) && (status != -101))
188 message=GetExceptionMessage(errno);
189 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
190 "`%s': %s",command,message);
191 message=DestroyString(message);
192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
193 "Ghostscript returns status %d, exit code %d",status,code);
198 status=SystemCommand(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) ((unsigned long) value << 4)+hex_digits[c];
313 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
315 #define BoundingBox "BoundingBox:"
316 #define BeginDocument "BeginDocument:"
317 #define BeginXMPPacket "<?xpacket begin="
318 #define EndXMPPacket "<?xpacket end="
319 #define ICCProfile "BeginICCProfile:"
320 #define CMYKCustomColor "CMYKCustomColor:"
321 #define CMYKProcessColor "CMYKProcessColor:"
322 #define DocumentMedia "DocumentMedia:"
323 #define DocumentCustomColors "DocumentCustomColors:"
324 #define DocumentProcessColors "DocumentProcessColors:"
325 #define EndDocument "EndDocument:"
326 #define ICCBased "ICCBased"
327 #define HiResBoundingBox "HiResBoundingBox:"
328 #define ImageData "ImageData:"
329 #define PageBoundingBox "PageBoundingBox:"
330 #define LanguageLevel "LanguageLevel:"
331 #define PageMedia "PageMedia:"
332 #define Pages "Pages:"
333 #define PhotoshopProfile "BeginPhotoshop:"
334 #define PostscriptLevel "!PS-"
335 #define RenderPostscriptText " Rendering Postscript... "
336 #define SpotColor "+ "
339 command[MaxTextExtent],
340 density[MaxTextExtent],
341 filename[MaxTextExtent],
342 geometry[MaxTextExtent],
343 input_filename[MaxTextExtent],
344 options[MaxTextExtent],
345 postscript_filename[MaxTextExtent],
346 translate_geometry[MaxTextExtent];
417 assert(image_info != (const ImageInfo *) NULL);
418 assert(image_info->signature == MagickSignature);
419 if (image_info->debug != MagickFalse)
420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
421 image_info->filename);
422 assert(exception != (ExceptionInfo *) NULL);
423 assert(exception->signature == MagickSignature);
424 image=AcquireImage(image_info);
425 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
426 if (status == MagickFalse)
428 image=DestroyImageList(image);
429 return((Image *) NULL);
431 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
432 if (status == MagickFalse)
434 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
435 image_info->filename);
436 image=DestroyImageList(image);
437 return((Image *) NULL);
440 Initialize hex values.
442 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
443 hex_digits[(int) '0']=0;
444 hex_digits[(int) '1']=1;
445 hex_digits[(int) '2']=2;
446 hex_digits[(int) '3']=3;
447 hex_digits[(int) '4']=4;
448 hex_digits[(int) '5']=5;
449 hex_digits[(int) '6']=6;
450 hex_digits[(int) '7']=7;
451 hex_digits[(int) '8']=8;
452 hex_digits[(int) '9']=9;
453 hex_digits[(int) 'a']=10;
454 hex_digits[(int) 'b']=11;
455 hex_digits[(int) 'c']=12;
456 hex_digits[(int) 'd']=13;
457 hex_digits[(int) 'e']=14;
458 hex_digits[(int) 'f']=15;
459 hex_digits[(int) 'A']=10;
460 hex_digits[(int) 'B']=11;
461 hex_digits[(int) 'C']=12;
462 hex_digits[(int) 'D']=13;
463 hex_digits[(int) 'E']=14;
464 hex_digits[(int) 'F']=15;
466 Set the page density.
468 delta.x=DefaultResolution;
469 delta.y=DefaultResolution;
470 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
472 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
473 image->x_resolution=geometry_info.rho;
474 image->y_resolution=geometry_info.sigma;
475 if ((flags & SigmaValue) == 0)
476 image->y_resolution=image->x_resolution;
479 Determine page geometry from the Postscript bounding box.
481 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
482 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
483 (void) ResetMagickMemory(&page,0,sizeof(page));
484 (void) ResetMagickMemory(command,0,sizeof(command));
493 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
496 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
499 Note document structuring comments.
502 if ((strchr("\n\r%",c) == (char *) NULL) &&
503 ((size_t) (p-command) < (MaxTextExtent-1)))
508 Skip %%BeginDocument thru %%EndDocument.
510 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
512 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
514 if (skip != MagickFalse)
516 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
518 (void) SetImageProperty(image,"ps:Level",command+4);
519 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
522 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
523 (void) sscanf(command,LanguageLevel " %lu",&language_level);
524 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
525 (void) sscanf(command,Pages " %lu",&pages);
526 if (LocaleNCompare(ImageData,command,strlen(Pages)) == 0)
527 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
528 if (LocaleNCompare(ICCProfile,command,strlen(PhotoshopProfile)) == 0)
536 profile=AcquireStringInfo(65536);
537 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
539 SetStringInfoLength(profile,(size_t) i+1);
540 datum=GetStringInfoDatum(profile);
541 datum[i]=(unsigned char) c;
543 (void) SetImageProfile(image,"icc",profile);
544 profile=DestroyStringInfo(profile);
547 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
553 Read Photoshop profile.
555 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
559 profile=AcquireStringInfo(length);
560 p=GetStringInfoDatum(profile);
561 for (i=0; i < (long) length; i++)
562 *p++=(unsigned char) ProfileInteger(image,hex_digits);
563 (void) SetImageProfile(image,"8bim",profile);
564 profile=DestroyStringInfo(profile);
567 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
576 profile=StringToStringInfo(command);
577 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
579 SetStringInfoLength(profile,i+1);
580 c=ReadBlobByte(image);
581 GetStringInfoDatum(profile)[i]=(unsigned char) c;
583 if ((strchr("\n\r%",c) == (char *) NULL) &&
584 ((size_t) (p-command) < (MaxTextExtent-1)))
588 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
591 SetStringInfoLength(profile,i);
592 (void) SetImageProfile(image,"xmp",profile);
593 profile=DestroyStringInfo(profile);
597 Is this a CMYK document?
599 length=strlen(DocumentProcessColors);
600 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
602 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
603 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
604 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
607 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
609 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
611 if (LocaleNCompare(ICCBased,command,strlen(ICCBased)) == 0)
613 length=strlen(DocumentCustomColors);
614 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
615 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
616 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
619 property[MaxTextExtent],
628 (void) FormatMagickString(property,MaxTextExtent,"ps:SpotColor-%lu",
630 for (p=command; *p != '\0'; p++)
631 if (isspace((int) (unsigned char) *p) != 0)
633 value=AcquireString(p);
634 (void) SubstituteString(&value,"(","");
635 (void) SubstituteString(&value,")","");
636 (void) StripString(value);
637 (void) SetImageProperty(image,property,value);
638 value=DestroyString(value);
642 Note region defined by bounding box.
645 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
646 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
647 &bounds.y1,&bounds.x2,&bounds.y2);
648 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
649 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
651 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
652 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
653 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
654 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
655 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
656 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
657 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
658 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
662 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
663 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
666 Set Postscript render geometry.
668 (void) FormatMagickString(geometry,MaxTextExtent,
669 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
670 bounds.x1,bounds.y1);
671 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
672 page.width=(unsigned long) floor(bounds.x2-bounds.x1+0.5);
673 page.height=(unsigned long) floor(bounds.y2-bounds.y1+0.5);
677 (void) CloseBlob(image);
678 if (image_info->colorspace == RGBColorspace)
681 Create Ghostscript control file.
683 file=AcquireUniqueFileResource(postscript_filename);
686 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
687 image_info->filename);
688 image=DestroyImageList(image);
689 return((Image *) NULL);
691 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
692 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
693 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
694 count=write(file,command,(unsigned int) strlen(command));
695 (void) FormatMagickString(translate_geometry,MaxTextExtent,
696 "%g %g translate\n",-bounds.x1,-bounds.y1);
697 count=write(file,translate_geometry,strlen(translate_geometry));
700 Render Postscript with the Ghostscript delegate.
702 if (image_info->monochrome != MagickFalse)
703 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
705 if (cmyk != MagickFalse)
706 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
709 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
711 delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception);
712 if (delegate_info == (const DelegateInfo *) NULL)
714 (void) RelinquishUniqueFileResource(postscript_filename);
715 image=DestroyImageList(image);
716 return((Image *) NULL);
719 if ((page.width == 0) || (page.height == 0))
720 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
721 if (image_info->density != (char *) NULL)
723 flags=ParseGeometry(image_info->density,&geometry_info);
724 image->x_resolution=geometry_info.rho;
725 image->y_resolution=geometry_info.sigma;
726 if ((flags & SigmaValue) == 0)
727 image->y_resolution=image->x_resolution;
729 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",
730 image->x_resolution,image->y_resolution);
731 if (image_info->page != (char *) NULL)
732 (void) ParseAbsoluteGeometry(image_info->page,&page);
733 page.width=(unsigned long) floor(page.width*image->x_resolution/delta.x+0.5);
734 page.height=(unsigned long) floor(page.height*image->y_resolution/delta.y+
736 (void) FormatMagickString(options,MaxTextExtent,"-g%lux%lu ",
737 page.width,page.height);
738 read_info=CloneImageInfo(image_info);
739 *read_info->magick='\0';
740 if (read_info->number_scenes != 0)
743 pages[MaxTextExtent];
745 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%lu "
746 "-dLastPage=%lu",read_info->scene+1,read_info->scene+
747 read_info->number_scenes);
748 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
749 read_info->number_scenes=0;
750 if (read_info->scenes != (char *) NULL)
751 *read_info->scenes='\0';
753 option=GetImageOption(image_info,"ps:use-cropbox");
754 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
755 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
756 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
757 (void) AcquireUniqueFilename(read_info->filename);
758 (void) FormatMagickString(command,MaxTextExtent,
759 GetDelegateCommands(delegate_info),
760 read_info->antialias != MagickFalse ? 4 : 1,
761 read_info->antialias != MagickFalse ? 4 : 1,density,options,
762 read_info->filename,postscript_filename,input_filename);
763 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
764 if ((status == MagickFalse) ||
765 (IsPostscriptRendered(read_info->filename) == MagickFalse))
767 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
768 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
770 postscript_image=(Image *) NULL;
771 if (status != MagickFalse)
772 postscript_image=ReadImage(read_info,exception);
773 (void) RelinquishUniqueFileResource(postscript_filename);
774 (void) RelinquishUniqueFileResource(read_info->filename);
775 (void) RelinquishUniqueFileResource(input_filename);
776 read_info=DestroyImageInfo(read_info);
777 if (postscript_image == (Image *) NULL)
779 image=DestroyImageList(image);
780 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
781 image_info->filename);
782 return((Image *) NULL);
784 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
789 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
790 if (cmyk_image != (Image *) NULL)
792 postscript_image=DestroyImageList(postscript_image);
793 postscript_image=cmyk_image;
796 if (image_info->number_scenes != 0)
805 Add place holder images to meet the subimage specification requirement.
807 for (i=0; i < (long) image_info->scene; i++)
809 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
810 if (clone_image != (Image *) NULL)
811 PrependImageToList(&postscript_image,clone_image);
816 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
818 postscript_image->magick_columns=columns;
820 postscript_image->magick_rows=rows;
821 postscript_image->page=page;
822 (void) CloneImageProfiles(postscript_image,image);
823 (void) CloneImageProperties(postscript_image,image);
824 next=SyncNextImageInList(postscript_image);
825 if (next != (Image *) NULL)
826 postscript_image=next;
827 } while (next != (Image *) NULL);
828 image=DestroyImageList(image);
830 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
833 next=GetNextImageInList(next);
835 return(GetFirstImageInList(postscript_image));
839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 % R e g i s t e r P S I m a g e %
847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
849 % RegisterPSImage() adds properties for the PS image format to
850 % the list of supported formats. The properties include the image format
851 % tag, a method to read and/or write the format, whether the format
852 % supports the saving of more than one frame to the same file or blob,
853 % whether the format supports native in-memory I/O, and a brief
854 % description of the format.
856 % The format of the RegisterPSImage method is:
858 % unsigned long RegisterPSImage(void)
861 ModuleExport unsigned long RegisterPSImage(void)
866 entry=SetMagickInfo("EPI");
867 entry->decoder=(DecodeImageHandler *) ReadPSImage;
868 entry->encoder=(EncodeImageHandler *) WritePSImage;
869 entry->magick=(IsImageFormatHandler *) IsPS;
870 entry->adjoin=MagickFalse;
871 entry->blob_support=MagickFalse;
872 entry->seekable_stream=MagickTrue;
873 entry->thread_support=EncoderThreadSupport;
874 entry->description=ConstantString(
875 "Encapsulated PostScript Interchange format");
876 entry->module=ConstantString("PS");
877 (void) RegisterMagickInfo(entry);
878 entry=SetMagickInfo("EPS");
879 entry->decoder=(DecodeImageHandler *) ReadPSImage;
880 entry->encoder=(EncodeImageHandler *) WritePSImage;
881 entry->magick=(IsImageFormatHandler *) IsPS;
882 entry->adjoin=MagickFalse;
883 entry->blob_support=MagickFalse;
884 entry->seekable_stream=MagickTrue;
885 entry->thread_support=EncoderThreadSupport;
886 entry->description=ConstantString("Encapsulated PostScript");
887 entry->module=ConstantString("PS");
888 (void) RegisterMagickInfo(entry);
889 entry=SetMagickInfo("EPSF");
890 entry->decoder=(DecodeImageHandler *) ReadPSImage;
891 entry->encoder=(EncodeImageHandler *) WritePSImage;
892 entry->magick=(IsImageFormatHandler *) IsPS;
893 entry->adjoin=MagickFalse;
894 entry->blob_support=MagickFalse;
895 entry->seekable_stream=MagickTrue;
896 entry->description=ConstantString("Encapsulated PostScript");
897 entry->module=ConstantString("PS");
898 (void) RegisterMagickInfo(entry);
899 entry=SetMagickInfo("EPSI");
900 entry->decoder=(DecodeImageHandler *) ReadPSImage;
901 entry->encoder=(EncodeImageHandler *) WritePSImage;
902 entry->magick=(IsImageFormatHandler *) IsPS;
903 entry->adjoin=MagickFalse;
904 entry->blob_support=MagickFalse;
905 entry->seekable_stream=MagickTrue;
906 entry->thread_support=EncoderThreadSupport;
907 entry->description=ConstantString(
908 "Encapsulated PostScript Interchange format");
909 entry->module=ConstantString("PS");
910 (void) RegisterMagickInfo(entry);
911 entry=SetMagickInfo("PS");
912 entry->decoder=(DecodeImageHandler *) ReadPSImage;
913 entry->encoder=(EncodeImageHandler *) WritePSImage;
914 entry->magick=(IsImageFormatHandler *) IsPS;
915 entry->module=ConstantString("PS");
916 entry->blob_support=MagickFalse;
917 entry->seekable_stream=MagickTrue;
918 entry->thread_support=EncoderThreadSupport;
919 entry->description=ConstantString("PostScript");
920 (void) RegisterMagickInfo(entry);
921 return(MagickImageCoderSignature);
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % U n r e g i s t e r P S I m a g e %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 % UnregisterPSImage() removes format registrations made by the
936 % PS module from the list of supported formats.
938 % The format of the UnregisterPSImage method is:
940 % UnregisterPSImage(void)
943 ModuleExport void UnregisterPSImage(void)
945 (void) UnregisterMagickInfo("EPI");
946 (void) UnregisterMagickInfo("EPS");
947 (void) UnregisterMagickInfo("EPSF");
948 (void) UnregisterMagickInfo("EPSI");
949 (void) UnregisterMagickInfo("PS");
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % W r i t e P S I m a g e %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 % WritePSImage translates an image to encapsulated Postscript
964 % Level I for printing. If the supplied geometry is null, the image is
965 % centered on the Postscript page. Otherwise, the image is positioned as
966 % specified by the geometry.
968 % The format of the WritePSImage method is:
970 % MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
972 % A description of each parameter follows:
974 % o image_info: the image info.
976 % o image: the image.
980 static inline size_t MagickMin(const size_t x,const size_t y)
987 static inline unsigned char *PopHexPixel(const char **hex_digits,
988 const unsigned long pixel,unsigned char *pixels)
993 hex=hex_digits[pixel];
994 *pixels++=(unsigned char) (*hex++);
995 *pixels++=(unsigned char) (*hex);
999 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image)
1001 #define WriteRunlengthPacket(image,pixel,length,p) \
1003 if ((image->matte != MagickFalse) && \
1004 (p->opacity == (Quantum) TransparentOpacity)) \
1006 q=PopHexPixel(hex_digits,0xff,q); \
1007 q=PopHexPixel(hex_digits,0xff,q); \
1008 q=PopHexPixel(hex_digits,0xff,q); \
1012 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1013 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1014 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1016 q=PopHexPixel(hex_digits,(const unsigned long) MagickMin(length,0xff),q); \
1022 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1023 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1024 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1025 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1026 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1027 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1028 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1029 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1030 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1031 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1032 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1033 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1034 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1035 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1036 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1037 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1038 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1039 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1040 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1041 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1042 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1043 "FC", "FD", "FE", "FF", (char *) NULL
1045 *PostscriptProlog[]=
1049 "% Display a color image. The image is displayed in color on",
1050 "% Postscript viewers or printers that support color, otherwise",
1051 "% it is displayed as grayscale.",
1053 "/DirectClassPacket",
1056 " % Get a DirectClass packet.",
1062 " % length: number of pixels minus one of this color (optional).",
1064 " currentfile color_packet readhexstring pop pop",
1065 " compression 0 eq",
1067 " /number_pixels 3 def",
1070 " currentfile byte readhexstring pop 0 get",
1071 " /number_pixels exch 1 add 3 mul def",
1073 " 0 3 number_pixels 1 sub",
1075 " pixels exch color_packet putinterval",
1077 " pixels 0 number_pixels getinterval",
1080 "/DirectClassImage",
1083 " % Display a DirectClass image.",
1085 " systemdict /colorimage known",
1092 " { DirectClassPacket } false 3 colorimage",
1096 " % No colorimage operator; convert to grayscale.",
1103 " { GrayDirectClassPacket } image",
1107 "/GrayDirectClassPacket",
1110 " % Get a DirectClass packet; convert to grayscale.",
1116 " % length: number of pixels minus one of this color (optional).",
1118 " currentfile color_packet readhexstring pop pop",
1119 " color_packet 0 get 0.299 mul",
1120 " color_packet 1 get 0.587 mul add",
1121 " color_packet 2 get 0.114 mul add",
1123 " /gray_packet exch def",
1124 " compression 0 eq",
1126 " /number_pixels 1 def",
1129 " currentfile byte readhexstring pop 0 get",
1130 " /number_pixels exch 1 add def",
1132 " 0 1 number_pixels 1 sub",
1134 " pixels exch gray_packet put",
1136 " pixels 0 number_pixels getinterval",
1139 "/GrayPseudoClassPacket",
1142 " % Get a PseudoClass packet; convert to grayscale.",
1145 " % index: index into the colormap.",
1146 " % length: number of pixels minus one of this color (optional).",
1148 " currentfile byte readhexstring pop 0 get",
1149 " /offset exch 3 mul def",
1150 " /color_packet colormap offset 3 getinterval def",
1151 " color_packet 0 get 0.299 mul",
1152 " color_packet 1 get 0.587 mul add",
1153 " color_packet 2 get 0.114 mul add",
1155 " /gray_packet exch def",
1156 " compression 0 eq",
1158 " /number_pixels 1 def",
1161 " currentfile byte readhexstring pop 0 get",
1162 " /number_pixels exch 1 add def",
1164 " 0 1 number_pixels 1 sub",
1166 " pixels exch gray_packet put",
1168 " pixels 0 number_pixels getinterval",
1171 "/PseudoClassPacket",
1174 " % Get a PseudoClass packet.",
1177 " % index: index into the colormap.",
1178 " % length: number of pixels minus one of this color (optional).",
1180 " currentfile byte readhexstring pop 0 get",
1181 " /offset exch 3 mul def",
1182 " /color_packet colormap offset 3 getinterval def",
1183 " compression 0 eq",
1185 " /number_pixels 3 def",
1188 " currentfile byte readhexstring pop 0 get",
1189 " /number_pixels exch 1 add 3 mul def",
1191 " 0 3 number_pixels 1 sub",
1193 " pixels exch color_packet putinterval",
1195 " pixels 0 number_pixels getinterval",
1198 "/PseudoClassImage",
1201 " % Display a PseudoClass image.",
1204 " % class: 0-PseudoClass or 1-Grayscale.",
1206 " currentfile buffer readline pop",
1207 " token pop /class exch def pop",
1210 " currentfile buffer readline pop",
1211 " token pop /depth exch def pop",
1212 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1213 " columns rows depth",
1218 " { currentfile grays readhexstring pop } image",
1223 " % colors: number of colors in the colormap.",
1224 " % colormap: red, green, blue color packets.",
1226 " currentfile buffer readline pop",
1227 " token pop /colors exch def pop",
1228 " /colors colors 3 mul def",
1229 " /colormap colors string def",
1230 " currentfile colormap readhexstring pop pop",
1231 " systemdict /colorimage known",
1238 " { PseudoClassPacket } false 3 colorimage",
1242 " % No colorimage operator; convert to grayscale.",
1249 " { GrayPseudoClassPacket } image",
1257 " % Display a DirectClass or PseudoClass image.",
1260 " % x & y translation.",
1262 " % label pointsize.",
1264 " % image columns & rows.",
1265 " % class: 0-DirectClass or 1-PseudoClass.",
1266 " % compression: 0-none or 1-RunlengthEncoded.",
1267 " % hex color packets.",
1270 " /buffer 512 string def",
1271 " /byte 1 string def",
1272 " /color_packet 3 string def",
1273 " /pixels 768 string def",
1275 " currentfile buffer readline pop",
1276 " token pop /x exch def",
1277 " token pop /y exch def pop",
1279 " currentfile buffer readline pop",
1280 " token pop /x exch def",
1281 " token pop /y exch def pop",
1282 " currentfile buffer readline pop",
1283 " token pop /pointsize exch def pop",
1284 " /Times-Roman findfont pointsize scalefont setfont",
1287 *PostscriptEpilog[]=
1290 " currentfile buffer readline pop",
1291 " token pop /columns exch def",
1292 " token pop /rows exch def pop",
1293 " currentfile buffer readline pop",
1294 " token pop /class exch def pop",
1295 " currentfile buffer readline pop",
1296 " token pop /compression exch def pop",
1297 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1302 buffer[MaxTextExtent],
1303 date[MaxTextExtent],
1305 page_geometry[MaxTextExtent];
1349 register const IndexPacket
1352 register const PixelPacket
1359 register unsigned char
1381 Open output image file.
1383 assert(image_info != (const ImageInfo *) NULL);
1384 assert(image_info->signature == MagickSignature);
1385 assert(image != (Image *) NULL);
1386 assert(image->signature == MagickSignature);
1387 if (image->debug != MagickFalse)
1388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1389 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1390 if (status == MagickFalse)
1392 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1398 Scale relative to dots-per-inch.
1400 if ((image->colorspace != RGBColorspace) &&
1401 (image->colorspace != CMYKColorspace))
1402 (void) TransformImageColorspace(image,RGBColorspace);
1403 delta.x=DefaultResolution;
1404 delta.y=DefaultResolution;
1405 resolution.x=image->x_resolution;
1406 resolution.y=image->y_resolution;
1407 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1409 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1410 resolution.x=geometry_info.rho;
1411 resolution.y=geometry_info.sigma;
1412 if ((flags & SigmaValue) == 0)
1413 resolution.y=resolution.x;
1415 if (image_info->density != (char *) NULL)
1417 flags=ParseGeometry(image_info->density,&geometry_info);
1418 resolution.x=geometry_info.rho;
1419 resolution.y=geometry_info.sigma;
1420 if ((flags & SigmaValue) == 0)
1421 resolution.y=resolution.x;
1423 if (image->units == PixelsPerCentimeterResolution)
1428 SetGeometry(image,&geometry);
1429 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
1430 image->columns,image->rows);
1431 if (image_info->page != (char *) NULL)
1432 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1434 if ((image->page.width != 0) && (image->page.height != 0))
1435 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
1436 image->page.width,image->page.height,image->page.x,image->page.y);
1438 if ((image->gravity != UndefinedGravity) &&
1439 (LocaleCompare(image_info->magick,"PS") == 0))
1440 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1441 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1442 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1443 &geometry.width,&geometry.height);
1444 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1445 geometry.width=(unsigned long) floor(scale.x+0.5);
1446 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1447 geometry.height=(unsigned long) floor(scale.y+0.5);
1448 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1449 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1451 if (image->gravity != UndefinedGravity)
1453 geometry.x=(-page_info.x);
1454 geometry.y=(long) (media_info.height+page_info.y-image->rows);
1457 if (image_info->pointsize != 0.0)
1458 pointsize=image_info->pointsize;
1460 value=GetImageProperty(image,"label");
1461 if (value != (const char *) NULL)
1462 text_size=(unsigned long) (MultilineCensus(value)*pointsize+12);
1466 Output Postscript header.
1468 if (LocaleCompare(image_info->magick,"PS") == 0)
1469 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1471 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1473 (void) WriteBlobString(image,buffer);
1474 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1475 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1477 (void) WriteBlobString(image,buffer);
1478 timer=time((time_t *) NULL);
1479 (void) FormatMagickTime(timer,MaxTextExtent,date);
1480 (void) FormatMagickString(buffer,MaxTextExtent,
1481 "%%%%CreationDate: (%s)\n",date);
1482 (void) WriteBlobString(image,buffer);
1483 bounds.x1=(double) geometry.x;
1484 bounds.y1=(double) geometry.y;
1485 bounds.x2=(double) geometry.x+scale.x;
1486 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1487 if ((image_info->adjoin != MagickFalse) &&
1488 (GetNextImageInList(image) != (Image *) NULL))
1489 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1493 (void) FormatMagickString(buffer,MaxTextExtent,
1494 "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) ceil(bounds.x1-0.5),
1495 (long) ceil(bounds.y1-0.5),(long) floor(bounds.x2+0.5),
1496 (long) floor(bounds.y2+0.5));
1497 (void) WriteBlobString(image,buffer);
1498 (void) FormatMagickString(buffer,MaxTextExtent,
1499 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1500 bounds.y1,bounds.x2,bounds.y2);
1502 (void) WriteBlobString(image,buffer);
1503 profile=GetImageProfile(image,"8bim");
1504 if (profile != (StringInfo *) NULL)
1507 Embed Photoshop profile.
1509 (void) FormatMagickString(buffer,MaxTextExtent,
1510 "%%BeginPhotoshop: %lu",(unsigned long) GetStringInfoLength(
1512 (void) WriteBlobString(image,buffer);
1513 for (i=0; i < (long) GetStringInfoLength(profile); i++)
1516 (void) WriteBlobString(image,"\n% ");
1517 (void) FormatMagickString(buffer,MaxTextExtent,"%02X",
1518 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1519 (void) WriteBlobString(image,buffer);
1521 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1523 profile=GetImageProfile(image,"xmp");
1524 if (0 && (profile != (StringInfo *) NULL))
1529 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1530 (void) FormatMagickString(buffer,MaxTextExtent,
1531 "\n%%begin_xml_packet: %lu\n",(unsigned long)
1532 GetStringInfoLength(profile));
1533 (void) WriteBlobString(image,buffer);
1534 for (i=0; i < (long) GetStringInfoLength(profile); i++)
1535 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1536 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1538 value=GetImageProperty(image,"label");
1539 if (value != (const char *) NULL)
1540 (void) WriteBlobString(image,
1541 "%%DocumentNeededResources: font Times-Roman\n");
1542 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1543 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1544 if (LocaleCompare(image_info->magick,"PS") != 0)
1545 (void) WriteBlobString(image,"%%Pages: 1\n");
1549 Compute the number of pages.
1551 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1552 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1553 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %lu\n",
1554 image_info->adjoin != MagickFalse ? (unsigned long)
1555 GetImageListLength(image) : 1UL);
1556 (void) WriteBlobString(image,buffer);
1558 (void) WriteBlobString(image,"%%EndComments\n");
1559 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1560 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1561 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1562 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1563 (LocaleCompare(image_info->magick,"EPT") == 0))
1578 Create preview image.
1580 preview_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1581 if (preview_image == (Image *) NULL)
1582 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1584 Dump image as bitmap.
1586 (void) FormatMagickString(buffer,MaxTextExtent,
1587 "%%%%BeginPreview: %lu %lu %lu %lu\n%% ",preview_image->columns,
1588 preview_image->rows,1L,(((preview_image->columns+7) >> 3)*
1589 preview_image->rows+35)/36);
1590 (void) WriteBlobString(image,buffer);
1592 for (y=0; y < (long) image->rows; y++)
1594 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1595 &preview_image->exception);
1596 if (p == (const PixelPacket *) NULL)
1598 indexes=GetVirtualIndexQueue(preview_image);
1601 for (x=0; x < (long) preview_image->columns; x++)
1604 pixel=PixelIntensityToQuantum(p);
1605 if (pixel >= (Quantum) (QuantumRange/2))
1610 q=PopHexPixel(hex_digits,byte,q);
1611 if ((q-pixels+8) >= 80)
1614 (void) WriteBlob(image,q-pixels,pixels);
1616 (void) WriteBlobString(image,"% ");
1625 q=PopHexPixel(hex_digits,byte,q);
1626 if ((q-pixels+8) >= 80)
1629 (void) WriteBlob(image,q-pixels,pixels);
1631 (void) WriteBlobString(image,"% ");
1638 (void) WriteBlob(image,q-pixels,pixels);
1640 (void) WriteBlobString(image,"\n%%EndPreview\n");
1641 preview_image=DestroyImage(preview_image);
1644 Output Postscript commands.
1646 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1648 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1649 (void) WriteBlobString(image,buffer);
1651 value=GetImageProperty(image,"label");
1652 if (value != (const char *) NULL)
1653 for (j=(long) MultilineCensus(value)-1; j >= 0; j--)
1655 (void) WriteBlobString(image," /label 512 string def\n");
1656 (void) WriteBlobString(image," currentfile label readline pop\n");
1657 (void) FormatMagickString(buffer,MaxTextExtent,
1658 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1659 (void) WriteBlobString(image,buffer);
1661 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1663 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*s);
1664 (void) WriteBlobString(image,buffer);
1666 if (LocaleCompare(image_info->magick,"PS") == 0)
1667 (void) WriteBlobString(image," showpage\n");
1668 (void) WriteBlobString(image,"} bind def\n");
1669 (void) WriteBlobString(image,"%%EndProlog\n");
1671 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page: 1 %lu\n",page++);
1672 (void) WriteBlobString(image,buffer);
1673 (void) FormatMagickString(buffer,MaxTextExtent,
1674 "%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,geometry.y,
1675 geometry.x+(long) geometry.width,geometry.y+(long) (geometry.height+
1677 (void) WriteBlobString(image,buffer);
1678 if ((double) geometry.x < bounds.x1)
1679 bounds.x1=(double) geometry.x;
1680 if ((double) geometry.y < bounds.y1)
1681 bounds.y1=(double) geometry.y;
1682 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1683 bounds.x2=(double) geometry.x+geometry.width-1;
1684 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1685 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1686 value=GetImageProperty(image,"label");
1687 if (value != (const char *) NULL)
1688 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1689 if (LocaleCompare(image_info->magick,"PS") != 0)
1690 (void) WriteBlobString(image,"userdict begin\n");
1691 (void) WriteBlobString(image,"DisplayImage\n");
1695 (void) FormatMagickString(buffer,MaxTextExtent,
1696 "%ld %ld\n%g %g\n%g\n",geometry.x,geometry.y,scale.x,scale.y,
1698 (void) WriteBlobString(image,buffer);
1699 labels=(char **) NULL;
1700 value=GetImageProperty(image,"label");
1701 if (value != (const char *) NULL)
1702 labels=StringToList(value);
1703 if (labels != (char **) NULL)
1705 for (i=0; labels[i] != (char *) NULL; i++)
1707 (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
1709 (void) WriteBlobString(image,buffer);
1710 labels[i]=DestroyString(labels[i]);
1712 labels=(char **) RelinquishMagickMemory(labels);
1714 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1715 pixel.opacity=(Quantum) TransparentOpacity;
1716 index=(IndexPacket) 0;
1718 if ((image_info->type != TrueColorType) &&
1719 (IsGrayImage(image,&image->exception) != MagickFalse))
1721 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
1727 Dump image as grayscale.
1729 (void) FormatMagickString(buffer,MaxTextExtent,
1730 "%lu %lu\n1\n1\n1\n8\n",image->columns,image->rows);
1731 (void) WriteBlobString(image,buffer);
1733 for (y=0; y < (long) image->rows; y++)
1735 p=GetVirtualPixels(image,0,y,image->columns,1,
1737 if (p == (const PixelPacket *) NULL)
1739 for (x=0; x < (long) image->columns; x++)
1741 pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1742 q=PopHexPixel(hex_digits,pixel,q);
1744 if ((q-pixels+8) >= 80)
1747 (void) WriteBlob(image,q-pixels,pixels);
1752 if (image->previous == (Image *) NULL)
1754 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1755 if (status == MagickFalse)
1762 (void) WriteBlob(image,q-pixels,pixels);
1774 Dump image as bitmap.
1776 (void) FormatMagickString(buffer,MaxTextExtent,
1777 "%lu %lu\n1\n1\n1\n1\n",image->columns,image->rows);
1778 (void) WriteBlobString(image,buffer);
1780 for (y=0; y < (long) image->rows; y++)
1782 p=GetVirtualPixels(image,0,y,image->columns,1,
1784 if (p == (const PixelPacket *) NULL)
1786 indexes=GetVirtualIndexQueue(image);
1789 for (x=0; x < (long) image->columns; x++)
1792 pixel=PixelIntensityToQuantum(p);
1793 if (pixel >= (Quantum) (QuantumRange/2))
1798 q=PopHexPixel(hex_digits,byte,q);
1799 if ((q-pixels+2) >= 80)
1802 (void) WriteBlob(image,q-pixels,pixels);
1813 q=PopHexPixel(hex_digits,byte,q);
1814 if ((q-pixels+2) >= 80)
1817 (void) WriteBlob(image,q-pixels,pixels);
1821 if (image->previous == (Image *) NULL)
1823 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1824 if (status == MagickFalse)
1831 (void) WriteBlob(image,q-pixels,pixels);
1836 if ((image->storage_class == DirectClass) ||
1837 (image->colors > 256) || (image->matte != MagickFalse))
1840 Dump DirectClass image.
1842 (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n0\n%d\n",
1843 image->columns,image->rows,
1844 image_info->compression == RLECompression ? 1 : 0);
1845 (void) WriteBlobString(image,buffer);
1846 switch (image_info->compression)
1848 case RLECompression:
1851 Dump runlength-encoded DirectColor packets.
1854 for (y=0; y < (long) image->rows; y++)
1856 p=GetVirtualPixels(image,0,y,image->columns,1,
1858 if (p == (const PixelPacket *) NULL)
1862 for (x=0; x < (long) image->columns; x++)
1864 if ((p->red == pixel.red) && (p->green == pixel.green) &&
1865 (p->blue == pixel.blue) &&
1866 (p->opacity == pixel.opacity) && (length < 255) &&
1867 (x < (long) (image->columns-1)))
1873 WriteRunlengthPacket(image,pixel,length,p);
1874 if ((q-pixels+10) >= 80)
1877 (void) WriteBlob(image,q-pixels,pixels);
1886 WriteRunlengthPacket(image,pixel,length,p);
1887 if ((q-pixels+10) >= 80)
1890 (void) WriteBlob(image,q-pixels,pixels);
1893 if (image->previous == (Image *) NULL)
1895 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1896 if (status == MagickFalse)
1903 (void) WriteBlob(image,q-pixels,pixels);
1911 Dump uncompressed DirectColor packets.
1914 for (y=0; y < (long) image->rows; y++)
1916 p=GetVirtualPixels(image,0,y,image->columns,1,
1918 if (p == (const PixelPacket *) NULL)
1920 for (x=0; x < (long) image->columns; x++)
1922 if ((image->matte != MagickFalse) &&
1923 (p->opacity == (Quantum) TransparentOpacity))
1925 q=PopHexPixel(hex_digits,0xff,q);
1926 q=PopHexPixel(hex_digits,0xff,q);
1927 q=PopHexPixel(hex_digits,0xff,q);
1931 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetRedPixelComponent(p)),q);
1932 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetGreenPixelComponent(p)),q);
1933 q=PopHexPixel(hex_digits,ScaleQuantumToChar(GetBluePixelComponent(p)),q);
1935 if ((q-pixels+6) >= 80)
1938 (void) WriteBlob(image,q-pixels,pixels);
1943 if (image->previous == (Image *) NULL)
1945 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1946 if (status == MagickFalse)
1953 (void) WriteBlob(image,q-pixels,pixels);
1958 (void) WriteBlobByte(image,'\n');
1963 Dump PseudoClass image.
1965 (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n%d\n%d\n0\n",
1966 image->columns,image->rows,
1967 image->storage_class == PseudoClass ? 1 : 0,
1968 image_info->compression == RLECompression ? 1 : 0);
1969 (void) WriteBlobString(image,buffer);
1971 Dump number of colors and colormap.
1973 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",image->colors);
1974 (void) WriteBlobString(image,buffer);
1975 for (i=0; i < (long) image->colors; i++)
1977 (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1978 ScaleQuantumToChar(image->colormap[i].red),
1979 ScaleQuantumToChar(image->colormap[i].green),
1980 ScaleQuantumToChar(image->colormap[i].blue));
1981 (void) WriteBlobString(image,buffer);
1983 switch (image_info->compression)
1985 case RLECompression:
1988 Dump runlength-encoded PseudoColor packets.
1991 for (y=0; y < (long) image->rows; y++)
1993 p=GetVirtualPixels(image,0,y,image->columns,1,
1995 if (p == (const PixelPacket *) NULL)
1997 indexes=GetVirtualIndexQueue(image);
2000 for (x=0; x < (long) image->columns; x++)
2002 if ((index == indexes[x]) && (length < 255) &&
2003 (x < ((long) image->columns-1)))
2009 q=PopHexPixel(hex_digits,index,q);
2010 q=PopHexPixel(hex_digits,(unsigned long)
2011 MagickMin(length,0xff),q);
2013 if ((q-pixels+6) >= 80)
2016 (void) WriteBlob(image,q-pixels,pixels);
2026 q=PopHexPixel(hex_digits,index,q);
2027 q=PopHexPixel(hex_digits,(unsigned long)
2028 MagickMin(length,0xff),q);
2029 if (image->previous == (Image *) NULL)
2031 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2032 if (status == MagickFalse)
2039 (void) WriteBlob(image,q-pixels,pixels);
2047 Dump uncompressed PseudoColor packets.
2050 for (y=0; y < (long) image->rows; y++)
2052 p=GetVirtualPixels(image,0,y,image->columns,1,
2054 if (p == (const PixelPacket *) NULL)
2056 indexes=GetVirtualIndexQueue(image);
2057 for (x=0; x < (long) image->columns; x++)
2059 q=PopHexPixel(hex_digits,indexes[x],q);
2060 if ((q-pixels+4) >= 80)
2063 (void) WriteBlob(image,q-pixels,pixels);
2068 if (image->previous == (Image *) NULL)
2070 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2071 if (status == MagickFalse)
2078 (void) WriteBlob(image,q-pixels,pixels);
2083 (void) WriteBlobByte(image,'\n');
2085 if (LocaleCompare(image_info->magick,"PS") != 0)
2086 (void) WriteBlobString(image,"end\n");
2087 (void) WriteBlobString(image,"%%PageTrailer\n");
2088 if (GetNextImageInList(image) == (Image *) NULL)
2090 image=SyncNextImageInList(image);
2091 status=SetImageProgress(image,SaveImagesTag,scene++,
2092 GetImageListLength(image));
2093 if (status == MagickFalse)
2095 } while (image_info->adjoin != MagickFalse);
2096 (void) WriteBlobString(image,"%%Trailer\n");
2099 (void) FormatMagickString(buffer,MaxTextExtent,
2100 "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) ceil(bounds.x1-0.5),
2101 (long) ceil(bounds.y1-0.5),(long) floor(bounds.x2+0.5),(long)
2102 floor(bounds.y2+0.5));
2103 (void) WriteBlobString(image,buffer);
2104 (void) FormatMagickString(buffer,MaxTextExtent,
2105 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
2106 bounds.x2,bounds.y2);
2107 (void) WriteBlobString(image,buffer);
2109 (void) WriteBlobString(image,"%%EOF\n");
2110 (void) CloseBlob(image);