2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Postscript Format %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/delegate-private.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/magick.h"
62 #include "MagickCore/memory_.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/resource_.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum-private.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/token.h"
75 #include "MagickCore/transform.h"
76 #include "MagickCore/utility.h"
81 static MagickBooleanType
82 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *);
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 % IsPS() returns MagickTrue if the image format type, identified by the
96 % magick string, is PS.
98 % The format of the IsPS method is:
100 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
102 % A description of each parameter follows:
104 % o magick: compare image format pattern against these bytes.
106 % o length: Specifies the length of the magick string.
109 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
113 if (memcmp(magick,"%!",2) == 0)
115 if (memcmp(magick,"\004%!",3) == 0)
121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 % R e a d P S I m a g e %
129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 % ReadPSImage() reads a Postscript image file and returns it. It allocates
132 % the memory necessary for the new Image structure and returns a pointer
135 % The format of the ReadPSImage method is:
137 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
139 % A description of each parameter follows:
141 % o image_info: the image info.
143 % o exception: return any errors or warnings in this structure.
147 static MagickBooleanType IsPostscriptRendered(const char *path)
155 if ((path == (const char *) NULL) || (*path == '\0'))
157 status=GetPathAttributes(path,&attributes);
158 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
159 (attributes.st_size > 0))
164 static inline int ProfileInteger(Image *image,short int *hex_digits)
178 c=ReadBlobByte(image);
179 if ((c == EOF) || ((c == '%') && (l == '%')))
186 if (isxdigit(c) == MagickFalse)
188 value=(int) ((size_t) value << 4)+hex_digits[c];
194 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
196 #define BoundingBox "BoundingBox:"
197 #define BeginDocument "BeginDocument:"
198 #define BeginXMPPacket "<?xpacket begin="
199 #define EndXMPPacket "<?xpacket end="
200 #define ICCProfile "BeginICCProfile:"
201 #define CMYKCustomColor "CMYKCustomColor:"
202 #define CMYKProcessColor "CMYKProcessColor:"
203 #define DocumentMedia "DocumentMedia:"
204 #define DocumentCustomColors "DocumentCustomColors:"
205 #define DocumentProcessColors "DocumentProcessColors:"
206 #define EndDocument "EndDocument:"
207 #define HiResBoundingBox "HiResBoundingBox:"
208 #define ImageData "ImageData:"
209 #define PageBoundingBox "PageBoundingBox:"
210 #define LanguageLevel "LanguageLevel:"
211 #define PageMedia "PageMedia:"
212 #define Pages "Pages:"
213 #define PhotoshopProfile "BeginPhotoshop:"
214 #define PostscriptLevel "!PS-"
215 #define RenderPostscriptText " Rendering Postscript... "
216 #define SpotColor "+ "
219 command[MaxTextExtent],
220 density[MaxTextExtent],
221 filename[MaxTextExtent],
222 geometry[MaxTextExtent],
223 input_filename[MaxTextExtent],
224 options[MaxTextExtent],
225 postscript_filename[MaxTextExtent];
298 assert(image_info != (const ImageInfo *) NULL);
299 assert(image_info->signature == MagickSignature);
300 if (image_info->debug != MagickFalse)
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
302 image_info->filename);
303 assert(exception != (ExceptionInfo *) NULL);
304 assert(exception->signature == MagickSignature);
305 image=AcquireImage(image_info,exception);
306 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
307 if (status == MagickFalse)
309 image=DestroyImageList(image);
310 return((Image *) NULL);
312 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
313 if (status == MagickFalse)
315 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
316 image_info->filename);
317 image=DestroyImageList(image);
318 return((Image *) NULL);
321 Initialize hex values.
323 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
324 hex_digits[(int) '0']=0;
325 hex_digits[(int) '1']=1;
326 hex_digits[(int) '2']=2;
327 hex_digits[(int) '3']=3;
328 hex_digits[(int) '4']=4;
329 hex_digits[(int) '5']=5;
330 hex_digits[(int) '6']=6;
331 hex_digits[(int) '7']=7;
332 hex_digits[(int) '8']=8;
333 hex_digits[(int) '9']=9;
334 hex_digits[(int) 'a']=10;
335 hex_digits[(int) 'b']=11;
336 hex_digits[(int) 'c']=12;
337 hex_digits[(int) 'd']=13;
338 hex_digits[(int) 'e']=14;
339 hex_digits[(int) 'f']=15;
340 hex_digits[(int) 'A']=10;
341 hex_digits[(int) 'B']=11;
342 hex_digits[(int) 'C']=12;
343 hex_digits[(int) 'D']=13;
344 hex_digits[(int) 'E']=14;
345 hex_digits[(int) 'F']=15;
347 Set the page density.
349 delta.x=DefaultResolution;
350 delta.y=DefaultResolution;
351 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
353 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
354 image->resolution.x=geometry_info.rho;
355 image->resolution.y=geometry_info.sigma;
356 if ((flags & SigmaValue) == 0)
357 image->resolution.y=image->resolution.x;
359 if (image_info->density != (char *) NULL)
361 flags=ParseGeometry(image_info->density,&geometry_info);
362 image->resolution.x=geometry_info.rho;
363 image->resolution.y=geometry_info.sigma;
364 if ((flags & SigmaValue) == 0)
365 image->resolution.y=image->resolution.x;
367 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
368 if (image_info->page != (char *) NULL)
369 (void) ParseAbsoluteGeometry(image_info->page,&page);
370 resolution=image->resolution;
371 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5);
372 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5);
374 Determine page geometry from the Postscript bounding box.
376 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
377 (void) ResetMagickMemory(command,0,sizeof(command));
378 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
379 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
388 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
391 Note document structuring comments.
394 if ((strchr("\n\r%",c) == (char *) NULL) &&
395 ((size_t) (p-command) < (MaxTextExtent-1)))
400 Skip %%BeginDocument thru %%EndDocument.
402 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
404 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
406 if (skip != MagickFalse)
408 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
410 (void) SetImageProperty(image,"ps:Level",command+4,exception);
411 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
414 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
415 (void) sscanf(command,LanguageLevel " %lu",&language_level);
416 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
417 (void) sscanf(command,Pages " %lu",&pages);
418 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
419 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
420 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
428 profile=AcquireStringInfo(65536);
429 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
431 SetStringInfoLength(profile,(size_t) i+1);
432 datum=GetStringInfoDatum(profile);
433 datum[i]=(unsigned char) c;
435 (void) SetImageProfile(image,"icc",profile,exception);
436 profile=DestroyStringInfo(profile);
439 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
445 Read Photoshop profile.
447 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
451 profile=BlobToStringInfo((const void *) NULL,length);
452 p=GetStringInfoDatum(profile);
453 for (i=0; i < (ssize_t) length; i++)
454 *p++=(unsigned char) ProfileInteger(image,hex_digits);
455 (void) SetImageProfile(image,"8bim",profile,exception);
456 profile=DestroyStringInfo(profile);
459 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
468 profile=StringToStringInfo(command);
469 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
471 SetStringInfoLength(profile,i+1);
472 c=ReadBlobByte(image);
473 GetStringInfoDatum(profile)[i]=(unsigned char) c;
475 if ((strchr("\n\r%",c) == (char *) NULL) &&
476 ((size_t) (p-command) < (MaxTextExtent-1)))
480 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
483 SetStringInfoLength(profile,i);
484 (void) SetImageProfile(image,"xmp",profile,exception);
485 profile=DestroyStringInfo(profile);
489 Is this a CMYK document?
491 length=strlen(DocumentProcessColors);
492 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
494 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
495 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
496 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
499 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
501 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
503 length=strlen(DocumentCustomColors);
504 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
505 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
506 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
509 property[MaxTextExtent],
518 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
519 (double) (spotcolor++));
520 for (p=command; *p != '\0'; p++)
521 if (isspace((int) (unsigned char) *p) != 0)
523 value=AcquireString(p);
524 (void) SubstituteString(&value,"(","");
525 (void) SubstituteString(&value,")","");
526 (void) StripString(value);
527 (void) SetImageProperty(image,property,value,exception);
528 value=DestroyString(value);
531 if (image_info->page != (char *) NULL)
534 Note region defined by bounding box.
538 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
540 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",
541 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
544 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
546 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf",
547 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
550 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
552 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
553 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
556 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
558 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
559 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
562 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
564 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf",
565 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
568 if ((count != 4) || (i < (ssize_t) priority))
570 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
571 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
576 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
577 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
580 Set Postscript render geometry.
582 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
583 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1,
584 hires_bounds.x1,hires_bounds.y1);
585 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception);
586 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
587 resolution.x/delta.x)-0.5);
588 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
589 resolution.y/delta.y)-0.5);
591 (void) CloseBlob(image);
592 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
595 Create Ghostscript control file.
597 file=AcquireUniqueFileResource(postscript_filename);
600 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
601 image_info->filename);
602 image=DestroyImageList(image);
603 return((Image *) NULL);
605 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
606 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
607 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
608 count=write(file,command,(unsigned int) strlen(command));
609 if (image_info->page == (char *) NULL)
612 translate_geometry[MaxTextExtent];
614 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
615 "%g %g translate\n",-bounds.x1,-bounds.y1);
616 count=write(file,translate_geometry,(unsigned int)
617 strlen(translate_geometry));
621 Render Postscript with the Ghostscript delegate.
623 if (image_info->monochrome != MagickFalse)
624 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
626 if (cmyk != MagickFalse)
627 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
629 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
630 if (delegate_info == (const DelegateInfo *) NULL)
632 (void) RelinquishUniqueFileResource(postscript_filename);
633 image=DestroyImageList(image);
634 return((Image *) NULL);
637 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",resolution.x,
639 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
640 page.width,(double) page.height);
641 read_info=CloneImageInfo(image_info);
642 *read_info->magick='\0';
643 if (read_info->number_scenes != 0)
646 pages[MaxTextExtent];
648 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
649 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
650 (read_info->scene+read_info->number_scenes));
651 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
652 read_info->number_scenes=0;
653 if (read_info->scenes != (char *) NULL)
654 *read_info->scenes='\0';
656 option=GetImageOption(image_info,"eps:use-cropbox");
657 if ((*image_info->magick == 'E') && ((option == (const char *) NULL) ||
658 (IsStringTrue(option) != MagickFalse)))
659 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
660 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
661 (void) AcquireUniqueFilename(filename);
662 (void) ConcatenateMagickString(filename,"%d",MaxTextExtent);
663 (void) FormatLocaleString(command,MaxTextExtent,
664 GetDelegateCommands(delegate_info),
665 read_info->antialias != MagickFalse ? 4 : 1,
666 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
667 postscript_filename,input_filename);
668 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
669 (void) InterpretImageFilename(image_info,image,filename,1,
670 read_info->filename,exception);
671 if ((status == MagickFalse) ||
672 (IsPostscriptRendered(read_info->filename) == MagickFalse))
674 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
675 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
677 (void) RelinquishUniqueFileResource(postscript_filename);
678 (void) RelinquishUniqueFileResource(input_filename);
679 postscript_image=(Image *) NULL;
680 if (status == MagickFalse)
683 (void) InterpretImageFilename(image_info,image,filename,(int) i,
684 read_info->filename,exception);
685 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
687 (void) RelinquishUniqueFileResource(read_info->filename);
692 (void) InterpretImageFilename(image_info,image,filename,(int) i,
693 read_info->filename,exception);
694 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
696 read_info->blob=NULL;
698 next=ReadImage(read_info,exception);
699 (void) RelinquishUniqueFileResource(read_info->filename);
700 if (next == (Image *) NULL)
702 AppendImageToList(&postscript_image,next);
704 (void) RelinquishUniqueFileResource(read_info->filename);
705 read_info=DestroyImageInfo(read_info);
706 if (postscript_image == (Image *) NULL)
708 image=DestroyImageList(image);
709 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
710 image_info->filename);
711 return((Image *) NULL);
713 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
718 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
719 if (cmyk_image != (Image *) NULL)
721 postscript_image=DestroyImageList(postscript_image);
722 postscript_image=cmyk_image;
725 if (image_info->number_scenes != 0)
734 Add place holder images to meet the subimage specification requirement.
736 for (i=0; i < (ssize_t) image_info->scene; i++)
738 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
739 if (clone_image != (Image *) NULL)
740 PrependImageToList(&postscript_image,clone_image);
745 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
747 postscript_image->magick_columns=columns;
749 postscript_image->magick_rows=rows;
750 postscript_image->page=page;
751 (void) CloneImageProfiles(postscript_image,image);
752 (void) CloneImageProperties(postscript_image,image);
753 next=SyncNextImageInList(postscript_image);
754 if (next != (Image *) NULL)
755 postscript_image=next;
756 } while (next != (Image *) NULL);
757 image=DestroyImageList(image);
759 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
762 next=GetNextImageInList(next);
764 return(GetFirstImageInList(postscript_image));
768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 % R e g i s t e r P S I m a g e %
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778 % RegisterPSImage() adds properties for the PS image format to
779 % the list of supported formats. The properties include the image format
780 % tag, a method to read and/or write the format, whether the format
781 % supports the saving of more than one frame to the same file or blob,
782 % whether the format supports native in-memory I/O, and a brief
783 % description of the format.
785 % The format of the RegisterPSImage method is:
787 % size_t RegisterPSImage(void)
790 ModuleExport size_t RegisterPSImage(void)
795 entry=SetMagickInfo("EPI");
796 entry->decoder=(DecodeImageHandler *) ReadPSImage;
797 entry->encoder=(EncodeImageHandler *) WritePSImage;
798 entry->magick=(IsImageFormatHandler *) IsPS;
799 entry->adjoin=MagickFalse;
800 entry->blob_support=MagickFalse;
801 entry->seekable_stream=MagickTrue;
802 entry->description=ConstantString(
803 "Encapsulated PostScript Interchange format");
804 entry->module=ConstantString("PS");
805 (void) RegisterMagickInfo(entry);
806 entry=SetMagickInfo("EPS");
807 entry->decoder=(DecodeImageHandler *) ReadPSImage;
808 entry->encoder=(EncodeImageHandler *) WritePSImage;
809 entry->magick=(IsImageFormatHandler *) IsPS;
810 entry->adjoin=MagickFalse;
811 entry->blob_support=MagickFalse;
812 entry->seekable_stream=MagickTrue;
813 entry->description=ConstantString("Encapsulated PostScript");
814 entry->module=ConstantString("PS");
815 (void) RegisterMagickInfo(entry);
816 entry=SetMagickInfo("EPSF");
817 entry->decoder=(DecodeImageHandler *) ReadPSImage;
818 entry->encoder=(EncodeImageHandler *) WritePSImage;
819 entry->magick=(IsImageFormatHandler *) IsPS;
820 entry->adjoin=MagickFalse;
821 entry->blob_support=MagickFalse;
822 entry->seekable_stream=MagickTrue;
823 entry->description=ConstantString("Encapsulated PostScript");
824 entry->module=ConstantString("PS");
825 (void) RegisterMagickInfo(entry);
826 entry=SetMagickInfo("EPSI");
827 entry->decoder=(DecodeImageHandler *) ReadPSImage;
828 entry->encoder=(EncodeImageHandler *) WritePSImage;
829 entry->magick=(IsImageFormatHandler *) IsPS;
830 entry->adjoin=MagickFalse;
831 entry->blob_support=MagickFalse;
832 entry->seekable_stream=MagickTrue;
833 entry->description=ConstantString(
834 "Encapsulated PostScript Interchange format");
835 entry->module=ConstantString("PS");
836 (void) RegisterMagickInfo(entry);
837 entry=SetMagickInfo("PS");
838 entry->decoder=(DecodeImageHandler *) ReadPSImage;
839 entry->encoder=(EncodeImageHandler *) WritePSImage;
840 entry->magick=(IsImageFormatHandler *) IsPS;
841 entry->module=ConstantString("PS");
842 entry->blob_support=MagickFalse;
843 entry->seekable_stream=MagickTrue;
844 entry->description=ConstantString("PostScript");
845 (void) RegisterMagickInfo(entry);
846 return(MagickImageCoderSignature);
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
854 % U n r e g i s t e r P S I m a g e %
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 % UnregisterPSImage() removes format registrations made by the
861 % PS module from the list of supported formats.
863 % The format of the UnregisterPSImage method is:
865 % UnregisterPSImage(void)
868 ModuleExport void UnregisterPSImage(void)
870 (void) UnregisterMagickInfo("EPI");
871 (void) UnregisterMagickInfo("EPS");
872 (void) UnregisterMagickInfo("EPSF");
873 (void) UnregisterMagickInfo("EPSI");
874 (void) UnregisterMagickInfo("PS");
878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882 % W r i t e P S I m a g e %
886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
888 % WritePSImage translates an image to encapsulated Postscript
889 % Level I for printing. If the supplied geometry is null, the image is
890 % centered on the Postscript page. Otherwise, the image is positioned as
891 % specified by the geometry.
893 % The format of the WritePSImage method is:
895 % MagickBooleanType WritePSImage(const ImageInfo *image_info,
896 % Image *image,ExceptionInfo *exception)
898 % A description of each parameter follows:
900 % o image_info: the image info.
902 % o image: the image.
904 % o exception: return any errors or warnings in this structure.
908 static inline size_t MagickMin(const size_t x,const size_t y)
915 static inline unsigned char *PopHexPixel(const char **hex_digits,
916 const size_t pixel,unsigned char *pixels)
921 hex=hex_digits[pixel];
922 *pixels++=(unsigned char) (*hex++);
923 *pixels++=(unsigned char) (*hex);
927 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
928 ExceptionInfo *exception)
930 #define WriteRunlengthPacket(image,pixel,length,p) \
932 if ((image->alpha_trait == BlendPixelTrait) && \
933 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
935 q=PopHexPixel(hex_digits,0xff,q); \
936 q=PopHexPixel(hex_digits,0xff,q); \
937 q=PopHexPixel(hex_digits,0xff,q); \
941 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
942 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
943 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
945 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
951 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
952 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
953 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
954 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
955 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
956 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
957 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
958 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
959 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
960 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
961 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
962 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
963 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
964 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
965 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
966 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
967 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
968 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
969 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
970 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
971 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
972 "FC", "FD", "FE", "FF", (char *) NULL
978 "% Display a color image. The image is displayed in color on",
979 "% Postscript viewers or printers that support color, otherwise",
980 "% it is displayed as grayscale.",
982 "/DirectClassPacket",
985 " % Get a DirectClass packet.",
991 " % length: number of pixels minus one of this color (optional).",
993 " currentfile color_packet readhexstring pop pop",
996 " /number_pixels 3 def",
999 " currentfile byte readhexstring pop 0 get",
1000 " /number_pixels exch 1 add 3 mul def",
1002 " 0 3 number_pixels 1 sub",
1004 " pixels exch color_packet putinterval",
1006 " pixels 0 number_pixels getinterval",
1009 "/DirectClassImage",
1012 " % Display a DirectClass image.",
1014 " systemdict /colorimage known",
1021 " { DirectClassPacket } false 3 colorimage",
1025 " % No colorimage operator; convert to grayscale.",
1032 " { GrayDirectClassPacket } image",
1036 "/GrayDirectClassPacket",
1039 " % Get a DirectClass packet; convert to grayscale.",
1045 " % length: number of pixels minus one of this color (optional).",
1047 " currentfile color_packet readhexstring pop pop",
1048 " color_packet 0 get 0.299 mul",
1049 " color_packet 1 get 0.587 mul add",
1050 " color_packet 2 get 0.114 mul add",
1052 " /gray_packet exch def",
1053 " compression 0 eq",
1055 " /number_pixels 1 def",
1058 " currentfile byte readhexstring pop 0 get",
1059 " /number_pixels exch 1 add def",
1061 " 0 1 number_pixels 1 sub",
1063 " pixels exch gray_packet put",
1065 " pixels 0 number_pixels getinterval",
1068 "/GrayPseudoClassPacket",
1071 " % Get a PseudoClass packet; convert to grayscale.",
1074 " % index: index into the colormap.",
1075 " % length: number of pixels minus one of this color (optional).",
1077 " currentfile byte readhexstring pop 0 get",
1078 " /offset exch 3 mul def",
1079 " /color_packet colormap offset 3 getinterval def",
1080 " color_packet 0 get 0.299 mul",
1081 " color_packet 1 get 0.587 mul add",
1082 " color_packet 2 get 0.114 mul add",
1084 " /gray_packet exch def",
1085 " compression 0 eq",
1087 " /number_pixels 1 def",
1090 " currentfile byte readhexstring pop 0 get",
1091 " /number_pixels exch 1 add def",
1093 " 0 1 number_pixels 1 sub",
1095 " pixels exch gray_packet put",
1097 " pixels 0 number_pixels getinterval",
1100 "/PseudoClassPacket",
1103 " % Get a PseudoClass packet.",
1106 " % index: index into the colormap.",
1107 " % length: number of pixels minus one of this color (optional).",
1109 " currentfile byte readhexstring pop 0 get",
1110 " /offset exch 3 mul def",
1111 " /color_packet colormap offset 3 getinterval def",
1112 " compression 0 eq",
1114 " /number_pixels 3 def",
1117 " currentfile byte readhexstring pop 0 get",
1118 " /number_pixels exch 1 add 3 mul def",
1120 " 0 3 number_pixels 1 sub",
1122 " pixels exch color_packet putinterval",
1124 " pixels 0 number_pixels getinterval",
1127 "/PseudoClassImage",
1130 " % Display a PseudoClass image.",
1133 " % class: 0-PseudoClass or 1-Grayscale.",
1135 " currentfile buffer readline pop",
1136 " token pop /class exch def pop",
1139 " currentfile buffer readline pop",
1140 " token pop /depth exch def pop",
1141 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1142 " columns rows depth",
1147 " { currentfile grays readhexstring pop } image",
1152 " % colors: number of colors in the colormap.",
1153 " % colormap: red, green, blue color packets.",
1155 " currentfile buffer readline pop",
1156 " token pop /colors exch def pop",
1157 " /colors colors 3 mul def",
1158 " /colormap colors string def",
1159 " currentfile colormap readhexstring pop pop",
1160 " systemdict /colorimage known",
1167 " { PseudoClassPacket } false 3 colorimage",
1171 " % No colorimage operator; convert to grayscale.",
1178 " { GrayPseudoClassPacket } image",
1186 " % Display a DirectClass or PseudoClass image.",
1189 " % x & y translation.",
1191 " % label pointsize.",
1193 " % image columns & rows.",
1194 " % class: 0-DirectClass or 1-PseudoClass.",
1195 " % compression: 0-none or 1-RunlengthEncoded.",
1196 " % hex color packets.",
1199 " /buffer 512 string def",
1200 " /byte 1 string def",
1201 " /color_packet 3 string def",
1202 " /pixels 768 string def",
1204 " currentfile buffer readline pop",
1205 " token pop /x exch def",
1206 " token pop /y exch def pop",
1208 " currentfile buffer readline pop",
1209 " token pop /x exch def",
1210 " token pop /y exch def pop",
1211 " currentfile buffer readline pop",
1212 " token pop /pointsize exch def pop",
1213 " /Times-Roman findfont pointsize scalefont setfont",
1216 *PostscriptEpilog[]=
1219 " currentfile buffer readline pop",
1220 " token pop /columns exch def",
1221 " token pop /rows exch def pop",
1222 " currentfile buffer readline pop",
1223 " token pop /class exch def pop",
1224 " currentfile buffer readline pop",
1225 " token pop /compression exch def pop",
1226 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1232 buffer[MaxTextExtent],
1233 date[MaxTextExtent],
1235 page_geometry[MaxTextExtent];
1275 register const Quantum
1282 register unsigned char
1306 Open output image file.
1308 assert(image_info != (const ImageInfo *) NULL);
1309 assert(image_info->signature == MagickSignature);
1310 assert(image != (Image *) NULL);
1311 assert(image->signature == MagickSignature);
1312 if (image->debug != MagickFalse)
1313 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1314 assert(exception != (ExceptionInfo *) NULL);
1315 assert(exception->signature == MagickSignature);
1316 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1317 if (status == MagickFalse)
1319 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1325 Scale relative to dots-per-inch.
1327 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1328 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1329 delta.x=DefaultResolution;
1330 delta.y=DefaultResolution;
1331 resolution.x=image->resolution.x;
1332 resolution.y=image->resolution.y;
1333 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1335 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1336 resolution.x=geometry_info.rho;
1337 resolution.y=geometry_info.sigma;
1338 if ((flags & SigmaValue) == 0)
1339 resolution.y=resolution.x;
1341 if (image_info->density != (char *) NULL)
1343 flags=ParseGeometry(image_info->density,&geometry_info);
1344 resolution.x=geometry_info.rho;
1345 resolution.y=geometry_info.sigma;
1346 if ((flags & SigmaValue) == 0)
1347 resolution.y=resolution.x;
1349 if (image->units == PixelsPerCentimeterResolution)
1351 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1352 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1354 SetGeometry(image,&geometry);
1355 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1356 (double) image->columns,(double) image->rows);
1357 if (image_info->page != (char *) NULL)
1358 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1360 if ((image->page.width != 0) && (image->page.height != 0))
1361 (void) FormatLocaleString(page_geometry,MaxTextExtent,
1362 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1363 image->page.height,(double) image->page.x,(double) image->page.y);
1365 if ((image->gravity != UndefinedGravity) &&
1366 (LocaleCompare(image_info->magick,"PS") == 0))
1367 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1368 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1369 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1370 &geometry.width,&geometry.height);
1371 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1372 geometry.width=(size_t) floor(scale.x+0.5);
1373 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1374 geometry.height=(size_t) floor(scale.y+0.5);
1375 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1376 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1377 if (image->gravity != UndefinedGravity)
1379 geometry.x=(-page_info.x);
1380 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1383 if (image_info->pointsize != 0.0)
1384 pointsize=image_info->pointsize;
1386 value=GetImageProperty(image,"label",exception);
1387 if (value != (const char *) NULL)
1388 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1392 Output Postscript header.
1394 if (LocaleCompare(image_info->magick,"PS") == 0)
1395 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1397 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1399 (void) WriteBlobString(image,buffer);
1400 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
1401 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
1403 (void) WriteBlobString(image,buffer);
1404 timer=time((time_t *) NULL);
1405 (void) FormatMagickTime(timer,MaxTextExtent,date);
1406 (void) FormatLocaleString(buffer,MaxTextExtent,
1407 "%%%%CreationDate: (%s)\n",date);
1408 (void) WriteBlobString(image,buffer);
1409 bounds.x1=(double) geometry.x;
1410 bounds.y1=(double) geometry.y;
1411 bounds.x2=(double) geometry.x+scale.x;
1412 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1413 if ((image_info->adjoin != MagickFalse) &&
1414 (GetNextImageInList(image) != (Image *) NULL))
1415 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1419 (void) FormatLocaleString(buffer,MaxTextExtent,
1420 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1421 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1422 (void) WriteBlobString(image,buffer);
1423 (void) FormatLocaleString(buffer,MaxTextExtent,
1424 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1425 bounds.y1,bounds.x2,bounds.y2);
1427 (void) WriteBlobString(image,buffer);
1428 profile=GetImageProfile(image,"8bim");
1429 if (profile != (StringInfo *) NULL)
1432 Embed Photoshop profile.
1434 (void) FormatLocaleString(buffer,MaxTextExtent,
1435 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
1436 (void) WriteBlobString(image,buffer);
1437 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1440 (void) WriteBlobString(image,"\n% ");
1441 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
1442 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1443 (void) WriteBlobString(image,buffer);
1445 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1447 profile=GetImageProfile(image,"xmp");
1448 if (0 && (profile != (StringInfo *) NULL))
1453 (void) WriteBlobString(image,"\n%begin_xml_code\n");
1454 (void) FormatLocaleString(buffer,MaxTextExtent,
1455 "\n%%begin_xml_packet: %.20g\n",(double)
1456 GetStringInfoLength(profile));
1457 (void) WriteBlobString(image,buffer);
1458 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
1459 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
1460 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
1462 value=GetImageProperty(image,"label",exception);
1463 if (value != (const char *) NULL)
1464 (void) WriteBlobString(image,
1465 "%%DocumentNeededResources: font Times-Roman\n");
1466 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1467 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1468 if (LocaleCompare(image_info->magick,"PS") != 0)
1469 (void) WriteBlobString(image,"%%Pages: 1\n");
1473 Compute the number of pages.
1475 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1476 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1477 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
1478 image_info->adjoin != MagickFalse ? (double)
1479 GetImageListLength(image) : 1.0);
1480 (void) WriteBlobString(image,buffer);
1482 (void) WriteBlobString(image,"%%EndComments\n");
1483 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1484 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1485 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1486 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1487 (LocaleCompare(image_info->magick,"EPT") == 0))
1502 Create preview image.
1504 preview_image=CloneImage(image,0,0,MagickTrue,exception);
1505 if (preview_image == (Image *) NULL)
1506 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1508 Dump image as bitmap.
1510 (void) FormatLocaleString(buffer,MaxTextExtent,
1511 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1512 preview_image->columns,(double) preview_image->rows,1.0,
1513 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1515 (void) WriteBlobString(image,buffer);
1517 for (y=0; y < (ssize_t) image->rows; y++)
1519 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
1521 if (p == (const Quantum *) NULL)
1525 for (x=0; x < (ssize_t) preview_image->columns; x++)
1528 pixel=GetPixelIntensity(preview_image,p);
1529 if (pixel >= (Quantum) (QuantumRange/2))
1534 q=PopHexPixel(hex_digits,byte,q);
1535 if ((q-pixels+8) >= 80)
1538 (void) WriteBlob(image,q-pixels,pixels);
1540 (void) WriteBlobString(image,"% ");
1549 q=PopHexPixel(hex_digits,byte,q);
1550 if ((q-pixels+8) >= 80)
1553 (void) WriteBlob(image,q-pixels,pixels);
1555 (void) WriteBlobString(image,"% ");
1562 (void) WriteBlob(image,q-pixels,pixels);
1564 (void) WriteBlobString(image,"\n%%EndPreview\n");
1565 preview_image=DestroyImage(preview_image);
1568 Output Postscript commands.
1570 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1572 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1573 (void) WriteBlobString(image,buffer);
1575 value=GetImageProperty(image,"label",exception);
1576 if (value != (const char *) NULL)
1577 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
1579 (void) WriteBlobString(image," /label 512 string def\n");
1580 (void) WriteBlobString(image," currentfile label readline pop\n");
1581 (void) FormatLocaleString(buffer,MaxTextExtent,
1582 " 0 y %g add moveto label show pop\n",j*pointsize+12);
1583 (void) WriteBlobString(image,buffer);
1585 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1587 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
1588 (void) WriteBlobString(image,buffer);
1590 if (LocaleCompare(image_info->magick,"PS") == 0)
1591 (void) WriteBlobString(image," showpage\n");
1592 (void) WriteBlobString(image,"} bind def\n");
1593 (void) WriteBlobString(image,"%%EndProlog\n");
1595 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1597 (void) WriteBlobString(image,buffer);
1598 (void) FormatLocaleString(buffer,MaxTextExtent,
1599 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1600 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
1601 (geometry.height+text_size));
1602 (void) WriteBlobString(image,buffer);
1603 if ((double) geometry.x < bounds.x1)
1604 bounds.x1=(double) geometry.x;
1605 if ((double) geometry.y < bounds.y1)
1606 bounds.y1=(double) geometry.y;
1607 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1608 bounds.x2=(double) geometry.x+geometry.width-1;
1609 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1610 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1611 value=GetImageProperty(image,"label",exception);
1612 if (value != (const char *) NULL)
1613 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1614 if (LocaleCompare(image_info->magick,"PS") != 0)
1615 (void) WriteBlobString(image,"userdict begin\n");
1616 (void) WriteBlobString(image,"DisplayImage\n");
1620 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1621 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1622 (void) WriteBlobString(image,buffer);
1623 labels=(char **) NULL;
1624 value=GetImageProperty(image,"label",exception);
1625 if (value != (const char *) NULL)
1626 labels=StringToList(value);
1627 if (labels != (char **) NULL)
1629 for (i=0; labels[i] != (char *) NULL; i++)
1631 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
1633 (void) WriteBlobString(image,buffer);
1634 labels[i]=DestroyString(labels[i]);
1636 labels=(char **) RelinquishMagickMemory(labels);
1638 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1639 pixel.alpha=(Quantum) TransparentAlpha;
1642 if ((image_info->type != TrueColorType) &&
1643 (IsImageGray(image,exception) != MagickFalse))
1645 if (IsImageMonochrome(image,exception) == MagickFalse)
1651 Dump image as grayscale.
1653 (void) FormatLocaleString(buffer,MaxTextExtent,
1654 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1656 (void) WriteBlobString(image,buffer);
1658 for (y=0; y < (ssize_t) image->rows; y++)
1660 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1661 if (p == (const Quantum *) NULL)
1663 for (x=0; x < (ssize_t) image->columns; x++)
1665 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
1666 q=PopHexPixel(hex_digits,(size_t) pixel,q);
1668 if ((q-pixels+8) >= 80)
1671 (void) WriteBlob(image,q-pixels,pixels);
1674 p+=GetPixelChannels(image);
1676 if (image->previous == (Image *) NULL)
1678 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1680 if (status == MagickFalse)
1687 (void) WriteBlob(image,q-pixels,pixels);
1699 Dump image as bitmap.
1701 (void) FormatLocaleString(buffer,MaxTextExtent,
1702 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1704 (void) WriteBlobString(image,buffer);
1706 for (y=0; y < (ssize_t) image->rows; y++)
1708 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1709 if (p == (const Quantum *) NULL)
1713 for (x=0; x < (ssize_t) image->columns; x++)
1716 pixel=GetPixelIntensity(image,p);
1717 if (pixel >= (Quantum) (QuantumRange/2))
1722 q=PopHexPixel(hex_digits,byte,q);
1723 if ((q-pixels+2) >= 80)
1726 (void) WriteBlob(image,q-pixels,pixels);
1732 p+=GetPixelChannels(image);
1737 q=PopHexPixel(hex_digits,byte,q);
1738 if ((q-pixels+2) >= 80)
1741 (void) WriteBlob(image,q-pixels,pixels);
1745 if (image->previous == (Image *) NULL)
1747 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1749 if (status == MagickFalse)
1756 (void) WriteBlob(image,q-pixels,pixels);
1761 if ((image->storage_class == DirectClass) ||
1762 (image->colors > 256) || (image->alpha_trait == BlendPixelTrait))
1765 Dump DirectClass image.
1767 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
1768 (double) image->columns,(double) image->rows,
1769 image_info->compression == RLECompression ? 1 : 0);
1770 (void) WriteBlobString(image,buffer);
1771 switch (image_info->compression)
1773 case RLECompression:
1776 Dump runlength-encoded DirectColor packets.
1779 for (y=0; y < (ssize_t) image->rows; y++)
1781 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1782 if (p == (const Quantum *) NULL)
1784 GetPixelInfoPixel(image,p,&pixel);
1786 for (x=0; x < (ssize_t) image->columns; x++)
1788 if ((GetPixelRed(image,p) == pixel.red) &&
1789 (GetPixelGreen(image,p) == pixel.green) &&
1790 (GetPixelBlue(image,p) == pixel.blue) &&
1791 (GetPixelAlpha(image,p) == pixel.alpha) &&
1792 (length < 255) && (x < (ssize_t) (image->columns-1)))
1798 WriteRunlengthPacket(image,pixel,length,p);
1799 if ((q-pixels+10) >= 80)
1802 (void) WriteBlob(image,q-pixels,pixels);
1808 GetPixelInfoPixel(image,p,&pixel);
1809 p+=GetPixelChannels(image);
1811 WriteRunlengthPacket(image,pixel,length,p);
1812 if ((q-pixels+10) >= 80)
1815 (void) WriteBlob(image,q-pixels,pixels);
1818 if (image->previous == (Image *) NULL)
1820 status=SetImageProgress(image,SaveImageTag,
1821 (MagickOffsetType) y,image->rows);
1822 if (status == MagickFalse)
1829 (void) WriteBlob(image,q-pixels,pixels);
1837 Dump uncompressed DirectColor packets.
1840 for (y=0; y < (ssize_t) image->rows; y++)
1842 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1843 if (p == (const Quantum *) NULL)
1845 for (x=0; x < (ssize_t) image->columns; x++)
1847 if ((image->alpha_trait == BlendPixelTrait) &&
1848 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
1850 q=PopHexPixel(hex_digits,0xff,q);
1851 q=PopHexPixel(hex_digits,0xff,q);
1852 q=PopHexPixel(hex_digits,0xff,q);
1856 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1857 GetPixelRed(image,p)),q);
1858 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1859 GetPixelGreen(image,p)),q);
1860 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
1861 GetPixelBlue(image,p)),q);
1863 if ((q-pixels+6) >= 80)
1866 (void) WriteBlob(image,q-pixels,pixels);
1869 p+=GetPixelChannels(image);
1871 if (image->previous == (Image *) NULL)
1873 status=SetImageProgress(image,SaveImageTag,
1874 (MagickOffsetType) y,image->rows);
1875 if (status == MagickFalse)
1882 (void) WriteBlob(image,q-pixels,pixels);
1887 (void) WriteBlobByte(image,'\n');
1892 Dump PseudoClass image.
1894 (void) FormatLocaleString(buffer,MaxTextExtent,
1895 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1896 image->rows,image->storage_class == PseudoClass ? 1 : 0,
1897 image_info->compression == RLECompression ? 1 : 0);
1898 (void) WriteBlobString(image,buffer);
1900 Dump number of colors and colormap.
1902 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
1904 (void) WriteBlobString(image,buffer);
1905 for (i=0; i < (ssize_t) image->colors; i++)
1907 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1908 ScaleQuantumToChar(image->colormap[i].red),
1909 ScaleQuantumToChar(image->colormap[i].green),
1910 ScaleQuantumToChar(image->colormap[i].blue));
1911 (void) WriteBlobString(image,buffer);
1913 switch (image_info->compression)
1915 case RLECompression:
1918 Dump runlength-encoded PseudoColor packets.
1921 for (y=0; y < (ssize_t) image->rows; y++)
1923 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1924 if (p == (const Quantum *) NULL)
1926 index=GetPixelIndex(image,p);
1928 for (x=0; x < (ssize_t) image->columns; x++)
1930 if ((index == GetPixelIndex(image,p)) &&
1931 (length < 255) && (x < ((ssize_t) image->columns-1)))
1937 q=PopHexPixel(hex_digits,(size_t) index,q);
1938 q=PopHexPixel(hex_digits,(size_t)
1939 MagickMin(length,0xff),q);
1941 if ((q-pixels+6) >= 80)
1944 (void) WriteBlob(image,q-pixels,pixels);
1950 index=GetPixelIndex(image,p);
1951 pixel.red=GetPixelRed(image,p);
1952 pixel.green=GetPixelGreen(image,p);
1953 pixel.blue=GetPixelBlue(image,p);
1954 pixel.alpha=GetPixelAlpha(image,p);
1955 p+=GetPixelChannels(image);
1957 q=PopHexPixel(hex_digits,(size_t) index,q);
1958 q=PopHexPixel(hex_digits,(size_t)
1959 MagickMin(length,0xff),q);
1960 if (image->previous == (Image *) NULL)
1962 status=SetImageProgress(image,SaveImageTag,
1963 (MagickOffsetType) y,image->rows);
1964 if (status == MagickFalse)
1971 (void) WriteBlob(image,q-pixels,pixels);
1979 Dump uncompressed PseudoColor packets.
1982 for (y=0; y < (ssize_t) image->rows; y++)
1984 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1985 if (p == (const Quantum *) NULL)
1987 for (x=0; x < (ssize_t) image->columns; x++)
1989 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
1990 if ((q-pixels+4) >= 80)
1993 (void) WriteBlob(image,q-pixels,pixels);
1996 p+=GetPixelChannels(image);
1998 if (image->previous == (Image *) NULL)
2000 status=SetImageProgress(image,SaveImageTag,
2001 (MagickOffsetType) y,image->rows);
2002 if (status == MagickFalse)
2009 (void) WriteBlob(image,q-pixels,pixels);
2014 (void) WriteBlobByte(image,'\n');
2016 if (LocaleCompare(image_info->magick,"PS") != 0)
2017 (void) WriteBlobString(image,"end\n");
2018 (void) WriteBlobString(image,"%%PageTrailer\n");
2019 if (GetNextImageInList(image) == (Image *) NULL)
2021 image=SyncNextImageInList(image);
2022 status=SetImageProgress(image,SaveImagesTag,scene++,
2023 GetImageListLength(image));
2024 if (status == MagickFalse)
2026 } while (image_info->adjoin != MagickFalse);
2027 (void) WriteBlobString(image,"%%Trailer\n");
2030 (void) FormatLocaleString(buffer,MaxTextExtent,
2031 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2032 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5));
2033 (void) WriteBlobString(image,buffer);
2034 (void) FormatLocaleString(buffer,MaxTextExtent,
2035 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
2037 (void) WriteBlobString(image,buffer);
2039 (void) WriteBlobString(image,"%%EOF\n");
2040 (void) CloseBlob(image);