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