]> granicus.if.org Git - imagemagick/blob - coders/ps2.c
779ce6784e9ccf9806f8aa8747b4085849a85fa5
[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 #if defined(MAGICKCORE_TIFF_DELEGATE)
71 #if defined(MAGICKCORE_HAVE_TIFFCONF_H)
72 #include "tiffconf.h"
73 #endif
74 #include "tiffio.h"
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 #if defined(MAGICKCORE_TIFF_DELEGATE)
184 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
185   Image *image,Image *inject_image)
186 {
187   char
188     filename[MaxTextExtent];
189
190   FILE
191     *file;
192
193   Image
194     *huffman_image;
195
196   ImageInfo
197     *write_info;
198
199   int
200     unique_file;
201
202   MagickBooleanType
203     status;
204
205   register long
206     i;
207
208   ssize_t
209     count;
210
211   TIFF
212     *tiff;
213
214   uint16
215     fillorder;
216
217   uint32
218     *byte_count,
219     strip_size;
220
221   unsigned char
222     *buffer;
223
224   /*
225     Write image as CCITTFax4 TIFF image to a temporary file.
226   */
227   assert(image_info != (const ImageInfo *) NULL);
228   assert(image_info->signature == MagickSignature);
229   assert(image != (Image *) NULL);
230   assert(image->signature == MagickSignature);
231   if (image->debug != MagickFalse)
232     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
233   assert(inject_image != (Image *) NULL);
234   assert(inject_image->signature == MagickSignature);
235   huffman_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
236   if (huffman_image == (Image *) NULL)
237     return(MagickFalse);
238   file=(FILE *) NULL;
239   unique_file=AcquireUniqueFileResource(filename);
240   if (unique_file != -1)
241     file=fdopen(unique_file,"wb"); 
242   if ((unique_file == -1) || (file == (FILE *) NULL))
243     {
244       ThrowFileException(&image->exception,FileOpenError,
245         "UnableToCreateTemporaryFile",filename);
246       return(MagickFalse);
247     }
248   (void) FormatMagickString(huffman_image->filename,MaxTextExtent,"tiff:%s",
249     filename);
250   write_info=CloneImageInfo(image_info);
251   SetImageInfoFile(write_info,file);
252   write_info->compression=Group4Compression;
253   write_info->type=BilevelType;
254   (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
255   status=WriteImage(write_info,huffman_image);
256   (void) fflush(file);
257   write_info=DestroyImageInfo(write_info);
258   if (status == MagickFalse)
259     return(MagickFalse);
260   tiff=TIFFOpen(filename,"rb");
261   if (tiff == (TIFF *) NULL)
262     {
263       huffman_image=DestroyImage(huffman_image);
264       (void) fclose(file);
265       (void) RelinquishUniqueFileResource(filename);
266       ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
267         image_info->filename);
268       return(MagickFalse);
269     }
270   /*
271     Allocate raw strip buffer.
272   */
273   byte_count=0;
274   (void) TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count);
275   strip_size=byte_count[0];
276   for (i=1; i < (long) TIFFNumberOfStrips(tiff); i++)
277     if (byte_count[i] > strip_size)
278       strip_size=byte_count[i];
279   buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
280     sizeof(*buffer));
281   if (buffer == (unsigned char *) NULL)
282     {
283       TIFFClose(tiff);
284       huffman_image=DestroyImage(huffman_image);
285       (void) fclose(file);
286       (void) RelinquishUniqueFileResource(filename);
287       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
288         image_info->filename);
289     }
290   /*
291     Compress runlength encoded to 2D Huffman pixels.
292   */
293   fillorder=FILLORDER_LSB2MSB;
294   (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder);
295   for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++)
296   {
297     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,(long)
298       byte_count[i]);
299     if (fillorder == FILLORDER_LSB2MSB)
300       TIFFReverseBits(buffer,(unsigned long) count);
301     (void) WriteBlob(image,(size_t) count,buffer);
302   }
303   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
304   TIFFClose(tiff);
305   huffman_image=DestroyImage(huffman_image);
306   (void) fclose(file);
307   (void) RelinquishUniqueFileResource(filename);
308   return(MagickTrue);
309 }
310 #else
311 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
312   Image *image,Image *inject_image)
313 {
314   assert(image_info != (const ImageInfo *) NULL);
315   assert(image_info->signature == MagickSignature);
316   assert(image != (Image *) NULL);
317   assert(image->signature == MagickSignature);
318   if (image->debug != MagickFalse)
319     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
320   assert(inject_image != (Image *) NULL);
321   assert(inject_image->signature == MagickSignature);
322   (void) ThrowMagickException(&image->exception,GetMagickModule(),
323     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (TIFF)",
324     image->filename);
325   return(MagickFalse);
326 }
327 #endif
328
329 static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image)
330 {
331   static const char
332     *PostscriptProlog[]=
333     {
334       "%%%%BeginProlog",
335       "%%",
336       "%% Display a color image.  The image is displayed in color on",
337       "%% Postscript viewers or printers that support color, otherwise",
338       "%% it is displayed as grayscale.",
339       "%%",
340       "/DirectClassImage",
341       "{",
342       "  %%",
343       "  %% Display a DirectClass image.",
344       "  %%",
345       "  colorspace 0 eq",
346       "  {",
347       "    /DeviceRGB setcolorspace",
348       "    <<",
349       "      /ImageType 1",
350       "      /Width columns",
351       "      /Height rows",
352       "      /BitsPerComponent 8",
353       "      /Decode [0 1 0 1 0 1]",
354       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
355       "      compression 0 gt",
356       "      { /DataSource pixel_stream /%s filter }",
357       "      { /DataSource pixel_stream /%s filter } ifelse",
358       "    >> image",
359       "  }",
360       "  {",
361       "    /DeviceCMYK setcolorspace",
362       "    <<",
363       "      /ImageType 1",
364       "      /Width columns",
365       "      /Height rows",
366       "      /BitsPerComponent 8",
367       "      /Decode [1 0 1 0 1 0 1 0]",
368       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
369       "      compression 0 gt",
370       "      { /DataSource pixel_stream /%s filter }",
371       "      { /DataSource pixel_stream /%s filter } ifelse",
372       "    >> image",
373       "  } ifelse",
374       "} bind def",
375       "",
376       "/PseudoClassImage",
377       "{",
378       "  %%",
379       "  %% Display a PseudoClass image.",
380       "  %%",
381       "  %% Parameters:",
382       "  %%   colors: number of colors in the colormap.",
383       "  %%",
384       "  currentfile buffer readline pop",
385       "  token pop /colors exch def pop",
386       "  colors 0 eq",
387       "  {",
388       "    %%",
389       "    %% Image is grayscale.",
390       "    %%",
391       "    currentfile buffer readline pop",
392       "    token pop /bits exch def pop",
393       "    /DeviceGray setcolorspace",
394       "    <<",
395       "      /ImageType 1",
396       "      /Width columns",
397       "      /Height rows",
398       "      /BitsPerComponent bits",
399       "      /Decode [0 1]",
400       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
401       "      compression 0 gt",
402       "      { /DataSource pixel_stream /%s filter }",
403       "      {",
404       "        /DataSource pixel_stream /%s filter",
405       "        <<",
406       "           /K "CCITTParam,
407       "           /Columns columns",
408       "           /Rows rows",
409       "        >> /CCITTFaxDecode filter",
410       "      } ifelse",
411       "    >> image",
412       "  }",
413       "  {",
414       "    %%",
415       "    %% Parameters:",
416       "    %%   colormap: red, green, blue color packets.",
417       "    %%",
418       "    /colormap colors 3 mul string def",
419       "    currentfile colormap readhexstring pop pop",
420       "    currentfile buffer readline pop",
421       "    [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
422       "    <<",
423       "      /ImageType 1",
424       "      /Width columns",
425       "      /Height rows",
426       "      /BitsPerComponent 8",
427       "      /Decode [0 255]",
428       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
429       "      compression 0 gt",
430       "      { /DataSource pixel_stream /%s filter }",
431       "      { /DataSource pixel_stream /%s filter } ifelse",
432       "    >> image",
433       "  } ifelse",
434       "} bind def",
435       "",
436       "/DisplayImage",
437       "{",
438       "  %%",
439       "  %% Display a DirectClass or PseudoClass image.",
440       "  %%",
441       "  %% Parameters:",
442       "  %%   x & y translation.",
443       "  %%   x & y scale.",
444       "  %%   label pointsize.",
445       "  %%   image label.",
446       "  %%   image columns & rows.",
447       "  %%   class: 0-DirectClass or 1-PseudoClass.",
448       "  %%   colorspace: 0-RGB or 1-CMYK.",
449       "  %%   compression: 0-RLECompression or 1-NoCompression.",
450       "  %%   hex color packets.",
451       "  %%",
452       "  gsave",
453       "  /buffer 512 string def",
454       "  /pixel_stream currentfile def",
455       "",
456       "  currentfile buffer readline pop",
457       "  token pop /x exch def",
458       "  token pop /y exch def pop",
459       "  x y translate",
460       "  currentfile buffer readline pop",
461       "  token pop /x exch def",
462       "  token pop /y exch def pop",
463       "  currentfile buffer readline pop",
464       "  token pop /pointsize exch def pop",
465       "  /Helvetica findfont pointsize scalefont setfont",
466       (char *) NULL
467     },
468     *PostscriptEpilog[]=
469     {
470       "  x y scale",
471       "  currentfile buffer readline pop",
472       "  token pop /columns exch def",
473       "  token pop /rows exch def pop",
474       "  currentfile buffer readline pop",
475       "  token pop /class exch def pop",
476       "  currentfile buffer readline pop",
477       "  token pop /colorspace exch def pop",
478       "  currentfile buffer readline pop",
479       "  token pop /compression exch def pop",
480       "  class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
481       (char *) NULL
482     };
483
484   char
485     buffer[MaxTextExtent],
486     date[MaxTextExtent],
487     page_geometry[MaxTextExtent],
488     **labels;
489
490   CompressionType
491     compression;
492
493   const char
494     **q,
495     *value;
496
497   double
498     pointsize;
499
500   GeometryInfo
501     geometry_info;
502
503   long
504     j,
505     y;
506
507   MagickOffsetType
508     scene,
509     start,
510     stop;
511
512   MagickBooleanType
513     progress,
514     status;
515
516   MagickOffsetType
517     offset;
518
519   MagickSizeType
520     number_pixels;
521
522   MagickStatusType
523     flags;
524
525   PointInfo
526     delta,
527     resolution,
528     scale;
529
530   RectangleInfo
531     geometry,
532     media_info,
533     page_info;
534
535   register const IndexPacket
536     *indexes;
537
538   register const PixelPacket
539     *p;
540
541   register long
542     x;
543
544   register long
545     i;
546
547   SegmentInfo
548     bounds;
549
550   size_t
551     length;
552
553   time_t
554     timer;
555
556   unsigned char
557     *pixels;
558
559   unsigned long
560     page,
561     text_size;
562
563   /*
564     Open output image file.
565   */
566   assert(image_info != (const ImageInfo *) NULL);
567   assert(image_info->signature == MagickSignature);
568   assert(image != (Image *) NULL);
569   assert(image->signature == MagickSignature);
570   if (image->debug != MagickFalse)
571     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
572   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
573   if (status == MagickFalse)
574     return(status);
575   compression=image->compression;
576   if (image_info->compression != UndefinedCompression)
577     compression=image_info->compression;
578   switch (compression)
579   {
580 #if !defined(MAGICKCORE_JPEG_DELEGATE)
581     case JPEGCompression:
582     {
583       compression=RLECompression;
584       (void) ThrowMagickException(&image->exception,GetMagickModule(),
585         MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
586         image->filename);
587       break;
588     }
589 #endif
590     default:
591       break;
592   }
593   (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
594   page=1;
595   scene=0;
596   do
597   {
598     /*
599       Scale relative to dots-per-inch.
600     */
601     delta.x=DefaultResolution;
602     delta.y=DefaultResolution;
603     resolution.x=image->x_resolution;
604     resolution.y=image->y_resolution;
605     if ((resolution.x == 0.0) || (resolution.y == 0.0))
606       {
607         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
608         resolution.x=geometry_info.rho;
609         resolution.y=geometry_info.sigma;
610         if ((flags & SigmaValue) == 0)
611           resolution.y=resolution.x;
612       }
613     if (image_info->density != (char *) NULL)
614       {
615         flags=ParseGeometry(image_info->density,&geometry_info);
616         resolution.x=geometry_info.rho;
617         resolution.y=geometry_info.sigma;
618         if ((flags & SigmaValue) == 0)
619           resolution.y=resolution.x;
620       }
621     if (image->units == PixelsPerCentimeterResolution)
622       {
623         resolution.x*=2.54;
624         resolution.y*=2.54;
625       }
626     SetGeometry(image,&geometry);
627     (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
628       image->columns,image->rows);
629     if (image_info->page != (char *) NULL)
630       (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
631     else
632       if ((image->page.width != 0) && (image->page.height != 0))
633         (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
634           image->page.width,image->page.height,image->page.x,image->page.y);
635       else
636         if ((image->gravity != UndefinedGravity) &&
637             (LocaleCompare(image_info->magick,"PS") == 0))
638           (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
639     (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
640     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
641       &geometry.width,&geometry.height);
642     scale.x=(double) (geometry.width*delta.x)/resolution.x;
643     geometry.width=(unsigned long) (scale.x+0.5);
644     scale.y=(double) (geometry.height*delta.y)/resolution.y;
645     geometry.height=(unsigned long) (scale.y+0.5);
646     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
647     (void) ParseGravityGeometry(image,page_geometry,&page_info,
648       &image->exception);
649     if (image->gravity != UndefinedGravity)
650       {
651         geometry.x=(-page_info.x);
652         geometry.y=(long) (media_info.height+page_info.y-image->rows);
653       }
654     pointsize=12.0;
655     if (image_info->pointsize != 0.0)
656       pointsize=image_info->pointsize;
657     text_size=0;
658     value=GetImageProperty(image,"label");
659     if (value != (const char *) NULL)
660       text_size=(unsigned long) (MultilineCensus(value)*pointsize+12);
661     if (page == 1)
662       {
663         /*
664           Output Postscript header.
665         */
666         if (LocaleCompare(image_info->magick,"PS2") == 0)
667           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
668         else
669           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
670             MaxTextExtent);
671         (void) WriteBlobString(image,buffer);
672         (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
673         (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
674           image->filename);
675         (void) WriteBlobString(image,buffer);
676         timer=time((time_t *) NULL);
677         (void) FormatMagickTime(timer,MaxTextExtent,date);
678         (void) FormatMagickString(buffer,MaxTextExtent,
679           "%%%%CreationDate: (%s)\n",date);
680         (void) WriteBlobString(image,buffer);
681         bounds.x1=(double) geometry.x;
682         bounds.y1=(double) geometry.y;
683         bounds.x2=(double) geometry.x+geometry.width;
684         bounds.y2=(double) geometry.y+geometry.height+text_size;
685         if ((image_info->adjoin != MagickFalse) &&
686             (GetNextImageInList(image) != (Image *) NULL))
687           (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n",
688             MaxTextExtent);
689         else
690           {
691             (void) FormatMagickString(buffer,MaxTextExtent,
692               "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
693               (long) (bounds.y1+0.5),
694               (long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
695             (void) WriteBlobString(image,buffer);
696             (void) FormatMagickString(buffer,MaxTextExtent,
697               "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
698               bounds.x2,bounds.y2);
699           }
700         (void) WriteBlobString(image,buffer);
701         value=GetImageProperty(image,"label");
702         if (value != (const char *) NULL)
703           (void) WriteBlobString(image,
704             "%%DocumentNeededResources: font Helvetica\n");
705         (void) WriteBlobString(image,"%%LanguageLevel: 2\n");
706         if (LocaleCompare(image_info->magick,"PS2") != 0)
707           (void) WriteBlobString(image,"%%Pages: 1\n");
708         else
709           {
710             (void) WriteBlobString(image,"%%Orientation: Portrait\n");
711             (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
712             if (image_info->adjoin == MagickFalse)
713               (void) CopyMagickString(buffer,"%%Pages: 1\n",MaxTextExtent);
714             else
715               (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Pages: %lu\n",
716                 (unsigned long) GetImageListLength(image));
717             (void) WriteBlobString(image,buffer);
718           }
719         (void) WriteBlobString(image,"%%EndComments\n");
720         (void) WriteBlobString(image,"\n%%BeginDefaults\n");
721         (void) WriteBlobString(image,"%%EndDefaults\n\n");
722         /*
723           Output Postscript commands.
724         */
725         for (q=PostscriptProlog; *q; q++)
726         {
727           switch (compression)
728           {
729             case NoCompression:
730             {
731               (void) FormatMagickString(buffer,MaxTextExtent,*q,
732                 "ASCII85Decode");
733               break;
734             }
735             case JPEGCompression:
736             {
737               (void) FormatMagickString(buffer,MaxTextExtent,*q,"DCTDecode");
738               break;
739             }
740             case LZWCompression:
741             {
742               (void) FormatMagickString(buffer,MaxTextExtent,*q,"LZWDecode");
743               break;
744             }
745             case FaxCompression:
746             case Group4Compression:
747             {
748               (void) FormatMagickString(buffer,MaxTextExtent,*q,
749                 "ASCII85Decode");
750               break;
751             }
752             default:
753             {
754               (void) FormatMagickString(buffer,MaxTextExtent,*q,
755                 "RunLengthDecode");
756               break;
757             }
758           }
759           (void) WriteBlobString(image,buffer);
760           (void) WriteBlobByte(image,'\n');
761         }
762         value=GetImageProperty(image,"label");
763         if (value != (const char *) NULL)
764           for (j=(long) MultilineCensus(value)-1; j >= 0; j--)
765           {
766             (void) WriteBlobString(image,"  /label 512 string def\n");
767             (void) WriteBlobString(image,"  currentfile label readline pop\n");
768             (void) FormatMagickString(buffer,MaxTextExtent,
769               "  0 y %g add moveto label show pop\n",j*pointsize+12);
770             (void) WriteBlobString(image,buffer);
771           }
772         for (q=PostscriptEpilog; *q; q++)
773         {
774           (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*q);
775           (void) WriteBlobString(image,buffer);
776         }
777         if (LocaleCompare(image_info->magick,"PS2") == 0)
778           (void) WriteBlobString(image,"  showpage\n");
779         (void) WriteBlobString(image,"} bind def\n");
780         (void) WriteBlobString(image,"%%EndProlog\n");
781       }
782     (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page:  1 %lu\n",page++);
783     (void) WriteBlobString(image,buffer);
784     (void) FormatMagickString(buffer,MaxTextExtent,
785       "%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,geometry.y,
786       geometry.x+(long) geometry.width,geometry.y+(long)
787       (geometry.height+text_size));
788     (void) WriteBlobString(image,buffer);
789     if ((double) geometry.x < bounds.x1)
790       bounds.x1=(double) geometry.x;
791     if ((double) geometry.y < bounds.y1)
792       bounds.y1=(double) geometry.y;
793     if ((double) (geometry.x+geometry.width-1) > bounds.x2)
794       bounds.x2=(double) geometry.x+geometry.width-1;
795     if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
796       bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
797     value=GetImageProperty(image,"label");
798     if (value != (const char *) NULL)
799       (void) WriteBlobString(image,"%%PageResources: font Times-Roman\n");
800     if (LocaleCompare(image_info->magick,"PS2") != 0)
801       (void) WriteBlobString(image,"userdict begin\n");
802     start=TellBlob(image);
803     (void) FormatMagickString(buffer,MaxTextExtent,
804       "%%%%BeginData:%13ld %s Bytes\n",0L,
805       compression == NoCompression ? "ASCII" : "Binary");
806     (void) WriteBlobString(image,buffer);
807     stop=TellBlob(image);
808     (void) WriteBlobString(image,"DisplayImage\n");
809     /*
810       Output image data.
811     */
812     (void) FormatMagickString(buffer,MaxTextExtent,"%ld %ld\n%g %g\n%f\n",
813       geometry.x,geometry.y,scale.x,scale.y,pointsize);
814     (void) WriteBlobString(image,buffer);
815     labels=(char **) NULL;
816     value=GetImageProperty(image,"label");
817     if (value != (const char *) NULL)
818       labels=StringToList(value);
819     if (labels != (char **) NULL)
820       {
821         for (i=0; labels[i] != (char *) NULL; i++)
822         {
823           (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
824             labels[i]);
825           (void) WriteBlobString(image,buffer);
826           labels[i]=DestroyString(labels[i]);
827         }
828         labels=(char **) RelinquishMagickMemory(labels);
829       }
830     number_pixels=(MagickSizeType) image->columns*image->rows;
831     if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
832       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
833     if ((compression == FaxCompression) || (compression == Group4Compression) ||
834         ((image_info->type != TrueColorType) &&
835          (IsGrayImage(image,&image->exception) != MagickFalse)))
836       {
837         (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
838           image->columns,image->rows,(int)
839           (image->colorspace == CMYKColorspace));
840         (void) WriteBlobString(image,buffer);
841         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
842           (int) ((compression != FaxCompression) &&
843            (compression != Group4Compression)));
844         (void) WriteBlobString(image,buffer);
845         (void) WriteBlobString(image,"0\n");
846         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
847            (compression == FaxCompression) ||
848            (compression == Group4Compression) ? 1 : 8);
849         (void) WriteBlobString(image,buffer);
850         switch (compression)
851         {
852           case FaxCompression:
853           case Group4Compression:
854           {
855             if (LocaleCompare(CCITTParam,"0") == 0)
856               {
857                 (void) HuffmanEncodeImage(image_info,image,image);
858                 break;
859               }
860             (void) Huffman2DEncodeImage(image_info,image,image);
861             break;
862           }
863           case JPEGCompression:
864           {
865             status=InjectImageBlob(image_info,image,image,"jpeg",
866               &image->exception);
867             if (status == MagickFalse)
868               ThrowWriterException(CoderError,image->exception.reason);
869             break;
870           }
871           case RLECompression:
872           default:
873           {
874             register unsigned char
875               *q;
876
877             /*
878               Allocate pixel array.
879             */
880             length=(size_t) number_pixels;
881             pixels=(unsigned char *) AcquireQuantumMemory(length,
882               sizeof(*pixels));
883             if (pixels == (unsigned char *) NULL)
884               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
885             /*
886               Dump Runlength encoded pixels.
887             */
888             q=pixels;
889             for (y=0; y < (long) image->rows; y++)
890             {
891               p=GetVirtualPixels(image,0,y,image->columns,1,
892                 &image->exception);
893               if (p == (const PixelPacket *) NULL)
894                 break;
895               for (x=0; x < (long) image->columns; x++)
896               {
897                 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
898                 p++;
899               }
900               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
901               if (progress == MagickFalse)
902                 break;
903             }
904             length=(size_t) (q-pixels);
905             if (compression == LZWCompression)
906               status=LZWEncodeImage(image,length,pixels);
907             else
908               status=PackbitsEncodeImage(image,length,pixels);
909             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
910             if (status == MagickFalse)
911               {
912                 (void) CloseBlob(image);
913                 return(MagickFalse);
914               }
915             break;
916           }
917           case NoCompression:
918           {
919             /*
920               Dump uncompressed PseudoColor packets.
921             */
922             Ascii85Initialize(image);
923             for (y=0; y < (long) image->rows; y++)
924             {
925               p=GetVirtualPixels(image,0,y,image->columns,1,
926                 &image->exception);
927               if (p == (const PixelPacket *) NULL)
928                 break;
929               for (x=0; x < (long) image->columns; x++)
930               {
931                 Ascii85Encode(image,
932                   ScaleQuantumToChar(PixelIntensityToQuantum(p)));
933                 p++;
934               }
935               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
936               if (progress == MagickFalse)
937                 break;
938             }
939             Ascii85Flush(image);
940             break;
941           }
942         }
943       }
944     else
945       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
946           (compression == JPEGCompression) || (image->matte != MagickFalse))
947         {
948           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n0\n%d\n",
949             image->columns,image->rows,(int)
950             (image->colorspace == CMYKColorspace));
951           (void) WriteBlobString(image,buffer);
952           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
953             (int) (compression == NoCompression));
954           (void) WriteBlobString(image,buffer);
955           switch (compression)
956           {
957             case JPEGCompression:
958             {
959               status=InjectImageBlob(image_info,image,image,"jpeg",
960                 &image->exception);
961               if (status == MagickFalse)
962                 ThrowWriterException(CoderError,image->exception.reason);
963               break;
964             }
965             case RLECompression:
966             default:
967             {
968               register unsigned char
969                 *q;
970
971               /*
972                 Allocate pixel array.
973               */
974               length=(size_t) number_pixels;
975               pixels=(unsigned char *) AcquireQuantumMemory(length,
976                 4*sizeof(*pixels));
977               if (pixels == (unsigned char *) NULL)
978                 ThrowWriterException(ResourceLimitError,
979                   "MemoryAllocationFailed");
980               /*
981                 Dump Packbit encoded pixels.
982               */
983               q=pixels;
984               for (y=0; y < (long) image->rows; y++)
985               {
986                 p=GetVirtualPixels(image,0,y,image->columns,1,
987                   &image->exception);
988                 if (p == (const PixelPacket *) NULL)
989                   break;
990                 indexes=GetVirtualIndexQueue(image);
991                 for (x=0; x < (long) image->columns; x++)
992                 {
993                   if ((image->matte != MagickFalse) &&
994                       (p->opacity == (Quantum) TransparentOpacity))
995                     {
996                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
997                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
998                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
999                     }
1000                   else
1001                     if (image->colorspace != CMYKColorspace)
1002                       {
1003                         *q++=ScaleQuantumToChar(p->red);
1004                         *q++=ScaleQuantumToChar(p->green);
1005                         *q++=ScaleQuantumToChar(p->blue);
1006                       }
1007                     else
1008                       {
1009                         *q++=ScaleQuantumToChar(p->red);
1010                         *q++=ScaleQuantumToChar(p->green);
1011                         *q++=ScaleQuantumToChar(p->blue);
1012                         *q++=ScaleQuantumToChar(indexes[x]);
1013                       }
1014                   p++;
1015                 }
1016                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1017                 if (progress == MagickFalse)
1018                   break;
1019               }
1020               length=(size_t) (q-pixels);
1021               if (compression == LZWCompression)
1022                 status=LZWEncodeImage(image,length,pixels);
1023               else
1024                 status=PackbitsEncodeImage(image,length,pixels);
1025               if (status == MagickFalse)
1026                 {
1027                   (void) CloseBlob(image);
1028                   return(MagickFalse);
1029                 }
1030               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1031               break;
1032             }
1033             case NoCompression:
1034             {
1035               /*
1036                 Dump uncompressed DirectColor packets.
1037               */
1038               Ascii85Initialize(image);
1039               for (y=0; y < (long) image->rows; y++)
1040               {
1041                 p=GetVirtualPixels(image,0,y,image->columns,1,
1042                   &image->exception);
1043                 if (p == (const PixelPacket *) NULL)
1044                   break;
1045                 indexes=GetVirtualIndexQueue(image);
1046                 for (x=0; x < (long) image->columns; x++)
1047                 {
1048                   if ((image->matte != MagickFalse) &&
1049                       (p->opacity == (Quantum) TransparentOpacity))
1050                     {
1051                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
1052                         QuantumRange));
1053                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
1054                         QuantumRange));
1055                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
1056                         QuantumRange));
1057                     }
1058                   else
1059                     if (image->colorspace != CMYKColorspace)
1060                       {
1061                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
1062                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
1063                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
1064                       }
1065                     else
1066                       {
1067                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
1068                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
1069                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
1070                         Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
1071                       }
1072                   p++;
1073                 }
1074                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1075                 if (progress == MagickFalse)
1076                   break;
1077               }
1078               Ascii85Flush(image);
1079               break;
1080             }
1081           }
1082         }
1083       else
1084         {
1085           /*
1086             Dump number of colors and colormap.
1087           */
1088           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
1089             image->columns,image->rows,(int)
1090             (image->colorspace == CMYKColorspace));
1091           (void) WriteBlobString(image,buffer);
1092           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
1093             (int) (compression == NoCompression));
1094           (void) WriteBlobString(image,buffer);
1095           (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",image->colors);
1096           (void) WriteBlobString(image,buffer);
1097           for (i=0; i < (long) image->colors; i++)
1098           {
1099             (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1100               ScaleQuantumToChar(image->colormap[i].red),
1101               ScaleQuantumToChar(image->colormap[i].green),
1102               ScaleQuantumToChar(image->colormap[i].blue));
1103             (void) WriteBlobString(image,buffer);
1104           }
1105           switch (compression)
1106           {
1107             case RLECompression:
1108             default:
1109             {
1110               register unsigned char
1111                 *q;
1112
1113               /*
1114                 Allocate pixel array.
1115               */
1116               length=(size_t) number_pixels;
1117               pixels=(unsigned char *) AcquireQuantumMemory(length,
1118                 sizeof(*pixels));
1119               if (pixels == (unsigned char *) NULL)
1120                 ThrowWriterException(ResourceLimitError,
1121                   "MemoryAllocationFailed");
1122               /*
1123                 Dump Runlength encoded pixels.
1124               */
1125               q=pixels;
1126               for (y=0; y < (long) image->rows; y++)
1127               {
1128                 p=GetVirtualPixels(image,0,y,image->columns,1,
1129                   &image->exception);
1130                 if (p == (const PixelPacket *) NULL)
1131                   break;
1132                 indexes=GetVirtualIndexQueue(image);
1133                 for (x=0; x < (long) image->columns; x++)
1134                   *q++=(unsigned char) indexes[x];
1135                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1136                 if (progress == MagickFalse)
1137                   break;
1138               }
1139               length=(size_t) (q-pixels);
1140               if (compression == LZWCompression)
1141                 status=LZWEncodeImage(image,length,pixels);
1142               else
1143                 status=PackbitsEncodeImage(image,length,pixels);
1144               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1145               if (status == MagickFalse)
1146                 {
1147                   (void) CloseBlob(image);
1148                   return(MagickFalse);
1149                 }
1150               break;
1151             }
1152             case NoCompression:
1153             {
1154               /*
1155                 Dump uncompressed PseudoColor packets.
1156               */
1157               Ascii85Initialize(image);
1158               for (y=0; y < (long) image->rows; y++)
1159               {
1160                 p=GetVirtualPixels(image,0,y,image->columns,1,
1161                   &image->exception);
1162                 if (p == (const PixelPacket *) NULL)
1163                   break;
1164                 indexes=GetVirtualIndexQueue(image);
1165                 for (x=0; x < (long) image->columns; x++)
1166                   Ascii85Encode(image,(unsigned char) indexes[x]);
1167                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1168                 if (progress == MagickFalse)
1169                   break;
1170               }
1171               Ascii85Flush(image);
1172               break;
1173             }
1174           }
1175         }
1176     (void) WriteBlobByte(image,'\n');
1177     length=(size_t) (TellBlob(image)-stop);
1178     stop=TellBlob(image);
1179     offset=SeekBlob(image,start,SEEK_SET);
1180     if (offset < 0)
1181       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1182     (void) FormatMagickString(buffer,MaxTextExtent,
1183       "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1184       compression == NoCompression ? "ASCII" : "Binary");
1185     (void) WriteBlobString(image,buffer);
1186     offset=SeekBlob(image,stop,SEEK_SET);
1187     (void) WriteBlobString(image,"%%EndData\n");
1188     if (LocaleCompare(image_info->magick,"PS2") != 0)
1189       (void) WriteBlobString(image,"end\n");
1190     (void) WriteBlobString(image,"%%PageTrailer\n");
1191     if (GetNextImageInList(image) == (Image *) NULL)
1192       break;
1193     image=SyncNextImageInList(image);
1194     status=SetImageProgress(image,SaveImagesTag,scene++,
1195       GetImageListLength(image));
1196     if (status == MagickFalse)
1197       break;
1198   } while (image_info->adjoin != MagickFalse);
1199   (void) WriteBlobString(image,"%%Trailer\n");
1200   if (page > 1)
1201     {
1202       (void) FormatMagickString(buffer,MaxTextExtent,
1203         "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
1204         (long) (bounds.y1+0.5),(long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
1205       (void) WriteBlobString(image,buffer);
1206       (void) FormatMagickString(buffer,MaxTextExtent,
1207         "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1208         bounds.y2);
1209       (void) WriteBlobString(image,buffer);
1210     }
1211   (void) WriteBlobString(image,"%%EOF\n");
1212   (void) CloseBlob(image);
1213   return(MagickTrue);
1214 }