]> granicus.if.org Git - imagemagick/blob - coders/ps2.c
(no commit message)
[imagemagick] / coders / ps2.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   SSSSS  22222                              %
7 %                            P   P  SS        22                              %
8 %                            PPPP    SSS    222                               %
9 %                            P         SS  22                                 %
10 %                            P      SSSSS  22222                              %
11 %                                                                             %
12 %                                                                             %
13 %                      Write Postscript Level II Format                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/compress.h"
49 #include "magick/constitute.h"
50 #include "magick/draw.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/geometry.h"
54 #include "magick/image.h"
55 #include "magick/image-private.h"
56 #include "magick/list.h"
57 #include "magick/magick.h"
58 #include "magick/memory_.h"
59 #include "magick/monitor.h"
60 #include "magick/monitor-private.h"
61 #include "magick/monitor-private.h"
62 #include "magick/option.h"
63 #include "magick/resource_.h"
64 #include "magick/property.h"
65 #include "magick/quantum-private.h"
66 #include "magick/static.h"
67 #include "magick/string_.h"
68 #include "magick/module.h"
69 #include "magick/utility.h"
70 \f
71 /*
72   Define declarations.
73 */
74 #if defined(MAGICKCORE_TIFF_DELEGATE)
75 #define CCITTParam  "-1"
76 #else
77 #define CCITTParam  "0"
78 #endif
79 \f
80 /*
81   Forward declarations.
82 */
83 static MagickBooleanType
84   WritePS2Image(const ImageInfo *,Image *);
85 \f
86 /*
87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88 %                                                                             %
89 %                                                                             %
90 %                                                                             %
91 %   R e g i s t e r P S 2 I m a g e                                           %
92 %                                                                             %
93 %                                                                             %
94 %                                                                             %
95 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 %
97 %  RegisterPS2Image() adds properties for the PS2 image format to
98 %  the list of supported formats.  The properties include the image format
99 %  tag, a method to read and/or write the format, whether the format
100 %  supports the saving of more than one frame to the same file or blob,
101 %  whether the format supports native in-memory I/O, and a brief
102 %  description of the format.
103 %
104 %  The format of the RegisterPS2Image method is:
105 %
106 %      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: %.15g %.15g %.15g %.15g\n",bounds.x1,
589               bounds.y1,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 %.15g 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,
705       "%ld %ld\n%.15g %.15g\n%.15g\n",geometry.x,geometry.y,scale.x,scale.y,
706       pointsize);
707     (void) WriteBlobString(image,buffer);
708     labels=(char **) NULL;
709     value=GetImageProperty(image,"label");
710     if (value != (const char *) NULL)
711       labels=StringToList(value);
712     if (labels != (char **) NULL)
713       {
714         for (i=0; labels[i] != (char *) NULL; i++)
715         {
716           (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
717             labels[i]);
718           (void) WriteBlobString(image,buffer);
719           labels[i]=DestroyString(labels[i]);
720         }
721         labels=(char **) RelinquishMagickMemory(labels);
722       }
723     number_pixels=(MagickSizeType) image->columns*image->rows;
724     if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
725       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
726     if ((compression == FaxCompression) || (compression == Group4Compression) ||
727         ((image_info->type != TrueColorType) &&
728          (IsGrayImage(image,&image->exception) != MagickFalse)))
729       {
730         (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
731           image->columns,image->rows,(int)
732           (image->colorspace == CMYKColorspace));
733         (void) WriteBlobString(image,buffer);
734         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
735           (int) ((compression != FaxCompression) &&
736            (compression != Group4Compression)));
737         (void) WriteBlobString(image,buffer);
738         (void) WriteBlobString(image,"0\n");
739         (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
740            (compression == FaxCompression) ||
741            (compression == Group4Compression) ? 1 : 8);
742         (void) WriteBlobString(image,buffer);
743         switch (compression)
744         {
745           case FaxCompression:
746           case Group4Compression:
747           {
748             if (LocaleCompare(CCITTParam,"0") == 0)
749               {
750                 (void) HuffmanEncodeImage(image_info,image,image);
751                 break;
752               }
753             (void) Huffman2DEncodeImage(image_info,image,image);
754             break;
755           }
756           case JPEGCompression:
757           {
758             status=InjectImageBlob(image_info,image,image,"jpeg",
759               &image->exception);
760             if (status == MagickFalse)
761               ThrowWriterException(CoderError,image->exception.reason);
762             break;
763           }
764           case RLECompression:
765           default:
766           {
767             register unsigned char
768               *q;
769
770             /*
771               Allocate pixel array.
772             */
773             length=(size_t) number_pixels;
774             pixels=(unsigned char *) AcquireQuantumMemory(length,
775               sizeof(*pixels));
776             if (pixels == (unsigned char *) NULL)
777               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
778             /*
779               Dump Runlength encoded pixels.
780             */
781             q=pixels;
782             for (y=0; y < (long) image->rows; y++)
783             {
784               p=GetVirtualPixels(image,0,y,image->columns,1,
785                 &image->exception);
786               if (p == (const PixelPacket *) NULL)
787                 break;
788               for (x=0; x < (long) image->columns; x++)
789               {
790                 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
791                 p++;
792               }
793               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
794               if (progress == MagickFalse)
795                 break;
796             }
797             length=(size_t) (q-pixels);
798             if (compression == LZWCompression)
799               status=LZWEncodeImage(image,length,pixels);
800             else
801               status=PackbitsEncodeImage(image,length,pixels);
802             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
803             if (status == MagickFalse)
804               {
805                 (void) CloseBlob(image);
806                 return(MagickFalse);
807               }
808             break;
809           }
810           case NoCompression:
811           {
812             /*
813               Dump uncompressed PseudoColor packets.
814             */
815             Ascii85Initialize(image);
816             for (y=0; y < (long) image->rows; y++)
817             {
818               p=GetVirtualPixels(image,0,y,image->columns,1,
819                 &image->exception);
820               if (p == (const PixelPacket *) NULL)
821                 break;
822               for (x=0; x < (long) image->columns; x++)
823               {
824                 Ascii85Encode(image,
825                   ScaleQuantumToChar(PixelIntensityToQuantum(p)));
826                 p++;
827               }
828               progress=SetImageProgress(image,SaveImageTag,y,image->rows);
829               if (progress == MagickFalse)
830                 break;
831             }
832             Ascii85Flush(image);
833             break;
834           }
835         }
836       }
837     else
838       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
839           (compression == JPEGCompression) || (image->matte != MagickFalse))
840         {
841           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n0\n%d\n",
842             image->columns,image->rows,(int)
843             (image->colorspace == CMYKColorspace));
844           (void) WriteBlobString(image,buffer);
845           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
846             (int) (compression == NoCompression));
847           (void) WriteBlobString(image,buffer);
848           switch (compression)
849           {
850             case JPEGCompression:
851             {
852               status=InjectImageBlob(image_info,image,image,"jpeg",
853                 &image->exception);
854               if (status == MagickFalse)
855                 ThrowWriterException(CoderError,image->exception.reason);
856               break;
857             }
858             case RLECompression:
859             default:
860             {
861               register unsigned char
862                 *q;
863
864               /*
865                 Allocate pixel array.
866               */
867               length=(size_t) number_pixels;
868               pixels=(unsigned char *) AcquireQuantumMemory(length,
869                 4*sizeof(*pixels));
870               if (pixels == (unsigned char *) NULL)
871                 ThrowWriterException(ResourceLimitError,
872                   "MemoryAllocationFailed");
873               /*
874                 Dump Packbit encoded pixels.
875               */
876               q=pixels;
877               for (y=0; y < (long) image->rows; y++)
878               {
879                 p=GetVirtualPixels(image,0,y,image->columns,1,
880                   &image->exception);
881                 if (p == (const PixelPacket *) NULL)
882                   break;
883                 indexes=GetVirtualIndexQueue(image);
884                 for (x=0; x < (long) image->columns; x++)
885                 {
886                   if ((image->matte != MagickFalse) &&
887                       (p->opacity == (Quantum) TransparentOpacity))
888                     {
889                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
890                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
891                       *q++=ScaleQuantumToChar((Quantum) QuantumRange);
892                     }
893                   else
894                     if (image->colorspace != CMYKColorspace)
895                       {
896                         *q++=ScaleQuantumToChar(p->red);
897                         *q++=ScaleQuantumToChar(p->green);
898                         *q++=ScaleQuantumToChar(p->blue);
899                       }
900                     else
901                       {
902                         *q++=ScaleQuantumToChar(p->red);
903                         *q++=ScaleQuantumToChar(p->green);
904                         *q++=ScaleQuantumToChar(p->blue);
905                         *q++=ScaleQuantumToChar(indexes[x]);
906                       }
907                   p++;
908                 }
909                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
910                 if (progress == MagickFalse)
911                   break;
912               }
913               length=(size_t) (q-pixels);
914               if (compression == LZWCompression)
915                 status=LZWEncodeImage(image,length,pixels);
916               else
917                 status=PackbitsEncodeImage(image,length,pixels);
918               if (status == MagickFalse)
919                 {
920                   (void) CloseBlob(image);
921                   return(MagickFalse);
922                 }
923               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
924               break;
925             }
926             case NoCompression:
927             {
928               /*
929                 Dump uncompressed DirectColor packets.
930               */
931               Ascii85Initialize(image);
932               for (y=0; y < (long) image->rows; y++)
933               {
934                 p=GetVirtualPixels(image,0,y,image->columns,1,
935                   &image->exception);
936                 if (p == (const PixelPacket *) NULL)
937                   break;
938                 indexes=GetVirtualIndexQueue(image);
939                 for (x=0; x < (long) image->columns; x++)
940                 {
941                   if ((image->matte != MagickFalse) &&
942                       (p->opacity == (Quantum) TransparentOpacity))
943                     {
944                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
945                         QuantumRange));
946                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
947                         QuantumRange));
948                       Ascii85Encode(image,ScaleQuantumToChar((Quantum)
949                         QuantumRange));
950                     }
951                   else
952                     if (image->colorspace != CMYKColorspace)
953                       {
954                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
955                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
956                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
957                       }
958                     else
959                       {
960                         Ascii85Encode(image,ScaleQuantumToChar(p->red));
961                         Ascii85Encode(image,ScaleQuantumToChar(p->green));
962                         Ascii85Encode(image,ScaleQuantumToChar(p->blue));
963                         Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
964                       }
965                   p++;
966                 }
967                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
968                 if (progress == MagickFalse)
969                   break;
970               }
971               Ascii85Flush(image);
972               break;
973             }
974           }
975         }
976       else
977         {
978           /*
979             Dump number of colors and colormap.
980           */
981           (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n1\n%d\n",
982             image->columns,image->rows,(int)
983             (image->colorspace == CMYKColorspace));
984           (void) WriteBlobString(image,buffer);
985           (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
986             (int) (compression == NoCompression));
987           (void) WriteBlobString(image,buffer);
988           (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",image->colors);
989           (void) WriteBlobString(image,buffer);
990           for (i=0; i < (long) image->colors; i++)
991           {
992             (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
993               ScaleQuantumToChar(image->colormap[i].red),
994               ScaleQuantumToChar(image->colormap[i].green),
995               ScaleQuantumToChar(image->colormap[i].blue));
996             (void) WriteBlobString(image,buffer);
997           }
998           switch (compression)
999           {
1000             case RLECompression:
1001             default:
1002             {
1003               register unsigned char
1004                 *q;
1005
1006               /*
1007                 Allocate pixel array.
1008               */
1009               length=(size_t) number_pixels;
1010               pixels=(unsigned char *) AcquireQuantumMemory(length,
1011                 sizeof(*pixels));
1012               if (pixels == (unsigned char *) NULL)
1013                 ThrowWriterException(ResourceLimitError,
1014                   "MemoryAllocationFailed");
1015               /*
1016                 Dump Runlength encoded pixels.
1017               */
1018               q=pixels;
1019               for (y=0; y < (long) image->rows; y++)
1020               {
1021                 p=GetVirtualPixels(image,0,y,image->columns,1,
1022                   &image->exception);
1023                 if (p == (const PixelPacket *) NULL)
1024                   break;
1025                 indexes=GetVirtualIndexQueue(image);
1026                 for (x=0; x < (long) image->columns; x++)
1027                   *q++=(unsigned char) indexes[x];
1028                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1029                 if (progress == MagickFalse)
1030                   break;
1031               }
1032               length=(size_t) (q-pixels);
1033               if (compression == LZWCompression)
1034                 status=LZWEncodeImage(image,length,pixels);
1035               else
1036                 status=PackbitsEncodeImage(image,length,pixels);
1037               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1038               if (status == MagickFalse)
1039                 {
1040                   (void) CloseBlob(image);
1041                   return(MagickFalse);
1042                 }
1043               break;
1044             }
1045             case NoCompression:
1046             {
1047               /*
1048                 Dump uncompressed PseudoColor packets.
1049               */
1050               Ascii85Initialize(image);
1051               for (y=0; y < (long) image->rows; y++)
1052               {
1053                 p=GetVirtualPixels(image,0,y,image->columns,1,
1054                   &image->exception);
1055                 if (p == (const PixelPacket *) NULL)
1056                   break;
1057                 indexes=GetVirtualIndexQueue(image);
1058                 for (x=0; x < (long) image->columns; x++)
1059                   Ascii85Encode(image,(unsigned char) indexes[x]);
1060                 progress=SetImageProgress(image,SaveImageTag,y,image->rows);
1061                 if (progress == MagickFalse)
1062                   break;
1063               }
1064               Ascii85Flush(image);
1065               break;
1066             }
1067           }
1068         }
1069     (void) WriteBlobByte(image,'\n');
1070     length=(size_t) (TellBlob(image)-stop);
1071     stop=TellBlob(image);
1072     offset=SeekBlob(image,start,SEEK_SET);
1073     if (offset < 0)
1074       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1075     (void) FormatMagickString(buffer,MaxTextExtent,
1076       "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1077       compression == NoCompression ? "ASCII" : "Binary");
1078     (void) WriteBlobString(image,buffer);
1079     offset=SeekBlob(image,stop,SEEK_SET);
1080     (void) WriteBlobString(image,"%%EndData\n");
1081     if (LocaleCompare(image_info->magick,"PS2") != 0)
1082       (void) WriteBlobString(image,"end\n");
1083     (void) WriteBlobString(image,"%%PageTrailer\n");
1084     if (GetNextImageInList(image) == (Image *) NULL)
1085       break;
1086     image=SyncNextImageInList(image);
1087     status=SetImageProgress(image,SaveImagesTag,scene++,
1088       GetImageListLength(image));
1089     if (status == MagickFalse)
1090       break;
1091   } while (image_info->adjoin != MagickFalse);
1092   (void) WriteBlobString(image,"%%Trailer\n");
1093   if (page > 1)
1094     {
1095       (void) FormatMagickString(buffer,MaxTextExtent,
1096         "%%%%BoundingBox: %ld %ld %ld %ld\n",(long) (bounds.x1+0.5),
1097         (long) (bounds.y1+0.5),(long) (bounds.x2+0.5),(long) (bounds.y2+0.5));
1098       (void) WriteBlobString(image,buffer);
1099       (void) FormatMagickString(buffer,MaxTextExtent,
1100         "%%%%HiResBoundingBox: %.15g %.15g %.15g %.15g\n",bounds.x1,bounds.y1,
1101         bounds.x2,bounds.y2);
1102       (void) WriteBlobString(image,buffer);
1103     }
1104   (void) WriteBlobString(image,"%%EOF\n");
1105   (void) CloseBlob(image);
1106   return(MagickTrue);
1107 }