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