Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            SSSSS  FFFFF  W   W                              %
      7 %                            SS     F      W   W                              %
      8 %                             SSS   FFF    W   W                              %
      9 %                               SS  F      W W W                              %
     10 %                            SSSSS  F       W W                               %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    Read/Write ImageMagick Image Format                      %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/blob.h"
     45 #include "MagickCore/blob-private.h"
     46 #include "MagickCore/constitute.h"
     47 #include "MagickCore/exception.h"
     48 #include "MagickCore/exception-private.h"
     49 #include "MagickCore/image.h"
     50 #include "MagickCore/image-private.h"
     51 #include "MagickCore/list.h"
     52 #include "MagickCore/magick.h"
     53 #include "MagickCore/memory_.h"
     54 #include "MagickCore/resource_.h"
     55 #include "MagickCore/quantum-private.h"
     56 #include "MagickCore/static.h"
     57 #include "MagickCore/string_.h"
     58 #include "MagickCore/module.h"
     59 #include "MagickCore/transform.h"
     60 #include "MagickCore/utility.h"
     61 #include "MagickCore/utility-private.h"
     62 
     63 /*
     65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     66 %                                                                             %
     67 %                                                                             %
     68 %                                                                             %
     69 %   I s S F W                                                                 %
     70 %                                                                             %
     71 %                                                                             %
     72 %                                                                             %
     73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     74 %
     75 %  IsSFW() returns MagickTrue if the image format type, identified by the
     76 %  magick string, is SFW.
     77 %
     78 %  The format of the IsSFW method is:
     79 %
     80 %      MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
     81 %
     82 %  A description of each parameter follows:
     83 %
     84 %    o magick: compare image format pattern against these bytes.
     85 %
     86 %    o length: Specifies the length of the magick string.
     87 %
     88 */
     89 static MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
     90 {
     91   if (length < 5)
     92     return(MagickFalse);
     93   if (LocaleNCompare((const char *) magick,"SFW94",5) == 0)
     94     return(MagickTrue);
     95   return(MagickFalse);
     96 }
     97 
     98 /*
    100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    101 %                                                                             %
    102 %                                                                             %
    103 %                                                                             %
    104 %   R e a d S F W I m a g e                                                   %
    105 %                                                                             %
    106 %                                                                             %
    107 %                                                                             %
    108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    109 %
    110 %  ReadSFWImage() reads a Seattle Film Works image file and returns it.
    111 %  It allocates the memory necessary for the new Image structure and returns a
    112 %  pointer to the new image.
    113 %
    114 %  The format of the ReadSFWImage method is:
    115 %
    116 %      Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
    117 %
    118 %  A description of each parameter follows:
    119 %
    120 %    o image_info: the image info.
    121 %
    122 %    o exception: return any errors or warnings in this structure.
    123 %
    124 */
    125 
    126 static unsigned char *SFWScan(const unsigned char *p,const unsigned char *q,
    127   const unsigned char *target,const size_t length)
    128 {
    129   register ssize_t
    130     i;
    131 
    132   if ((p+length) < q)
    133     while (p < q)
    134     {
    135       for (i=0; i < (ssize_t) length; i++)
    136         if (p[i] != target[i])
    137           break;
    138       if (i == (ssize_t) length)
    139         return((unsigned char *) p);
    140       p++;
    141     }
    142   return((unsigned char *) NULL);
    143 }
    144 
    145 static void TranslateSFWMarker(unsigned char *marker)
    146 {
    147   switch (marker[1])
    148   {
    149     case 0xc8: marker[1]=0xd8; break;  /* soi */
    150     case 0xd0: marker[1]=0xe0; break;  /* app */
    151     case 0xcb: marker[1]=0xdb; break;  /* dqt */
    152     case 0xa0: marker[1]=0xc0; break;  /* sof */
    153     case 0xa4: marker[1]=0xc4; break;  /* sof */
    154     case 0xca: marker[1]=0xda; break;  /* sos */
    155     case 0xc9: marker[1]=0xd9; break;  /* eoi */
    156     default: break;
    157   }
    158 }
    159 
    160 static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
    161 {
    162   static unsigned char
    163     HuffmanTable[] =
    164     {
    165       0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
    166       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    167       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
    168       0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    169       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
    170       0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
    171       0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
    172       0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
    173       0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
    174       0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
    175       0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
    176       0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
    177       0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
    178       0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
    179       0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
    180       0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
    181       0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
    182       0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
    183       0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
    184       0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
    185       0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
    186       0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11,
    187       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
    188       0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
    189       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
    190       0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
    191       0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
    192       0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28,
    193       0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
    194       0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
    195       0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73,
    196       0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
    197       0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    198       0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
    199       0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
    200       0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
    201       0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
    202       0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    203       0xF9, 0xFA
    204     };
    205 
    206   FILE
    207     *file;
    208 
    209   Image
    210     *flipped_image,
    211     *jpeg_image,
    212     *image;
    213 
    214   ImageInfo
    215     *read_info;
    216 
    217   int
    218     unique_file;
    219 
    220   MagickBooleanType
    221     status;
    222 
    223   register unsigned char
    224     *header,
    225     *data;
    226 
    227   size_t
    228     extent;
    229 
    230   ssize_t
    231     count;
    232 
    233   unsigned char
    234     *buffer,
    235     *offset;
    236 
    237   /*
    238     Open image file.
    239   */
    240   assert(image_info != (const ImageInfo *) NULL);
    241   assert(image_info->signature == MagickCoreSignature);
    242   if (image_info->debug != MagickFalse)
    243     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    244       image_info->filename);
    245   assert(exception != (ExceptionInfo *) NULL);
    246   assert(exception->signature == MagickCoreSignature);
    247   image=AcquireImage(image_info,exception);
    248   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    249   if (status == MagickFalse)
    250     {
    251       image=DestroyImageList(image);
    252       return((Image *) NULL);
    253     }
    254   /*
    255     Read image into a buffer.
    256   */
    257   if (GetBlobSize(image) != (size_t) GetBlobSize(image))
    258     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    259   buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image),
    260     sizeof(*buffer));
    261   if (buffer == (unsigned char *) NULL)
    262     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    263   count=ReadBlob(image,(size_t) GetBlobSize(image),buffer);
    264   if ((count != (ssize_t) GetBlobSize(image)) ||
    265       (LocaleNCompare((char *) buffer,"SFW",3) != 0))
    266     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    267   (void) CloseBlob(image);
    268   /*
    269     Find the start of the JFIF data
    270   */
    271   header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
    272     "\377\310\377\320",4);
    273   if (header == (unsigned char *) NULL)
    274     {
    275       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    276       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    277     }
    278   TranslateSFWMarker(header);  /* translate soi and app tags */
    279   TranslateSFWMarker(header+2);
    280   (void) CopyMagickMemory(header+6,"JFIF\0\001\0",7);  /* JFIF magic */
    281   /*
    282     Translate remaining markers.
    283   */
    284   offset=header+2;
    285   offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
    286   for ( ; ; )
    287   {
    288     if ((offset+4) > (buffer+count-1))
    289       {
    290         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    291         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    292       }
    293     TranslateSFWMarker(offset);
    294     if (offset[1] == 0xda)
    295       break;
    296     offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
    297   }
    298   offset--;
    299   data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
    300   if (data == (unsigned char *) NULL)
    301     {
    302       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    303       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    304     }
    305   TranslateSFWMarker(data++);  /* translate eoi marker */
    306   /*
    307     Write JFIF file.
    308   */
    309   read_info=CloneImageInfo(image_info);
    310   SetImageInfoBlob(read_info,(void *) NULL,0);
    311   file=(FILE *) NULL;
    312   unique_file=AcquireUniqueFileResource(read_info->filename);
    313   if (unique_file != -1)
    314     file=fopen_utf8(read_info->filename,"wb");
    315   if ((unique_file == -1) || (file == (FILE *) NULL))
    316     {
    317       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    318       read_info=DestroyImageInfo(read_info);
    319       (void) CopyMagickString(image->filename,read_info->filename,
    320         MagickPathExtent);
    321       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
    322         image->filename);
    323       image=DestroyImageList(image);
    324       return((Image *) NULL);
    325     }
    326   extent=fwrite(header,(size_t) (offset-header+1),1,file);
    327   (void) extent;
    328   extent=fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
    329   extent=fwrite(offset+1,(size_t) (data-offset),1,file);
    330   status=ferror(file) == -1 ? MagickFalse : MagickTrue;
    331   (void) fclose(file);
    332   (void) close(unique_file);
    333   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    334   if (status == MagickFalse)
    335     {
    336       char
    337         *message;
    338 
    339       (void) remove_utf8(read_info->filename);
    340       read_info=DestroyImageInfo(read_info);
    341       message=GetExceptionMessage(errno);
    342       (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
    343         "UnableToWriteFile","`%s': %s",image->filename,message);
    344       message=DestroyString(message);
    345       image=DestroyImageList(image);
    346       return((Image *) NULL);
    347     }
    348   /*
    349     Read JPEG image.
    350   */
    351   jpeg_image=ReadImage(read_info,exception);
    352   (void) RelinquishUniqueFileResource(read_info->filename);
    353   read_info=DestroyImageInfo(read_info);
    354   if (jpeg_image == (Image *) NULL)
    355     {
    356       image=DestroyImageList(image);
    357       return(jpeg_image);
    358     }
    359   (void) CopyMagickString(jpeg_image->filename,image->filename,MagickPathExtent);
    360   (void) CopyMagickString(jpeg_image->magick,image->magick,MagickPathExtent);
    361   image=DestroyImageList(image);
    362   image=jpeg_image;
    363   /*
    364     Correct image orientation.
    365   */
    366   flipped_image=FlipImage(image,exception);
    367   if (flipped_image != (Image *) NULL)
    368     {
    369       DuplicateBlob(flipped_image,image);
    370       image=DestroyImage(image);
    371       image=flipped_image;
    372     }
    373   return(GetFirstImageInList(image));
    374 }
    375 
    376 /*
    378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    379 %                                                                             %
    380 %                                                                             %
    381 %                                                                             %
    382 %   R e g i s t e r S F W I m a g e                                           %
    383 %                                                                             %
    384 %                                                                             %
    385 %                                                                             %
    386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    387 %
    388 %  RegisterSFWImage() adds attributes for the SFW image format to
    389 %  the list of supported formats.  The attributes include the image format
    390 %  tag, a method to read and/or write the format, whether the format
    391 %  supports the saving of more than one frame to the same file or blob,
    392 %  whether the format supports native in-memory I/O, and a brief
    393 %  description of the format.
    394 %
    395 %  The format of the RegisterSFWImage method is:
    396 %
    397 %      size_t RegisterSFWImage(void)
    398 %
    399 */
    400 ModuleExport size_t RegisterSFWImage(void)
    401 {
    402   MagickInfo
    403     *entry;
    404 
    405   entry=AcquireMagickInfo("SFW","SFW","Seattle Film Works");
    406   entry->decoder=(DecodeImageHandler *) ReadSFWImage;
    407   entry->magick=(IsImageFormatHandler *) IsSFW;
    408   entry->flags^=CoderAdjoinFlag;
    409   (void) RegisterMagickInfo(entry);
    410   return(MagickImageCoderSignature);
    411 }
    412 
    413 /*
    415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    416 %                                                                             %
    417 %                                                                             %
    418 %                                                                             %
    419 %   U n r e g i s t e r S F W I m a g e                                       %
    420 %                                                                             %
    421 %                                                                             %
    422 %                                                                             %
    423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    424 %
    425 %  UnregisterSFWImage() removes format registrations made by the
    426 %  SFW module from the list of supported formats.
    427 %
    428 %  The format of the UnregisterSFWImage method is:
    429 %
    430 %      UnregisterSFWImage(void)
    431 %
    432 */
    433 ModuleExport void UnregisterSFWImage(void)
    434 {
    435   (void) UnregisterMagickInfo("SFW");
    436 }
    437