Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            EEEEE  PPPP   TTTTT                              %
      7 %                            E      P   P    T                                %
      8 %                            EEE    PPPP     T                                %
      9 %                            E      P        T                                %
     10 %                            EEEEE  P        T                                %
     11 %                                                                             %
     12 %                                                                             %
     13 %           Read/Write Encapsulated Postscript Format (with preview).         %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/blob.h"
     45 #include "MagickCore/blob-private.h"
     46 #include "MagickCore/color.h"
     47 #include "MagickCore/constitute.h"
     48 #include "MagickCore/draw.h"
     49 #include "MagickCore/exception.h"
     50 #include "MagickCore/exception-private.h"
     51 #include "MagickCore/delegate.h"
     52 #include "MagickCore/geometry.h"
     53 #include "MagickCore/histogram.h"
     54 #include "MagickCore/image.h"
     55 #include "MagickCore/image-private.h"
     56 #include "MagickCore/list.h"
     57 #include "MagickCore/magick.h"
     58 #include "MagickCore/memory_.h"
     59 #include "MagickCore/monitor.h"
     60 #include "MagickCore/monitor-private.h"
     61 #include "MagickCore/quantize.h"
     62 #include "MagickCore/resource_.h"
     63 #include "MagickCore/resize.h"
     64 #include "MagickCore/quantum-private.h"
     65 #include "MagickCore/static.h"
     66 #include "MagickCore/string_.h"
     67 #include "MagickCore/module.h"
     68 #include "MagickCore/utility.h"
     69 
     70 /*
     72   Typedef declarations.
     73 */
     74 typedef struct _EPTInfo
     75 {
     76   size_t
     77     magick;
     78 
     79   MagickOffsetType
     80     postscript_offset,
     81     tiff_offset;
     82 
     83   size_t
     84     postscript_length,
     85     tiff_length;
     86 
     87   unsigned char
     88     *postscript,
     89     *tiff;
     90 } EPTInfo;
     91 
     92 /*
     94   Forward declarations.
     95 */
     96 static MagickBooleanType
     97   WriteEPTImage(const ImageInfo *,Image *,ExceptionInfo *);
     98 
     99 /*
    101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    102 %                                                                             %
    103 %                                                                             %
    104 %                                                                             %
    105 %   I s E P T                                                                 %
    106 %                                                                             %
    107 %                                                                             %
    108 %                                                                             %
    109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    110 %
    111 %  IsEPT() returns MagickTrue if the image format type, identified by the
    112 %  magick string, is EPT.
    113 %
    114 %  The format of the IsEPT method is:
    115 %
    116 %      MagickBooleanType IsEPT(const unsigned char *magick,const size_t length)
    117 %
    118 %  A description of each parameter follows:
    119 %
    120 %    o magick: compare image format pattern against these bytes.
    121 %
    122 %    o length: Specifies the length of the magick string.
    123 %
    124 */
    125 static MagickBooleanType IsEPT(const unsigned char *magick,const size_t length)
    126 {
    127   if (length < 4)
    128     return(MagickFalse);
    129   if (memcmp(magick,"\305\320\323\306",4) == 0)
    130     return(MagickTrue);
    131   return(MagickFalse);
    132 }
    133 
    134 /*
    136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    137 %                                                                             %
    138 %                                                                             %
    139 %                                                                             %
    140 %   R e a d E P T I m a g e                                                   %
    141 %                                                                             %
    142 %                                                                             %
    143 %                                                                             %
    144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    145 %
    146 %  ReadEPTImage() reads a binary Postscript image file and returns it.  It
    147 %  allocates the memory necessary for the new Image structure and returns a
    148 %  pointer to the new image.
    149 %
    150 %  The format of the ReadEPTImage method is:
    151 %
    152 %      Image *ReadEPTImage(const ImageInfo *image_info,
    153 %        ExceptionInfo *exception)
    154 %
    155 %  A description of each parameter follows:
    156 %
    157 %    o image_info: the image info.
    158 %
    159 %    o exception: return any errors or warnings in this structure.
    160 %
    161 */
    162 static Image *ReadEPTImage(const ImageInfo *image_info,ExceptionInfo *exception)
    163 {
    164   EPTInfo
    165     ept_info;
    166 
    167   Image
    168     *image;
    169 
    170   ImageInfo
    171     *read_info;
    172 
    173   MagickBooleanType
    174     status;
    175 
    176   MagickOffsetType
    177     offset;
    178 
    179   ssize_t
    180     count;
    181 
    182   /*
    183     Open image file.
    184   */
    185   assert(image_info != (const ImageInfo *) NULL);
    186   assert(image_info->signature == MagickCoreSignature);
    187   if (image_info->debug != MagickFalse)
    188     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    189       image_info->filename);
    190   assert(exception != (ExceptionInfo *) NULL);
    191   assert(exception->signature == MagickCoreSignature);
    192   image=AcquireImage(image_info,exception);
    193   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    194   if (status == MagickFalse)
    195     {
    196       image=DestroyImageList(image);
    197       return((Image *) NULL);
    198     }
    199   ept_info.magick=ReadBlobLSBLong(image);
    200   if (ept_info.magick != 0xc6d3d0c5ul)
    201     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    202   ept_info.postscript_offset=(MagickOffsetType) ReadBlobLSBLong(image);
    203   ept_info.postscript_length=ReadBlobLSBLong(image);
    204   (void) ReadBlobLSBLong(image);
    205   (void) ReadBlobLSBLong(image);
    206   ept_info.tiff_offset=(MagickOffsetType) ReadBlobLSBLong(image);
    207   ept_info.tiff_length=ReadBlobLSBLong(image);
    208   (void) ReadBlobLSBShort(image);
    209   ept_info.postscript=(unsigned char *) AcquireQuantumMemory(
    210     ept_info.postscript_length+1,sizeof(*ept_info.postscript));
    211   if (ept_info.postscript == (unsigned char *) NULL)
    212     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    213   (void) ResetMagickMemory(ept_info.postscript,0,(ept_info.postscript_length+1)*
    214     sizeof(*ept_info.postscript));
    215   ept_info.tiff=(unsigned char *) AcquireQuantumMemory(ept_info.tiff_length+1,
    216     sizeof(*ept_info.tiff));
    217   if (ept_info.tiff == (unsigned char *) NULL)
    218     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    219   (void) ResetMagickMemory(ept_info.tiff,0,(ept_info.tiff_length+1)*
    220     sizeof(*ept_info.tiff));
    221   offset=SeekBlob(image,ept_info.tiff_offset,SEEK_SET);
    222   if (offset < 30)
    223     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    224   count=ReadBlob(image,ept_info.tiff_length,ept_info.tiff);
    225   if (count != (ssize_t) (ept_info.tiff_length))
    226     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
    227       "InsufficientImageDataInFile","`%s'",image->filename);
    228   offset=SeekBlob(image,ept_info.postscript_offset,SEEK_SET);
    229   if (offset < 30)
    230     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    231   count=ReadBlob(image,ept_info.postscript_length,ept_info.postscript);
    232   if (count != (ssize_t) (ept_info.postscript_length))
    233     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
    234       "InsufficientImageDataInFile","`%s'",image->filename);
    235   (void) CloseBlob(image);
    236   image=DestroyImage(image);
    237   read_info=CloneImageInfo(image_info);
    238   (void) CopyMagickString(read_info->magick,"EPS",MagickPathExtent);
    239   image=BlobToImage(read_info,ept_info.postscript,ept_info.postscript_length,
    240     exception);
    241   if (image == (Image *) NULL)
    242     {
    243       (void) CopyMagickString(read_info->magick,"TIFF",MagickPathExtent);
    244       image=BlobToImage(read_info,ept_info.tiff,ept_info.tiff_length,exception);
    245     }
    246   read_info=DestroyImageInfo(read_info);
    247   if (image != (Image *) NULL)
    248     {
    249       (void) CopyMagickString(image->filename,image_info->filename,
    250         MagickPathExtent);
    251       (void) CopyMagickString(image->magick,"EPT",MagickPathExtent);
    252     }
    253   ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    254   ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    255     ept_info.postscript);
    256   return(image);
    257 }
    258 
    259 /*
    261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    262 %                                                                             %
    263 %                                                                             %
    264 %                                                                             %
    265 %   R e g i s t e r E P T I m a g e                                           %
    266 %                                                                             %
    267 %                                                                             %
    268 %                                                                             %
    269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    270 %
    271 %  RegisterEPTImage() adds attributes for the EPT image format to
    272 %  the list of supported formats.  The attributes include the image format
    273 %  tag, a method to read and/or write the format, whether the format
    274 %  supports the saving of more than one frame to the same file or blob,
    275 %  whether the format supports native in-memory I/O, and a brief
    276 %  description of the format.
    277 %
    278 %  The format of the RegisterEPTImage method is:
    279 %
    280 %      size_t RegisterEPTImage(void)
    281 %
    282 */
    283 ModuleExport size_t RegisterEPTImage(void)
    284 {
    285   MagickInfo
    286     *entry;
    287 
    288   entry=AcquireMagickInfo("EPT","EPT",
    289     "Encapsulated PostScript with TIFF preview");
    290   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    291   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    292   entry->magick=(IsImageFormatHandler *) IsEPT;
    293   entry->flags|=CoderSeekableStreamFlag;
    294   entry->flags^=CoderAdjoinFlag;
    295   entry->flags^=CoderBlobSupportFlag;
    296   (void) RegisterMagickInfo(entry);
    297   entry=AcquireMagickInfo("EPT","EPT2",
    298     "Encapsulated PostScript Level II with TIFF preview");
    299   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    300   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    301   entry->magick=(IsImageFormatHandler *) IsEPT;
    302   entry->flags^=CoderAdjoinFlag;
    303   entry->flags|=CoderSeekableStreamFlag;
    304   entry->flags^=CoderBlobSupportFlag;
    305   (void) RegisterMagickInfo(entry);
    306   entry=AcquireMagickInfo("EPT","EPT3",
    307     "Encapsulated PostScript Level III with TIFF preview");
    308   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    309   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    310   entry->magick=(IsImageFormatHandler *) IsEPT;
    311   entry->flags|=CoderSeekableStreamFlag;
    312   entry->flags^=CoderBlobSupportFlag;
    313   (void) RegisterMagickInfo(entry);
    314   return(MagickImageCoderSignature);
    315 }
    316 
    317 /*
    319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    320 %                                                                             %
    321 %                                                                             %
    322 %                                                                             %
    323 %   U n r e g i s t e r E P T I m a g e                                       %
    324 %                                                                             %
    325 %                                                                             %
    326 %                                                                             %
    327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    328 %
    329 %  UnregisterEPTImage() removes format registrations made by the
    330 %  EPT module from the list of supported formats.
    331 %
    332 %  The format of the UnregisterEPTImage method is:
    333 %
    334 %      UnregisterEPTImage(void)
    335 %
    336 */
    337 ModuleExport void UnregisterEPTImage(void)
    338 {
    339   (void) UnregisterMagickInfo("EPT");
    340 }
    341 
    342 /*
    344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    345 %                                                                             %
    346 %                                                                             %
    347 %                                                                             %
    348 %   W r i t e E P T I m a g e                                                 %
    349 %                                                                             %
    350 %                                                                             %
    351 %                                                                             %
    352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    353 %
    354 %  WriteEPTImage() writes an image in the Encapsulated Postscript format
    355 %  with a TIFF preview.
    356 %
    357 %  The format of the WriteEPTImage method is:
    358 %
    359 %      MagickBooleanType WriteEPTImage(const ImageInfo *image_info,
    360 %        Image *image,ExceptionInfo *exception)
    361 %
    362 %  A description of each parameter follows.
    363 %
    364 %    o image_info: the image info.
    365 %
    366 %    o image:  The image.
    367 %
    368 %    o exception: return any errors or warnings in this structure.
    369 %
    370 */
    371 static MagickBooleanType WriteEPTImage(const ImageInfo *image_info,Image *image,
    372   ExceptionInfo *exception)
    373 {
    374   char
    375      filename[MagickPathExtent];
    376 
    377   EPTInfo
    378     ept_info;
    379 
    380   Image
    381     *write_image;
    382 
    383   ImageInfo
    384     *write_info;
    385 
    386   MagickBooleanType
    387     status;
    388 
    389   /*
    390     Write EPT image.
    391   */
    392   assert(image_info != (const ImageInfo *) NULL);
    393   assert(image_info->signature == MagickCoreSignature);
    394   assert(image != (Image *) NULL);
    395   assert(image->signature == MagickCoreSignature);
    396   if (image->debug != MagickFalse)
    397     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    398   assert(exception != (ExceptionInfo *) NULL);
    399   assert(exception->signature == MagickCoreSignature);
    400   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    401   if (status == MagickFalse)
    402     return(status);
    403   write_image=CloneImage(image,0,0,MagickTrue,exception);
    404   if (write_image == (Image *) NULL)
    405     return(MagickFalse);
    406   write_info=CloneImageInfo(image_info);
    407   (void) CopyMagickString(write_info->magick,"EPS",MagickPathExtent);
    408   if (LocaleCompare(image_info->magick,"EPT2") == 0)
    409     (void) CopyMagickString(write_info->magick,"EPS2",MagickPathExtent);
    410   if (LocaleCompare(image_info->magick,"EPT3") == 0)
    411     (void) CopyMagickString(write_info->magick,"EPS3",MagickPathExtent);
    412   (void) ResetMagickMemory(&ept_info,0,sizeof(ept_info));
    413   ept_info.magick=0xc6d3d0c5ul;
    414   ept_info.postscript=(unsigned char *) ImageToBlob(write_info,write_image,
    415     &ept_info.postscript_length,exception);
    416   write_image=DestroyImage(write_image);
    417   write_info=DestroyImageInfo(write_info);
    418   if (ept_info.postscript == (void *) NULL)
    419     return(MagickFalse);
    420   write_image=CloneImage(image,0,0,MagickTrue,exception);
    421   if (write_image == (Image *) NULL)
    422     return(MagickFalse);
    423   write_info=CloneImageInfo(image_info);
    424   *write_info->magick='\0';
    425   (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent);
    426   (void) FormatLocaleString(filename,MagickPathExtent,"tiff:%s",
    427     write_info->filename);
    428   (void) CopyMagickString(write_info->filename,filename,MagickPathExtent);
    429   if ((write_image->columns > 512) || (write_image->rows > 512))
    430     {
    431       Image
    432         *resize_image;
    433 
    434       resize_image=ResizeImage(write_image,512,512,write_image->filter,
    435         exception);
    436       if (resize_image != (Image *) NULL)
    437         {
    438           write_image=DestroyImage(write_image);
    439           write_image=resize_image;
    440         }
    441     }
    442   if ((write_image->storage_class == DirectClass) ||
    443       (write_image->colors > 256))
    444     {
    445       QuantizeInfo
    446         quantize_info;
    447 
    448       /*
    449         EPT preview requires that the image is colormapped.
    450       */
    451       GetQuantizeInfo(&quantize_info);
    452       quantize_info.dither_method=IdentifyPaletteImage(write_image,
    453         exception) == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod;
    454       (void) QuantizeImage(&quantize_info,write_image,exception);
    455     }
    456   write_info->compression=NoCompression;
    457   ept_info.tiff=(unsigned char *) ImageToBlob(write_info,write_image,
    458     &ept_info.tiff_length,exception);
    459   write_image=DestroyImage(write_image);
    460   write_info=DestroyImageInfo(write_info);
    461   if (ept_info.tiff == (void *) NULL)
    462     {
    463       ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    464         ept_info.postscript);
    465       return(MagickFalse);
    466     }
    467   /*
    468     Write EPT image.
    469   */
    470   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.magick);
    471   (void) WriteBlobLSBLong(image,30);
    472   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length);
    473   (void) WriteBlobLSBLong(image,0);
    474   (void) WriteBlobLSBLong(image,0);
    475   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length+30);
    476   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.tiff_length);
    477   (void) WriteBlobLSBShort(image,0xffff);
    478   (void) WriteBlob(image,ept_info.postscript_length,ept_info.postscript);
    479   (void) WriteBlob(image,ept_info.tiff_length,ept_info.tiff);
    480   /*
    481     Relinquish resources.
    482   */
    483   ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    484     ept_info.postscript);
    485   ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    486   (void) CloseBlob(image);
    487   return(MagickTrue);
    488 }
    489