2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Write Postscript Level III Format %
21 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/channel.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/compress.h"
53 #include "MagickCore/constitute.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/pixel-accessor.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/quantum-private.h"
69 #include "MagickCore/resource_.h"
70 #include "MagickCore/static.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/module.h"
73 #include "MagickCore/token.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/module.h"
80 #define PS3_NoCompression "0"
81 #define PS3_FaxCompression "1"
82 #define PS3_JPEGCompression "2"
83 #define PS3_LZWCompression "3"
84 #define PS3_RLECompression "4"
85 #define PS3_ZipCompression "5"
87 #define PS3_RGBColorspace "0"
88 #define PS3_CMYKColorspace "1"
90 #define PS3_DirectClass "0"
91 #define PS3_PseudoClass "1"
93 #if defined(MAGICKCORE_TIFF_DELEGATE)
94 #define CCITTParam "-1"
96 #define CCITTParam "0"
100 Forward declarations.
102 static MagickBooleanType
103 WritePS3Image(const ImageInfo *,Image *,ExceptionInfo *);
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % R e g i s t e r P S 3 I m a g e %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 % RegisterPS3Image() adds properties for the PS3 image format to the list of
117 % supported formats. The properties include the image format tag, a method to
118 % read and/or write the format, whether the format supports the saving of more
119 % than one frame to the same file or blob, whether the format supports native
120 % in-memory I/O, and a brief description of the format.
122 % The format of the RegisterPS3Image method is:
124 % size_t RegisterPS3Image(void)
127 ModuleExport size_t RegisterPS3Image(void)
132 entry=SetMagickInfo("EPS3");
133 entry->encoder=(EncodeImageHandler *) WritePS3Image;
134 entry->description=ConstantString("Level III Encapsulated PostScript");
135 entry->mime_type=ConstantString("application/postscript");
136 entry->module=ConstantString("PS3");
137 entry->seekable_stream=MagickTrue;
138 (void) RegisterMagickInfo(entry);
139 entry=SetMagickInfo("PS3");
140 entry->encoder=(EncodeImageHandler *) WritePS3Image;
141 entry->description=ConstantString("Level III PostScript");
142 entry->mime_type=ConstantString("application/postscript");
143 entry->module=ConstantString("PS3");
144 entry->seekable_stream=MagickTrue;
145 (void) RegisterMagickInfo(entry);
146 return(MagickImageCoderSignature);
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 % U n r e g i s t e r P S 3 I m a g e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % UnregisterPS3Image() removes format registrations made by the PS3 module
161 % from the list of supported formats.
163 % The format of the UnregisterPS3Image method is:
165 % UnregisterPS3Image(void)
168 ModuleExport void UnregisterPS3Image(void)
170 (void) UnregisterMagickInfo("EPS3");
171 (void) UnregisterMagickInfo("PS3");
175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179 % W r i t e P S 3 I m a g e %
183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 % WritePS3Image() translates an image to encapsulated Postscript Level III
186 % for printing. If the supplied geometry is null, the image is centered on
187 % the Postscript page. Otherwise, the image is positioned as specified by the
190 % The format of the WritePS3Image method is:
192 % MagickBooleanType WritePS3Image(const ImageInfo *image_info,
193 % Image *image,ExceptionInfo *exception)
195 % A description of each parameter follows:
197 % o image_info: Specifies a pointer to a ImageInfo structure.
199 % o image: the image.
201 % o exception: return any errors or warnings in this structure.
205 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
206 Image *image,Image *inject_image,ExceptionInfo *exception)
224 write_info=CloneImageInfo(image_info);
225 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
226 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
227 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
228 if (group4_image == (Image *) NULL)
230 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
232 group4_image=DestroyImage(group4_image);
233 if (group4 == (unsigned char *) NULL)
235 write_info=DestroyImageInfo(write_info);
236 if (WriteBlob(image,length,group4) != (ssize_t) length)
238 group4=(unsigned char *) RelinquishMagickMemory(group4);
242 static MagickBooleanType SerializeImage(const ImageInfo *image_info,
243 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
248 register const Quantum
254 register unsigned char
260 assert(image != (Image *) NULL);
261 assert(image->signature == MagickSignature);
262 if (image->debug != MagickFalse)
263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
265 *length=(image->colorspace == CMYKColorspace ? 4 : 3)*(size_t)
266 image->columns*image->rows;
267 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
268 if (*pixel_info == (MemoryInfo *) NULL)
269 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
270 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
271 for (y=0; y < (ssize_t) image->rows; y++)
273 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
274 if (p == (const Quantum *) NULL)
276 if (image->colorspace != CMYKColorspace)
277 for (x=0; x < (ssize_t) image->columns; x++)
279 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
280 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
281 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
282 p+=GetPixelChannels(image);
285 for (x=0; x < (ssize_t) image->columns; x++)
287 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
288 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
289 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
290 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
291 p+=GetPixelChannels(image);
293 if (image->previous == (Image *) NULL)
295 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
297 if (status == MagickFalse)
301 if (status == MagickFalse)
302 *pixel_info=RelinquishVirtualMemory(*pixel_info);
306 static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
307 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
312 register const Quantum
318 register unsigned char
332 assert(image != (Image *) NULL);
333 assert(image->signature == MagickSignature);
334 if (image->debug != MagickFalse)
335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
337 pack=IsImageMonochrome(image,exception) == MagickFalse ? 1UL : 8UL;
338 padded_columns=((image->columns+pack-1)/pack)*pack;
339 *length=(size_t) padded_columns*image->rows/pack;
340 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
341 if (*pixel_info == (MemoryInfo *) NULL)
342 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
343 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
344 for (y=0; y < (ssize_t) image->rows; y++)
346 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
347 if (p == (const Quantum *) NULL)
350 for (x=0; x < (ssize_t) image->columns; x++)
352 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
353 p+=GetPixelChannels(image);
358 for (x=0; x < (ssize_t) padded_columns; x++)
360 bit=(unsigned char) 0x00;
361 if (x < (ssize_t) image->columns)
362 bit=(unsigned char) (GetPixelLuma(image,p) == TransparentAlpha ?
364 code=(code << 1)+bit;
365 if (((x+1) % pack) == 0)
370 p+=GetPixelChannels(image);
373 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
375 if (status == MagickFalse)
378 if (status == MagickFalse)
379 *pixel_info=RelinquishVirtualMemory(*pixel_info);
383 static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
384 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
389 register const Quantum
395 register unsigned char
401 assert(image != (Image *) NULL);
402 assert(image->signature == MagickSignature);
403 if (image->debug != MagickFalse)
404 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
406 *length=(size_t) image->columns*image->rows;
407 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
408 if (*pixel_info == (MemoryInfo *) NULL)
409 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
410 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
411 for (y=0; y < (ssize_t) image->rows; y++)
413 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
414 if (p == (const Quantum *) NULL)
416 for (x=0; x < (ssize_t) image->columns; x++)
418 *q++=(unsigned char) GetPixelIndex(image,p);
419 p+=GetPixelChannels(image);
421 if (image->previous == (Image *) NULL)
423 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
425 if (status == MagickFalse)
429 if (status == MagickFalse)
430 *pixel_info=RelinquishVirtualMemory(*pixel_info);
434 static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
435 Image *image,const CompressionType compression,ExceptionInfo *exception)
438 buffer[MaxTextExtent];
463 assert(image_info != (ImageInfo *) NULL);
464 assert(image_info->signature == MagickSignature);
465 assert(image != (Image *) NULL);
466 assert(image->signature == MagickSignature);
467 if (image->debug != MagickFalse)
468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
469 assert(image->alpha_trait == BlendPixelTrait);
472 Note BeginData DSC comment for update later.
474 start=TellBlob(image);
475 (void) FormatLocaleString(buffer,MaxTextExtent,
476 "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
478 (void) WriteBlobString(image,buffer);
479 stop=TellBlob(image);
481 Only lossless compressions for the mask.
488 (void) FormatLocaleString(buffer,MaxTextExtent,
489 "currentfile %.20g %.20g "PS3_NoCompression" ByteStreamDecodeFilter\n",
490 (double) image->columns,(double) image->rows);
494 case Group4Compression:
496 (void) FormatLocaleString(buffer,MaxTextExtent,
497 "currentfile %.20g %.20g "PS3_FaxCompression" ByteStreamDecodeFilter\n",
498 (double) image->columns,(double) image->rows);
503 (void) FormatLocaleString(buffer,MaxTextExtent,
504 "currentfile %.20g %.20g "PS3_LZWCompression" ByteStreamDecodeFilter\n",
505 (double) image->columns,(double) image->rows);
510 (void) FormatLocaleString(buffer,MaxTextExtent,
511 "currentfile %.20g %.20g "PS3_RLECompression" ByteStreamDecodeFilter\n",
512 (double) image->columns,(double) image->rows);
517 (void) FormatLocaleString(buffer,MaxTextExtent,
518 "currentfile %.20g %.20g "PS3_ZipCompression" ByteStreamDecodeFilter\n",
519 (double) image->columns,(double) image->rows);
523 (void) WriteBlobString(image,buffer);
524 (void) WriteBlobString(image,"/ReusableStreamDecode filter\n");
525 mask_image=SeparateImage(image,AlphaChannel,exception);
526 if (mask_image == (Image *) NULL)
527 ThrowWriterException(CoderError,exception->reason);
528 (void) SetImageType(mask_image,BilevelType,exception);
529 (void) SetImageType(mask_image,PaletteType,exception);
530 mask_image->alpha_trait=UndefinedPixelTrait;
531 pixels=(unsigned char *) NULL;
538 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
540 if (status == MagickFalse)
542 Ascii85Initialize(image);
543 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
544 for (i=0; i < (ssize_t) length; i++)
545 Ascii85Encode(image,pixels[i]);
547 pixel_info=RelinquishVirtualMemory(pixel_info);
551 case Group4Compression:
553 if ((compression == FaxCompression) ||
554 (LocaleCompare(CCITTParam,"0") == 0))
555 status=HuffmanEncodeImage(image_info,image,mask_image,exception);
557 status=Huffman2DEncodeImage(image_info,image,mask_image,exception);
562 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
564 if (status == MagickFalse)
566 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
567 status=LZWEncodeImage(image,length,pixels,exception);
568 pixel_info=RelinquishVirtualMemory(pixel_info);
573 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
575 if (status == MagickFalse)
577 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
578 status=PackbitsEncodeImage(image,length,pixels,exception);
579 pixel_info=RelinquishVirtualMemory(pixel_info);
584 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
586 if (status == MagickFalse)
588 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
589 status=ZLIBEncodeImage(image,length,pixels,exception);
590 pixel_info=RelinquishVirtualMemory(pixel_info);
594 mask_image=DestroyImage(mask_image);
595 (void) WriteBlobByte(image,'\n');
596 length=(size_t) (TellBlob(image)-stop);
597 stop=TellBlob(image);
598 offset=SeekBlob(image,start,SEEK_SET);
600 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
601 (void) FormatLocaleString(buffer,MaxTextExtent,
602 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
603 compression == NoCompression ? "ASCII" : "BINARY");
604 (void) WriteBlobString(image,buffer);
605 offset=SeekBlob(image,stop,SEEK_SET);
607 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
608 (void) WriteBlobString(image,"%%EndData\n");
609 (void) WriteBlobString(image, "/mask_stream exch def\n");
613 static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
614 ExceptionInfo *exception)
619 "/ByteStreamDecodeFilter",
624 " z "PS3_NoCompression" eq { /ASCII85Decode filter } if",
625 " z "PS3_FaxCompression" eq",
632 " /CCITTFaxDecode filter",
634 " z "PS3_JPEGCompression" eq { /DCTDecode filter } if",
635 " z "PS3_LZWCompression" eq { /LZWDecode filter } if",
636 " z "PS3_RLECompression" eq { /RunLengthDecode filter } if",
637 " z "PS3_ZipCompression" eq { /FlateDecode filter } if",
640 "/DirectClassImageDict",
642 " colorspace "PS3_RGBColorspace" eq",
644 " /DeviceRGB setcolorspace",
649 " /BitsPerComponent 8",
650 " /DataSource pixel_stream",
651 " /MultipleDataSources false",
652 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
653 " /Decode [0 1 0 1 0 1]",
657 " /DeviceCMYK setcolorspace",
662 " /BitsPerComponent 8",
663 " /DataSource pixel_stream",
664 " /MultipleDataSources false",
665 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
667 " compression "PS3_JPEGCompression" eq",
668 " { [1 0 1 0 1 0 1 0] }",
669 " { [0 1 0 1 0 1 0 1] }",
676 "/PseudoClassImageDict",
678 " % Colors in colormap image.",
679 " currentfile buffer readline pop",
680 " token pop /colors exch def pop",
683 " % Depth of grayscale image.",
684 " currentfile buffer readline pop",
685 " token pop /bits exch def pop",
686 " /DeviceGray setcolorspace",
691 " /BitsPerComponent bits",
693 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
694 " /DataSource pixel_stream",
699 " /colormap colors 3 mul string def",
700 " compression "PS3_NoCompression" eq",
701 " { currentfile /ASCII85Decode filter colormap readstring pop pop }",
702 " { currentfile colormap readstring pop pop }",
704 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
709 " /BitsPerComponent 8",
711 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
712 " /DataSource pixel_stream",
718 "/NonMaskedImageDict",
720 " class "PS3_PseudoClass" eq",
721 " { PseudoClassImageDict }",
722 " { DirectClassImageDict }",
730 " /InterleaveType 3",
731 " /DataDict NonMaskedImageDict",
737 " /BitsPerComponent 1",
738 " /DataSource mask_stream",
739 " /MultipleDataSources false",
740 " /ImageMatrix [ columns 0 0 rows neg 0 rows]",
752 " /buffer 512 string def",
754 " currentfile buffer readline pop",
755 " token pop /x exch def",
756 " token pop /y exch def pop",
758 " % Image size and font size.",
759 " currentfile buffer readline pop",
760 " token pop /x exch def",
761 " token pop /y exch def pop",
762 " currentfile buffer readline pop",
763 " token pop /pointsize exch def pop",
770 " currentfile buffer readline pop",
771 " token pop /clipped exch def pop",
773 " currentfile buffer readline pop",
774 " token pop /sp exch def pop",
775 " % Image pixel size.",
776 " currentfile buffer readline pop",
777 " token pop /columns exch def",
778 " token pop /rows exch def pop",
779 " % Colorspace (RGB/CMYK).",
780 " currentfile buffer readline pop",
781 " token pop /colorspace exch def pop",
783 " currentfile buffer readline pop",
784 " token pop /alpha exch def pop",
786 " currentfile buffer readline pop",
787 " token pop /stencil exch def pop",
788 " % Image class (direct/pseudo).",
789 " currentfile buffer readline pop",
790 " token pop /class exch def pop",
791 " % Compression type.",
792 " currentfile buffer readline pop",
793 " token pop /compression exch def pop",
794 " % Clip and render.",
795 " /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def",
796 " clipped { ClipImage } if",
797 " alpha stencil not and",
798 " { MaskedImageDict mask_stream resetfile }",
799 " { NonMaskedImageDict }",
801 " stencil { 0 setgray imagemask } { image } ifelse",
803 " sp { showpage } if",
809 buffer[MaxTextExtent],
812 page_geometry[MaxTextExtent];
875 Open output image file.
877 assert(image_info != (const ImageInfo *) NULL);
878 assert(image_info->signature == MagickSignature);
879 assert(image != (Image *) NULL);
880 assert(image->signature == MagickSignature);
881 if (image->debug != MagickFalse)
882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
883 assert(exception != (ExceptionInfo *) NULL);
884 assert(exception->signature == MagickSignature);
885 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
886 if (status == MagickFalse)
888 compression=image->compression;
889 if (image_info->compression != UndefinedCompression)
890 compression=image_info->compression;
894 case Group4Compression:
896 if ((IsImageMonochrome(image,exception) == MagickFalse) ||
897 (image->alpha_trait == BlendPixelTrait))
898 compression=RLECompression;
901 #if !defined(MAGICKCORE_JPEG_DELEGATE)
902 case JPEGCompression:
904 compression=RLECompression;
905 (void) ThrowMagickException(exception,GetMagickModule(),
906 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
911 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
914 compression=RLECompression;
915 (void) ThrowMagickException(exception,GetMagickModule(),
916 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
924 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
930 Scale relative to dots-per-inch.
932 delta.x=DefaultResolution;
933 delta.y=DefaultResolution;
934 resolution.x=image->resolution.x;
935 resolution.y=image->resolution.y;
936 if ((resolution.x == 0.0) || (resolution.y == 0.0))
938 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
939 resolution.x=geometry_info.rho;
940 resolution.y=geometry_info.sigma;
941 if ((flags & SigmaValue) == 0)
942 resolution.y=resolution.x;
944 if (image_info->density != (char *) NULL)
946 flags=ParseGeometry(image_info->density,&geometry_info);
947 resolution.x=geometry_info.rho;
948 resolution.y=geometry_info.sigma;
949 if ((flags & SigmaValue) == 0)
950 resolution.y=resolution.x;
952 if (image->units == PixelsPerCentimeterResolution)
954 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
955 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
957 SetGeometry(image,&geometry);
958 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
959 (double) image->columns,(double) image->rows);
960 if (image_info->page != (char *) NULL)
961 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
963 if ((image->page.width != 0) && (image->page.height != 0))
964 (void) FormatLocaleString(page_geometry,MaxTextExtent,
965 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
966 image->page.height,(double) image->page.x,(double) image->page.y);
968 if ((image->gravity != UndefinedGravity) &&
969 (LocaleCompare(image_info->magick,"PS") == 0))
970 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
971 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
972 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
973 &geometry.width,&geometry.height);
974 scale.x=(double) (geometry.width*delta.x)/resolution.x;
975 geometry.width=(size_t) floor(scale.x+0.5);
976 scale.y=(double) (geometry.height*delta.y)/resolution.y;
977 geometry.height=(size_t) floor(scale.y+0.5);
978 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
979 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
980 if (image->gravity != UndefinedGravity)
982 geometry.x=(-page_info.x);
983 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
986 if (image_info->pointsize != 0.0)
987 pointsize=image_info->pointsize;
989 value=GetImageProperty(image,"label",exception);
990 if (value != (const char *) NULL)
991 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
996 Postscript header on the first page.
998 if (LocaleCompare(image_info->magick,"PS3") == 0)
999 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1001 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1003 (void) WriteBlobString(image,buffer);
1004 (void) FormatLocaleString(buffer,MaxTextExtent,
1005 "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
1006 (void) WriteBlobString(image,buffer);
1007 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: %s\n",
1009 (void) WriteBlobString(image,buffer);
1010 timer=time((time_t *) NULL);
1011 (void) FormatMagickTime(timer,MaxTextExtent,date);
1012 (void) FormatLocaleString(buffer,MaxTextExtent,
1013 "%%%%CreationDate: %s\n",date);
1014 (void) WriteBlobString(image,buffer);
1015 bounds.x1=(double) geometry.x;
1016 bounds.y1=(double) geometry.y;
1017 bounds.x2=(double) geometry.x+scale.x;
1018 bounds.y2=(double) geometry.y+scale.y+text_size;
1019 if ((image_info->adjoin != MagickFalse) &&
1020 (GetNextImageInList(image) != (Image *) NULL))
1022 (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1023 (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1027 (void) FormatLocaleString(buffer,MaxTextExtent,
1028 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1029 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1030 (void) WriteBlobString(image,buffer);
1031 (void) FormatLocaleString(buffer,MaxTextExtent,
1032 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1033 bounds.y1,bounds.x2,bounds.y2);
1034 (void) WriteBlobString(image,buffer);
1035 if (image->colorspace == CMYKColorspace)
1036 (void) WriteBlobString(image,
1037 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1039 if (IsImageGray(image,exception) != MagickFalse)
1040 (void) WriteBlobString(image,
1041 "%%DocumentProcessColors: Black\n");
1046 value=GetImageProperty(image,"label",exception);
1047 if (value != (const char *) NULL)
1048 (void) WriteBlobString(image,
1049 "%%DocumentNeededResources: font Helvetica\n");
1050 (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1052 Pages, orientation and order.
1054 if (LocaleCompare(image_info->magick,"PS3") != 0)
1055 (void) WriteBlobString(image,"%%Pages: 1\n");
1058 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1059 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1060 if (image_info->adjoin == MagickFalse)
1061 (void) CopyMagickString(buffer,"%%Pages: 1\n",MaxTextExtent);
1063 (void) FormatLocaleString(buffer,MaxTextExtent,
1064 "%%%%Pages: %.20g\n",(double) GetImageListLength(image));
1065 (void) WriteBlobString(image,buffer);
1067 if (image->colorspace == CMYKColorspace)
1068 (void) WriteBlobString(image,
1069 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1070 (void) WriteBlobString(image,"%%EndComments\n");
1072 The static postscript procedures prolog.
1074 (void)WriteBlobString(image,"%%BeginProlog\n");
1075 for (q=PostscriptProlog; *q; q++)
1077 (void) WriteBlobString(image,*q);
1078 (void) WriteBlobByte(image,'\n');
1081 One label line for each line in label string.
1083 value=GetImageProperty(image,"label",exception);
1084 if (value != (const char *) NULL)
1086 (void) WriteBlobString(image,"\n %% Labels.\n /Helvetica "
1087 " findfont pointsize scalefont setfont\n");
1088 for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
1090 (void) WriteBlobString(image,
1091 " currentfile buffer readline pop token pop\n");
1092 (void) FormatLocaleString(buffer,MaxTextExtent,
1093 " 0 y %g add moveto show pop\n",i*pointsize+12);
1094 (void) WriteBlobString(image,buffer);
1098 The static postscript procedures epilog.
1100 for (q=PostscriptEpilog; *q; q++)
1102 (void) WriteBlobString(image,*q);
1103 (void) WriteBlobByte(image,'\n');
1105 (void)WriteBlobString(image,"%%EndProlog\n");
1107 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
1109 (void) WriteBlobString(image,buffer);
1113 (void) FormatLocaleString(buffer,MaxTextExtent,
1114 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1115 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
1116 (double) (geometry.height+text_size));
1117 (void) WriteBlobString(image,buffer);
1119 Page process colors if not RGB.
1121 if (image->colorspace == CMYKColorspace)
1122 (void) WriteBlobString(image,
1123 "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1125 if (IsImageGray(image,exception) != MagickFalse)
1126 (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1128 Adjust document bounding box to bound page bounding box.
1130 if ((double) geometry.x < bounds.x1)
1131 bounds.x1=(double) geometry.x;
1132 if ((double) geometry.y < bounds.y1)
1133 bounds.y1=(double) geometry.y;
1134 if ((double) (geometry.x+scale.x) > bounds.x2)
1135 bounds.x2=(double) geometry.x+scale.x;
1136 if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
1137 bounds.y2=(double) geometry.y+scale.y+text_size;
1139 Page font resource if there's a label.
1141 value=GetImageProperty(image,"label",exception);
1142 if (value != (const char *) NULL)
1143 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1145 PS clipping path from Photoshop clipping path.
1147 if ((image->read_mask != MagickFalse) ||
1148 (LocaleNCompare("8BIM:",image->magick_filename,5) != 0))
1149 (void) WriteBlobString(image,"/ClipImage {} def\n");
1155 value=GetImageProperty(image,image->magick_filename,exception);
1156 if (value == (const char *) NULL)
1157 return(MagickFalse);
1158 (void) WriteBlobString(image,value);
1159 (void) WriteBlobByte(image,'\n');
1162 Push a dictionary for our own def's if this an EPS.
1164 if (LocaleCompare(image_info->magick,"PS3") != 0)
1165 (void) WriteBlobString(image,"userdict begin\n");
1169 if ((image->alpha_trait == BlendPixelTrait) &&
1170 (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
1172 (void) CloseBlob(image);
1173 return(MagickFalse);
1176 Remember position of BeginData comment so we can update it.
1178 start=TellBlob(image);
1179 (void) FormatLocaleString(buffer,MaxTextExtent,
1180 "%%%%BeginData:%13ld %s Bytes\n",0L,
1181 compression == NoCompression ? "ASCII" : "BINARY");
1182 (void) WriteBlobString(image,buffer);
1183 stop=TellBlob(image);
1184 (void) WriteBlobString(image,"DisplayImage\n");
1186 Translate, scale, and font point size.
1188 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
1189 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1190 (void) WriteBlobString(image,buffer);
1194 labels=(char **) NULL;
1195 value=GetImageProperty(image,"label",exception);
1196 if (value != (const char *) NULL)
1197 labels=StringToList(value);
1198 if (labels != (char **) NULL)
1200 for (i=0; labels[i] != (char *) NULL; i++)
1202 if (compression != NoCompression)
1204 for (j=0; labels[i][j] != '\0'; j++)
1205 (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
1206 (void) WriteBlobByte(image,'\n');
1210 (void) WriteBlobString(image,"<~");
1211 Ascii85Initialize(image);
1212 for (j=0; labels[i][j] != '\0'; j++)
1213 Ascii85Encode(image,(unsigned char) labels[i][j]);
1214 Ascii85Flush(image);
1216 labels[i]=DestroyString(labels[i]);
1218 labels=(char **) RelinquishMagickMemory(labels);
1221 Photoshop clipping path active?
1223 if ((image->read_mask != MagickFalse) &&
1224 (LocaleNCompare("8BIM:",image->magick_filename,5) == 0))
1225 (void) WriteBlobString(image,"true\n");
1227 (void) WriteBlobString(image,"false\n");
1229 Showpage for non-EPS.
1231 (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
1232 "true\n" : "false\n");
1234 Image columns, rows, and color space.
1236 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%s\n",
1237 (double) image->columns,(double) image->rows,image->colorspace ==
1238 CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
1239 (void) WriteBlobString(image,buffer);
1243 (void) WriteBlobString(image,image->alpha_trait == BlendPixelTrait ?
1244 "true\n" : "false\n");
1246 Render with imagemask operator?
1248 option=GetImageOption(image_info,"ps3:imagemask");
1249 (void) WriteBlobString(image,((option != (const char *) NULL) &&
1250 (IsImageMonochrome(image,exception) != MagickFalse)) ?
1251 "true\n" : "false\n");
1255 pixels=(unsigned char *) NULL;
1257 if ((image_info->type != TrueColorType) &&
1258 (image_info->type != TrueColorMatteType) &&
1259 (image_info->type != ColorSeparationType) &&
1260 (image_info->type != ColorSeparationMatteType) &&
1261 (image->colorspace != CMYKColorspace) &&
1262 ((IsImageGray(image,exception) != MagickFalse) ||
1263 (IsImageMonochrome(image,exception) != MagickFalse)))
1268 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1269 switch (compression)
1274 (void) WriteBlobString(image,PS3_NoCompression"\n");
1277 case FaxCompression:
1278 case Group4Compression:
1280 (void) WriteBlobString(image,PS3_FaxCompression"\n");
1283 case JPEGCompression:
1285 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1288 case LZWCompression:
1290 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1293 case RLECompression:
1295 (void) WriteBlobString(image,PS3_RLECompression"\n");
1298 case ZipCompression:
1300 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1305 Number of colors -- 0 for single component non-color mapped data.
1307 (void) WriteBlobString(image,"0\n");
1309 1 bit or 8 bit components?
1311 (void) FormatLocaleString(buffer,MaxTextExtent,"%d\n",
1312 IsImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
1313 (void) WriteBlobString(image,buffer);
1317 if (compression == JPEGCompression)
1318 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1320 if ((compression == FaxCompression) ||
1321 (compression == Group4Compression))
1323 if (LocaleCompare(CCITTParam,"0") == 0)
1324 status=HuffmanEncodeImage(image_info,image,image,exception);
1326 status=Huffman2DEncodeImage(image_info,image,image,exception);
1330 status=SerializeImageChannel(image_info,image,&pixel_info,&length,
1332 if (status == MagickFalse)
1334 (void) CloseBlob(image);
1335 return(MagickFalse);
1337 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1338 switch (compression)
1343 Ascii85Initialize(image);
1344 for (i=0; i < (ssize_t) length; i++)
1345 Ascii85Encode(image,pixels[i]);
1346 Ascii85Flush(image);
1350 case LZWCompression:
1352 status=LZWEncodeImage(image,length,pixels,exception);
1355 case RLECompression:
1357 status=PackbitsEncodeImage(image,length,pixels,exception);
1360 case ZipCompression:
1362 status=ZLIBEncodeImage(image,length,pixels,exception);
1366 pixel_info=RelinquishVirtualMemory(pixel_info);
1370 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1371 (compression == JPEGCompression))
1376 (void) WriteBlobString(image,PS3_DirectClass"\n");
1377 switch (compression)
1382 (void) WriteBlobString(image,PS3_NoCompression"\n");
1385 case RLECompression:
1387 (void) WriteBlobString(image,PS3_RLECompression"\n");
1390 case JPEGCompression:
1392 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1395 case LZWCompression:
1397 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1400 case ZipCompression:
1402 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1409 if (compression == JPEGCompression)
1410 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1414 Stream based compressions.
1416 status=SerializeImage(image_info,image,&pixel_info,&length,
1418 if (status == MagickFalse)
1420 (void) CloseBlob(image);
1421 return(MagickFalse);
1423 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1424 switch (compression)
1429 Ascii85Initialize(image);
1430 for (i=0; i < (ssize_t) length; i++)
1431 Ascii85Encode(image,pixels[i]);
1432 Ascii85Flush(image);
1436 case RLECompression:
1438 status=PackbitsEncodeImage(image,length,pixels,exception);
1441 case LZWCompression:
1443 status=LZWEncodeImage(image,length,pixels,exception);
1446 case ZipCompression:
1448 status=ZLIBEncodeImage(image,length,pixels,exception);
1452 pixel_info=RelinquishVirtualMemory(pixel_info);
1460 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1461 switch (compression)
1466 (void) WriteBlobString(image,PS3_NoCompression"\n");
1469 case JPEGCompression:
1471 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1474 case RLECompression:
1476 (void) WriteBlobString(image,PS3_RLECompression"\n");
1479 case LZWCompression:
1481 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1484 case ZipCompression:
1486 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1491 Number of colors in color map.
1493 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",
1494 (double) image->colors);
1495 (void) WriteBlobString(image,buffer);
1497 Color map - uncompressed.
1499 if ((compression != NoCompression) &&
1500 (compression != UndefinedCompression))
1502 for (i=0; i < (ssize_t) image->colors; i++)
1504 pixel=ScaleQuantumToChar(image->colormap[i].red);
1505 (void) WriteBlobByte(image,(unsigned char) pixel);
1506 pixel=ScaleQuantumToChar(image->colormap[i].green);
1507 (void) WriteBlobByte(image,(unsigned char) pixel);
1508 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1509 (void) WriteBlobByte(image,(unsigned char) pixel);
1514 Ascii85Initialize(image);
1515 for (i=0; i < (ssize_t) image->colors; i++)
1517 pixel=ScaleQuantumToChar(image->colormap[i].red);
1518 Ascii85Encode(image,(unsigned char) pixel);
1519 pixel=ScaleQuantumToChar(image->colormap[i].green);
1520 Ascii85Encode(image,(unsigned char) pixel);
1521 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1522 Ascii85Encode(image,(unsigned char) pixel);
1524 Ascii85Flush(image);
1526 status=SerializeImageIndexes(image_info,image,&pixel_info,&length,
1528 if (status == MagickFalse)
1530 (void) CloseBlob(image);
1531 return(MagickFalse);
1533 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1534 switch (compression)
1539 Ascii85Initialize(image);
1540 for (i=0; i < (ssize_t) length; i++)
1541 Ascii85Encode(image,pixels[i]);
1542 Ascii85Flush(image);
1546 case JPEGCompression:
1548 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1551 case RLECompression:
1553 status=PackbitsEncodeImage(image,length,pixels,exception);
1556 case LZWCompression:
1558 status=LZWEncodeImage(image,length,pixels,exception);
1561 case ZipCompression:
1563 status=ZLIBEncodeImage(image,length,pixels,exception);
1567 pixel_info=RelinquishVirtualMemory(pixel_info);
1569 (void) WriteBlobByte(image,'\n');
1570 if (status == MagickFalse)
1572 (void) CloseBlob(image);
1573 return(MagickFalse);
1576 Update BeginData now that we know the data size.
1578 length=(size_t) (TellBlob(image)-stop);
1579 stop=TellBlob(image);
1580 offset=SeekBlob(image,start,SEEK_SET);
1582 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1583 (void) FormatLocaleString(buffer,MaxTextExtent,
1584 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1585 compression == NoCompression ? "ASCII" : "BINARY");
1586 (void) WriteBlobString(image,buffer);
1587 offset=SeekBlob(image,stop,SEEK_SET);
1588 (void) WriteBlobString(image,"%%EndData\n");
1590 End private dictionary if this an EPS.
1592 if (LocaleCompare(image_info->magick,"PS3") != 0)
1593 (void) WriteBlobString(image,"end\n");
1594 (void) WriteBlobString(image,"%%PageTrailer\n");
1595 if (GetNextImageInList(image) == (Image *) NULL)
1597 image=SyncNextImageInList(image);
1598 status=SetImageProgress(image,SaveImagesTag,scene++,
1599 GetImageListLength(image));
1600 if (status == MagickFalse)
1602 } while (image_info->adjoin != MagickFalse);
1603 (void) WriteBlobString(image,"%%Trailer\n");
1606 (void) FormatLocaleString(buffer,MaxTextExtent,
1607 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1608 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1609 (void) WriteBlobString(image,buffer);
1610 (void) FormatLocaleString(buffer,MaxTextExtent,
1611 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1613 (void) WriteBlobString(image,buffer);
1615 (void) WriteBlobString(image,"%%EOF\n");
1616 (void) CloseBlob(image);