]> granicus.if.org Git - imagemagick/blob - coders/ps2.c
523049dc94a32cdcb32788919a522adbf98a8da5
[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-2009 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 %      unsigned long RegisterPS2Image(void)
107 %
108 */
109 ModuleExport unsigned long 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   long
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 long
433     x;
434
435   register long
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   unsigned long
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*=2.54;
515         resolution.y*=2.54;
516       }
517     SetGeometry(image,&geometry);
518     (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
519       image->columns,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           image->page.width,image->page.height,image->page.x,image->page.y);
526       else
527         if ((image->gravity != UndefinedGravity) &&
528             (LocaleCompare(image_info->magick,"PS") == 0))
529           (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
530     (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
531     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
532       &geometry.width,&geometry.height);
533     scale.x=(double) (geometry.width*delta.x)/resolution.x;
534     geometry.width=(unsigned long) (scale.x+0.5);
535     scale.y=(double) (geometry.height*delta.y)/resolution.y;
536     geometry.height=(unsigned long) (scale.y+0.5);
537     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
538     (void) ParseGravityGeometry(image,page_geometry,&page_info,
539       &image->exception);
540     if (image->gravity != UndefinedGravity)
541       {
542         geometry.x=(-page_info.x);
543         geometry.y=(long) (media_info.height+page_info.y-image->rows);
544       }
545     pointsize=12.0;
546     if (image_info->pointsize != 0.0)
547       pointsize=image_info->pointsize;
548     text_size=0;
549     value=GetImageProperty(image,"label");
550     if (value != (const char *) NULL)
551       text_size=(unsigned long) (MultilineCensus(value)*pointsize+12);
552     if (page == 1)
553       {
554         /*
555           Output Postscript header.
556         */
557         if (LocaleCompare(image_info->magick,"PS2") == 0)
558           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
559         else
560           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
561             MaxTextExtent);
562         (void) WriteBlobString(image,buffer);
563         (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
564         (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
565           image->filename);
566         (void) WriteBlobString(image,buffer);
567         timer=time((time_t *) NULL);
568         (void) FormatMagickTime(timer,MaxTextExtent,date);
569         (void) FormatMagickString(buffer,MaxTextExtent,
570           "%%%%CreationDate: (%s)\n",date);
571         (void) WriteBlobString(image,buffer);
572         bounds.x1=(double) geometry.x;
573         bounds.y1=(double) geometry.y;
574         bounds.x2=(double) geometry.x+geometry.width;
575         bounds.y2=(double) geometry.y+geometry.height+text_size;
576         if ((image_info->adjoin != MagickFalse) &&
577             (GetNextImageInList(image) != (Image *) NULL))
578           (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n",
579             MaxTextExtent);
580         else
581           {
582             (void) FormatMagickString(buffer,MaxTextExtent,
583               "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
584               (long) (bounds.y1+0.5),
585               (long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
586             (void) WriteBlobString(image,buffer);
587             (void) FormatMagickString(buffer,MaxTextExtent,
588               "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
589               bounds.x2,bounds.y2);
590           }
591         (void) WriteBlobString(image,buffer);
592         value=GetImageProperty(image,"label");
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",MaxTextExtent);
605             else
606               (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %lu\n",
607                 (unsigned long) GetImageListLength(image));
608             (void) WriteBlobString(image,buffer);
609           }
610         (void) WriteBlobString(image,"%%EndComments\n");
611         (void) WriteBlobString(image,"\n%%BeginDefaults\n");
612         (void) WriteBlobString(image,"%%EndDefaults\n\n");
613         /*
614           Output Postscript commands.
615         */
616         for (q=PostscriptProlog; *q; q++)
617         {
618           switch (compression)
619           {
620             case NoCompression:
621             {
622               (void) FormatMagickString(buffer,MaxTextExtent,*q,
623                 "/ASCII85Decode filter");
624               break;
625             }
626             case JPEGCompression:
627             {
628               (void) FormatMagickString(buffer,MaxTextExtent,*q,
629                 "/DCTDecode filter");
630               break;
631             }
632             case LZWCompression:
633             {
634               (void) FormatMagickString(buffer,MaxTextExtent,*q,
635                 "/LZWDecode filter");
636               break;
637             }
638             case FaxCompression:
639             case Group4Compression:
640             {
641               (void) FormatMagickString(buffer,MaxTextExtent,*q," ");
642               break;
643             }
644             default:
645             {
646               (void) FormatMagickString(buffer,MaxTextExtent,*q,
647                 "/RunLengthDecode filter");
648               break;
649             }
650           }
651           (void) WriteBlobString(image,buffer);
652           (void) WriteBlobByte(image,'\n');
653         }
654         value=GetImageProperty(image,"label");
655         if (value != (const char *) NULL)
656           for (j=(long) MultilineCensus(value)-1; j >= 0; j--)
657           {
658             (void) WriteBlobString(image,"  /label 512 string def\n");
659             (void) WriteBlobString(image,"  currentfile label readline pop\n");
660             (void) FormatMagickString(buffer,MaxTextExtent,
661               "  0 y %g add moveto label show pop\n",j*pointsize+12);
662             (void) WriteBlobString(image,buffer);
663           }
664         for (q=PostscriptEpilog; *q; q++)
665         {
666           (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*q);
667           (void) WriteBlobString(image,buffer);
668         }
669         if (LocaleCompare(image_info->magick,"PS2") == 0)
670           (void) WriteBlobString(image,"  showpage\n");
671         (void) WriteBlobString(image,"} bind def\n");
672         (void) WriteBlobString(image,"%%EndProlog\n");
673       }
674     (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page:  1 %lu\n",page++);
675     (void) WriteBlobString(image,buffer);
676     (void) FormatMagickString(buffer,MaxTextExtent,
677       "%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,geometry.y,
678       geometry.x+(long) geometry.width,geometry.y+(long)
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");
690     if (value != (const char *) NULL)
691       (void) WriteBlobString(image,"%%PageResources: font Times-Roman\n");
692     if (LocaleCompare(image_info->magick,"PS2") != 0)
693       (void) WriteBlobString(image,"userdict begin\n");
694     start=TellBlob(image);
695     (void) FormatMagickString(buffer,MaxTextExtent,
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) FormatMagickString(buffer,MaxTextExtent,"%ld %ld\n%g %g\n%f\n",
705       geometry.x,geometry.y,scale.x,scale.y,pointsize);
706     (void) WriteBlobString(image,buffer);
707     labels=(char **) NULL;
708     value=GetImageProperty(image,"label");
709     if (value != (const char *) NULL)
710       labels=StringToList(value);
711     if (labels != (char **) NULL)
712       {
713         for (i=0; labels[i] != (char *) NULL; i++)
714         {
715           (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
716             labels[i]);
717           (void) WriteBlobString(image,buffer);
718           labels[i]=DestroyString(labels[i]);
719         }
720         labels=(char **) RelinquishMagickMemory(labels);
721       }
722     number_pixels=(MagickSizeType) image->columns*image->rows;
723     if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
724       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
725     if ((compression == FaxCompression) || (compression == Group4Compression) ||
726         ((image_info->type != TrueColorType) &&
727          (IsGrayImage(image,&image->exception) != MagickFalse)))
728       {
729         (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
730           image->columns,image->rows,(int)
731           (image->colorspace == CMYKColorspace));
732         (void) WriteBlobString(image,buffer);
733         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
734           (int) ((compression != FaxCompression) &&
735            (compression != Group4Compression)));
736         (void) WriteBlobString(image,buffer);
737         (void) WriteBlobString(image,"0\n");
738         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
739            (compression == FaxCompression) ||
740            (compression == Group4Compression) ? 1 : 8);
741         (void) WriteBlobString(image,buffer);
742         switch (compression)
743         {
744           case FaxCompression:
745           case Group4Compression:
746           {
747             if (LocaleCompare(CCITTParam,"0") == 0)
748               {
749                 (void) HuffmanEncodeImage(image_info,image,image);
750                 break;
751               }
752             (void) Huffman2DEncodeImage(image_info,image,image);
753             break;
754           }
755           case JPEGCompression:
756           {
757             status=InjectImageBlob(image_info,image,image,"jpeg",
758               &image->exception);
759             if (status == MagickFalse)
760               ThrowWriterException(CoderError,image->exception.reason);
761             break;
762           }
763           case RLECompression:
764           default:
765           {
766             register unsigned char
767               *q;
768
769             /*
770               Allocate pixel array.
771             */
772             length=(size_t) number_pixels;
773             pixels=(unsigned char *) AcquireQuantumMemory(length,
774               sizeof(*pixels));
775             if (pixels == (unsigned char *) NULL)
776               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
777             /*
778               Dump Runlength encoded pixels.
779             */
780             q=pixels;
781             for (y=0; y < (long) image->rows; y++)
782             {
783               p=GetVirtualPixels(image,0,y,image->columns,1,
784                 &image->exception);
785               if (p == (const PixelPacket *) NULL)
786                 break;
787               for (x=0; x < (long) image->columns; x++)
788               {
789                 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
790                 p++;
791               }
792               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
793               if (progress == MagickFalse)
794                 break;
795             }
796             length=(size_t) (q-pixels);
797             if (compression == LZWCompression)
798               status=LZWEncodeImage(image,length,pixels);
799             else
800               status=PackbitsEncodeImage(image,length,pixels);
801             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
802             if (status == MagickFalse)
803               {
804                 (void) CloseBlob(image);
805                 return(MagickFalse);
806               }
807             break;
808           }
809           case NoCompression:
810           {
811             /*
812               Dump uncompressed PseudoColor packets.
813             */
814             Ascii85Initialize(image);
815             for (y=0; y < (long) image->rows; y++)
816             {
817               p=GetVirtualPixels(image,0,y,image->columns,1,
818                 &image->exception);
819               if (p == (const PixelPacket *) NULL)
820                 break;
821               for (x=0; x < (long) image->columns; x++)
822               {
823                 Ascii85Encode(image,
824                   ScaleQuantumToChar(PixelIntensityToQuantum(p)));
825                 p++;
826               }
827               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
828               if (progress == MagickFalse)
829                 break;
830             }
831             Ascii85Flush(image);
832             break;
833           }
834         }
835       }
836     else
837       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
838           (compression == JPEGCompression) || (image->matte != MagickFalse))
839         {
840           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n0\n%d\n",
841             image->columns,image->rows,(int)
842             (image->colorspace == CMYKColorspace));
843           (void) WriteBlobString(image,buffer);
844           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
845             (int) (compression == NoCompression));
846           (void) WriteBlobString(image,buffer);
847           switch (compression)
848           {
849             case JPEGCompression:
850             {
851               status=InjectImageBlob(image_info,image,image,"jpeg",
852                 &image->exception);
853               if (status == MagickFalse)
854                 ThrowWriterException(CoderError,image->exception.reason);
855               break;
856             }
857             case RLECompression:
858             default:
859             {
860               register unsigned char
861                 *q;
862
863               /*
864                 Allocate pixel array.
865               */
866               length=(size_t) number_pixels;
867               pixels=(unsigned char *) AcquireQuantumMemory(length,
868                 4*sizeof(*pixels));
869               if (pixels == (unsigned char *) NULL)
870                 ThrowWriterException(ResourceLimitError,
871                   "MemoryAllocationFailed");
872               /*
873                 Dump Packbit encoded pixels.
874               */
875               q=pixels;
876               for (y=0; y < (long) image->rows; y++)
877               {
878                 p=GetVirtualPixels(image,0,y,image->columns,1,
879                   &image->exception);
880                 if (p == (const PixelPacket *) NULL)
881                   break;
882                 indexes=GetVirtualIndexQueue(image);
883                 for (x=0; x < (long) image->columns; x++)
884                 {
885                   if ((image->matte != MagickFalse) &&
886                       (p->opacity == (Quantum) TransparentOpacity))
887                     {
888                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
889                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
890                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
891                     }
892                   else
893                     if (image->colorspace != CMYKColorspace)
894                       {
895                         *q++=ScaleQuantumToChar(p->red);
896                         *q++=ScaleQuantumToChar(p->green);
897                         *q++=ScaleQuantumToChar(p->blue);
898                       }
899                     else
900                       {
901                         *q++=ScaleQuantumToChar(p->red);
902                         *q++=ScaleQuantumToChar(p->green);
903                         *q++=ScaleQuantumToChar(p->blue);
904                         *q++=ScaleQuantumToChar(indexes[x]);
905                       }
906                   p++;
907                 }
908                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
909                 if (progress == MagickFalse)
910                   break;
911               }
912               length=(size_t) (q-pixels);
913               if (compression == LZWCompression)
914                 status=LZWEncodeImage(image,length,pixels);
915               else
916                 status=PackbitsEncodeImage(image,length,pixels);
917               if (status == MagickFalse)
918                 {
919                   (void) CloseBlob(image);
920                   return(MagickFalse);
921                 }
922               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
923               break;
924             }
925             case NoCompression:
926             {
927               /*
928                 Dump uncompressed DirectColor packets.
929               */
930               Ascii85Initialize(image);
931               for (y=0; y < (long) image->rows; y++)
932               {
933                 p=GetVirtualPixels(image,0,y,image->columns,1,
934                   &image->exception);
935                 if (p == (const PixelPacket *) NULL)
936                   break;
937                 indexes=GetVirtualIndexQueue(image);
938                 for (x=0; x < (long) image->columns; x++)
939                 {
940                   if ((image->matte != MagickFalse) &&
941                       (p->opacity == (Quantum) TransparentOpacity))
942                     {
943                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
944                         QuantumRange));
945                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
946                         QuantumRange));
947                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
948                         QuantumRange));
949                     }
950                   else
951                     if (image->colorspace != CMYKColorspace)
952                       {
953                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
954                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
955                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
956                       }
957                     else
958                       {
959                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
960                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
961                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
962                         Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
963                       }
964                   p++;
965                 }
966                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
967                 if (progress == MagickFalse)
968                   break;
969               }
970               Ascii85Flush(image);
971               break;
972             }
973           }
974         }
975       else
976         {
977           /*
978             Dump number of colors and colormap.
979           */
980           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
981             image->columns,image->rows,(int)
982             (image->colorspace == CMYKColorspace));
983           (void) WriteBlobString(image,buffer);
984           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
985             (int) (compression == NoCompression));
986           (void) WriteBlobString(image,buffer);
987           (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",image->colors);
988           (void) WriteBlobString(image,buffer);
989           for (i=0; i < (long) image->colors; i++)
990           {
991             (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
992               ScaleQuantumToChar(image->colormap[i].red),
993               ScaleQuantumToChar(image->colormap[i].green),
994               ScaleQuantumToChar(image->colormap[i].blue));
995             (void) WriteBlobString(image,buffer);
996           }
997           switch (compression)
998           {
999             case RLECompression:
1000             default:
1001             {
1002               register unsigned char
1003                 *q;
1004
1005               /*
1006                 Allocate pixel array.
1007               */
1008               length=(size_t) number_pixels;
1009               pixels=(unsigned char *) AcquireQuantumMemory(length,
1010                 sizeof(*pixels));
1011               if (pixels == (unsigned char *) NULL)
1012                 ThrowWriterException(ResourceLimitError,
1013                   "MemoryAllocationFailed");
1014               /*
1015                 Dump Runlength encoded pixels.
1016               */
1017               q=pixels;
1018               for (y=0; y < (long) image->rows; y++)
1019               {
1020                 p=GetVirtualPixels(image,0,y,image->columns,1,
1021                   &image->exception);
1022                 if (p == (const PixelPacket *) NULL)
1023                   break;
1024                 indexes=GetVirtualIndexQueue(image);
1025                 for (x=0; x < (long) image->columns; x++)
1026                   *q++=(unsigned char) indexes[x];
1027                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1028                 if (progress == MagickFalse)
1029                   break;
1030               }
1031               length=(size_t) (q-pixels);
1032               if (compression == LZWCompression)
1033                 status=LZWEncodeImage(image,length,pixels);
1034               else
1035                 status=PackbitsEncodeImage(image,length,pixels);
1036               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1037               if (status == MagickFalse)
1038                 {
1039                   (void) CloseBlob(image);
1040                   return(MagickFalse);
1041                 }
1042               break;
1043             }
1044             case NoCompression:
1045             {
1046               /*
1047                 Dump uncompressed PseudoColor packets.
1048               */
1049               Ascii85Initialize(image);
1050               for (y=0; y < (long) image->rows; y++)
1051               {
1052                 p=GetVirtualPixels(image,0,y,image->columns,1,
1053                   &image->exception);
1054                 if (p == (const PixelPacket *) NULL)
1055                   break;
1056                 indexes=GetVirtualIndexQueue(image);
1057                 for (x=0; x < (long) image->columns; x++)
1058                   Ascii85Encode(image,(unsigned char) indexes[x]);
1059                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1060                 if (progress == MagickFalse)
1061                   break;
1062               }
1063               Ascii85Flush(image);
1064               break;
1065             }
1066           }
1067         }
1068     (void) WriteBlobByte(image,'\n');
1069     length=(size_t) (TellBlob(image)-stop);
1070     stop=TellBlob(image);
1071     offset=SeekBlob(image,start,SEEK_SET);
1072     if (offset < 0)
1073       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1074     (void) FormatMagickString(buffer,MaxTextExtent,
1075       "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1076       compression == NoCompression ? "ASCII" : "Binary");
1077     (void) WriteBlobString(image,buffer);
1078     offset=SeekBlob(image,stop,SEEK_SET);
1079     (void) WriteBlobString(image,"%%EndData\n");
1080     if (LocaleCompare(image_info->magick,"PS2") != 0)
1081       (void) WriteBlobString(image,"end\n");
1082     (void) WriteBlobString(image,"%%PageTrailer\n");
1083     if (GetNextImageInList(image) == (Image *) NULL)
1084       break;
1085     image=SyncNextImageInList(image);
1086     status=SetImageProgress(image,SaveImagesTag,scene++,
1087       GetImageListLength(image));
1088     if (status == MagickFalse)
1089       break;
1090   } while (image_info->adjoin != MagickFalse);
1091   (void) WriteBlobString(image,"%%Trailer\n");
1092   if (page > 1)
1093     {
1094       (void) FormatMagickString(buffer,MaxTextExtent,
1095         "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
1096         (long) (bounds.y1+0.5),(long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
1097       (void) WriteBlobString(image,buffer);
1098       (void) FormatMagickString(buffer,MaxTextExtent,
1099         "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1100         bounds.y2);
1101       (void) WriteBlobString(image,buffer);
1102     }
1103   (void) WriteBlobString(image,"%%EOF\n");
1104   (void) CloseBlob(image);
1105   return(MagickTrue);
1106 }