@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Performs the gif decoding operation.
/// </summary>
internal sealed class GifDecoderCore : IImageDecoderInternals
internal sealed class GifDecoderCore : IImageDecoderInternals < GifDecoderOptions >
{
/// <summary>
/// The temp buffer used to reduce allocations.
@ -56,6 +56,26 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
private GifImageDescriptor imageDescriptor ;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration ;
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
private readonly MemoryAllocator memoryAllocator ;
/// <summary>
/// The maximum number of frames to decode.
/// </summary>
private readonly int maxFrames ;
/// <summary>
/// Whether to skip metadata during decode.
/// </summary>
private readonly bool skipMetadata ;
/// <summary>
/// The abstract metadata.
/// </summary>
@ -69,39 +89,26 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The decoder options.</param>
public GifDecoderCore ( Configuration configuration , I GifDecoderOptions options )
public GifDecoderCore ( GifDecoderOptions options )
{
this . IgnoreMetadata = options . IgnoreMetadata ;
this . DecodingMode = options . DecodingMode ;
this . Configuration = configuration ? ? Configuration . Default ;
this . skipMetadata = options . GeneralOptions . SkipMetadata ;
this . configuration = options . GeneralOptions . Configuration ;
this . memoryAllocator = this . configuration . MemoryAllocator ;
this . maxFrames = options . GeneralOptions . MaxFrames ;
}
/// <inheritdoc />
public Configuration Configuration { get ; }
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreMetadata { get ; internal set ; }
public GifDecoderOptions Options { get ; }
/// <summary>
/// Gets the decoding mode for multi-frame images.
/// </summary>
public FrameDecodingMode DecodingMode { get ; }
/// <summary>
/// Gets the dimensions of the image.
/// </summary>
/// <inheritdoc />
public Size Dimensions = > new ( this . imageDescriptor . Width , this . imageDescriptor . Height ) ;
private MemoryAllocator MemoryAllocator = > this . Configuration . MemoryAllocator ;
/// <inheritdoc />
public Image < TPixel > Decode < TPixel > ( BufferedReadStream stream , CancellationToken cancellationToken )
where TPixel : unmanaged , IPixel < TPixel >
{
int frameCount = 0 ;
Image < TPixel > image = null ;
ImageFrame < TPixel > previousFrame = null ;
try
@ -114,7 +121,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
if ( nextFlag = = GifConstants . ImageLabel )
{
if ( previousFrame ! = null & & this . DecodingMode = = FrameDecodingMode . First )
if ( previousFrame ! = null & & frameCount + + < = this . maxFrames )
{
break ;
}
@ -277,9 +284,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
this . stream . Read ( this . buffer , 0 , GifConstants . ApplicationBlockSize ) ;
bool isXmp = this . buffer . AsSpan ( ) . StartsWith ( GifConstants . XmpApplicationIdentificationBytes ) ;
if ( isXmp & & ! this . Ignore Metadata)
if ( isXmp & & ! this . skip Metadata)
{
var extension = GifXmpApplicationExtension . Read ( this . stream , this . M emoryAllocator) ;
var extension = GifXmpApplicationExtension . Read ( this . stream , this . m emoryAllocator) ;
if ( extension . Data . Length > 0 )
{
this . metadata . XmpProfile = new XmpProfile ( extension . Data ) ;
@ -346,13 +353,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
GifThrowHelper . ThrowInvalidImageContentException ( $"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentSubBlockLength}' of a comment data block" ) ;
}
if ( this . Ignore Metadata)
if ( this . skip Metadata)
{
this . stream . Seek ( length , SeekOrigin . Current ) ;
continue ;
}
using IMemoryOwner < byte > commentsBuffer = this . M emoryAllocator. Allocate < byte > ( length ) ;
using IMemoryOwner < byte > commentsBuffer = this . m emoryAllocator. Allocate < byte > ( length ) ;
Span < byte > commentsSpan = commentsBuffer . GetSpan ( ) ;
this . stream . Read ( commentsSpan ) ;
@ -385,11 +392,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
if ( this . imageDescriptor . LocalColorTableFlag )
{
int length = this . imageDescriptor . LocalColorTableSize * 3 ;
localColorTable = this . C onfiguration. MemoryAllocator . Allocate < byte > ( length , AllocationOptions . Clean ) ;
localColorTable = this . c onfiguration. MemoryAllocator . Allocate < byte > ( length , AllocationOptions . Clean ) ;
this . stream . Read ( localColorTable . GetSpan ( ) ) ;
}
indices = this . C onfiguration. MemoryAllocator . Allocate2D < byte > ( this . imageDescriptor . Width , this . imageDescriptor . Height , AllocationOptions . Clean ) ;
indices = this . c onfiguration. MemoryAllocator . Allocate2D < byte > ( this . imageDescriptor . Width , this . imageDescriptor . Height , AllocationOptions . Clean ) ;
this . ReadFrameIndices ( indices ) ;
Span < byte > rawColorTable = default ;
@ -423,7 +430,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void ReadFrameIndices ( Buffer2D < byte > indices )
{
int minCodeSize = this . stream . ReadByte ( ) ;
using var lzwDecoder = new LzwDecoder ( this . C onfiguration. MemoryAllocator , this . stream ) ;
using var lzwDecoder = new LzwDecoder ( this . c onfiguration. MemoryAllocator , this . stream ) ;
lzwDecoder . DecodePixels ( minCodeSize , indices ) ;
}
@ -451,12 +458,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
if ( ! transFlag )
{
image = new Image < TPixel > ( this . C onfiguration, imageWidth , imageHeight , Color . Black . ToPixel < TPixel > ( ) , this . metadata ) ;
image = new Image < TPixel > ( this . c onfiguration, imageWidth , imageHeight , Color . Black . ToPixel < TPixel > ( ) , this . metadata ) ;
}
else
{
// This initializes the image to become fully transparent because the alpha channel is zero.
image = new Image < TPixel > ( this . C onfiguration, imageWidth , imageHeight , this . metadata ) ;
image = new Image < TPixel > ( this . c onfiguration, imageWidth , imageHeight , this . metadata ) ;
}
this . SetFrameMetadata ( image . Frames . RootFrame . Metadata ) ;
@ -675,7 +682,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
if ( globalColorTableLength > 0 )
{
this . globalColorTable = this . M emoryAllocator. Allocate < byte > ( globalColorTableLength , AllocationOptions . Clean ) ;
this . globalColorTable = this . m emoryAllocator. Allocate < byte > ( globalColorTableLength , AllocationOptions . Clean ) ;
// Read the global color table data from the stream
stream . Read ( this . globalColorTable . GetSpan ( ) ) ;