text: /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %                         FFFFF  L      IIIII  FFFFF                          %
  %                         F      L        I    F                              %
  %                         FFF    L        I    FFF                            %
  %                         F      L        I    F                              %
  %                         F      LLLLL  IIIII  F                              %
  %                                                                             %
  %                                                                             %
  %                    Read/Write Free Lossless Image Format                    %
  %                                                                             %
  %                              Software Design                                %
  %                                Jon Sneyers                                  %
  %                                April 2016                                   %
  %                                                                             %
  %                                                                             %
  %  Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization      %
  %  dedicated to making software imaging solutions freely available.           %
  %                                                                             %
  %  You may not use this file except in compliance with the License.  You may  %
  %  obtain a copy of the License at                                            %
  %                                                                             %
  %    https://imagemagick.org/script/license.php                               %
  %                                                                             %
  %  Unless required by applicable law or agreed to in writing, software        %
  %  distributed under the License is distributed on an "AS IS" BASIS,          %
  %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
  %  See the License for the specific language governing permissions and        %
  %  limitations under the License.                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %
  */
  
  /*
    Include declarations.
  */
  #include "MagickCore/studio.h"
  #include "MagickCore/artifact.h"
  #include "MagickCore/blob.h"
  #include "MagickCore/blob-private.h"
  #include "MagickCore/client.h"
  #include "MagickCore/colorspace-private.h"
  #include "MagickCore/display.h"
  #include "MagickCore/exception.h"
  #include "MagickCore/exception-private.h"
  #include "MagickCore/image.h"
  #include "MagickCore/image-private.h"
  #include "MagickCore/list.h"
  #include "MagickCore/magick.h"
  #include "MagickCore/monitor.h"
  #include "MagickCore/monitor-private.h"
  #include "MagickCore/memory_.h"
  #include "MagickCore/option.h"
  #include "MagickCore/pixel-accessor.h"
  #include "MagickCore/quantum-private.h"
  #include "MagickCore/static.h"
  #include "MagickCore/string_.h"
  #include "MagickCore/string-private.h"
  #include "MagickCore/module.h"
  #include "MagickCore/utility.h"
  #include "MagickCore/xwindow.h"
  #include "MagickCore/xwindow-private.h"
  #if defined(MAGICKCORE_FLIF_DELEGATE)
  #include <flif.h>
  #endif
  
  /*
    Forward declarations.
  */
  #if defined(MAGICKCORE_FLIF_DELEGATE)
  static MagickBooleanType
    WriteFLIFImage(const ImageInfo *,Image *,ExceptionInfo *);
  #endif
  
  #if defined(MAGICKCORE_FLIF_DELEGATE)
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   R e a d F L I F I m a g e                                                 %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  ReadFLIFImage() reads an image in the FLIF image format.
  %
  %  The format of the ReadFLIFImage method is:
  %
  %      Image *ReadFLIFImage(const ImageInfo *image_info,
  %        ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o image_info: the image info.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  static Image *ReadFLIFImage(const ImageInfo *image_info,
    ExceptionInfo *exception)
  {
    FLIF_DECODER
      *flifdec;
  
    FLIF_IMAGE
      *flifimage;
  
    Image
      *image;
  
    MagickBooleanType
      status;
  
    register Quantum
      *q;
  
    register ssize_t
      x;
  
    register unsigned short
      *p;
  
    size_t
      count,
      image_count,
      length;
  
    ssize_t
      y;
  
    unsigned char
      *stream;
  
    unsigned short
      *pixels;
  
    /*
      Open image file.
    */
    assert(image_info != (const ImageInfo *) NULL);
    assert(image_info->signature == MagickCoreSignature);
    if (image_info->debug != MagickFalse)
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
        image_info->filename);
    assert(exception != (ExceptionInfo *) NULL);
    assert(exception->signature == MagickCoreSignature);
    image=AcquireImage(image_info,exception);
    status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    if (status == MagickFalse)
      {
        image=DestroyImageList(image);
        return((Image *) NULL);
      }
    length=(size_t) GetBlobSize(image);
    stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
    if (stream == (unsigned char *) NULL)
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    count=ReadBlob(image,length,stream);
    if (count != length)
      {
        stream=(unsigned char *) RelinquishMagickMemory(stream);
        ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
      }
    flifdec=flif_create_decoder();
    if (image_info->quality != UndefinedCompressionQuality)
      flif_decoder_set_quality(flifdec,(int32_t) image_info->quality);
    if (!flif_decoder_decode_memory(flifdec,stream,length))
      {
        flif_destroy_decoder(flifdec);
        ThrowReaderException(CorruptImageError,"CorruptImage");
      }
    image_count=flif_decoder_num_images(flifdec);
    flifimage=flif_decoder_get_image(flifdec,0);
    length=sizeof(unsigned short)*4*flif_image_get_width(flifimage);
    pixels=(unsigned short *) AcquireMagickMemory(length);
    if (pixels == (unsigned short *) NULL)
      {
        flif_destroy_decoder(flifdec);
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
      }
  
    for (count=0; count < image_count; count++)
    {
      if (count > 0)
        {
          /*
            Allocate next image structure.
          */
          AcquireNextImage(image_info,image,exception);
          if (GetNextImageInList(image) == (Image *) NULL)
            {
              status=MagickFalse;
              break;
            }
          image=SyncNextImageInList(image);
        }
      flifimage=flif_decoder_get_image(flifdec,count);
      image->columns=(size_t) flif_image_get_width(flifimage);
      image->rows=(size_t) flif_image_get_height(flifimage);
      image->depth=flif_image_get_depth(flifimage);
      image->alpha_trait=(flif_image_get_nb_channels(flifimage) > 3 ?
        BlendPixelTrait : UndefinedPixelTrait);
      image->delay=flif_image_get_frame_delay(flifimage);
      image->ticks_per_second=1000;
      image->scene=count;
      image->dispose=BackgroundDispose;
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        flif_image_read_row_RGBA16(flifimage,y,pixels,length);
        p=pixels;
        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
        if (q == (Quantum *) NULL)
          break;
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          SetPixelRed(image,ScaleShortToQuantum(*p++),q);
          SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
          SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
          SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
          q+=GetPixelChannels(image);
        }
        if (SyncAuthenticPixels(image,exception) == MagickFalse)
          break;
        status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
          image->rows);
        if (status == MagickFalse)
          break;
      }
    }
    flif_destroy_decoder(flifdec);
    pixels=(unsigned short *) RelinquishMagickMemory(pixels);
    if (status == MagickFalse)
      return(DestroyImageList(image));
    return(image);
  }
  #endif
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   I s F L I F                                                               %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  IsFLIF() returns MagickTrue if the image format type, identified by the
  %  magick string, is FLIF.
  %
  %  The format of the IsFLIF method is:
  %
  %      MagickBooleanType IsFLIF(const unsigned char *magick,
  %        const size_t length)
  %
  %  A description of each parameter follows:
  %
  %    o magick: compare image format pattern against these bytes.
  %
  %    o length: Specifies the length of the magick string.
  %
  */
  static MagickBooleanType IsFLIF(const unsigned char *magick,
    const size_t length)
  {
    if (length < 4)
      return(MagickFalse);
    if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
      return(MagickTrue);
    return(MagickFalse);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   R e g i s t e r F L I F I m a g e                                         %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  RegisterFLIFImage() adds attributes for the FLIF image format to
  %  the list of supported formats.  The attributes include the image format
  %  tag, a method to read and/or write the format, whether the format
  %  supports the saving of more than one frame to the same file or blob,
  %  whether the format supports native in-memory I/O, and a brief
  %  description of the format.
  %
  %  The format of the RegisterFLIFImage method is:
  %
  %      size_t RegisterFLIFImage(void)
  %
  */
  ModuleExport size_t RegisterFLIFImage(void)
  {
    char
      version[MagickPathExtent];
  
    MagickInfo
      *entry;
  
    *version='\0';
    entry=AcquireMagickInfo("FLIF","FLIF","Free Lossless Image Format");
  #if defined(MAGICKCORE_FLIF_DELEGATE)
    entry->decoder=(DecodeImageHandler *) ReadFLIFImage;
    entry->encoder=(EncodeImageHandler *) WriteFLIFImage;
    (void) FormatLocaleString(version,MagickPathExtent,"libflif %d.%d.%d [%04X]",
      (FLIF_VERSION >> 16) & 0xff,
      (FLIF_VERSION  >> 8) & 0xff,
      (FLIF_VERSION  >> 0) & 0xff,FLIF_ABI_VERSION);
  #endif
    entry->mime_type=ConstantString("image/flif");
    entry->magick=(IsImageFormatHandler *) IsFLIF;
    if (*version != '\0')
      entry->version=ConstantString(version);
    (void) RegisterMagickInfo(entry);
    return(MagickImageCoderSignature);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   U n r e g i s t e r F L I F I m a g e                                     %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  UnregisterFLIFImage() removes format registrations made by the FLIF module
  %  from the list of supported formats.
  %
  %  The format of the UnregisterFLIFImage method is:
  %
  %      UnregisterFLIFImage(void)
  %
  */
  ModuleExport void UnregisterFLIFImage(void)
  {
    (void) UnregisterMagickInfo("FLIF");
  }
  
  #if defined(MAGICKCORE_FLIF_DELEGATE)
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   W r i t e F L I F I m a g e                                               %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  WriteFLIFImage() writes an image in the FLIF image format.
  %
  %  The format of the WriteFLIFImage method is:
  %
  %      MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
  %        Image *image)
  %
  %  A description of each parameter follows.
  %
  %    o image_info: the image info.
  %
  %    o image:  The image.
  %
  */
  static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
    Image *image, ExceptionInfo *exception)
  {
    FLIF_ENCODER
      *flifenc;
  
    FLIF_IMAGE
      *flifimage;
  
    int
      flif_status;
  
    MagickBooleanType
      status;
  
    MagickOffsetType
      scene;
  
    register const Quantum
      *magick_restrict p;
  
    register ssize_t
      x;
  
    register unsigned char
      *magick_restrict qc;
  
    register unsigned short
      *magick_restrict qs;
  
    size_t
      columns,
      imageListLength,
      length,
      rows;
  
    ssize_t
      y;
  
    void
      *buffer;
  
    void
      *pixels;
  
    assert(image_info != (const ImageInfo *) NULL);
    assert(image_info->signature == MagickCoreSignature);
    assert(image != (Image *) NULL);
    assert(image->signature == MagickCoreSignature);
    if (image->debug != MagickFalse)
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    if ((image->columns > 0xFFFF) || (image->rows > 0xFFFF))
      ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
    status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    if (status == MagickFalse)
      return(status);
    flifenc=flif_create_encoder();
    if (image_info->quality != UndefinedCompressionQuality)
      flif_encoder_set_lossy(flifenc,3*(100-(int32_t) image_info->quality));
  
    /* relatively fast encoding */
    flif_encoder_set_learn_repeat(flifenc,1);
    flif_encoder_set_split_threshold(flifenc,5461*8*5);
  
    columns=image->columns;
    rows=image->rows;
  
    /* Convert image to FLIFIMAGE */
    if (image->depth > 8)
      {
        flifimage=flif_create_image_HDR((uint32_t) image->columns,
          (uint32_t) image->rows);
        length=sizeof(unsigned short)*4*image->columns;
      }
    else
      {
        flifimage=flif_create_image((uint32_t) image->columns,
          (uint32_t) image->rows);
        length=sizeof(unsigned char)*4*image->columns;
      }
    if (flifimage == (FLIF_IMAGE *) NULL)
      {
        flif_destroy_encoder(flifenc);
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
      }
    pixels=AcquireMagickMemory(length);
    if (pixels == (void *) NULL)
      {
        flif_destroy_image(flifimage);
        flif_destroy_encoder(flifenc);
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
      }
    scene=0;
    imageListLength=GetImageListLength(image);
    do
    {
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        p=GetVirtualPixels(image,0,y,image->columns,1,exception);
        if (p == (Quantum *) NULL)
          break;
  
        if (image->depth > 8)
          {
            qs=(unsigned short *) pixels;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              *qs++=ScaleQuantumToShort(GetPixelRed(image,p));
              *qs++=ScaleQuantumToShort(GetPixelGreen(image,p));
              *qs++=ScaleQuantumToShort(GetPixelBlue(image,p));
              if (image->alpha_trait != UndefinedPixelTrait)
                *qs++=ScaleQuantumToShort(GetPixelAlpha(image,p));
              else
                *qs++=0xFFFF;
              p+=GetPixelChannels(image);
            }
            flif_image_write_row_RGBA16(flifimage,y,pixels,length);
          }
        else
          {
            qc=pixels;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              *qc++=ScaleQuantumToChar(GetPixelRed(image,p));
              *qc++=ScaleQuantumToChar(GetPixelGreen(image,p));
              *qc++=ScaleQuantumToChar(GetPixelBlue(image,p));
              if (image->alpha_trait != UndefinedPixelTrait)
                *qc++=ScaleQuantumToChar(GetPixelAlpha(image,p));
              else
                *qc++=0xFF;
              p+=GetPixelChannels(image);
            }
            flif_image_write_row_RGBA8(flifimage,y,pixels,length);
          }
      }
      flif_image_set_frame_delay(flifimage,(uint32_t) image->delay*100/
        image->ticks_per_second);
      flif_encoder_add_image(flifenc,flifimage);
      if (GetNextImageInList(image) == (Image *) NULL)
        break;
      image=SyncNextImageInList(image);
      if ((columns != image->columns) || (rows != image->rows))
        {
          flif_destroy_image(flifimage);
          flif_destroy_encoder(flifenc);
          pixels=RelinquishMagickMemory(pixels);
          ThrowWriterException(ImageError,"FramesNotSameDimensions");
        }
      scene++;
      status=SetImageProgress(image,SaveImagesTag,scene,imageListLength);
      if (status == MagickFalse)
         break;
    } while (image_info->adjoin != MagickFalse);
    flif_destroy_image(flifimage);
    pixels=RelinquishMagickMemory(pixels);
    flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
    if (flif_status)
      WriteBlob(image,length,buffer);
    CloseBlob(image);
    flif_destroy_encoder(flifenc);
    buffer=RelinquishMagickMemory(buffer);
    return(flif_status == 0 ? MagickFalse : MagickTrue);
  }
  #endif
  