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