2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Write Postscript Level III Format %
21 % Copyright 1999-2016 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=AcquireMagickInfo("PS3","EPS3","Level III Encapsulated PostScript");
133 entry->encoder=(EncodeImageHandler *) WritePS3Image;
134 entry->mime_type=ConstantString("application/postscript");
135 entry->flags|=CoderSeekableStreamFlag;
136 (void) RegisterMagickInfo(entry);
137 entry=AcquireMagickInfo("PS3","PS3","Level III PostScript");
138 entry->encoder=(EncodeImageHandler *) WritePS3Image;
139 entry->mime_type=ConstantString("application/postscript");
140 entry->flags|=CoderSeekableStreamFlag;
141 (void) RegisterMagickInfo(entry);
142 return(MagickImageCoderSignature);
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 % U n r e g i s t e r P S 3 I m a g e %
154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 % UnregisterPS3Image() removes format registrations made by the PS3 module
157 % from the list of supported formats.
159 % The format of the UnregisterPS3Image method is:
161 % UnregisterPS3Image(void)
164 ModuleExport void UnregisterPS3Image(void)
166 (void) UnregisterMagickInfo("EPS3");
167 (void) UnregisterMagickInfo("PS3");
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175 % W r i t e P S 3 I m a g e %
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
181 % WritePS3Image() translates an image to encapsulated Postscript Level III
182 % for printing. If the supplied geometry is null, the image is centered on
183 % the Postscript page. Otherwise, the image is positioned as specified by the
186 % The format of the WritePS3Image method is:
188 % MagickBooleanType WritePS3Image(const ImageInfo *image_info,
189 % Image *image,ExceptionInfo *exception)
191 % A description of each parameter follows:
193 % o image_info: Specifies a pointer to a ImageInfo structure.
195 % o image: the image.
197 % o exception: return any errors or warnings in this structure.
201 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
202 Image *image,Image *inject_image,ExceptionInfo *exception)
220 write_info=CloneImageInfo(image_info);
221 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
222 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
223 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
224 if (group4_image == (Image *) NULL)
226 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
228 group4_image=DestroyImage(group4_image);
229 if (group4 == (unsigned char *) NULL)
231 write_info=DestroyImageInfo(write_info);
232 if (WriteBlob(image,length,group4) != (ssize_t) length)
234 group4=(unsigned char *) RelinquishMagickMemory(group4);
238 static MagickBooleanType SerializeImage(const ImageInfo *image_info,
239 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
244 register const Quantum
250 register unsigned char
256 assert(image != (Image *) NULL);
257 assert(image->signature == MagickCoreSignature);
258 if (image->debug != MagickFalse)
259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
261 *length=(image->colorspace == CMYKColorspace ? 4 : 3)*(size_t)
262 image->columns*image->rows;
263 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
264 if (*pixel_info == (MemoryInfo *) NULL)
265 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
266 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
267 for (y=0; y < (ssize_t) image->rows; y++)
269 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
270 if (p == (const Quantum *) NULL)
272 if (image->colorspace != CMYKColorspace)
273 for (x=0; x < (ssize_t) image->columns; x++)
275 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
276 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
277 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
278 p+=GetPixelChannels(image);
281 for (x=0; x < (ssize_t) image->columns; x++)
283 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
284 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
285 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
286 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
287 p+=GetPixelChannels(image);
289 if (image->previous == (Image *) NULL)
291 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
293 if (status == MagickFalse)
297 if (status == MagickFalse)
298 *pixel_info=RelinquishVirtualMemory(*pixel_info);
302 static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
303 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
308 register const Quantum
314 register unsigned char
328 assert(image != (Image *) NULL);
329 assert(image->signature == MagickCoreSignature);
330 if (image->debug != MagickFalse)
331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
333 pack=SetImageMonochrome(image,exception) == MagickFalse ? 1UL : 8UL;
334 padded_columns=((image->columns+pack-1)/pack)*pack;
335 *length=(size_t) padded_columns*image->rows/pack;
336 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
337 if (*pixel_info == (MemoryInfo *) NULL)
338 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
339 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
340 for (y=0; y < (ssize_t) image->rows; y++)
342 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
343 if (p == (const Quantum *) NULL)
346 for (x=0; x < (ssize_t) image->columns; x++)
348 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
349 p+=GetPixelChannels(image);
354 for (x=0; x < (ssize_t) padded_columns; x++)
356 bit=(unsigned char) 0x00;
357 if (x < (ssize_t) image->columns)
358 bit=(unsigned char) (GetPixelLuma(image,p) == TransparentAlpha ?
360 code=(code << 1)+bit;
361 if (((x+1) % pack) == 0)
366 p+=GetPixelChannels(image);
369 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
371 if (status == MagickFalse)
374 if (status == MagickFalse)
375 *pixel_info=RelinquishVirtualMemory(*pixel_info);
379 static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
380 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
385 register const Quantum
391 register unsigned char
397 assert(image != (Image *) NULL);
398 assert(image->signature == MagickCoreSignature);
399 if (image->debug != MagickFalse)
400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
402 *length=(size_t) image->columns*image->rows;
403 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
404 if (*pixel_info == (MemoryInfo *) NULL)
405 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
406 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
407 for (y=0; y < (ssize_t) image->rows; y++)
409 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
410 if (p == (const Quantum *) NULL)
412 for (x=0; x < (ssize_t) image->columns; x++)
414 *q++=(unsigned char) GetPixelIndex(image,p);
415 p+=GetPixelChannels(image);
417 if (image->previous == (Image *) NULL)
419 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
421 if (status == MagickFalse)
425 if (status == MagickFalse)
426 *pixel_info=RelinquishVirtualMemory(*pixel_info);
430 static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
431 Image *image,const CompressionType compression,ExceptionInfo *exception)
434 buffer[MagickPathExtent];
459 assert(image_info != (ImageInfo *) NULL);
460 assert(image_info->signature == MagickCoreSignature);
461 assert(image != (Image *) NULL);
462 assert(image->signature == MagickCoreSignature);
463 if (image->debug != MagickFalse)
464 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
465 assert(image->alpha_trait != UndefinedPixelTrait);
468 Note BeginData DSC comment for update later.
470 start=TellBlob(image);
472 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
473 (void) FormatLocaleString(buffer,MagickPathExtent,
474 "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
476 (void) WriteBlobString(image,buffer);
477 stop=TellBlob(image);
479 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
481 Only lossless compressions for the mask.
488 (void) FormatLocaleString(buffer,MagickPathExtent,
489 "currentfile %.20g %.20g "PS3_NoCompression" ByteStreamDecodeFilter\n",
490 (double) image->columns,(double) image->rows);
494 case Group4Compression:
496 (void) FormatLocaleString(buffer,MagickPathExtent,
497 "currentfile %.20g %.20g "PS3_FaxCompression" ByteStreamDecodeFilter\n",
498 (double) image->columns,(double) image->rows);
503 (void) FormatLocaleString(buffer,MagickPathExtent,
504 "currentfile %.20g %.20g "PS3_LZWCompression" ByteStreamDecodeFilter\n",
505 (double) image->columns,(double) image->rows);
510 (void) FormatLocaleString(buffer,MagickPathExtent,
511 "currentfile %.20g %.20g "PS3_RLECompression" ByteStreamDecodeFilter\n",
512 (double) image->columns,(double) image->rows);
517 (void) FormatLocaleString(buffer,MagickPathExtent,
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);
599 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
600 offset=SeekBlob(image,start,SEEK_SET);
602 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
603 (void) FormatLocaleString(buffer,MagickPathExtent,
604 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
605 compression == NoCompression ? "ASCII" : "BINARY");
606 (void) WriteBlobString(image,buffer);
607 offset=SeekBlob(image,stop,SEEK_SET);
609 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
610 (void) WriteBlobString(image,"%%EndData\n");
611 (void) WriteBlobString(image, "/mask_stream exch def\n");
615 static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
616 ExceptionInfo *exception)
619 *const PostscriptProlog[]=
621 "/ByteStreamDecodeFilter",
626 " z "PS3_NoCompression" eq { /ASCII85Decode filter } if",
627 " z "PS3_FaxCompression" eq",
634 " /CCITTFaxDecode filter",
636 " z "PS3_JPEGCompression" eq { /DCTDecode filter } if",
637 " z "PS3_LZWCompression" eq { /LZWDecode filter } if",
638 " z "PS3_RLECompression" eq { /RunLengthDecode filter } if",
639 " z "PS3_ZipCompression" eq { /FlateDecode filter } if",
642 "/DirectClassImageDict",
644 " colorspace "PS3_RGBColorspace" eq",
646 " /DeviceRGB setcolorspace",
651 " /BitsPerComponent 8",
652 " /DataSource pixel_stream",
653 " /MultipleDataSources false",
654 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
655 " /Decode [0 1 0 1 0 1]",
659 " /DeviceCMYK setcolorspace",
664 " /BitsPerComponent 8",
665 " /DataSource pixel_stream",
666 " /MultipleDataSources false",
667 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
669 " compression "PS3_JPEGCompression" eq",
670 " { [1 0 1 0 1 0 1 0] }",
671 " { [0 1 0 1 0 1 0 1] }",
678 "/PseudoClassImageDict",
680 " % Colors in colormap image.",
681 " currentfile buffer readline pop",
682 " token pop /colors exch def pop",
685 " % Depth of grayscale image.",
686 " currentfile buffer readline pop",
687 " token pop /bits exch def pop",
688 " /DeviceGray setcolorspace",
693 " /BitsPerComponent bits",
695 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
696 " /DataSource pixel_stream",
701 " /colormap colors 3 mul string def",
702 " compression "PS3_NoCompression" eq",
703 " { currentfile /ASCII85Decode filter colormap readstring pop pop }",
704 " { currentfile colormap readstring pop pop }",
706 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
711 " /BitsPerComponent 8",
713 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
714 " /DataSource pixel_stream",
720 "/NonMaskedImageDict",
722 " class "PS3_PseudoClass" eq",
723 " { PseudoClassImageDict }",
724 " { DirectClassImageDict }",
732 " /InterleaveType 3",
733 " /DataDict NonMaskedImageDict",
739 " /BitsPerComponent 1",
740 " /DataSource mask_stream",
741 " /MultipleDataSources false",
742 " /ImageMatrix [ columns 0 0 rows neg 0 rows]",
754 " /buffer 512 string def",
756 " currentfile buffer readline pop",
757 " token pop /x exch def",
758 " token pop /y exch def pop",
760 " % Image size and font size.",
761 " currentfile buffer readline pop",
762 " token pop /x exch def",
763 " token pop /y exch def pop",
764 " currentfile buffer readline pop",
765 " token pop /pointsize exch def pop",
768 *const PostscriptEpilog[]=
772 " currentfile buffer readline pop",
773 " token pop /clipped exch def pop",
775 " currentfile buffer readline pop",
776 " token pop /sp exch def pop",
777 " % Image pixel size.",
778 " currentfile buffer readline pop",
779 " token pop /columns exch def",
780 " token pop /rows exch def pop",
781 " % Colorspace (RGB/CMYK).",
782 " currentfile buffer readline pop",
783 " token pop /colorspace exch def pop",
785 " currentfile buffer readline pop",
786 " token pop /alpha exch def pop",
788 " currentfile buffer readline pop",
789 " token pop /stencil exch def pop",
790 " % Image class (direct/pseudo).",
791 " currentfile buffer readline pop",
792 " token pop /class exch def pop",
793 " % Compression type.",
794 " currentfile buffer readline pop",
795 " token pop /compression exch def pop",
796 " % Clip and render.",
797 " /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def",
798 " clipped { ClipImage } if",
799 " alpha stencil not and",
800 " { MaskedImageDict mask_stream resetfile }",
801 " { NonMaskedImageDict }",
803 " stencil { 0 setgray imagemask } { image } ifelse",
805 " sp { showpage } if",
811 buffer[MagickPathExtent],
812 date[MagickPathExtent],
814 page_geometry[MagickPathExtent];
877 Open output image file.
879 assert(image_info != (const ImageInfo *) NULL);
880 assert(image_info->signature == MagickCoreSignature);
881 assert(image != (Image *) NULL);
882 assert(image->signature == MagickCoreSignature);
883 if (image->debug != MagickFalse)
884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
885 assert(exception != (ExceptionInfo *) NULL);
886 assert(exception->signature == MagickCoreSignature);
887 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
888 if (status == MagickFalse)
890 compression=image->compression;
891 if (image_info->compression != UndefinedCompression)
892 compression=image_info->compression;
896 case Group4Compression:
898 if ((SetImageMonochrome(image,exception) == MagickFalse) ||
899 (image->alpha_trait != UndefinedPixelTrait))
900 compression=RLECompression;
903 #if !defined(MAGICKCORE_JPEG_DELEGATE)
904 case JPEGCompression:
906 compression=RLECompression;
907 (void) ThrowMagickException(exception,GetMagickModule(),
908 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
913 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
916 compression=RLECompression;
917 (void) ThrowMagickException(exception,GetMagickModule(),
918 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
926 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
932 Scale relative to dots-per-inch.
934 delta.x=DefaultResolution;
935 delta.y=DefaultResolution;
936 resolution.x=image->resolution.x;
937 resolution.y=image->resolution.y;
938 if ((resolution.x == 0.0) || (resolution.y == 0.0))
940 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
941 resolution.x=geometry_info.rho;
942 resolution.y=geometry_info.sigma;
943 if ((flags & SigmaValue) == 0)
944 resolution.y=resolution.x;
946 if (image_info->density != (char *) NULL)
948 flags=ParseGeometry(image_info->density,&geometry_info);
949 resolution.x=geometry_info.rho;
950 resolution.y=geometry_info.sigma;
951 if ((flags & SigmaValue) == 0)
952 resolution.y=resolution.x;
954 if (image->units == PixelsPerCentimeterResolution)
956 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
957 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
959 SetGeometry(image,&geometry);
960 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
961 (double) image->columns,(double) image->rows);
962 if (image_info->page != (char *) NULL)
963 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
965 if ((image->page.width != 0) && (image->page.height != 0))
966 (void) FormatLocaleString(page_geometry,MagickPathExtent,
967 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
968 image->page.height,(double) image->page.x,(double) image->page.y);
970 if ((image->gravity != UndefinedGravity) &&
971 (LocaleCompare(image_info->magick,"PS") == 0))
972 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent);
973 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
974 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
975 &geometry.width,&geometry.height);
976 scale.x=(double) (geometry.width*delta.x)/resolution.x;
977 geometry.width=(size_t) floor(scale.x+0.5);
978 scale.y=(double) (geometry.height*delta.y)/resolution.y;
979 geometry.height=(size_t) floor(scale.y+0.5);
980 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
981 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
982 if (image->gravity != UndefinedGravity)
984 geometry.x=(-page_info.x);
985 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
988 if (image_info->pointsize != 0.0)
989 pointsize=image_info->pointsize;
991 value=GetImageProperty(image,"label",exception);
992 if (value != (const char *) NULL)
993 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
998 Postscript header on the first page.
1000 if (LocaleCompare(image_info->magick,"PS3") == 0)
1001 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
1003 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1005 (void) WriteBlobString(image,buffer);
1006 (void) FormatLocaleString(buffer,MagickPathExtent,
1007 "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
1008 (void) WriteBlobString(image,buffer);
1009 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: %s\n",
1011 (void) WriteBlobString(image,buffer);
1012 timer=time((time_t *) NULL);
1013 (void) FormatMagickTime(timer,MagickPathExtent,date);
1014 (void) FormatLocaleString(buffer,MagickPathExtent,
1015 "%%%%CreationDate: %s\n",date);
1016 (void) WriteBlobString(image,buffer);
1017 bounds.x1=(double) geometry.x;
1018 bounds.y1=(double) geometry.y;
1019 bounds.x2=(double) geometry.x+scale.x;
1020 bounds.y2=(double) geometry.y+scale.y+text_size;
1021 if ((image_info->adjoin != MagickFalse) &&
1022 (GetNextImageInList(image) != (Image *) NULL))
1024 (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1025 (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1029 (void) FormatLocaleString(buffer,MagickPathExtent,
1030 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1031 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1032 (void) WriteBlobString(image,buffer);
1033 (void) FormatLocaleString(buffer,MagickPathExtent,
1034 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1035 bounds.y1,bounds.x2,bounds.y2);
1036 (void) WriteBlobString(image,buffer);
1037 if (image->colorspace == CMYKColorspace)
1038 (void) WriteBlobString(image,
1039 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1041 if (SetImageGray(image,exception) != MagickFalse)
1042 (void) WriteBlobString(image,
1043 "%%DocumentProcessColors: Black\n");
1048 value=GetImageProperty(image,"label",exception);
1049 if (value != (const char *) NULL)
1050 (void) WriteBlobString(image,
1051 "%%DocumentNeededResources: font Helvetica\n");
1052 (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1054 Pages, orientation and order.
1056 if (LocaleCompare(image_info->magick,"PS3") != 0)
1057 (void) WriteBlobString(image,"%%Pages: 1\n");
1060 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1061 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1062 if (image_info->adjoin == MagickFalse)
1063 (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
1065 (void) FormatLocaleString(buffer,MagickPathExtent,
1066 "%%%%Pages: %.20g\n",(double) GetImageListLength(image));
1067 (void) WriteBlobString(image,buffer);
1069 if (image->colorspace == CMYKColorspace)
1070 (void) WriteBlobString(image,
1071 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1072 (void) WriteBlobString(image,"%%EndComments\n");
1074 The static postscript procedures prolog.
1076 (void)WriteBlobString(image,"%%BeginProlog\n");
1077 for (q=PostscriptProlog; *q; q++)
1079 (void) WriteBlobString(image,*q);
1080 (void) WriteBlobByte(image,'\n');
1083 One label line for each line in label string.
1085 value=GetImageProperty(image,"label",exception);
1086 if (value != (const char *) NULL)
1088 (void) WriteBlobString(image,"\n %% Labels.\n /Helvetica "
1089 " findfont pointsize scalefont setfont\n");
1090 for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
1092 (void) WriteBlobString(image,
1093 " currentfile buffer readline pop token pop\n");
1094 (void) FormatLocaleString(buffer,MagickPathExtent,
1095 " 0 y %g add moveto show pop\n",i*pointsize+12);
1096 (void) WriteBlobString(image,buffer);
1100 The static postscript procedures epilog.
1102 for (q=PostscriptEpilog; *q; q++)
1104 (void) WriteBlobString(image,*q);
1105 (void) WriteBlobByte(image,'\n');
1107 (void)WriteBlobString(image,"%%EndProlog\n");
1109 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
1111 (void) WriteBlobString(image,buffer);
1115 (void) FormatLocaleString(buffer,MagickPathExtent,
1116 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1117 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
1118 (double) (geometry.height+text_size));
1119 (void) WriteBlobString(image,buffer);
1121 Page process colors if not RGB.
1123 if (image->colorspace == CMYKColorspace)
1124 (void) WriteBlobString(image,
1125 "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1127 if (SetImageGray(image,exception) != MagickFalse)
1128 (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1130 Adjust document bounding box to bound page bounding box.
1132 if ((double) geometry.x < bounds.x1)
1133 bounds.x1=(double) geometry.x;
1134 if ((double) geometry.y < bounds.y1)
1135 bounds.y1=(double) geometry.y;
1136 if ((double) (geometry.x+scale.x) > bounds.x2)
1137 bounds.x2=(double) geometry.x+scale.x;
1138 if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
1139 bounds.y2=(double) geometry.y+scale.y+text_size;
1141 Page font resource if there's a label.
1143 value=GetImageProperty(image,"label",exception);
1144 if (value != (const char *) NULL)
1145 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1147 PS clipping path from Photoshop clipping path.
1149 if ((image->read_mask != MagickFalse) ||
1150 (LocaleNCompare("8BIM:",image->magick_filename,5) != 0))
1151 (void) WriteBlobString(image,"/ClipImage {} def\n");
1157 value=GetImageProperty(image,image->magick_filename,exception);
1158 if (value == (const char *) NULL)
1159 return(MagickFalse);
1160 (void) WriteBlobString(image,value);
1161 (void) WriteBlobByte(image,'\n');
1164 Push a dictionary for our own def's if this an EPS.
1166 if (LocaleCompare(image_info->magick,"PS3") != 0)
1167 (void) WriteBlobString(image,"userdict begin\n");
1171 if ((image->alpha_trait != UndefinedPixelTrait) &&
1172 (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
1174 (void) CloseBlob(image);
1175 return(MagickFalse);
1178 Remember position of BeginData comment so we can update it.
1180 start=TellBlob(image);
1182 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1183 (void) FormatLocaleString(buffer,MagickPathExtent,
1184 "%%%%BeginData:%13ld %s Bytes\n",0L,
1185 compression == NoCompression ? "ASCII" : "BINARY");
1186 (void) WriteBlobString(image,buffer);
1187 stop=TellBlob(image);
1189 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1190 (void) WriteBlobString(image,"DisplayImage\n");
1192 Translate, scale, and font point size.
1194 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
1195 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1196 (void) WriteBlobString(image,buffer);
1200 labels=(char **) NULL;
1201 value=GetImageProperty(image,"label",exception);
1202 if (value != (const char *) NULL)
1203 labels=StringToList(value);
1204 if (labels != (char **) NULL)
1206 for (i=0; labels[i] != (char *) NULL; i++)
1208 if (compression != NoCompression)
1210 for (j=0; labels[i][j] != '\0'; j++)
1211 (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
1212 (void) WriteBlobByte(image,'\n');
1216 (void) WriteBlobString(image,"<~");
1217 Ascii85Initialize(image);
1218 for (j=0; labels[i][j] != '\0'; j++)
1219 Ascii85Encode(image,(unsigned char) labels[i][j]);
1220 Ascii85Flush(image);
1222 labels[i]=DestroyString(labels[i]);
1224 labels=(char **) RelinquishMagickMemory(labels);
1227 Photoshop clipping path active?
1229 if ((image->read_mask != MagickFalse) &&
1230 (LocaleNCompare("8BIM:",image->magick_filename,5) == 0))
1231 (void) WriteBlobString(image,"true\n");
1233 (void) WriteBlobString(image,"false\n");
1235 Showpage for non-EPS.
1237 (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
1238 "true\n" : "false\n");
1240 Image columns, rows, and color space.
1242 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%s\n",
1243 (double) image->columns,(double) image->rows,image->colorspace ==
1244 CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
1245 (void) WriteBlobString(image,buffer);
1249 (void) WriteBlobString(image,image->alpha_trait != UndefinedPixelTrait ?
1250 "true\n" : "false\n");
1252 Render with imagemask operator?
1254 option=GetImageOption(image_info,"ps3:imagemask");
1255 (void) WriteBlobString(image,((option != (const char *) NULL) &&
1256 (SetImageMonochrome(image,exception) != MagickFalse)) ?
1257 "true\n" : "false\n");
1261 pixels=(unsigned char *) NULL;
1263 if ((image_info->type != TrueColorType) &&
1264 (image_info->type != TrueColorAlphaType) &&
1265 (image_info->type != ColorSeparationType) &&
1266 (image_info->type != ColorSeparationAlphaType) &&
1267 (image->colorspace != CMYKColorspace) &&
1268 ((SetImageGray(image,exception) != MagickFalse) ||
1269 (SetImageMonochrome(image,exception) != MagickFalse)))
1274 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1275 switch (compression)
1280 (void) WriteBlobString(image,PS3_NoCompression"\n");
1283 case FaxCompression:
1284 case Group4Compression:
1286 (void) WriteBlobString(image,PS3_FaxCompression"\n");
1289 case JPEGCompression:
1291 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1294 case LZWCompression:
1296 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1299 case RLECompression:
1301 (void) WriteBlobString(image,PS3_RLECompression"\n");
1304 case ZipCompression:
1306 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1311 Number of colors -- 0 for single component non-color mapped data.
1313 (void) WriteBlobString(image,"0\n");
1315 1 bit or 8 bit components?
1317 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
1318 SetImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
1319 (void) WriteBlobString(image,buffer);
1323 if (compression == JPEGCompression)
1324 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1326 if ((compression == FaxCompression) ||
1327 (compression == Group4Compression))
1329 if (LocaleCompare(CCITTParam,"0") == 0)
1330 status=HuffmanEncodeImage(image_info,image,image,exception);
1332 status=Huffman2DEncodeImage(image_info,image,image,exception);
1336 status=SerializeImageChannel(image_info,image,&pixel_info,&length,
1338 if (status == MagickFalse)
1340 (void) CloseBlob(image);
1341 return(MagickFalse);
1343 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1344 switch (compression)
1349 Ascii85Initialize(image);
1350 for (i=0; i < (ssize_t) length; i++)
1351 Ascii85Encode(image,pixels[i]);
1352 Ascii85Flush(image);
1356 case LZWCompression:
1358 status=LZWEncodeImage(image,length,pixels,exception);
1361 case RLECompression:
1363 status=PackbitsEncodeImage(image,length,pixels,exception);
1366 case ZipCompression:
1368 status=ZLIBEncodeImage(image,length,pixels,exception);
1372 pixel_info=RelinquishVirtualMemory(pixel_info);
1376 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1377 (compression == JPEGCompression))
1382 (void) WriteBlobString(image,PS3_DirectClass"\n");
1383 switch (compression)
1388 (void) WriteBlobString(image,PS3_NoCompression"\n");
1391 case RLECompression:
1393 (void) WriteBlobString(image,PS3_RLECompression"\n");
1396 case JPEGCompression:
1398 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1401 case LZWCompression:
1403 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1406 case ZipCompression:
1408 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1415 if (compression == JPEGCompression)
1416 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1420 Stream based compressions.
1422 status=SerializeImage(image_info,image,&pixel_info,&length,
1424 if (status == MagickFalse)
1426 (void) CloseBlob(image);
1427 return(MagickFalse);
1429 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1430 switch (compression)
1435 Ascii85Initialize(image);
1436 for (i=0; i < (ssize_t) length; i++)
1437 Ascii85Encode(image,pixels[i]);
1438 Ascii85Flush(image);
1442 case RLECompression:
1444 status=PackbitsEncodeImage(image,length,pixels,exception);
1447 case LZWCompression:
1449 status=LZWEncodeImage(image,length,pixels,exception);
1452 case ZipCompression:
1454 status=ZLIBEncodeImage(image,length,pixels,exception);
1458 pixel_info=RelinquishVirtualMemory(pixel_info);
1466 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1467 switch (compression)
1472 (void) WriteBlobString(image,PS3_NoCompression"\n");
1475 case RLECompression:
1477 (void) WriteBlobString(image,PS3_RLECompression"\n");
1480 case LZWCompression:
1482 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1485 case ZipCompression:
1487 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1492 Number of colors in color map.
1494 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
1495 (double) image->colors);
1496 (void) WriteBlobString(image,buffer);
1498 Color map - uncompressed.
1500 if ((compression != NoCompression) &&
1501 (compression != UndefinedCompression))
1503 for (i=0; i < (ssize_t) image->colors; i++)
1505 pixel=ScaleQuantumToChar(image->colormap[i].red);
1506 (void) WriteBlobByte(image,(unsigned char) pixel);
1507 pixel=ScaleQuantumToChar(image->colormap[i].green);
1508 (void) WriteBlobByte(image,(unsigned char) pixel);
1509 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1510 (void) WriteBlobByte(image,(unsigned char) pixel);
1515 Ascii85Initialize(image);
1516 for (i=0; i < (ssize_t) image->colors; i++)
1518 pixel=ScaleQuantumToChar(image->colormap[i].red);
1519 Ascii85Encode(image,(unsigned char) pixel);
1520 pixel=ScaleQuantumToChar(image->colormap[i].green);
1521 Ascii85Encode(image,(unsigned char) pixel);
1522 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1523 Ascii85Encode(image,(unsigned char) pixel);
1525 Ascii85Flush(image);
1527 status=SerializeImageIndexes(image_info,image,&pixel_info,&length,
1529 if (status == MagickFalse)
1531 (void) CloseBlob(image);
1532 return(MagickFalse);
1534 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1535 switch (compression)
1540 Ascii85Initialize(image);
1541 for (i=0; i < (ssize_t) length; i++)
1542 Ascii85Encode(image,pixels[i]);
1543 Ascii85Flush(image);
1547 case RLECompression:
1549 status=PackbitsEncodeImage(image,length,pixels,exception);
1552 case LZWCompression:
1554 status=LZWEncodeImage(image,length,pixels,exception);
1557 case ZipCompression:
1559 status=ZLIBEncodeImage(image,length,pixels,exception);
1563 pixel_info=RelinquishVirtualMemory(pixel_info);
1565 (void) WriteBlobByte(image,'\n');
1566 if (status == MagickFalse)
1568 (void) CloseBlob(image);
1569 return(MagickFalse);
1572 Update BeginData now that we know the data size.
1574 length=(size_t) (TellBlob(image)-stop);
1575 stop=TellBlob(image);
1577 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1578 offset=SeekBlob(image,start,SEEK_SET);
1580 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1581 (void) FormatLocaleString(buffer,MagickPathExtent,
1582 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1583 compression == NoCompression ? "ASCII" : "BINARY");
1584 (void) WriteBlobString(image,buffer);
1585 offset=SeekBlob(image,stop,SEEK_SET);
1586 (void) WriteBlobString(image,"%%EndData\n");
1588 End private dictionary if this an EPS.
1590 if (LocaleCompare(image_info->magick,"PS3") != 0)
1591 (void) WriteBlobString(image,"end\n");
1592 (void) WriteBlobString(image,"%%PageTrailer\n");
1593 if (GetNextImageInList(image) == (Image *) NULL)
1595 image=SyncNextImageInList(image);
1596 status=SetImageProgress(image,SaveImagesTag,scene++,
1597 GetImageListLength(image));
1598 if (status == MagickFalse)
1600 } while (image_info->adjoin != MagickFalse);
1601 (void) WriteBlobString(image,"%%Trailer\n");
1604 (void) FormatLocaleString(buffer,MagickPathExtent,
1605 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1606 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1607 (void) WriteBlobString(image,buffer);
1608 (void) FormatLocaleString(buffer,MagickPathExtent,
1609 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1611 (void) WriteBlobString(image,buffer);
1613 (void) WriteBlobString(image,"%%EOF\n");
1614 (void) CloseBlob(image);