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-2019 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 %    https://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   if (ept_info.postscript_length > GetBlobSize(image))
    205     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    206   (void) ReadBlobLSBLong(image);
    207   (void) ReadBlobLSBLong(image);
    208   ept_info.tiff_offset=(MagickOffsetType) ReadBlobLSBLong(image);
    209   ept_info.tiff_length=ReadBlobLSBLong(image);
    210   if (ept_info.tiff_length > GetBlobSize(image))
    211     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    212   (void) ReadBlobLSBShort(image);
    213   ept_info.postscript=(unsigned char *) AcquireQuantumMemory(
    214     ept_info.postscript_length+1,sizeof(*ept_info.postscript));
    215   if (ept_info.postscript == (unsigned char *) NULL)
    216     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    217   (void) memset(ept_info.postscript,0,(ept_info.postscript_length+1)*
    218     sizeof(*ept_info.postscript));
    219   ept_info.tiff=(unsigned char *) AcquireQuantumMemory(ept_info.tiff_length+1,
    220     sizeof(*ept_info.tiff));
    221   if (ept_info.tiff == (unsigned char *) NULL)
    222     {
    223       ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    224         ept_info.postscript);
    225       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    226     }
    227   (void) memset(ept_info.tiff,0,(ept_info.tiff_length+1)*
    228     sizeof(*ept_info.tiff));
    229   offset=SeekBlob(image,ept_info.tiff_offset,SEEK_SET);
    230   if ((ept_info.tiff_length != 0) && (offset < 30))
    231     {
    232       ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    233       ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    234         ept_info.postscript);
    235       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    236     }
    237   count=ReadBlob(image,ept_info.tiff_length,ept_info.tiff);
    238   if (count != (ssize_t) (ept_info.tiff_length))
    239     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
    240       "InsufficientImageDataInFile","`%s'",image->filename);
    241   offset=SeekBlob(image,ept_info.postscript_offset,SEEK_SET);
    242   if ((ept_info.postscript_length != 0) && (offset < 30))
    243     {
    244       ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    245       ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    246         ept_info.postscript);
    247       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    248     }
    249   count=ReadBlob(image,ept_info.postscript_length,ept_info.postscript);
    250   if (count != (ssize_t) (ept_info.postscript_length))
    251     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
    252       "InsufficientImageDataInFile","`%s'",image->filename);
    253   (void) CloseBlob(image);
    254   image=DestroyImage(image);
    255   read_info=CloneImageInfo(image_info);
    256   (void) CopyMagickString(read_info->magick,"EPS",MagickPathExtent);
    257   image=BlobToImage(read_info,ept_info.postscript,ept_info.postscript_length,
    258     exception);
    259   if (image == (Image *) NULL)
    260     {
    261       (void) CopyMagickString(read_info->magick,"TIFF",MagickPathExtent);
    262       image=BlobToImage(read_info,ept_info.tiff,ept_info.tiff_length,exception);
    263     }
    264   read_info=DestroyImageInfo(read_info);
    265   if (image != (Image *) NULL)
    266     {
    267       (void) CopyMagickString(image->filename,image_info->filename,
    268         MagickPathExtent);
    269       (void) CopyMagickString(image->magick,"EPT",MagickPathExtent);
    270     }
    271   ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    272   ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    273     ept_info.postscript);
    274   return(image);
    275 }
    276 
    277 /*
    279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    280 %                                                                             %
    281 %                                                                             %
    282 %                                                                             %
    283 %   R e g i s t e r E P T I m a g e                                           %
    284 %                                                                             %
    285 %                                                                             %
    286 %                                                                             %
    287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    288 %
    289 %  RegisterEPTImage() adds attributes for the EPT image format to
    290 %  the list of supported formats.  The attributes include the image format
    291 %  tag, a method to read and/or write the format, whether the format
    292 %  supports the saving of more than one frame to the same file or blob,
    293 %  whether the format supports native in-memory I/O, and a brief
    294 %  description of the format.
    295 %
    296 %  The format of the RegisterEPTImage method is:
    297 %
    298 %      size_t RegisterEPTImage(void)
    299 %
    300 */
    301 ModuleExport size_t RegisterEPTImage(void)
    302 {
    303   MagickInfo
    304     *entry;
    305 
    306   entry=AcquireMagickInfo("EPT","EPT",
    307     "Encapsulated PostScript with TIFF preview");
    308   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    309   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    310   entry->magick=(IsImageFormatHandler *) IsEPT;
    311   entry->flags|=CoderDecoderSeekableStreamFlag;
    312   entry->flags^=CoderAdjoinFlag;
    313   entry->flags^=CoderBlobSupportFlag;
    314   (void) RegisterMagickInfo(entry);
    315   entry=AcquireMagickInfo("EPT","EPT2",
    316     "Encapsulated PostScript Level II with TIFF preview");
    317   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    318   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    319   entry->magick=(IsImageFormatHandler *) IsEPT;
    320   entry->flags^=CoderAdjoinFlag;
    321   entry->flags|=CoderDecoderSeekableStreamFlag;
    322   entry->flags^=CoderBlobSupportFlag;
    323   (void) RegisterMagickInfo(entry);
    324   entry=AcquireMagickInfo("EPT","EPT3",
    325     "Encapsulated PostScript Level III with TIFF preview");
    326   entry->decoder=(DecodeImageHandler *) ReadEPTImage;
    327   entry->encoder=(EncodeImageHandler *) WriteEPTImage;
    328   entry->magick=(IsImageFormatHandler *) IsEPT;
    329   entry->flags|=CoderDecoderSeekableStreamFlag;
    330   entry->flags^=CoderBlobSupportFlag;
    331   (void) RegisterMagickInfo(entry);
    332   return(MagickImageCoderSignature);
    333 }
    334 
    335 /*
    337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    338 %                                                                             %
    339 %                                                                             %
    340 %                                                                             %
    341 %   U n r e g i s t e r E P T I m a g e                                       %
    342 %                                                                             %
    343 %                                                                             %
    344 %                                                                             %
    345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    346 %
    347 %  UnregisterEPTImage() removes format registrations made by the
    348 %  EPT module from the list of supported formats.
    349 %
    350 %  The format of the UnregisterEPTImage method is:
    351 %
    352 %      UnregisterEPTImage(void)
    353 %
    354 */
    355 ModuleExport void UnregisterEPTImage(void)
    356 {
    357   (void) UnregisterMagickInfo("EPT");
    358 }
    359 
    360 /*
    362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    363 %                                                                             %
    364 %                                                                             %
    365 %                                                                             %
    366 %   W r i t e E P T I m a g e                                                 %
    367 %                                                                             %
    368 %                                                                             %
    369 %                                                                             %
    370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    371 %
    372 %  WriteEPTImage() writes an image in the Encapsulated Postscript format
    373 %  with a TIFF preview.
    374 %
    375 %  The format of the WriteEPTImage method is:
    376 %
    377 %      MagickBooleanType WriteEPTImage(const ImageInfo *image_info,
    378 %        Image *image,ExceptionInfo *exception)
    379 %
    380 %  A description of each parameter follows.
    381 %
    382 %    o image_info: the image info.
    383 %
    384 %    o image:  The image.
    385 %
    386 %    o exception: return any errors or warnings in this structure.
    387 %
    388 */
    389 static MagickBooleanType WriteEPTImage(const ImageInfo *image_info,Image *image,
    390   ExceptionInfo *exception)
    391 {
    392   char
    393     filename[MagickPathExtent];
    394 
    395   EPTInfo
    396     ept_info;
    397 
    398   Image
    399     *write_image;
    400 
    401   ImageInfo
    402     *write_info;
    403 
    404   MagickBooleanType
    405     status;
    406 
    407   /*
    408     Write EPT image.
    409   */
    410   assert(image_info != (const ImageInfo *) NULL);
    411   assert(image_info->signature == MagickCoreSignature);
    412   assert(image != (Image *) NULL);
    413   assert(image->signature == MagickCoreSignature);
    414   if (image->debug != MagickFalse)
    415     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    416   assert(exception != (ExceptionInfo *) NULL);
    417   assert(exception->signature == MagickCoreSignature);
    418   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    419   if (status == MagickFalse)
    420     return(status);
    421   write_image=CloneImage(image,0,0,MagickTrue,exception);
    422   if (write_image == (Image *) NULL)
    423     return(MagickFalse);
    424   write_info=CloneImageInfo(image_info);
    425   (void) CopyMagickString(write_info->filename,"EPS:",MagickPathExtent);
    426   (void) CopyMagickString(write_info->magick,"EPS",MagickPathExtent);
    427   if (LocaleCompare(image_info->magick,"EPT2") == 0)
    428     {
    429       (void) CopyMagickString(write_info->filename,"EPS2:",MagickPathExtent);
    430       (void) CopyMagickString(write_info->magick,"EPS2",MagickPathExtent);
    431     }
    432   if (LocaleCompare(image_info->magick,"EPT3") == 0)
    433     {
    434       (void) CopyMagickString(write_info->filename,"EPS3:",MagickPathExtent);
    435       (void) CopyMagickString(write_info->magick,"EPS3",MagickPathExtent);
    436     }
    437   (void) memset(&ept_info,0,sizeof(ept_info));
    438   ept_info.magick=0xc6d3d0c5ul;
    439   ept_info.postscript=(unsigned char *) ImageToBlob(write_info,write_image,
    440     &ept_info.postscript_length,exception);
    441   write_image=DestroyImage(write_image);
    442   write_info=DestroyImageInfo(write_info);
    443   if (ept_info.postscript == (void *) NULL)
    444     return(MagickFalse);
    445   write_image=CloneImage(image,0,0,MagickTrue,exception);
    446   if (write_image == (Image *) NULL)
    447     return(MagickFalse);
    448   write_info=CloneImageInfo(image_info);
    449   (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent);
    450   (void) FormatLocaleString(filename,MagickPathExtent,"tiff:%s",
    451     write_info->filename);
    452   (void) CopyMagickString(write_info->filename,filename,MagickPathExtent);
    453   if ((write_image->columns > 512) || (write_image->rows > 512))
    454     {
    455       Image
    456         *resize_image;
    457 
    458       resize_image=ResizeImage(write_image,512,512,write_image->filter,
    459         exception);
    460       if (resize_image != (Image *) NULL)
    461         {
    462           write_image=DestroyImage(write_image);
    463           write_image=resize_image;
    464         }
    465     }
    466   if ((write_image->storage_class == DirectClass) ||
    467       (write_image->colors > 256))
    468     {
    469       QuantizeInfo
    470         quantize_info;
    471 
    472       /*
    473         EPT preview requires that the image is colormapped.
    474       */
    475       GetQuantizeInfo(&quantize_info);
    476       quantize_info.dither_method=IdentifyPaletteImage(write_image,
    477         exception) == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod;
    478       (void) QuantizeImage(&quantize_info,write_image,exception);
    479     }
    480   write_info->compression=NoCompression;
    481   ept_info.tiff=(unsigned char *) ImageToBlob(write_info,write_image,
    482     &ept_info.tiff_length,exception);
    483   write_image=DestroyImage(write_image);
    484   write_info=DestroyImageInfo(write_info);
    485   if (ept_info.tiff == (void *) NULL)
    486     {
    487       ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    488         ept_info.postscript);
    489       return(MagickFalse);
    490     }
    491   /*
    492     Write EPT image.
    493   */
    494   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.magick);
    495   (void) WriteBlobLSBLong(image,30);
    496   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length);
    497   (void) WriteBlobLSBLong(image,0);
    498   (void) WriteBlobLSBLong(image,0);
    499   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length+30);
    500   (void) WriteBlobLSBLong(image,(unsigned int) ept_info.tiff_length);
    501   (void) WriteBlobLSBShort(image,0xffff);
    502   (void) WriteBlob(image,ept_info.postscript_length,ept_info.postscript);
    503   (void) WriteBlob(image,ept_info.tiff_length,ept_info.tiff);
    504   /*
    505     Relinquish resources.
    506   */
    507   ept_info.postscript=(unsigned char *) RelinquishMagickMemory(
    508     ept_info.postscript);
    509   ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff);
    510   (void) CloseBlob(image);
    511   return(MagickTrue);
    512 }
    513