Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            PPPP   SSSSS  33333                              %
      7 %                            P   P  SS        33                              %
      8 %                            PPPP    SSS    333                               %
      9 %                            P         SS     33                              %
     10 %                            P      SSSSS  33333                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     Write Postscript Level III Format                       %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                              Lars Ruben Skyum                               %
     18 %                                 July 1992                                   %
     19 %                                                                             %
     20 %                                                                             %
     21 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     22 %  dedicated to making software imaging solutions freely available.           %
     23 %                                                                             %
     24 %  You may not use this file except in compliance with the License.  You may  %
     25 %  obtain a copy of the License at                                            %
     26 %                                                                             %
     27 %    https://imagemagick.org/script/license.php                               %
     28 %                                                                             %
     29 %  Unless required by applicable law or agreed to in writing, software        %
     30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     32 %  See the License for the specific language governing permissions and        %
     33 %  limitations under the License.                                             %
     34 %                                                                             %
     35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     36 %
     37 %
     38 */
     39 
     40 /*
     42   Include declarations.
     43 */
     44 #include "MagickCore/studio.h"
     45 #include "MagickCore/artifact.h"
     46 #include "MagickCore/attribute.h"
     47 #include "MagickCore/blob.h"
     48 #include "MagickCore/blob-private.h"
     49 #include "MagickCore/cache.h"
     50 #include "MagickCore/channel.h"
     51 #include "MagickCore/color.h"
     52 #include "MagickCore/color-private.h"
     53 #include "MagickCore/compress.h"
     54 #include "MagickCore/constitute.h"
     55 #include "MagickCore/draw.h"
     56 #include "MagickCore/exception.h"
     57 #include "MagickCore/exception-private.h"
     58 #include "MagickCore/geometry.h"
     59 #include "MagickCore/image.h"
     60 #include "MagickCore/image-private.h"
     61 #include "MagickCore/list.h"
     62 #include "MagickCore/magick.h"
     63 #include "MagickCore/memory_.h"
     64 #include "MagickCore/monitor.h"
     65 #include "MagickCore/monitor-private.h"
     66 #include "MagickCore/option.h"
     67 #include "MagickCore/pixel-accessor.h"
     68 #include "MagickCore/property.h"
     69 #include "MagickCore/quantum-private.h"
     70 #include "MagickCore/resource_.h"
     71 #include "MagickCore/static.h"
     72 #include "MagickCore/string_.h"
     73 #include "MagickCore/module.h"
     74 #include "MagickCore/token.h"
     75 #include "MagickCore/utility.h"
     76 #include "MagickCore/module.h"
     77 
     78 /*
     80   Define declarations.
     81 */
     82 #define PS3_NoCompression "0"
     83 #define PS3_FaxCompression "1"
     84 #define PS3_JPEGCompression "2"
     85 #define PS3_LZWCompression "3"
     86 #define PS3_RLECompression "4"
     87 #define PS3_ZipCompression "5"
     88 
     89 #define PS3_RGBColorspace "0"
     90 #define PS3_CMYKColorspace "1"
     91 
     92 #define PS3_DirectClass "0"
     93 #define PS3_PseudoClass "1"
     94 
     95 #if defined(MAGICKCORE_TIFF_DELEGATE)
     96 #define CCITTParam  "-1"
     97 #else
     98 #define CCITTParam  "0"
     99 #endif
    100 
    101 /*
    103   Forward declarations.
    104 */
    105 static MagickBooleanType
    106   WritePS3Image(const ImageInfo *,Image *,ExceptionInfo *);
    107 
    108 /*
    110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    111 %                                                                             %
    112 %                                                                             %
    113 %                                                                             %
    114 %   R e g i s t e r P S 3 I m a g e                                           %
    115 %                                                                             %
    116 %                                                                             %
    117 %                                                                             %
    118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    119 %
    120 %  RegisterPS3Image() adds properties for the PS3 image format to the list of
    121 %  supported formats.  The properties include the image format tag, a method to
    122 %  read and/or write the format, whether the format supports the saving of more
    123 %  than one frame to the same file or blob, whether the format supports native
    124 %  in-memory I/O, and a brief description of the format.
    125 %
    126 %  The format of the RegisterPS3Image method is:
    127 %
    128 %      size_t RegisterPS3Image(void)
    129 %
    130 */
    131 ModuleExport size_t RegisterPS3Image(void)
    132 {
    133   MagickInfo
    134     *entry;
    135 
    136   entry=AcquireMagickInfo("PS3","EPS3","Level III Encapsulated PostScript");
    137   entry->encoder=(EncodeImageHandler *) WritePS3Image;
    138   entry->mime_type=ConstantString("application/postscript");
    139   entry->flags|=CoderEncoderSeekableStreamFlag;
    140   entry->flags^=CoderBlobSupportFlag;
    141   (void) RegisterMagickInfo(entry);
    142   entry=AcquireMagickInfo("PS3","PS3","Level III PostScript");
    143   entry->encoder=(EncodeImageHandler *) WritePS3Image;
    144   entry->mime_type=ConstantString("application/postscript");
    145   entry->flags|=CoderEncoderSeekableStreamFlag;
    146   entry->flags^=CoderBlobSupportFlag;
    147   (void) RegisterMagickInfo(entry);
    148   return(MagickImageCoderSignature);
    149 }
    150 
    151 /*
    153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    154 %                                                                             %
    155 %                                                                             %
    156 %                                                                             %
    157 %   U n r e g i s t e r P S 3 I m a g e                                       %
    158 %                                                                             %
    159 %                                                                             %
    160 %                                                                             %
    161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    162 %
    163 %  UnregisterPS3Image() removes format registrations made by the PS3 module
    164 %  from the list of supported formats.
    165 %
    166 %  The format of the UnregisterPS3Image method is:
    167 %
    168 %      UnregisterPS3Image(void)
    169 %
    170 */
    171 ModuleExport void UnregisterPS3Image(void)
    172 {
    173   (void) UnregisterMagickInfo("EPS3");
    174   (void) UnregisterMagickInfo("PS3");
    175 }
    176 
    177 /*
    179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    180 %                                                                             %
    181 %                                                                             %
    182 %                                                                             %
    183 %   W r i t e P S 3 I m a g e                                                 %
    184 %                                                                             %
    185 %                                                                             %
    186 %                                                                             %
    187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    188 %
    189 %  WritePS3Image() translates an image to encapsulated Postscript Level III
    190 %  for printing.  If the supplied geometry is null, the image is centered on
    191 %  the Postscript page.  Otherwise, the image is positioned as specified by the
    192 %  geometry.
    193 %
    194 %  The format of the WritePS3Image method is:
    195 %
    196 %      MagickBooleanType WritePS3Image(const ImageInfo *image_info,
    197 %        Image *image,ExceptionInfo *exception)
    198 %
    199 %  A description of each parameter follows:
    200 %
    201 %    o image_info: Specifies a pointer to a ImageInfo structure.
    202 %
    203 %    o image: the image.
    204 %
    205 %    o exception: return any errors or warnings in this structure.
    206 %
    207 */
    208 
    209 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
    210   Image *image,Image *inject_image,ExceptionInfo *exception)
    211 {
    212   Image
    213     *group4_image;
    214 
    215   ImageInfo
    216     *write_info;
    217 
    218   MagickBooleanType
    219     status;
    220 
    221   size_t
    222     length;
    223 
    224   unsigned char
    225     *group4;
    226 
    227   status=MagickTrue;
    228   write_info=CloneImageInfo(image_info);
    229   (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
    230   (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
    231   group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
    232   if (group4_image == (Image *) NULL)
    233     return(MagickFalse);
    234   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
    235     exception);
    236   group4_image=DestroyImage(group4_image);
    237   if (group4 == (unsigned char *) NULL)
    238     return(MagickFalse);
    239   write_info=DestroyImageInfo(write_info);
    240   if (WriteBlob(image,length,group4) != (ssize_t) length)
    241     status=MagickFalse;
    242   group4=(unsigned char *) RelinquishMagickMemory(group4);
    243   return(status);
    244 }
    245 
    246 static MagickBooleanType SerializeImage(const ImageInfo *image_info,
    247   Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
    248 {
    249   MagickBooleanType
    250     status;
    251 
    252   register const Quantum
    253     *p;
    254 
    255   register ssize_t
    256     x;
    257 
    258   register unsigned char
    259     *q;
    260 
    261   ssize_t
    262     y;
    263 
    264   assert(image != (Image *) NULL);
    265   assert(image->signature == MagickCoreSignature);
    266   if (image->debug != MagickFalse)
    267     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    268   status=MagickTrue;
    269   *length=(image->colorspace == CMYKColorspace ? 4 : 3)*(size_t)
    270     image->columns*image->rows;
    271   *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
    272   if (*pixel_info == (MemoryInfo *) NULL)
    273     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    274   q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
    275   for (y=0; y < (ssize_t) image->rows; y++)
    276   {
    277     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    278     if (p == (const Quantum *) NULL)
    279       break;
    280     if (image->colorspace != CMYKColorspace)
    281       for (x=0; x < (ssize_t) image->columns; x++)
    282       {
    283         *q++=ScaleQuantumToChar(GetPixelRed(image,p));
    284         *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
    285         *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
    286         p+=GetPixelChannels(image);
    287       }
    288     else
    289       for (x=0; x < (ssize_t) image->columns; x++)
    290       {
    291         *q++=ScaleQuantumToChar(GetPixelRed(image,p));
    292         *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
    293         *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
    294         *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
    295         p+=GetPixelChannels(image);
    296       }
    297     if (image->previous == (Image *) NULL)
    298       {
    299         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    300           image->rows);
    301         if (status == MagickFalse)
    302           break;
    303       }
    304   }
    305   if (status == MagickFalse)
    306     *pixel_info=RelinquishVirtualMemory(*pixel_info);
    307   return(status);
    308 }
    309 
    310 static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
    311   Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
    312 {
    313   MagickBooleanType
    314     status;
    315 
    316   register const Quantum
    317     *p;
    318 
    319   register ssize_t
    320     x;
    321 
    322   register unsigned char
    323     *q;
    324 
    325   size_t
    326     pack,
    327     padded_columns;
    328 
    329   ssize_t
    330     y;
    331 
    332   unsigned char
    333     code,
    334     bit;
    335 
    336   assert(image != (Image *) NULL);
    337   assert(image->signature == MagickCoreSignature);
    338   if (image->debug != MagickFalse)
    339     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    340   status=MagickTrue;
    341   pack=SetImageMonochrome(image,exception) == MagickFalse ? 1UL : 8UL;
    342   padded_columns=((image->columns+pack-1)/pack)*pack;
    343   *length=(size_t) padded_columns*image->rows/pack;
    344   *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
    345   if (*pixel_info == (MemoryInfo *) NULL)
    346     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    347   q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
    348   for (y=0; y < (ssize_t) image->rows; y++)
    349   {
    350     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    351     if (p == (const Quantum *) NULL)
    352       break;
    353     if (pack == 1)
    354       for (x=0; x < (ssize_t) image->columns; x++)
    355       {
    356         *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
    357         p+=GetPixelChannels(image);
    358       }
    359     else
    360       {
    361         code='\0';
    362         for (x=0; x < (ssize_t) padded_columns; x++)
    363         {
    364           bit=(unsigned char) 0x00;
    365           if (x < (ssize_t) image->columns)
    366             bit=(unsigned char) (GetPixelLuma(image,p) == TransparentAlpha ?
    367               0x01 : 0x00);
    368           code=(code << 1)+bit;
    369           if (((x+1) % pack) == 0)
    370             {
    371               *q++=code;
    372               code='\0';
    373             }
    374           p+=GetPixelChannels(image);
    375         }
    376       }
    377     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    378       image->rows);
    379     if (status == MagickFalse)
    380       break;
    381   }
    382   if (status == MagickFalse)
    383     *pixel_info=RelinquishVirtualMemory(*pixel_info);
    384   return(status);
    385 }
    386 
    387 static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
    388   Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
    389 {
    390   MagickBooleanType
    391     status;
    392 
    393   register const Quantum
    394     *p;
    395 
    396   register ssize_t
    397     x;
    398 
    399   register unsigned char
    400     *q;
    401 
    402   ssize_t
    403     y;
    404 
    405   assert(image != (Image *) NULL);
    406   assert(image->signature == MagickCoreSignature);
    407   if (image->debug != MagickFalse)
    408     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    409   status=MagickTrue;
    410   *length=(size_t) image->columns*image->rows;
    411   *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
    412   if (*pixel_info == (MemoryInfo *) NULL)
    413     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    414   q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
    415   for (y=0; y < (ssize_t) image->rows; y++)
    416   {
    417     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    418     if (p == (const Quantum *) NULL)
    419       break;
    420     for (x=0; x < (ssize_t) image->columns; x++)
    421     {
    422       *q++=(unsigned char) GetPixelIndex(image,p);
    423       p+=GetPixelChannels(image);
    424     }
    425     if (image->previous == (Image *) NULL)
    426       {
    427         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    428           image->rows);
    429         if (status == MagickFalse)
    430           break;
    431       }
    432   }
    433   if (status == MagickFalse)
    434     *pixel_info=RelinquishVirtualMemory(*pixel_info);
    435   return(status);
    436 }
    437 
    438 static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
    439   Image *image,const CompressionType compression,ExceptionInfo *exception)
    440 {
    441   char
    442     buffer[MagickPathExtent];
    443 
    444   Image
    445     *mask_image;
    446 
    447   MagickBooleanType
    448     status;
    449 
    450   MagickOffsetType
    451     offset,
    452     start,
    453     stop;
    454 
    455   MemoryInfo
    456     *pixel_info;
    457 
    458   register ssize_t
    459     i;
    460 
    461   size_t
    462     length;
    463 
    464   unsigned char
    465     *pixels;
    466 
    467   assert(image_info != (ImageInfo *) NULL);
    468   assert(image_info->signature == MagickCoreSignature);
    469   assert(image != (Image *) NULL);
    470   assert(image->signature == MagickCoreSignature);
    471   if (image->debug != MagickFalse)
    472     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    473   assert(image->alpha_trait != UndefinedPixelTrait);
    474   status=MagickTrue;
    475   /*
    476     Note BeginData DSC comment for update later.
    477   */
    478   start=TellBlob(image);
    479   if (start < 0)
    480     ThrowWriterException(CorruptImageError,"ImproperImageHeader");
    481   (void) FormatLocaleString(buffer,MagickPathExtent,
    482     "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
    483     "ASCII" : "BINARY");
    484   (void) WriteBlobString(image,buffer);
    485   stop=TellBlob(image);
    486   if (stop < 0)
    487     ThrowWriterException(CorruptImageError,"ImproperImageHeader");
    488   /*
    489     Only lossless compressions for the mask.
    490   */
    491   switch (compression)
    492   {
    493     case NoCompression:
    494     default:
    495     {
    496       (void) FormatLocaleString(buffer,MagickPathExtent,
    497         "currentfile %.20g %.20g " PS3_NoCompression
    498         " ByteStreamDecodeFilter\n",(double) image->columns,(double)
    499         image->rows);
    500       break;
    501     }
    502     case FaxCompression:
    503     case Group4Compression:
    504     {
    505       (void) FormatLocaleString(buffer,MagickPathExtent,
    506         "currentfile %.20g %.20g " PS3_FaxCompression
    507         " ByteStreamDecodeFilter\n",(double) image->columns,(double)
    508         image->rows);
    509       break;
    510     }
    511     case LZWCompression:
    512     {
    513       (void) FormatLocaleString(buffer,MagickPathExtent,
    514         "currentfile %.20g %.20g " PS3_LZWCompression
    515         " ByteStreamDecodeFilter\n",(double) image->columns,(double)
    516         image->rows);
    517       break;
    518     }
    519     case RLECompression:
    520     {
    521       (void) FormatLocaleString(buffer,MagickPathExtent,
    522         "currentfile %.20g %.20g " PS3_RLECompression
    523         " ByteStreamDecodeFilter\n",(double) image->columns,(double)
    524         image->rows);
    525       break;
    526     }
    527     case ZipCompression:
    528     {
    529       (void) FormatLocaleString(buffer,MagickPathExtent,
    530         "currentfile %.20g %.20g " PS3_ZipCompression
    531         " ByteStreamDecodeFilter\n",(double) image->columns,(double)
    532         image->rows);
    533       break;
    534     }
    535   }
    536   (void) WriteBlobString(image,buffer);
    537   (void) WriteBlobString(image,"/ReusableStreamDecode filter\n");
    538   mask_image=SeparateImage(image,AlphaChannel,exception);
    539   if (mask_image == (Image *) NULL)
    540     ThrowWriterException(CoderError,exception->reason);
    541   (void) SetImageType(mask_image,BilevelType,exception);
    542   (void) SetImageType(mask_image,PaletteType,exception);
    543   mask_image->alpha_trait=UndefinedPixelTrait;
    544   pixels=(unsigned char *) NULL;
    545   length=0;
    546   switch (compression)
    547   {
    548     case NoCompression:
    549     default:
    550     {
    551       status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
    552         exception);
    553       if (status == MagickFalse)
    554         break;
    555       Ascii85Initialize(image);
    556       pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    557       for (i=0; i < (ssize_t) length; i++)
    558         Ascii85Encode(image,pixels[i]);
    559       Ascii85Flush(image);
    560       pixel_info=RelinquishVirtualMemory(pixel_info);
    561       break;
    562     }
    563     case FaxCompression:
    564     case Group4Compression:
    565     {
    566       if ((compression == FaxCompression) ||
    567           (LocaleCompare(CCITTParam,"0") == 0))
    568         status=HuffmanEncodeImage(image_info,image,mask_image,exception);
    569       else
    570         status=Huffman2DEncodeImage(image_info,image,mask_image,exception);
    571       break;
    572     }
    573     case LZWCompression:
    574     {
    575       status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
    576         exception);
    577       if (status == MagickFalse)
    578         break;
    579       pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    580       status=LZWEncodeImage(image,length,pixels,exception);
    581       pixel_info=RelinquishVirtualMemory(pixel_info);
    582       break;
    583     }
    584     case RLECompression:
    585     {
    586       status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
    587         exception);
    588       if (status == MagickFalse)
    589         break;
    590       pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    591       status=PackbitsEncodeImage(image,length,pixels,exception);
    592       pixel_info=RelinquishVirtualMemory(pixel_info);
    593       break;
    594     }
    595     case ZipCompression:
    596     {
    597       status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
    598         exception);
    599       if (status == MagickFalse)
    600         break;
    601       pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    602       status=ZLIBEncodeImage(image,length,pixels,exception);
    603       pixel_info=RelinquishVirtualMemory(pixel_info);
    604       break;
    605     }
    606   }
    607   mask_image=DestroyImage(mask_image);
    608   (void) WriteBlobByte(image,'\n');
    609   length=(size_t) (TellBlob(image)-stop);
    610   stop=TellBlob(image);
    611   if (stop < 0)
    612     ThrowWriterException(CorruptImageError,"ImproperImageHeader");
    613   offset=SeekBlob(image,start,SEEK_SET);
    614   if (offset < 0)
    615     ThrowWriterException(CorruptImageError,"ImproperImageHeader");
    616   (void) FormatLocaleString(buffer,MagickPathExtent,
    617     "%%%%BeginData:%13ld %s Bytes\n",(long) length,
    618     compression == NoCompression ? "ASCII" : "BINARY");
    619   (void) WriteBlobString(image,buffer);
    620   offset=SeekBlob(image,stop,SEEK_SET);
    621   if (offset < 0)
    622     ThrowWriterException(CorruptImageError,"ImproperImageHeader");
    623   (void) WriteBlobString(image,"%%EndData\n");
    624   (void) WriteBlobString(image, "/mask_stream exch def\n");
    625   return(status);
    626 }
    627 
    628 static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
    629   ExceptionInfo *exception)
    630 {
    631   static const char
    632     *const PostscriptProlog[]=
    633     {
    634       "/ByteStreamDecodeFilter",
    635       "{",
    636       "  /z exch def",
    637       "  /r exch def",
    638       "  /c exch def",
    639       "  z " PS3_NoCompression " eq { /ASCII85Decode filter } if",
    640       "  z " PS3_FaxCompression " eq",
    641       "  {",
    642       "    <<",
    643       "      /K " CCITTParam,
    644       "      /Columns c",
    645       "      /Rows r",
    646       "    >>",
    647       "    /CCITTFaxDecode filter",
    648       "  } if",
    649       "  z " PS3_JPEGCompression " eq { /DCTDecode filter } if",
    650       "  z " PS3_LZWCompression " eq { /LZWDecode filter } if",
    651       "  z " PS3_RLECompression " eq { /RunLengthDecode filter } if",
    652       "  z " PS3_ZipCompression " eq { /FlateDecode filter } if",
    653       "} bind def",
    654       "",
    655       "/DirectClassImageDict",
    656       "{",
    657       "  colorspace " PS3_RGBColorspace " eq",
    658       "  {",
    659       "    /DeviceRGB setcolorspace",
    660       "    <<",
    661       "      /ImageType 1",
    662       "      /Width columns",
    663       "      /Height rows",
    664       "      /BitsPerComponent 8",
    665       "      /DataSource pixel_stream",
    666       "      /MultipleDataSources false",
    667       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
    668       "      /Decode [0 1 0 1 0 1]",
    669       "    >>",
    670       "  }",
    671       "  {",
    672       "    /DeviceCMYK setcolorspace",
    673       "    <<",
    674       "      /ImageType 1",
    675       "      /Width columns",
    676       "      /Height rows",
    677       "      /BitsPerComponent 8",
    678       "      /DataSource pixel_stream",
    679       "      /MultipleDataSources false",
    680       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
    681       "      /Decode",
    682       "        compression " PS3_JPEGCompression " eq",
    683       "        { [1 0 1 0 1 0 1 0] }",
    684       "        { [0 1 0 1 0 1 0 1] }",
    685       "        ifelse",
    686       "    >>",
    687       "  }",
    688       "  ifelse",
    689       "} bind def",
    690       "",
    691       "/PseudoClassImageDict",
    692       "{",
    693       "  % Colors in colormap image.",
    694       "  currentfile buffer readline pop",
    695       "  token pop /colors exch def pop",
    696       "  colors 0 eq",
    697       "  {",
    698       "    % Depth of grayscale image.",
    699       "    currentfile buffer readline pop",
    700       "    token pop /bits exch def pop",
    701       "    /DeviceGray setcolorspace",
    702       "    <<",
    703       "      /ImageType 1",
    704       "      /Width columns",
    705       "      /Height rows",
    706       "      /BitsPerComponent bits",
    707       "      /Decode [0 1]",
    708       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
    709       "      /DataSource pixel_stream",
    710       "    >>",
    711       "  }",
    712       "  {",
    713       "    % RGB colormap.",
    714       "    /colormap colors 3 mul string def",
    715       "    compression " PS3_NoCompression " eq",
    716       "    { currentfile /ASCII85Decode filter colormap readstring pop pop }",
    717       "    { currentfile colormap readstring pop pop }",
    718       "    ifelse",
    719       "    [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
    720       "    <<",
    721       "      /ImageType 1",
    722       "      /Width columns",
    723       "      /Height rows",
    724       "      /BitsPerComponent 8",
    725       "      /Decode [0 255]",
    726       "      /ImageMatrix [columns 0 0 rows neg 0 rows]",
    727       "      /DataSource pixel_stream",
    728       "    >>",
    729       "  }",
    730       "  ifelse",
    731       "} bind def",
    732       "",
    733       "/NonMaskedImageDict",
    734       "{",
    735       "  class " PS3_PseudoClass " eq",
    736       "  { PseudoClassImageDict }",
    737       "  { DirectClassImageDict }",
    738       "  ifelse",
    739       "} bind def",
    740       "",
    741       "/MaskedImageDict",
    742       "{",
    743       "  <<",
    744       "    /ImageType 3",
    745       "    /InterleaveType 3",
    746       "    /DataDict NonMaskedImageDict",
    747       "    /MaskDict",
    748       "    <<",
    749       "      /ImageType 1",
    750       "      /Width columns",
    751       "      /Height rows",
    752       "      /BitsPerComponent 1",
    753       "      /DataSource mask_stream",
    754       "      /MultipleDataSources false",
    755       "      /ImageMatrix [ columns 0 0 rows neg 0 rows]",
    756       "      /Decode [ 0 1 ]",
    757       "    >>",
    758       "  >>",
    759       "} bind def",
    760       "",
    761       "/ClipImage",
    762       "{} def",
    763       "",
    764       "/DisplayImage",
    765       "{",
    766       "  gsave",
    767       "  /buffer 512 string def",
    768       "  % Translation.",
    769       "  currentfile buffer readline pop",
    770       "  token pop /x exch def",
    771       "  token pop /y exch def pop",
    772       "  x y translate",
    773       "  % Image size and font size.",
    774       "  currentfile buffer readline pop",
    775       "  token pop /x exch def",
    776       "  token pop /y exch def pop",
    777       "  currentfile buffer readline pop",
    778       "  token pop /pointsize exch def pop",
    779       (const char *) NULL
    780     },
    781     *const PostscriptEpilog[]=
    782     {
    783       "  x y scale",
    784       "  % Clipping path.",
    785       "  currentfile buffer readline pop",
    786       "  token pop /clipped exch def pop",
    787       "  % Showpage.",
    788       "  currentfile buffer readline pop",
    789       "  token pop /sp exch def pop",
    790       "  % Image pixel size.",
    791       "  currentfile buffer readline pop",
    792       "  token pop /columns exch def",
    793       "  token pop /rows exch def pop",
    794       "  % Colorspace (RGB/CMYK).",
    795       "  currentfile buffer readline pop",
    796       "  token pop /colorspace exch def pop",
    797       "  % Transparency.",
    798       "  currentfile buffer readline pop",
    799       "  token pop /alpha exch def pop",
    800       "  % Stencil mask?",
    801       "  currentfile buffer readline pop",
    802       "  token pop /stencil exch def pop",
    803       "  % Image class (direct/pseudo).",
    804       "  currentfile buffer readline pop",
    805       "  token pop /class exch def pop",
    806       "  % Compression type.",
    807       "  currentfile buffer readline pop",
    808       "  token pop /compression exch def pop",
    809       "  % Clip and render.",
    810       "  /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def",
    811       "  clipped { ClipImage } if",
    812       "  alpha stencil not and",
    813       "  { MaskedImageDict mask_stream resetfile }",
    814       "  { NonMaskedImageDict }",
    815       "  ifelse",
    816       "  stencil { 0 setgray imagemask } { image } ifelse",
    817       "  grestore",
    818       "  sp { showpage } if",
    819       "} bind def",
    820       (const char *) NULL
    821     };
    822 
    823   char
    824     buffer[MagickPathExtent],
    825     date[MagickPathExtent],
    826     **labels,
    827     page_geometry[MagickPathExtent];
    828 
    829   CompressionType
    830     compression;
    831 
    832   const char
    833     *option,
    834     *const *q,
    835     *value;
    836 
    837   double
    838     pointsize;
    839 
    840   GeometryInfo
    841     geometry_info;
    842 
    843   MagickBooleanType
    844     status;
    845 
    846   MagickOffsetType
    847     offset,
    848     scene,
    849     start,
    850     stop;
    851 
    852   MagickStatusType
    853     flags;
    854 
    855   MemoryInfo
    856     *pixel_info;
    857 
    858   PointInfo
    859     delta,
    860     resolution,
    861     scale;
    862 
    863   RectangleInfo
    864     geometry,
    865     media_info,
    866     page_info;
    867 
    868   register ssize_t
    869     i;
    870 
    871   SegmentInfo
    872     bounds;
    873 
    874   size_t
    875     imageListLength,
    876     length,
    877     page,
    878     pixel,
    879     text_size;
    880 
    881   ssize_t
    882     j;
    883 
    884   time_t
    885     timer;
    886 
    887   unsigned char
    888     *pixels;
    889 
    890   /*
    891     Open output image file.
    892   */
    893   assert(image_info != (const ImageInfo *) NULL);
    894   assert(image_info->signature == MagickCoreSignature);
    895   assert(image != (Image *) NULL);
    896   assert(image->signature == MagickCoreSignature);
    897   if (image->debug != MagickFalse)
    898     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    899   assert(exception != (ExceptionInfo *) NULL);
    900   assert(exception->signature == MagickCoreSignature);
    901   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    902   if (status == MagickFalse)
    903     return(MagickFalse);
    904   compression=image->compression;
    905   if (image_info->compression != UndefinedCompression)
    906     compression=image_info->compression;
    907   switch (compression)
    908   {
    909     case FaxCompression:
    910     case Group4Compression:
    911     {
    912       if ((SetImageMonochrome(image,exception) == MagickFalse) ||
    913           (image->alpha_trait != UndefinedPixelTrait))
    914         compression=RLECompression;
    915       break;
    916     }
    917 #if !defined(MAGICKCORE_JPEG_DELEGATE)
    918     case JPEGCompression:
    919     {
    920       compression=RLECompression;
    921       (void) ThrowMagickException(exception,GetMagickModule(),
    922         MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
    923         image->filename);
    924       break;
    925     }
    926 #endif
    927 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
    928     case ZipCompression:
    929     {
    930       compression=RLECompression;
    931       (void) ThrowMagickException(exception,GetMagickModule(),
    932         MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
    933         image->filename);
    934       break;
    935     }
    936 #endif
    937     default:
    938       break;
    939   }
    940   (void) memset(&bounds,0,sizeof(bounds));
    941   page=0;
    942   scene=0;
    943   imageListLength=GetImageListLength(image);
    944   do
    945   {
    946     /*
    947       Scale relative to dots-per-inch.
    948     */
    949     delta.x=DefaultResolution;
    950     delta.y=DefaultResolution;
    951     resolution.x=image->resolution.x;
    952     resolution.y=image->resolution.y;
    953     if ((resolution.x == 0.0) || (resolution.y == 0.0))
    954       {
    955         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
    956         resolution.x=geometry_info.rho;
    957         resolution.y=geometry_info.sigma;
    958         if ((flags & SigmaValue) == 0)
    959           resolution.y=resolution.x;
    960       }
    961     if (image_info->density != (char *) NULL)
    962       {
    963         flags=ParseGeometry(image_info->density,&geometry_info);
    964         resolution.x=geometry_info.rho;
    965         resolution.y=geometry_info.sigma;
    966         if ((flags & SigmaValue) == 0)
    967           resolution.y=resolution.x;
    968       }
    969     if (image->units == PixelsPerCentimeterResolution)
    970       {
    971         resolution.x=(size_t) ((100.0*2.54*resolution.x+0.5)/100.0);
    972         resolution.y=(size_t) ((100.0*2.54*resolution.y+0.5)/100.0);
    973       }
    974     SetGeometry(image,&geometry);
    975     (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
    976       (double) image->columns,(double) image->rows);
    977     if (image_info->page != (char *) NULL)
    978       (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
    979     else
    980       if ((image->page.width != 0) && (image->page.height != 0))
    981         (void) FormatLocaleString(page_geometry,MagickPathExtent,
    982           "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
    983           image->page.height,(double) image->page.x,(double) image->page.y);
    984       else
    985         if ((image->gravity != UndefinedGravity) &&
    986             (LocaleCompare(image_info->magick,"PS") == 0))
    987           (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent);
    988     (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
    989     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
    990       &geometry.width,&geometry.height);
    991     scale.x=(double) (geometry.width*delta.x)/resolution.x;
    992     geometry.width=(size_t) floor(scale.x+0.5);
    993     scale.y=(double) (geometry.height*delta.y)/resolution.y;
    994     geometry.height=(size_t) floor(scale.y+0.5);
    995     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
    996     (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
    997     if (image->gravity != UndefinedGravity)
    998       {
    999         geometry.x=(-page_info.x);
   1000         geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
   1001       }
   1002     pointsize=12.0;
   1003     if (image_info->pointsize != 0.0)
   1004       pointsize=image_info->pointsize;
   1005     text_size=0;
   1006     value=GetImageProperty(image,"label",exception);
   1007     if (value != (const char *) NULL)
   1008       text_size=(size_t) (MultilineCensus(value)*pointsize+12);
   1009     page++;
   1010     if (page == 1)
   1011       {
   1012         /*
   1013           Postscript header on the first page.
   1014         */
   1015         if (LocaleCompare(image_info->magick,"PS3") == 0)
   1016           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
   1017         else
   1018           (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
   1019             MagickPathExtent);
   1020         (void) WriteBlobString(image,buffer);
   1021         (void) FormatLocaleString(buffer,MagickPathExtent,
   1022           "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
   1023         (void) WriteBlobString(image,buffer);
   1024         (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: %s\n",
   1025           image->filename);
   1026         (void) WriteBlobString(image,buffer);
   1027         timer=time((time_t *) NULL);
   1028         (void) FormatMagickTime(timer,MagickPathExtent,date);
   1029         (void) FormatLocaleString(buffer,MagickPathExtent,
   1030           "%%%%CreationDate: %s\n",date);
   1031         (void) WriteBlobString(image,buffer);
   1032         bounds.x1=(double) geometry.x;
   1033         bounds.y1=(double) geometry.y;
   1034         bounds.x2=(double) geometry.x+scale.x;
   1035         bounds.y2=(double) geometry.y+scale.y+text_size;
   1036         if ((image_info->adjoin != MagickFalse) &&
   1037             (GetNextImageInList(image) != (Image *) NULL))
   1038           {
   1039             (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
   1040             (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
   1041           }
   1042         else
   1043           {
   1044             (void) FormatLocaleString(buffer,MagickPathExtent,
   1045               "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
   1046               ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
   1047             (void) WriteBlobString(image,buffer);
   1048             (void) FormatLocaleString(buffer,MagickPathExtent,
   1049               "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
   1050               bounds.y1,bounds.x2,bounds.y2);
   1051             (void) WriteBlobString(image,buffer);
   1052             if (image->colorspace == CMYKColorspace)
   1053               (void) WriteBlobString(image,
   1054                 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
   1055             else
   1056               if (SetImageGray(image,exception) != MagickFalse)
   1057                 (void) WriteBlobString(image,
   1058                   "%%DocumentProcessColors: Black\n");
   1059           }
   1060         /*
   1061           Font resources
   1062         */
   1063         value=GetImageProperty(image,"label",exception);
   1064         if (value != (const char *) NULL)
   1065           (void) WriteBlobString(image,
   1066             "%%DocumentNeededResources: font Helvetica\n");
   1067         (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
   1068         /*
   1069           Pages, orientation and order.
   1070         */
   1071         if (LocaleCompare(image_info->magick,"PS3") != 0)
   1072           (void) WriteBlobString(image,"%%Pages: 1\n");
   1073         else
   1074           {
   1075             (void) WriteBlobString(image,"%%Orientation: Portrait\n");
   1076             (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
   1077             if (image_info->adjoin == MagickFalse)
   1078               (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
   1079             else
   1080               (void) FormatLocaleString(buffer,MagickPathExtent,
   1081                 "%%%%Pages: %.20g\n",(double) imageListLength);
   1082             (void) WriteBlobString(image,buffer);
   1083           }
   1084         if (image->colorspace == CMYKColorspace)
   1085           (void) WriteBlobString(image,
   1086             "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
   1087         (void) WriteBlobString(image,"%%EndComments\n");
   1088         /*
   1089           The static postscript procedures prolog.
   1090         */
   1091         (void)WriteBlobString(image,"%%BeginProlog\n");
   1092         for (q=PostscriptProlog; *q; q++)
   1093         {
   1094           (void) WriteBlobString(image,*q);
   1095           (void) WriteBlobByte(image,'\n');
   1096         }
   1097         /*
   1098           One label line for each line in label string.
   1099         */
   1100         value=GetImageProperty(image,"label",exception);
   1101         if (value != (const char *) NULL)
   1102           {
   1103               (void) WriteBlobString(image,"\n  %% Labels.\n  /Helvetica "
   1104               " findfont pointsize scalefont setfont\n");
   1105             for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
   1106             {
   1107               (void) WriteBlobString(image,
   1108                 "  currentfile buffer readline pop token pop\n");
   1109               (void) FormatLocaleString(buffer,MagickPathExtent,
   1110                 "  0 y %g add moveto show pop\n",i*pointsize+12);
   1111               (void) WriteBlobString(image,buffer);
   1112             }
   1113           }
   1114         /*
   1115           The static postscript procedures epilog.
   1116         */
   1117         for (q=PostscriptEpilog; *q; q++)
   1118         {
   1119           (void) WriteBlobString(image,*q);
   1120           (void) WriteBlobByte(image,'\n');
   1121         }
   1122         (void)WriteBlobString(image,"%%EndProlog\n");
   1123       }
   1124     (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
   1125       (double) page);
   1126     (void) WriteBlobString(image,buffer);
   1127     /*
   1128       Page bounding box.
   1129     */
   1130     (void) FormatLocaleString(buffer,MagickPathExtent,
   1131       "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
   1132        (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
   1133        (double) (geometry.height+text_size));
   1134     (void) WriteBlobString(image,buffer);
   1135     /*
   1136       Page process colors if not RGB.
   1137     */
   1138     if (image->colorspace == CMYKColorspace)
   1139       (void) WriteBlobString(image,
   1140         "%%PageProcessColors: Cyan Magenta Yellow Black\n");
   1141     else
   1142       if (SetImageGray(image,exception) != MagickFalse)
   1143         (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
   1144     /*
   1145       Adjust document bounding box to bound page bounding box.
   1146     */
   1147     if ((double) geometry.x < bounds.x1)
   1148       bounds.x1=(double) geometry.x;
   1149     if ((double) geometry.y < bounds.y1)
   1150       bounds.y1=(double) geometry.y;
   1151     if ((double) (geometry.x+scale.x) > bounds.x2)
   1152       bounds.x2=(double) geometry.x+scale.x;
   1153     if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
   1154       bounds.y2=(double) geometry.y+scale.y+text_size;
   1155     /*
   1156       Page font resource if there's a label.
   1157     */
   1158     value=GetImageProperty(image,"label",exception);
   1159     if (value != (const char *) NULL)
   1160       (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
   1161     /*
   1162       PS clipping path from Photoshop clipping path.
   1163     */
   1164     if (((image->channels & WriteMaskChannel) != 0) ||
   1165         (LocaleNCompare("8BIM:",image->magick_filename,5) != 0))
   1166       (void) WriteBlobString(image,"/ClipImage {} def\n");
   1167     else
   1168       {
   1169         const char
   1170           *value;
   1171 
   1172         value=GetImageProperty(image,image->magick_filename,exception);
   1173         if (value == (const char *) NULL)
   1174           return(MagickFalse);
   1175         (void) WriteBlobString(image,value);
   1176         (void) WriteBlobByte(image,'\n');
   1177       }
   1178     /*
   1179       Push a dictionary for our own def's if this an EPS.
   1180     */
   1181     if (LocaleCompare(image_info->magick,"PS3") != 0)
   1182       (void) WriteBlobString(image,"userdict begin\n");
   1183     /*
   1184       Image mask.
   1185     */
   1186     if ((image->alpha_trait != UndefinedPixelTrait) &&
   1187         (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
   1188       {
   1189         (void) CloseBlob(image);
   1190         return(MagickFalse);
   1191       }
   1192     /*
   1193       Remember position of BeginData comment so we can update it.
   1194     */
   1195     start=TellBlob(image);
   1196     if (start < 0)
   1197       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
   1198     (void) FormatLocaleString(buffer,MagickPathExtent,
   1199       "%%%%BeginData:%13ld %s Bytes\n",0L,
   1200       compression == NoCompression ? "ASCII" : "BINARY");
   1201     (void) WriteBlobString(image,buffer);
   1202     stop=TellBlob(image);
   1203     if (stop < 0)
   1204       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
   1205     (void) WriteBlobString(image,"DisplayImage\n");
   1206     /*
   1207       Translate, scale, and font point size.
   1208     */
   1209     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
   1210       (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
   1211     (void) WriteBlobString(image,buffer);
   1212     /*
   1213       Output labels.
   1214     */
   1215     labels=(char **) NULL;
   1216     value=GetImageProperty(image,"label",exception);
   1217     if (value != (const char *) NULL)
   1218       labels=StringToList(value);
   1219     if (labels != (char **) NULL)
   1220       {
   1221         for (i=0; labels[i] != (char *) NULL; i++)
   1222         {
   1223           if (compression != NoCompression)
   1224             {
   1225               for (j=0; labels[i][j] != '\0'; j++)
   1226                 (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
   1227               (void) WriteBlobByte(image,'\n');
   1228             }
   1229           else
   1230             {
   1231               (void) WriteBlobString(image,"<~");
   1232               Ascii85Initialize(image);
   1233               for (j=0; labels[i][j] != '\0'; j++)
   1234                 Ascii85Encode(image,(unsigned char) labels[i][j]);
   1235               Ascii85Flush(image);
   1236             }
   1237           labels[i]=DestroyString(labels[i]);
   1238         }
   1239         labels=(char **) RelinquishMagickMemory(labels);
   1240       }
   1241     /*
   1242       Photoshop clipping path active?
   1243     */
   1244     if (((image->channels & WriteMaskChannel) != 0) &&
   1245         (LocaleNCompare("8BIM:",image->magick_filename,5) == 0))
   1246         (void) WriteBlobString(image,"true\n");
   1247       else
   1248         (void) WriteBlobString(image,"false\n");
   1249     /*
   1250       Showpage for non-EPS.
   1251     */
   1252     (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
   1253       "true\n" : "false\n");
   1254     /*
   1255       Image columns, rows, and color space.
   1256     */
   1257     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%s\n",
   1258       (double) image->columns,(double) image->rows,image->colorspace ==
   1259       CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
   1260     (void) WriteBlobString(image,buffer);
   1261     /*
   1262       Masked image?
   1263     */
   1264     (void) WriteBlobString(image,image->alpha_trait != UndefinedPixelTrait ?
   1265       "true\n" : "false\n");
   1266     /*
   1267       Render with imagemask operator?
   1268     */
   1269     option=GetImageOption(image_info,"ps3:imagemask");
   1270     (void) WriteBlobString(image,((option != (const char *) NULL) &&
   1271       (SetImageMonochrome(image,exception) != MagickFalse)) ?
   1272       "true\n" : "false\n");
   1273     /*
   1274       Output pixel data.
   1275     */
   1276     pixels=(unsigned char *) NULL;
   1277     length=0;
   1278     if ((image_info->type != TrueColorType) &&
   1279         (image_info->type != TrueColorAlphaType) &&
   1280         (image_info->type != ColorSeparationType) &&
   1281         (image_info->type != ColorSeparationAlphaType) &&
   1282         (image->colorspace != CMYKColorspace) &&
   1283         ((SetImageGray(image,exception) != MagickFalse) ||
   1284          (SetImageMonochrome(image,exception) != MagickFalse)))
   1285       {
   1286         /*
   1287           Gray images.
   1288         */
   1289         (void) WriteBlobString(image,PS3_PseudoClass"\n");
   1290         switch (compression)
   1291         {
   1292           case NoCompression:
   1293           default:
   1294           {
   1295             (void) WriteBlobString(image,PS3_NoCompression"\n");
   1296             break;
   1297           }
   1298           case FaxCompression:
   1299           case Group4Compression:
   1300           {
   1301             (void) WriteBlobString(image,PS3_FaxCompression"\n");
   1302             break;
   1303           }
   1304           case JPEGCompression:
   1305           {
   1306             (void) WriteBlobString(image,PS3_JPEGCompression"\n");
   1307             break;
   1308           }
   1309           case LZWCompression:
   1310           {
   1311             (void) WriteBlobString(image,PS3_LZWCompression"\n");
   1312             break;
   1313           }
   1314           case RLECompression:
   1315           {
   1316             (void) WriteBlobString(image,PS3_RLECompression"\n");
   1317             break;
   1318           }
   1319           case ZipCompression:
   1320           {
   1321             (void) WriteBlobString(image,PS3_ZipCompression"\n");
   1322             break;
   1323           }
   1324         }
   1325         /*
   1326           Number of colors -- 0 for single component non-color mapped data.
   1327         */
   1328         (void) WriteBlobString(image,"0\n");
   1329         /*
   1330           1 bit or 8 bit components?
   1331         */
   1332         (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
   1333           SetImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
   1334         (void) WriteBlobString(image,buffer);
   1335         /*
   1336           Image data.
   1337         */
   1338         if (compression == JPEGCompression)
   1339           status=InjectImageBlob(image_info,image,image,"jpeg",exception);
   1340         else
   1341           if ((compression == FaxCompression) ||
   1342               (compression == Group4Compression))
   1343             {
   1344               if (LocaleCompare(CCITTParam,"0") == 0)
   1345                 status=HuffmanEncodeImage(image_info,image,image,exception);
   1346               else
   1347                 status=Huffman2DEncodeImage(image_info,image,image,exception);
   1348             }
   1349           else
   1350             {
   1351               status=SerializeImageChannel(image_info,image,&pixel_info,&length,
   1352                 exception);
   1353               if (status == MagickFalse)
   1354                 {
   1355                   (void) CloseBlob(image);
   1356                   return(MagickFalse);
   1357                 }
   1358               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   1359               switch (compression)
   1360               {
   1361                 case NoCompression:
   1362                 default:
   1363                 {
   1364                   Ascii85Initialize(image);
   1365                   for (i=0; i < (ssize_t) length; i++)
   1366                     Ascii85Encode(image,pixels[i]);
   1367                   Ascii85Flush(image);
   1368                   status=MagickTrue;
   1369                   break;
   1370                 }
   1371                 case LZWCompression:
   1372                 {
   1373                   status=LZWEncodeImage(image,length,pixels,exception);
   1374                   break;
   1375                 }
   1376                 case RLECompression:
   1377                 {
   1378                   status=PackbitsEncodeImage(image,length,pixels,exception);
   1379                   break;
   1380                 }
   1381                 case ZipCompression:
   1382                 {
   1383                   status=ZLIBEncodeImage(image,length,pixels,exception);
   1384                   break;
   1385                 }
   1386               }
   1387               pixel_info=RelinquishVirtualMemory(pixel_info);
   1388             }
   1389       }
   1390     else
   1391       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
   1392           (compression == JPEGCompression))
   1393         {
   1394           /*
   1395             Truecolor image.
   1396           */
   1397           (void) WriteBlobString(image,PS3_DirectClass"\n");
   1398           switch (compression)
   1399           {
   1400             case NoCompression:
   1401             default:
   1402             {
   1403               (void) WriteBlobString(image,PS3_NoCompression"\n");
   1404               break;
   1405             }
   1406             case RLECompression:
   1407             {
   1408               (void) WriteBlobString(image,PS3_RLECompression"\n");
   1409               break;
   1410             }
   1411             case JPEGCompression:
   1412             {
   1413               (void) WriteBlobString(image,PS3_JPEGCompression"\n");
   1414               break;
   1415             }
   1416             case LZWCompression:
   1417             {
   1418               (void) WriteBlobString(image,PS3_LZWCompression"\n");
   1419               break;
   1420             }
   1421             case ZipCompression:
   1422             {
   1423               (void) WriteBlobString(image,PS3_ZipCompression"\n");
   1424               break;
   1425             }
   1426           }
   1427           /*
   1428             Image data.
   1429           */
   1430           if (compression == JPEGCompression)
   1431             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
   1432           else
   1433             {
   1434               /*
   1435                 Stream based compressions.
   1436               */
   1437               status=SerializeImage(image_info,image,&pixel_info,&length,
   1438                 exception);
   1439               if (status == MagickFalse)
   1440                 {
   1441                   (void) CloseBlob(image);
   1442                   return(MagickFalse);
   1443                 }
   1444               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   1445               switch (compression)
   1446               {
   1447                 case NoCompression:
   1448                 default:
   1449                 {
   1450                   Ascii85Initialize(image);
   1451                   for (i=0; i < (ssize_t) length; i++)
   1452                     Ascii85Encode(image,pixels[i]);
   1453                   Ascii85Flush(image);
   1454                   status=MagickTrue;
   1455                   break;
   1456                 }
   1457                 case RLECompression:
   1458                 {
   1459                   status=PackbitsEncodeImage(image,length,pixels,exception);
   1460                   break;
   1461                 }
   1462                 case LZWCompression:
   1463                 {
   1464                   status=LZWEncodeImage(image,length,pixels,exception);
   1465                   break;
   1466                 }
   1467                 case ZipCompression:
   1468                 {
   1469                   status=ZLIBEncodeImage(image,length,pixels,exception);
   1470                   break;
   1471                 }
   1472               }
   1473               pixel_info=RelinquishVirtualMemory(pixel_info);
   1474             }
   1475           }
   1476         else
   1477           {
   1478             /*
   1479               Colormapped images.
   1480             */
   1481             (void) WriteBlobString(image,PS3_PseudoClass"\n");
   1482             switch (compression)
   1483             {
   1484               case NoCompression:
   1485               default:
   1486               {
   1487                 (void) WriteBlobString(image,PS3_NoCompression"\n");
   1488                 break;
   1489               }
   1490               case RLECompression:
   1491               {
   1492                 (void) WriteBlobString(image,PS3_RLECompression"\n");
   1493                 break;
   1494               }
   1495               case LZWCompression:
   1496               {
   1497                 (void) WriteBlobString(image,PS3_LZWCompression"\n");
   1498                 break;
   1499               }
   1500               case ZipCompression:
   1501               {
   1502                 (void) WriteBlobString(image,PS3_ZipCompression"\n");
   1503                 break;
   1504               }
   1505             }
   1506             /*
   1507               Number of colors in color map.
   1508             */
   1509             (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
   1510               (double) image->colors);
   1511             (void) WriteBlobString(image,buffer);
   1512             /*
   1513               Color map - uncompressed.
   1514             */
   1515             if ((compression != NoCompression) &&
   1516                 (compression != UndefinedCompression))
   1517               {
   1518                 for (i=0; i < (ssize_t) image->colors; i++)
   1519                 {
   1520                   pixel=ScaleQuantumToChar(image->colormap[i].red);
   1521                   (void) WriteBlobByte(image,(unsigned char) pixel);
   1522                   pixel=ScaleQuantumToChar(image->colormap[i].green);
   1523                   (void) WriteBlobByte(image,(unsigned char) pixel);
   1524                   pixel=ScaleQuantumToChar(image->colormap[i].blue);
   1525                   (void) WriteBlobByte(image,(unsigned char) pixel);
   1526                 }
   1527               }
   1528             else
   1529               {
   1530                 Ascii85Initialize(image);
   1531                 for (i=0; i < (ssize_t) image->colors; i++)
   1532                 {
   1533                   pixel=ScaleQuantumToChar(image->colormap[i].red);
   1534                   Ascii85Encode(image,(unsigned char) pixel);
   1535                   pixel=ScaleQuantumToChar(image->colormap[i].green);
   1536                   Ascii85Encode(image,(unsigned char) pixel);
   1537                   pixel=ScaleQuantumToChar(image->colormap[i].blue);
   1538                   Ascii85Encode(image,(unsigned char) pixel);
   1539                 }
   1540                 Ascii85Flush(image);
   1541               }
   1542             status=SerializeImageIndexes(image_info,image,&pixel_info,&length,
   1543               exception);
   1544             if (status == MagickFalse)
   1545               {
   1546                 (void) CloseBlob(image);
   1547                 return(MagickFalse);
   1548               }
   1549             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   1550             switch (compression)
   1551             {
   1552               case NoCompression:
   1553               default:
   1554               {
   1555                 Ascii85Initialize(image);
   1556                 for (i=0; i < (ssize_t) length; i++)
   1557                   Ascii85Encode(image,pixels[i]);
   1558                 Ascii85Flush(image);
   1559                 status=MagickTrue;
   1560                 break;
   1561               }
   1562               case RLECompression:
   1563               {
   1564                 status=PackbitsEncodeImage(image,length,pixels,exception);
   1565                 break;
   1566               }
   1567               case LZWCompression:
   1568               {
   1569                 status=LZWEncodeImage(image,length,pixels,exception);
   1570                 break;
   1571               }
   1572               case ZipCompression:
   1573               {
   1574                 status=ZLIBEncodeImage(image,length,pixels,exception);
   1575                 break;
   1576               }
   1577             }
   1578             pixel_info=RelinquishVirtualMemory(pixel_info);
   1579           }
   1580     (void) WriteBlobByte(image,'\n');
   1581     if (status == MagickFalse)
   1582       {
   1583         (void) CloseBlob(image);
   1584         return(MagickFalse);
   1585       }
   1586     /*
   1587       Update BeginData now that we know the data size.
   1588     */
   1589     length=(size_t) (TellBlob(image)-stop);
   1590     stop=TellBlob(image);
   1591     if (stop < 0)
   1592       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
   1593     offset=SeekBlob(image,start,SEEK_SET);
   1594     if (offset < 0)
   1595       ThrowWriterException(CorruptImageError,"ImproperImageHeader");
   1596     (void) FormatLocaleString(buffer,MagickPathExtent,
   1597       "%%%%BeginData:%13ld %s Bytes\n",(long) length,
   1598       compression == NoCompression ? "ASCII" : "BINARY");
   1599     (void) WriteBlobString(image,buffer);
   1600     offset=SeekBlob(image,stop,SEEK_SET);
   1601     (void) WriteBlobString(image,"%%EndData\n");
   1602     /*
   1603       End private dictionary if this an EPS.
   1604     */
   1605     if (LocaleCompare(image_info->magick,"PS3") != 0)
   1606       (void) WriteBlobString(image,"end\n");
   1607     (void) WriteBlobString(image,"%%PageTrailer\n");
   1608     if (GetNextImageInList(image) == (Image *) NULL)
   1609       break;
   1610     image=SyncNextImageInList(image);
   1611     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
   1612     if (status == MagickFalse)
   1613       break;
   1614   } while (image_info->adjoin != MagickFalse);
   1615   (void) WriteBlobString(image,"%%Trailer\n");
   1616   if (page > 1)
   1617     {
   1618       (void) FormatLocaleString(buffer,MagickPathExtent,
   1619         "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
   1620         ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
   1621       (void) WriteBlobString(image,buffer);
   1622       (void) FormatLocaleString(buffer,MagickPathExtent,
   1623         "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
   1624         bounds.y2);
   1625       (void) WriteBlobString(image,buffer);
   1626     }
   1627   (void) WriteBlobString(image,"%%EOF\n");
   1628   (void) CloseBlob(image);
   1629   return(MagickTrue);
   1630 }
   1631