Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                         FFFFF  L      IIIII  FFFFF                          %
      7 %                         F      L        I    F                              %
      8 %                         FFF    L        I    FFF                            %
      9 %                         F      L        I    F                              %
     10 %                         F      LLLLL  IIIII  F                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    Read/Write Free Lossless Image Format                    %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                Jon Sneyers                                  %
     17 %                                April 2016                                   %
     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/artifact.h"
     45 #include "MagickCore/blob.h"
     46 #include "MagickCore/blob-private.h"
     47 #include "MagickCore/client.h"
     48 #include "MagickCore/colorspace-private.h"
     49 #include "MagickCore/display.h"
     50 #include "MagickCore/exception.h"
     51 #include "MagickCore/exception-private.h"
     52 #include "MagickCore/image.h"
     53 #include "MagickCore/image-private.h"
     54 #include "MagickCore/list.h"
     55 #include "MagickCore/magick.h"
     56 #include "MagickCore/monitor.h"
     57 #include "MagickCore/monitor-private.h"
     58 #include "MagickCore/memory_.h"
     59 #include "MagickCore/option.h"
     60 #include "MagickCore/pixel-accessor.h"
     61 #include "MagickCore/quantum-private.h"
     62 #include "MagickCore/static.h"
     63 #include "MagickCore/string_.h"
     64 #include "MagickCore/string-private.h"
     65 #include "MagickCore/module.h"
     66 #include "MagickCore/utility.h"
     67 #include "MagickCore/xwindow.h"
     68 #include "MagickCore/xwindow-private.h"
     69 #if defined(MAGICKCORE_FLIF_DELEGATE)
     70 #include <flif.h>
     71 #endif
     72 
     73 /*
     75   Forward declarations.
     76 */
     77 #if defined(MAGICKCORE_FLIF_DELEGATE)
     78 static MagickBooleanType
     79   WriteFLIFImage(const ImageInfo *,Image *,ExceptionInfo *);
     80 #endif
     81 
     82 #if defined(MAGICKCORE_FLIF_DELEGATE)
     84 /*
     85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     86 %                                                                             %
     87 %                                                                             %
     88 %                                                                             %
     89 %   R e a d F L I F I m a g e                                                 %
     90 %                                                                             %
     91 %                                                                             %
     92 %                                                                             %
     93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     94 %
     95 %  ReadFLIFImage() reads an image in the FLIF image format.
     96 %
     97 %  The format of the ReadFLIFImage method is:
     98 %
     99 %      Image *ReadFLIFImage(const ImageInfo *image_info,
    100 %        ExceptionInfo *exception)
    101 %
    102 %  A description of each parameter follows:
    103 %
    104 %    o image_info: the image info.
    105 %
    106 %    o exception: return any errors or warnings in this structure.
    107 %
    108 */
    109 static Image *ReadFLIFImage(const ImageInfo *image_info,
    110   ExceptionInfo *exception)
    111 {
    112   FLIF_DECODER
    113     *flifdec;
    114 
    115   FLIF_IMAGE
    116     *flifimage;
    117 
    118   Image
    119     *image;
    120 
    121   MagickBooleanType
    122     status;
    123 
    124   register Quantum
    125     *q;
    126 
    127   register ssize_t
    128     x;
    129 
    130   register unsigned short
    131     *p;
    132 
    133   size_t
    134     count,
    135     image_count,
    136     length;
    137 
    138   ssize_t
    139     y;
    140 
    141   unsigned char
    142     *stream;
    143 
    144   unsigned short
    145     *pixels;
    146 
    147   /*
    148     Open image file.
    149   */
    150   assert(image_info != (const ImageInfo *) NULL);
    151   assert(image_info->signature == MagickCoreSignature);
    152   if (image_info->debug != MagickFalse)
    153     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    154       image_info->filename);
    155   assert(exception != (ExceptionInfo *) NULL);
    156   assert(exception->signature == MagickCoreSignature);
    157   image=AcquireImage(image_info,exception);
    158   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    159   if (status == MagickFalse)
    160     {
    161       image=DestroyImageList(image);
    162       return((Image *) NULL);
    163     }
    164   length=(size_t) GetBlobSize(image);
    165   stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
    166   if (stream == (unsigned char *) NULL)
    167     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    168   count=ReadBlob(image,length,stream);
    169   if (count != length)
    170     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    171   flifdec=flif_create_decoder();
    172   if (image_info->quality != UndefinedCompressionQuality)
    173     flif_decoder_set_quality(flifdec,image_info->quality);
    174   if (!flif_decoder_decode_memory(flifdec,stream,length))
    175     {
    176       flif_destroy_decoder(flifdec);
    177       ThrowReaderException(CorruptImageError,"CorruptImage");
    178     }
    179   image_count=flif_decoder_num_images(flifdec);
    180   flifimage=flif_decoder_get_image(flifdec,0);
    181   length=sizeof(unsigned short)*4*flif_image_get_width(flifimage);
    182   pixels=(unsigned short *) AcquireMagickMemory(length);
    183   if (pixels == (unsigned short *) NULL)
    184     {
    185       flif_destroy_decoder(flifdec);
    186       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    187     }
    188 
    189   for (count=0; count < image_count; count++)
    190   {
    191     if (count > 0)
    192       {
    193         /*
    194           Allocate next image structure.
    195         */
    196         AcquireNextImage(image_info,image,exception);
    197         if (GetNextImageInList(image) == (Image *) NULL)
    198           {
    199             image=DestroyImageList(image);
    200             flif_destroy_decoder(flifdec);
    201             pixels=(unsigned short *) RelinquishMagickMemory(pixels);
    202             return((Image *) NULL);
    203           }
    204         image=SyncNextImageInList(image);
    205       }
    206     flifimage=flif_decoder_get_image(flifdec,count);
    207     image->columns=(size_t) flif_image_get_width(flifimage);
    208     image->rows=(size_t) flif_image_get_height(flifimage);
    209     image->depth=flif_image_get_depth(flifimage);
    210     image->alpha_trait=(flif_image_get_nb_channels(flifimage) > 3 ?
    211       BlendPixelTrait : UndefinedPixelTrait);
    212     image->delay=flif_image_get_frame_delay(flifimage);
    213     image->ticks_per_second=1000;
    214     image->scene=count;
    215     image->dispose=BackgroundDispose;
    216     for (y=0; y < (ssize_t) image->rows; y++)
    217     {
    218       flif_image_read_row_RGBA16(flifimage,y,pixels,length);
    219       p=pixels;
    220       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    221       if (q == (Quantum *) NULL)
    222         break;
    223       for (x=0; x < (ssize_t) image->columns; x++)
    224       {
    225         SetPixelRed(image,ScaleShortToQuantum(*p++),q);
    226         SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
    227         SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
    228         SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
    229         q+=GetPixelChannels(image);
    230       }
    231       if (SyncAuthenticPixels(image,exception) == MagickFalse)
    232         break;
    233       status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    234         image->rows);
    235       if (status == MagickFalse)
    236         break;
    237     }
    238   }
    239   flif_destroy_decoder(flifdec);
    240   pixels=(unsigned short *) RelinquishMagickMemory(pixels);
    241   return(image);
    242 }
    243 #endif
    244 
    245 /*
    247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    248 %                                                                             %
    249 %                                                                             %
    250 %                                                                             %
    251 %   I s F L I F                                                               %
    252 %                                                                             %
    253 %                                                                             %
    254 %                                                                             %
    255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    256 %
    257 %  IsFLIF() returns MagickTrue if the image format type, identified by the
    258 %  magick string, is FLIF.
    259 %
    260 %  The format of the IsFLIF method is:
    261 %
    262 %      MagickBooleanType IsFLIF(const unsigned char *magick,
    263 %        const size_t length)
    264 %
    265 %  A description of each parameter follows:
    266 %
    267 %    o magick: compare image format pattern against these bytes.
    268 %
    269 %    o length: Specifies the length of the magick string.
    270 %
    271 */
    272 static MagickBooleanType IsFLIF(const unsigned char *magick,
    273   const size_t length)
    274 {
    275   if (length < 4)
    276     return(MagickFalse);
    277   if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
    278     return(MagickTrue);
    279   return(MagickFalse);
    280 }
    281 
    282 /*
    283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    284 %                                                                             %
    285 %                                                                             %
    286 %                                                                             %
    287 %   R e g i s t e r F L I F I m a g e                                         %
    288 %                                                                             %
    289 %                                                                             %
    290 %                                                                             %
    291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    292 %
    293 %  RegisterFLIFImage() adds attributes for the FLIF image format to
    294 %  the list of supported formats.  The attributes include the image format
    295 %  tag, a method to read and/or write the format, whether the format
    296 %  supports the saving of more than one frame to the same file or blob,
    297 %  whether the format supports native in-memory I/O, and a brief
    298 %  description of the format.
    299 %
    300 %  The format of the RegisterFLIFImage method is:
    301 %
    302 %      size_t RegisterFLIFImage(void)
    303 %
    304 */
    305 ModuleExport size_t RegisterFLIFImage(void)
    306 {
    307   char
    308     version[MagickPathExtent];
    309 
    310   MagickInfo
    311     *entry;
    312 
    313   *version='\0';
    314   entry=AcquireMagickInfo("FLIF","FLIF","Free Lossless Image Format");
    315 #if defined(MAGICKCORE_FLIF_DELEGATE)
    316   entry->decoder=(DecodeImageHandler *) ReadFLIFImage;
    317   entry->encoder=(EncodeImageHandler *) WriteFLIFImage;
    318   (void) FormatLocaleString(version,MagickPathExtent,"libflif %d.%d.%d [%04X]",
    319     (FLIF_VERSION >> 16) & 0xff,
    320     (FLIF_VERSION  >> 8) & 0xff,
    321     (FLIF_VERSION  >> 0) & 0xff,FLIF_ABI_VERSION);
    322 #endif
    323   entry->mime_type=ConstantString("image/flif");
    324   entry->magick=(IsImageFormatHandler *) IsFLIF;
    325   if (*version != '\0')
    326     entry->version=ConstantString(version);
    327   (void) RegisterMagickInfo(entry);
    328   return(MagickImageCoderSignature);
    329 }
    330 
    331 /*
    333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    334 %                                                                             %
    335 %                                                                             %
    336 %                                                                             %
    337 %   U n r e g i s t e r F L I F I m a g e                                     %
    338 %                                                                             %
    339 %                                                                             %
    340 %                                                                             %
    341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    342 %
    343 %  UnregisterFLIFImage() removes format registrations made by the FLIF module
    344 %  from the list of supported formats.
    345 %
    346 %  The format of the UnregisterFLIFImage method is:
    347 %
    348 %      UnregisterFLIFImage(void)
    349 %
    350 */
    351 ModuleExport void UnregisterFLIFImage(void)
    352 {
    353   (void) UnregisterMagickInfo("FLIF");
    354 }
    355 
    356 #if defined(MAGICKCORE_FLIF_DELEGATE)
    357 /*
    358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    359 %                                                                             %
    360 %                                                                             %
    361 %                                                                             %
    362 %   W r i t e F L I F I m a g e                                               %
    363 %                                                                             %
    364 %                                                                             %
    365 %                                                                             %
    366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    367 %
    368 %  WriteFLIFImage() writes an image in the FLIF image format.
    369 %
    370 %  The format of the WriteFLIFImage method is:
    371 %
    372 %      MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
    373 %        Image *image)
    374 %
    375 %  A description of each parameter follows.
    376 %
    377 %    o image_info: the image info.
    378 %
    379 %    o image:  The image.
    380 %
    381 */
    382 static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
    383   Image *image, ExceptionInfo *exception)
    384 {
    385   FLIF_ENCODER
    386     *flifenc;
    387 
    388   FLIF_IMAGE
    389     *flifimage;
    390 
    391   int
    392     flif_status;
    393 
    394   MagickBooleanType
    395     status;
    396 
    397   MagickOffsetType
    398     scene;
    399 
    400   register const Quantum
    401     *magick_restrict p;
    402 
    403   register ssize_t
    404     x;
    405 
    406   register unsigned char
    407     *magick_restrict qc;
    408 
    409   register unsigned short
    410     *magick_restrict qs;
    411 
    412   size_t
    413     columns,
    414     length,
    415     rows;
    416 
    417   ssize_t
    418     y;
    419 
    420   void
    421     *buffer;
    422 
    423   void
    424     *pixels;
    425 
    426   assert(image_info != (const ImageInfo *) NULL);
    427   assert(image_info->signature == MagickCoreSignature);
    428   assert(image != (Image *) NULL);
    429   assert(image->signature == MagickCoreSignature);
    430   if (image->debug != MagickFalse)
    431     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    432   if ((image->columns > 0xFFFF) || (image->rows > 0xFFFF))
    433     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
    434   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    435   if (status == MagickFalse)
    436     return(status);
    437   flifenc=flif_create_encoder();
    438   if (image_info->quality != UndefinedCompressionQuality)
    439     flif_encoder_set_lossy(flifenc,3*(100-image_info->quality));
    440 
    441   /* relatively fast encoding */
    442   flif_encoder_set_learn_repeat(flifenc,1);
    443   flif_encoder_set_split_threshold(flifenc,5461*8*5);
    444 
    445   columns=image->columns;
    446   rows=image->rows;
    447 
    448   /* Convert image to FLIFIMAGE */
    449   if (image->depth > 8)
    450     {
    451       flifimage=flif_create_image_HDR(image->columns,image->rows);
    452       length=sizeof(unsigned short)*4*image->columns;
    453     }
    454   else
    455     {
    456       flifimage=flif_create_image(image->columns,image->rows);
    457       length=sizeof(unsigned char)*4*image->columns;
    458     }
    459   if (flifimage == (FLIF_IMAGE *) NULL)
    460     {
    461       flif_destroy_encoder(flifenc);
    462       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    463     }
    464   pixels=AcquireMagickMemory(length);
    465   if (pixels == (void *) NULL)
    466     {
    467       flif_destroy_image(flifimage);
    468       flif_destroy_encoder(flifenc);
    469       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    470     }
    471   scene=0;
    472 
    473   do
    474   {
    475     for (y=0; y < (ssize_t) image->rows; y++)
    476     {
    477       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    478       if (p == (Quantum *) NULL)
    479         break;
    480 
    481       if (image->depth > 8)
    482         {
    483           qs=(unsigned short *) pixels;
    484           for (x=0; x < (ssize_t) image->columns; x++)
    485           {
    486             *qs++=ScaleQuantumToShort(GetPixelRed(image,p));
    487             *qs++=ScaleQuantumToShort(GetPixelGreen(image,p));
    488             *qs++=ScaleQuantumToShort(GetPixelBlue(image,p));
    489             if (image->alpha_trait != UndefinedPixelTrait)
    490               *qs++=ScaleQuantumToShort(GetPixelAlpha(image,p));
    491             else
    492               *qs++=0xFFFF;
    493             p+=GetPixelChannels(image);
    494           }
    495           flif_image_write_row_RGBA16(flifimage,y,pixels,length);
    496         }
    497       else
    498         {
    499           qc=pixels;
    500           for (x=0; x < (ssize_t) image->columns; x++)
    501           {
    502             *qc++=ScaleQuantumToChar(GetPixelRed(image,p));
    503             *qc++=ScaleQuantumToChar(GetPixelGreen(image,p));
    504             *qc++=ScaleQuantumToChar(GetPixelBlue(image,p));
    505             if (image->alpha_trait != UndefinedPixelTrait)
    506               *qc++=ScaleQuantumToChar(GetPixelAlpha(image,p));
    507             else
    508               *qc++=0xFF;
    509             p+=GetPixelChannels(image);
    510           }
    511           flif_image_write_row_RGBA8(flifimage,y,pixels,length);
    512         }
    513     }
    514     flif_image_set_frame_delay(flifimage,image->delay*100/
    515       image->ticks_per_second);
    516     flif_encoder_add_image(flifenc,flifimage);
    517     if (GetNextImageInList(image) == (Image *) NULL)
    518       break;
    519     image=SyncNextImageInList(image);
    520     if ((columns != image->columns) || (rows != image->rows))
    521       {
    522         flif_destroy_image(flifimage);
    523         flif_destroy_encoder(flifenc);
    524         pixels=RelinquishMagickMemory(pixels);
    525         ThrowWriterException(ImageError,"FramesNotSameDimensions");
    526       }
    527     scene++;
    528     status=SetImageProgress(image,SaveImagesTag,scene,GetImageListLength(
    529       image));
    530     if (status == MagickFalse)
    531        break;
    532   } while (image_info->adjoin != MagickFalse);
    533 
    534   flif_destroy_image(flifimage);
    535   pixels=RelinquishMagickMemory(pixels);
    536   flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
    537   if (flif_status)
    538     WriteBlob(image,length,buffer);
    539   CloseBlob(image);
    540   flif_destroy_encoder(flifenc);
    541   buffer=RelinquishMagickMemory(buffer);
    542   return(flif_status == 0 ? MagickFalse : MagickTrue);
    543 }
    544 #endif
    545