• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   SSSSS  22222                              %
7 %                            P   P  SS        22                              %
8 %                            PPPP    SSS    222                               %
9 %                            P         SS  22                                 %
10 %                            P      SSSSS  22222                              %
11 %                                                                             %
12 %                                                                             %
13 %                      Write Postscript Level II Format                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
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.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
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/compress.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/module.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/monitor-private.h"
64 #include "MagickCore/option.h"
65 #include "MagickCore/pixel-accessor.h"
66 #include "MagickCore/property.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/string_.h"
71 #include "MagickCore/timer-private.h"
72 #include "MagickCore/utility.h"
73 
74 /*
75   Define declarations.
76 */
77 #if defined(MAGICKCORE_TIFF_DELEGATE)
78 #define CCITTParam  "-1"
79 #else
80 #define CCITTParam  "0"
81 #endif
82 
83 /*
84   Forward declarations.
85 */
86 static MagickBooleanType
87   WritePS2Image(const ImageInfo *,Image *,ExceptionInfo *);
88 
89 /*
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 %                                                                             %
92 %                                                                             %
93 %                                                                             %
94 %   R e g i s t e r P S 2 I m a g e                                           %
95 %                                                                             %
96 %                                                                             %
97 %                                                                             %
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 %
100 %  RegisterPS2Image() adds properties for the PS2 image format to
101 %  the list of supported formats.  The properties include the image format
102 %  tag, a method to read and/or write the format, whether the format
103 %  supports the saving of more than one frame to the same file or blob,
104 %  whether the format supports native in-memory I/O, and a brief
105 %  description of the format.
106 %
107 %  The format of the RegisterPS2Image method is:
108 %
109 %      size_t RegisterPS2Image(void)
110 %
111 */
RegisterPS2Image(void)112 ModuleExport size_t RegisterPS2Image(void)
113 {
114   MagickInfo
115     *entry;
116 
117   entry=AcquireMagickInfo("PS2","EPS2","Level II Encapsulated PostScript");
118   entry->encoder=(EncodeImageHandler *) WritePS2Image;
119   entry->flags^=CoderAdjoinFlag;
120   entry->flags|=CoderEncoderSeekableStreamFlag;
121   entry->flags^=CoderBlobSupportFlag;
122   entry->mime_type=ConstantString("application/postscript");
123   (void) RegisterMagickInfo(entry);
124   entry=AcquireMagickInfo("PS2","PS2","Level II PostScript");
125   entry->encoder=(EncodeImageHandler *) WritePS2Image;
126   entry->flags|=CoderEncoderSeekableStreamFlag;
127   entry->flags^=CoderBlobSupportFlag;
128   entry->mime_type=ConstantString("application/postscript");
129   (void) RegisterMagickInfo(entry);
130   return(MagickImageCoderSignature);
131 }
132 
133 /*
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 %   U n r e g i s t e r P S 2 I m a g e                                       %
139 %                                                                             %
140 %                                                                             %
141 %                                                                             %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 %
144 %  UnregisterPS2Image() removes format registrations made by the
145 %  PS2 module from the list of supported formats.
146 %
147 %  The format of the UnregisterPS2Image method is:
148 %
149 %      UnregisterPS2Image(void)
150 %
151 */
UnregisterPS2Image(void)152 ModuleExport void UnregisterPS2Image(void)
153 {
154   (void) UnregisterMagickInfo("EPS2");
155   (void) UnregisterMagickInfo("PS2");
156 }
157 
158 /*
159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 %                                                                             %
161 %                                                                             %
162 %                                                                             %
163 %   W r i t e P S 2 I m a g e                                                 %
164 %                                                                             %
165 %                                                                             %
166 %                                                                             %
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 %
169 %  WritePS2Image translates an image to encapsulated Postscript
170 %  Level II for printing.  If the supplied geometry is null, the image is
171 %  centered on the Postscript page.  Otherwise, the image is positioned as
172 %  specified by the geometry.
173 %
174 %  The format of the WritePS2Image method is:
175 %
176 %      MagickBooleanType WritePS2Image(const ImageInfo *image_info,
177 %        Image *image,ExceptionInfo *exception)
178 %
179 %  A description of each parameter follows:
180 %
181 %    o image_info: the image info.
182 %
183 %    o image: the image.
184 %
185 %    o exception: return any errors or warnings in this structure.
186 %
187 */
188 
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image,Image * inject_image,ExceptionInfo * exception)189 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
190   Image *image,Image *inject_image,ExceptionInfo *exception)
191 {
192   Image
193     *group4_image;
194 
195   ImageInfo
196     *write_info;
197 
198   MagickBooleanType
199     status;
200 
201   size_t
202     length;
203 
204   unsigned char
205     *group4;
206 
207   group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
208   if (group4_image == (Image *) NULL)
209     return(MagickFalse);
210   write_info=CloneImageInfo(image_info);
211   (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
212   (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
213   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
214     exception);
215   write_info=DestroyImageInfo(write_info);
216   group4_image=DestroyImage(group4_image);
217   if (group4 == (unsigned char *) NULL)
218     return(MagickFalse);
219   status=MagickTrue;
220   if (WriteBlob(image,length,group4) != (ssize_t) length)
221     status=MagickFalse;
222   group4=(unsigned char *) RelinquishMagickMemory(group4);
223   return(status);
224 }
225 
WritePS2Image(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)226 static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image,
227   ExceptionInfo *exception)
228 {
229   static const char
230     PostscriptProlog[] =
231       "%%%%BeginProlog\n"
232       "%%\n"
233       "%% Display a color image.  The image is displayed in color on\n"
234       "%% Postscript viewers or printers that support color, otherwise\n"
235       "%% it is displayed as grayscale.\n"
236       "%%\n"
237       "/DirectClassImage\n"
238       "{\n"
239       "  %%\n"
240       "  %% Display a DirectClass image.\n"
241       "  %%\n"
242       "  colorspace 0 eq\n"
243       "  {\n"
244       "    /DeviceRGB setcolorspace\n"
245       "    <<\n"
246       "      /ImageType 1\n"
247       "      /Width columns\n"
248       "      /Height rows\n"
249       "      /BitsPerComponent 8\n"
250       "      /Decode [0 1 0 1 0 1]\n"
251       "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
252       "      compression 0 gt\n"
253       "      { /DataSource pixel_stream %s }\n"
254       "      { /DataSource pixel_stream %s } ifelse\n"
255       "    >> image\n"
256       "  }\n"
257       "  {\n"
258       "    /DeviceCMYK setcolorspace\n"
259       "    <<\n"
260       "      /ImageType 1\n"
261       "      /Width columns\n"
262       "      /Height rows\n"
263       "      /BitsPerComponent 8\n"
264       "      /Decode [1 0 1 0 1 0 1 0]\n"
265       "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
266       "      compression 0 gt\n"
267       "      { /DataSource pixel_stream %s }\n"
268       "      { /DataSource pixel_stream %s } ifelse\n"
269       "    >> image\n"
270       "  } ifelse\n"
271       "} bind def\n"
272       "\n"
273       "/PseudoClassImage\n"
274       "{\n"
275       "  %%\n"
276       "  %% Display a PseudoClass image.\n"
277       "  %%\n"
278       "  %% Parameters:\n"
279       "  %%   colors: number of colors in the colormap.\n"
280       "  %%\n"
281       "  currentfile buffer readline pop\n"
282       "  token pop /colors exch def pop\n"
283       "  colors 0 eq\n"
284       "  {\n"
285       "    %%\n"
286       "    %% Image is grayscale.\n"
287       "    %%\n"
288       "    currentfile buffer readline pop\n"
289       "    token pop /bits exch def pop\n"
290       "    /DeviceGray setcolorspace\n"
291       "    <<\n"
292       "      /ImageType 1\n"
293       "      /Width columns\n"
294       "      /Height rows\n"
295       "      /BitsPerComponent bits\n"
296       "      /Decode [0 1]\n"
297       "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
298       "      compression 0 gt\n"
299       "      { /DataSource pixel_stream %s }\n"
300       "      {\n"
301       "        /DataSource pixel_stream %s\n"
302       "        <<\n"
303       "           /K " CCITTParam "\n"
304       "           /Columns columns\n"
305       "           /Rows rows\n"
306       "        >> /CCITTFaxDecode filter\n"
307       "      } ifelse\n"
308       "    >> image\n"
309       "  }\n"
310       "  {\n"
311       "    %%\n"
312       "    %% Parameters:\n"
313       "    %%   colormap: red, green, blue color packets.\n"
314       "    %%\n"
315       "    /colormap colors 3 mul string def\n"
316       "    currentfile colormap readhexstring pop pop\n"
317       "    currentfile buffer readline pop\n"
318       "    [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n"
319       "    <<\n"
320       "      /ImageType 1\n"
321       "      /Width columns\n"
322       "      /Height rows\n"
323       "      /BitsPerComponent 8\n"
324       "      /Decode [0 255]\n"
325       "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
326       "      compression 0 gt\n"
327       "      { /DataSource pixel_stream %s }\n"
328       "      { /DataSource pixel_stream %s } ifelse\n"
329       "    >> image\n"
330       "  } ifelse\n"
331       "} bind def\n"
332       "\n"
333       "/DisplayImage\n"
334       "{\n"
335       "  %%\n"
336       "  %% Display a DirectClass or PseudoClass image.\n"
337       "  %%\n"
338       "  %% Parameters:\n"
339       "  %%   x & y translation.\n"
340       "  %%   x & y scale.\n"
341       "  %%   label pointsize.\n"
342       "  %%   image label.\n"
343       "  %%   image columns & rows.\n"
344       "  %%   class: 0-DirectClass or 1-PseudoClass.\n"
345       "  %%   colorspace: 0-RGB or 1-CMYK.\n"
346       "  %%   compression: 0-RLECompression or 1-NoCompression.\n"
347       "  %%   hex color packets.\n"
348       "  %%\n"
349       "  gsave\n"
350       "  /buffer 512 string def\n"
351       "  /pixel_stream currentfile def\n"
352       "\n"
353       "  currentfile buffer readline pop\n"
354       "  token pop /x exch def\n"
355       "  token pop /y exch def pop\n"
356       "  x y translate\n"
357       "  currentfile buffer readline pop\n"
358       "  token pop /x exch def\n"
359       "  token pop /y exch def pop\n"
360       "  currentfile buffer readline pop\n"
361       "  token pop /pointsize exch def pop\n",
362     PostscriptEpilog[] =
363       "  x y scale\n"
364       "  currentfile buffer readline pop\n"
365       "  token pop /columns exch def\n"
366       "  token pop /rows exch def pop\n"
367       "  currentfile buffer readline pop\n"
368       "  token pop /class exch def pop\n"
369       "  currentfile buffer readline pop\n"
370       "  token pop /colorspace exch def pop\n"
371       "  currentfile buffer readline pop\n"
372       "  token pop /compression exch def pop\n"
373       "  class 0 gt { PseudoClassImage } { DirectClassImage } ifelse\n"
374       "  grestore\n";
375 
376   char
377     buffer[MagickPathExtent],
378     date[MagickPathExtent],
379     page_geometry[MagickPathExtent],
380     **labels;
381 
382   CompressionType
383     compression;
384 
385   const char
386     *filter,
387     *value;
388 
389   double
390     pointsize;
391 
392   GeometryInfo
393     geometry_info;
394 
395   MagickOffsetType
396     scene,
397     start,
398     stop;
399 
400   MagickBooleanType
401     progress,
402     status;
403 
404   MagickOffsetType
405     offset;
406 
407   MagickSizeType
408     number_pixels;
409 
410   MagickStatusType
411     flags;
412 
413   PointInfo
414     delta,
415     resolution,
416     scale;
417 
418   RectangleInfo
419     geometry,
420     media_info,
421     page_info;
422 
423   register const Quantum
424     *p;
425 
426   register ssize_t
427     x;
428 
429   register ssize_t
430     i;
431 
432   SegmentInfo
433     bounds;
434 
435   size_t
436     imageListLength,
437     length,
438     page,
439     text_size;
440 
441   ssize_t
442     j,
443     y;
444 
445   time_t
446     timer;
447 
448   unsigned char
449     *pixels;
450 
451   /*
452     Open output image file.
453   */
454   assert(image_info != (const ImageInfo *) NULL);
455   assert(image_info->signature == MagickCoreSignature);
456   assert(image != (Image *) NULL);
457   assert(image->signature == MagickCoreSignature);
458   if (image->debug != MagickFalse)
459     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
460   assert(exception != (ExceptionInfo *) NULL);
461   assert(exception->signature == MagickCoreSignature);
462   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
463   if (status == MagickFalse)
464     return(status);
465   compression=image->compression;
466   if (image_info->compression != UndefinedCompression)
467     compression=image_info->compression;
468   switch (compression)
469   {
470 #if !defined(MAGICKCORE_JPEG_DELEGATE)
471     case JPEGCompression:
472     {
473       compression=RLECompression;
474       (void) ThrowMagickException(exception,GetMagickModule(),
475         MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
476         image->filename);
477       break;
478     }
479 #endif
480     default:
481       break;
482   }
483   (void) memset(&bounds,0,sizeof(bounds));
484   page=1;
485   scene=0;
486   imageListLength=GetImageListLength(image);
487   do
488   {
489     /*
490       Scale relative to dots-per-inch.
491     */
492     delta.x=DefaultResolution;
493     delta.y=DefaultResolution;
494     resolution.x=image->resolution.x;
495     resolution.y=image->resolution.y;
496     if ((resolution.x == 0.0) || (resolution.y == 0.0))
497       {
498         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
499         resolution.x=geometry_info.rho;
500         resolution.y=geometry_info.sigma;
501         if ((flags & SigmaValue) == 0)
502           resolution.y=resolution.x;
503       }
504     if (image_info->density != (char *) NULL)
505       {
506         flags=ParseGeometry(image_info->density,&geometry_info);
507         resolution.x=geometry_info.rho;
508         resolution.y=geometry_info.sigma;
509         if ((flags & SigmaValue) == 0)
510           resolution.y=resolution.x;
511       }
512     if (image->units == PixelsPerCentimeterResolution)
513       {
514         resolution.x=(double) (100.0*2.54*resolution.x+0.5)/100.0;
515         resolution.y=(double) (100.0*2.54*resolution.y+0.5)/100.0;
516       }
517     SetGeometry(image,&geometry);
518     (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
519       (double) image->columns,(double) image->rows);
520     if (image_info->page != (char *) NULL)
521       (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
522     else
523       if ((image->page.width != 0) && (image->page.height != 0))
524         (void) FormatLocaleString(page_geometry,MagickPathExtent,
525           "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
526           image->page.height,(double) image->page.x,(double) image->page.y);
527       else
528         if ((image->gravity != UndefinedGravity) &&
529             (LocaleCompare(image_info->magick,"PS") == 0))
530           (void) CopyMagickString(page_geometry,PSPageGeometry,
531             MagickPathExtent);
532     (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
533     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
534       &geometry.width,&geometry.height);
535     scale.x=PerceptibleReciprocal(resolution.x)*geometry.width*delta.x;
536     geometry.width=(size_t) floor(scale.x+0.5);
537     scale.y=PerceptibleReciprocal(resolution.y)*geometry.height*delta.y;
538     geometry.height=(size_t) floor(scale.y+0.5);
539     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
540     (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
541     if (image->gravity != UndefinedGravity)
542       {
543         geometry.x=(-page_info.x);
544         geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
545       }
546     pointsize=12.0;
547     if (image_info->pointsize != 0.0)
548       pointsize=image_info->pointsize;
549     text_size=0;
550     value=GetImageProperty(image,"label",exception);
551     if (value != (const char *) NULL)
552       text_size=(size_t) (MultilineCensus(value)*pointsize+12);
553     if (page == 1)
554       {
555         /*
556           Output Postscript header.
557         */
558         if (LocaleCompare(image_info->magick,"PS2") == 0)
559           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
560         else
561           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
562             MagickPathExtent);
563         (void) WriteBlobString(image,buffer);
564         (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
565         (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
566           image->filename);
567         (void) WriteBlobString(image,buffer);
568         timer=GetMagickTime();
569         (void) FormatMagickTime(timer,MagickPathExtent,date);
570         (void) FormatLocaleString(buffer,MagickPathExtent,
571           "%%%%CreationDate: (%s)\n",date);
572         (void) WriteBlobString(image,buffer);
573         bounds.x1=(double) geometry.x;
574         bounds.y1=(double) geometry.y;
575         bounds.x2=(double) geometry.x+geometry.width;
576         bounds.y2=(double) geometry.y+geometry.height+text_size;
577         if ((image_info->adjoin != MagickFalse) &&
578             (GetNextImageInList(image) != (Image *) NULL))
579           (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n",
580             MagickPathExtent);
581         else
582           {
583             (void) FormatLocaleString(buffer,MagickPathExtent,
584               "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
585               ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
586             (void) WriteBlobString(image,buffer);
587             (void) FormatLocaleString(buffer,MagickPathExtent,
588               "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
589               bounds.y1,bounds.x2,bounds.y2);
590           }
591         (void) WriteBlobString(image,buffer);
592         value=GetImageProperty(image,"label",exception);
593         if (value != (const char *) NULL)
594           (void) WriteBlobString(image,
595             "%%DocumentNeededResources: font Helvetica\n");
596         (void) WriteBlobString(image,"%%LanguageLevel: 2\n");
597         if (LocaleCompare(image_info->magick,"PS2") != 0)
598           (void) WriteBlobString(image,"%%Pages: 1\n");
599         else
600           {
601             (void) WriteBlobString(image,"%%Orientation: Portrait\n");
602             (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
603             if (image_info->adjoin == MagickFalse)
604               (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
605             else
606               (void) FormatLocaleString(buffer,MagickPathExtent,
607                 "%%%%Pages: %.20g\n",(double) imageListLength);
608             (void) WriteBlobString(image,buffer);
609           }
610         if (image->colorspace == CMYKColorspace)
611           (void) WriteBlobString(image,
612             "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
613         (void) WriteBlobString(image,"%%EndComments\n");
614         (void) WriteBlobString(image,"\n%%BeginDefaults\n");
615         (void) WriteBlobString(image,"%%EndDefaults\n\n");
616         /*
617           Output Postscript commands.
618         */
619         switch (compression)
620         {
621           case NoCompression:
622           {
623             filter="/ASCII85Decode filter";
624             break;
625           }
626           case JPEGCompression:
627           {
628             filter="/DCTDecode filter";
629             break;
630           }
631           case LZWCompression:
632           {
633             filter="/LZWDecode filter";
634             break;
635           }
636           case FaxCompression:
637           case Group4Compression:
638           {
639             filter=" ";
640             break;
641           }
642           default:
643           {
644             filter="/RunLengthDecode filter";
645             break;
646           }
647         }
648         (void) FormatLocaleString(buffer,MagickPathExtent,PostscriptProlog,
649           filter,filter,filter,filter,filter,filter,filter,filter);
650         (void) WriteBlob(image,strlen(buffer),buffer);
651         value=GetImageProperty(image,"label",exception);
652         if (value != (const char *) NULL)
653           {
654             (void) WriteBlobString(image,
655               "  /Helvetica findfont pointsize scalefont setfont\n");
656             for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
657             {
658               (void) WriteBlobString(image,"  /label 512 string def\n");
659               (void) WriteBlobString(image,
660                 "  currentfile label readline pop\n");
661               (void) FormatLocaleString(buffer,MagickPathExtent,
662                 "  0 y %g add moveto label show pop\n",j*pointsize+12);
663               (void) WriteBlobString(image,buffer);
664             }
665           }
666         (void) WriteBlob(image,sizeof(PostscriptEpilog)-1,
667           (const unsigned char *) PostscriptEpilog);
668         if (LocaleCompare(image_info->magick,"PS2") == 0)
669           (void) WriteBlobString(image,"  showpage\n");
670         (void) WriteBlobString(image,"} bind def\n");
671         (void) WriteBlobString(image,"%%EndProlog\n");
672       }
673     (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page:  1 %.20g\n",
674       (double) page++);
675     (void) WriteBlobString(image,buffer);
676     (void) FormatLocaleString(buffer,MagickPathExtent,
677       "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
678       (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
679       (geometry.height+text_size));
680     (void) WriteBlobString(image,buffer);
681     if ((double) geometry.x < bounds.x1)
682       bounds.x1=(double) geometry.x;
683     if ((double) geometry.y < bounds.y1)
684       bounds.y1=(double) geometry.y;
685     if ((double) (geometry.x+geometry.width-1) > bounds.x2)
686       bounds.x2=(double) geometry.x+geometry.width-1;
687     if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
688       bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
689     value=GetImageProperty(image,"label",exception);
690     if (value != (const char *) NULL)
691       (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
692     if (LocaleCompare(image_info->magick,"PS2") != 0)
693       (void) WriteBlobString(image,"userdict begin\n");
694     start=TellBlob(image);
695     (void) FormatLocaleString(buffer,MagickPathExtent,
696       "%%%%BeginData:%13ld %s Bytes\n",0L,
697       compression == NoCompression ? "ASCII" : "Binary");
698     (void) WriteBlobString(image,buffer);
699     stop=TellBlob(image);
700     (void) WriteBlobString(image,"DisplayImage\n");
701     /*
702       Output image data.
703     */
704     (void) FormatLocaleString(buffer,MagickPathExtent,
705       "%.20g %.20g\n%g %g\n%g\n",(double) geometry.x,(double) geometry.y,
706       scale.x,scale.y,pointsize);
707     (void) WriteBlobString(image,buffer);
708     labels=(char **) NULL;
709     value=GetImageProperty(image,"label",exception);
710     if (value != (const char *) NULL)
711       labels=StringToList(value);
712     if (labels != (char **) NULL)
713       {
714         for (i=0; labels[i] != (char *) NULL; i++)
715         {
716           (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",
717             labels[i]);
718           (void) WriteBlobString(image,buffer);
719           labels[i]=DestroyString(labels[i]);
720         }
721         labels=(char **) RelinquishMagickMemory(labels);
722       }
723     number_pixels=(MagickSizeType) image->columns*image->rows;
724     if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
725       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
726     if ((compression == FaxCompression) || (compression == Group4Compression) ||
727         ((image_info->type != TrueColorType) &&
728          (SetImageGray(image,exception) != MagickFalse)))
729       {
730         (void) FormatLocaleString(buffer,MagickPathExtent,
731           "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows,
732           (int) (image->colorspace == CMYKColorspace));
733         (void) WriteBlobString(image,buffer);
734         (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",(int)
735           ((compression != FaxCompression) &&
736            (compression != Group4Compression)));
737         (void) WriteBlobString(image,buffer);
738         (void) WriteBlobString(image,"0\n");
739         (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
740            (compression == FaxCompression) ||
741            (compression == Group4Compression) ? 1 : 8);
742         (void) WriteBlobString(image,buffer);
743         switch (compression)
744         {
745           case FaxCompression:
746           case Group4Compression:
747           {
748             if (LocaleCompare(CCITTParam,"0") == 0)
749               {
750                 (void) HuffmanEncodeImage(image_info,image,image,exception);
751                 break;
752               }
753             (void) Huffman2DEncodeImage(image_info,image,image,exception);
754             break;
755           }
756           case JPEGCompression:
757           {
758             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
759             if (status == MagickFalse)
760               {
761                 (void) CloseBlob(image);
762                 return(MagickFalse);
763               }
764             break;
765           }
766           case RLECompression:
767           default:
768           {
769             MemoryInfo
770               *pixel_info;
771 
772             register unsigned char
773               *q;
774 
775             /*
776               Allocate pixel array.
777             */
778             length=(size_t) number_pixels;
779             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
780             if (pixel_info == (MemoryInfo *) NULL)
781               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
782             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
783             /*
784               Dump runlength encoded pixels.
785             */
786             q=pixels;
787             for (y=0; y < (ssize_t) image->rows; y++)
788             {
789               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
790               if (p == (const Quantum *) NULL)
791                 break;
792               for (x=0; x < (ssize_t) image->columns; x++)
793               {
794                 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
795                 p+=GetPixelChannels(image);
796               }
797               progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
798                 image->rows);
799               if (progress == MagickFalse)
800                 break;
801             }
802             length=(size_t) (q-pixels);
803             if (compression == LZWCompression)
804               status=LZWEncodeImage(image,length,pixels,exception);
805             else
806               status=PackbitsEncodeImage(image,length,pixels,exception);
807             pixel_info=RelinquishVirtualMemory(pixel_info);
808             if (status == MagickFalse)
809               {
810                 (void) CloseBlob(image);
811                 return(MagickFalse);
812               }
813             break;
814           }
815           case NoCompression:
816           {
817             /*
818               Dump uncompressed PseudoColor packets.
819             */
820             Ascii85Initialize(image);
821             for (y=0; y < (ssize_t) image->rows; y++)
822             {
823               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
824               if (p == (const Quantum *) NULL)
825                 break;
826               for (x=0; x < (ssize_t) image->columns; x++)
827               {
828                 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
829                   GetPixelLuma(image,p))));
830                 p+=GetPixelChannels(image);
831               }
832               progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
833                 y,image->rows);
834               if (progress == MagickFalse)
835                 break;
836             }
837             Ascii85Flush(image);
838             break;
839           }
840         }
841       }
842     else
843       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
844           (compression == JPEGCompression) || (image->alpha_trait != UndefinedPixelTrait))
845         {
846           (void) FormatLocaleString(buffer,MagickPathExtent,
847             "%.20g %.20g\n0\n%d\n",(double) image->columns,(double) image->rows,
848             (int) (image->colorspace == CMYKColorspace));
849           (void) WriteBlobString(image,buffer);
850           (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
851             (int) (compression == NoCompression));
852           (void) WriteBlobString(image,buffer);
853           switch (compression)
854           {
855             case JPEGCompression:
856             {
857               status=InjectImageBlob(image_info,image,image,"jpeg",exception);
858               if (status == MagickFalse)
859                 {
860                   (void) CloseBlob(image);
861                   return(MagickFalse);
862                 }
863               break;
864             }
865             case RLECompression:
866             default:
867             {
868               MemoryInfo
869                 *pixel_info;
870 
871               register unsigned char
872                 *q;
873 
874               /*
875                 Allocate pixel array.
876               */
877               length=(size_t) number_pixels;
878               pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
879               if (pixel_info == (MemoryInfo *) NULL)
880                 ThrowWriterException(ResourceLimitError,
881                   "MemoryAllocationFailed");
882               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
883               /*
884                 Dump runlength encoded pixels.
885               */
886               q=pixels;
887               for (y=0; y < (ssize_t) image->rows; y++)
888               {
889                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
890                 if (p == (const Quantum *) NULL)
891                   break;
892                 for (x=0; x < (ssize_t) image->columns; x++)
893                 {
894                   if ((image->alpha_trait != UndefinedPixelTrait) &&
895                       (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
896                     {
897                       *q++=ScaleQuantumToChar(QuantumRange);
898                       *q++=ScaleQuantumToChar(QuantumRange);
899                       *q++=ScaleQuantumToChar(QuantumRange);
900                     }
901                   else
902                     if (image->colorspace != CMYKColorspace)
903                       {
904                         *q++=ScaleQuantumToChar(GetPixelRed(image,p));
905                         *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
906                         *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
907                       }
908                     else
909                       {
910                         *q++=ScaleQuantumToChar(GetPixelRed(image,p));
911                         *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
912                         *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
913                         *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
914                       }
915                   p+=GetPixelChannels(image);
916                 }
917                 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
918                   y,image->rows);
919                 if (progress == MagickFalse)
920                   break;
921               }
922               length=(size_t) (q-pixels);
923               if (compression == LZWCompression)
924                 status=LZWEncodeImage(image,length,pixels,exception);
925               else
926                 status=PackbitsEncodeImage(image,length,pixels,exception);
927               if (status == MagickFalse)
928                 {
929                   (void) CloseBlob(image);
930                   return(MagickFalse);
931                 }
932               pixel_info=RelinquishVirtualMemory(pixel_info);
933               break;
934             }
935             case NoCompression:
936             {
937               /*
938                 Dump uncompressed DirectColor packets.
939               */
940               Ascii85Initialize(image);
941               for (y=0; y < (ssize_t) image->rows; y++)
942               {
943                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
944                 if (p == (const Quantum *) NULL)
945                   break;
946                 for (x=0; x < (ssize_t) image->columns; x++)
947                 {
948                   if ((image->alpha_trait != UndefinedPixelTrait) &&
949                       (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
950                     {
951                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
952                         QuantumRange));
953                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
954                         QuantumRange));
955                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
956                         QuantumRange));
957                     }
958                   else
959                     if (image->colorspace != CMYKColorspace)
960                       {
961                         Ascii85Encode(image,ScaleQuantumToChar(
962                           GetPixelRed(image,p)));
963                         Ascii85Encode(image,ScaleQuantumToChar(
964                           GetPixelGreen(image,p)));
965                         Ascii85Encode(image,ScaleQuantumToChar(
966                           GetPixelBlue(image,p)));
967                       }
968                     else
969                       {
970                         Ascii85Encode(image,ScaleQuantumToChar(
971                           GetPixelRed(image,p)));
972                         Ascii85Encode(image,ScaleQuantumToChar(
973                           GetPixelGreen(image,p)));
974                         Ascii85Encode(image,ScaleQuantumToChar(
975                           GetPixelBlue(image,p)));
976                         Ascii85Encode(image,ScaleQuantumToChar(
977                           GetPixelBlack(image,p)));
978                       }
979                   p+=GetPixelChannels(image);
980                 }
981                 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
982                   y,image->rows);
983                 if (progress == MagickFalse)
984                   break;
985               }
986               Ascii85Flush(image);
987               break;
988             }
989           }
990         }
991       else
992         {
993           /*
994             Dump number of colors and colormap.
995           */
996           (void) FormatLocaleString(buffer,MagickPathExtent,
997             "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows,
998             (int) (image->colorspace == CMYKColorspace));
999           (void) WriteBlobString(image,buffer);
1000           (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
1001             (int) (compression == NoCompression));
1002           (void) WriteBlobString(image,buffer);
1003           (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
1004             image->colors);
1005           (void) WriteBlobString(image,buffer);
1006           for (i=0; i < (ssize_t) image->colors; i++)
1007           {
1008             (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n",
1009               ScaleQuantumToChar(image->colormap[i].red),
1010               ScaleQuantumToChar(image->colormap[i].green),
1011               ScaleQuantumToChar(image->colormap[i].blue));
1012             (void) WriteBlobString(image,buffer);
1013           }
1014           switch (compression)
1015           {
1016             case RLECompression:
1017             default:
1018             {
1019               MemoryInfo
1020                 *pixel_info;
1021 
1022               register unsigned char
1023                 *q;
1024 
1025               /*
1026                 Allocate pixel array.
1027               */
1028               length=(size_t) number_pixels;
1029               pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1030               if (pixel_info == (MemoryInfo *) NULL)
1031                 ThrowWriterException(ResourceLimitError,
1032                   "MemoryAllocationFailed");
1033               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1034               /*
1035                 Dump runlength encoded pixels.
1036               */
1037               q=pixels;
1038               for (y=0; y < (ssize_t) image->rows; y++)
1039               {
1040                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1041                 if (p == (const Quantum *) NULL)
1042                   break;
1043                 for (x=0; x < (ssize_t) image->columns; x++)
1044                 {
1045                   *q++=(unsigned char) GetPixelIndex(image,p);
1046                   p+=GetPixelChannels(image);
1047                 }
1048                 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1049                   y,image->rows);
1050                 if (progress == MagickFalse)
1051                   break;
1052               }
1053               length=(size_t) (q-pixels);
1054               if (compression == LZWCompression)
1055                 status=LZWEncodeImage(image,length,pixels,exception);
1056               else
1057                 status=PackbitsEncodeImage(image,length,pixels,exception);
1058               pixel_info=RelinquishVirtualMemory(pixel_info);
1059               if (status == MagickFalse)
1060                 {
1061                   (void) CloseBlob(image);
1062                   return(MagickFalse);
1063                 }
1064               break;
1065             }
1066             case NoCompression:
1067             {
1068               /*
1069                 Dump uncompressed PseudoColor packets.
1070               */
1071               Ascii85Initialize(image);
1072               for (y=0; y < (ssize_t) image->rows; y++)
1073               {
1074                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1075                 if (p == (const Quantum *) NULL)
1076                   break;
1077                 for (x=0; x < (ssize_t) image->columns; x++)
1078                 {
1079                   Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
1080                   p+=GetPixelChannels(image);
1081                 }
1082                 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1083                   y,image->rows);
1084                 if (progress == MagickFalse)
1085                   break;
1086               }
1087               Ascii85Flush(image);
1088               break;
1089             }
1090           }
1091         }
1092     (void) WriteBlobByte(image,'\n');
1093     length=(size_t) (TellBlob(image)-stop);
1094     stop=TellBlob(image);
1095     offset=SeekBlob(image,start,SEEK_SET);
1096     if (offset < 0)
1097       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1098     (void) FormatLocaleString(buffer,MagickPathExtent,
1099       "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1100       compression == NoCompression ? "ASCII" : "Binary");
1101     (void) WriteBlobString(image,buffer);
1102     offset=SeekBlob(image,stop,SEEK_SET);
1103     (void) WriteBlobString(image,"%%EndData\n");
1104     if (LocaleCompare(image_info->magick,"PS2") != 0)
1105       (void) WriteBlobString(image,"end\n");
1106     (void) WriteBlobString(image,"%%PageTrailer\n");
1107     if (GetNextImageInList(image) == (Image *) NULL)
1108       break;
1109     image=SyncNextImageInList(image);
1110     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
1111     if (status == MagickFalse)
1112       break;
1113   } while (image_info->adjoin != MagickFalse);
1114   (void) WriteBlobString(image,"%%Trailer\n");
1115   if (page > 1)
1116     {
1117       (void) FormatLocaleString(buffer,MagickPathExtent,
1118         "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1119         ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1120       (void) WriteBlobString(image,buffer);
1121       (void) FormatLocaleString(buffer,MagickPathExtent,
1122         "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
1123         bounds.x2,bounds.y2);
1124       (void) WriteBlobString(image,buffer);
1125     }
1126   (void) WriteBlobString(image,"%%EOF\n");
1127   (void) CloseBlob(image);
1128   return(MagickTrue);
1129 }
1130