diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index c8a22610d..775b3be98 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -258,9 +258,11 @@ namespace ImageSharp.Formats
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
{
int dataSize = this.currentStream.ReadByte();
- LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream);
-
- byte[] indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize);
+ byte[] indices;
+ using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream))
+ {
+ indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize);
+ }
return indices;
}
@@ -355,17 +357,17 @@ namespace ImageSharp.Formats
interlacePass++;
switch (interlacePass)
{
- case 1:
- interlaceY = 4;
- break;
- case 2:
- interlaceY = 2;
- interlaceIncrement = 4;
- break;
- case 3:
- interlaceY = 1;
- interlaceIncrement = 2;
- break;
+ case 1:
+ interlaceY = 4;
+ break;
+ case 2:
+ interlaceY = 2;
+ interlaceIncrement = 4;
+ break;
+ case 3:
+ interlaceY = 1;
+ interlaceIncrement = 2;
+ break;
}
}
@@ -411,14 +413,7 @@ namespace ImageSharp.Formats
return;
}
- if (currentFrame == null)
- {
- this.nextFrame = this.decodedImage.ToFrame();
- }
- else
- {
- this.nextFrame = currentFrame.Clone();
- }
+ this.nextFrame = currentFrame == null ? this.decodedImage.ToFrame() : currentFrame.Clone();
if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
@@ -427,6 +422,10 @@ namespace ImageSharp.Formats
}
}
+ ///
+ /// Restores the current frame background.
+ ///
+ /// The frame.
private void RestoreToBackground(ImageBase frame)
{
if (this.restoreArea == null)
diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
index c1b300dff..001f775ed 100644
--- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
@@ -2,15 +2,16 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
-
namespace ImageSharp.Formats
{
+ using System;
+ using System.Buffers;
using System.IO;
///
/// Decompresses and decodes data using the dynamic LZW algorithms.
///
- internal sealed class LzwDecoder
+ internal sealed class LzwDecoder : IDisposable
{
///
/// The max decoder pixel stack size.
@@ -27,6 +28,34 @@ namespace ImageSharp.Formats
///
private readonly Stream stream;
+ ///
+ /// The prefix buffer.
+ ///
+ private readonly int[] prefix;
+
+ ///
+ /// The suffix buffer.
+ ///
+ private readonly int[] suffix;
+
+ ///
+ /// The pixel stack buffer.
+ ///
+ private readonly int[] pixelStack;
+
+ ///
+ /// A value indicating whether this instance of the given entity has been disposed.
+ ///
+ /// if this instance has been disposed; otherwise, .
+ ///
+ /// If the entity is disposed, it must not be disposed a second
+ /// time. The isDisposed field is set the first time the entity
+ /// is disposed. If the isDisposed field is true, then the Dispose()
+ /// method will not dispose again. This help not to prolong the entity's
+ /// life in the Garbage Collector.
+ ///
+ private bool isDisposed;
+
///
/// Initializes a new instance of the class
/// and sets the stream, where the compressed data should be read from.
@@ -38,6 +67,10 @@ namespace ImageSharp.Formats
Guard.NotNull(stream, nameof(stream));
this.stream = stream;
+
+ this.prefix = ArrayPool.Shared.Rent(MaxStackSize);
+ this.suffix = ArrayPool.Shared.Rent(MaxStackSize);
+ this.pixelStack = ArrayPool.Shared.Rent(MaxStackSize + 1);
}
///
@@ -72,10 +105,6 @@ namespace ImageSharp.Formats
int codeMask = (1 << codeSize) - 1;
int bits = 0;
- int[] prefix = new int[MaxStackSize];
- int[] suffix = new int[MaxStackSize];
- int[] pixelStatck = new int[MaxStackSize + 1];
-
int top = 0;
int count = 0;
int bi = 0;
@@ -86,8 +115,8 @@ namespace ImageSharp.Formats
for (code = 0; code < clearCode; code++)
{
- prefix[code] = 0;
- suffix[code] = (byte)code;
+ this.prefix[code] = 0;
+ this.suffix[code] = (byte)code;
}
byte[] buffer = new byte[255];
@@ -141,7 +170,7 @@ namespace ImageSharp.Formats
if (oldCode == NullCode)
{
- pixelStatck[top++] = suffix[code];
+ this.pixelStack[top++] = this.suffix[code];
oldCode = code;
first = code;
continue;
@@ -150,27 +179,27 @@ namespace ImageSharp.Formats
int inCode = code;
if (code == availableCode)
{
- pixelStatck[top++] = (byte)first;
+ this.pixelStack[top++] = (byte)first;
code = oldCode;
}
while (code > clearCode)
{
- pixelStatck[top++] = suffix[code];
- code = prefix[code];
+ this.pixelStack[top++] = this.suffix[code];
+ code = this.prefix[code];
}
- first = suffix[code];
+ first = this.suffix[code];
- pixelStatck[top++] = suffix[code];
+ this.pixelStack[top++] = this.suffix[code];
// Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize)
{
- prefix[availableCode] = oldCode;
- suffix[availableCode] = first;
+ this.prefix[availableCode] = oldCode;
+ this.suffix[availableCode] = first;
availableCode++;
if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
@@ -186,12 +215,19 @@ namespace ImageSharp.Formats
top--;
// Clear missing pixels
- pixels[xyz++] = (byte)pixelStatck[top];
+ pixels[xyz++] = (byte)this.pixelStack[top];
}
return pixels;
}
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ this.Dispose(true);
+ }
+
///
/// Reads the next data block from the stream. A data block begins with a byte,
/// which defines the size of the block, followed by the block itself.
@@ -211,5 +247,26 @@ namespace ImageSharp.Formats
int count = this.stream.Read(buffer, 0, bufferSize);
return count != bufferSize ? 0 : bufferSize;
}
+
+ ///
+ /// Disposes the object and frees resources for the Garbage Collector.
+ ///
+ /// If true, the object gets disposed.
+ private void Dispose(bool disposing)
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ ArrayPool.Shared.Return(this.prefix);
+ ArrayPool.Shared.Return(this.suffix);
+ ArrayPool.Shared.Return(this.pixelStack);
+ }
+
+ this.isDisposed = true;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index fcfadfbba..4cc125e2f 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -94,7 +94,7 @@ namespace ImageSharp.Formats
/// method will not dispose again. This help not to prolong the entity's
/// life in the Garbage Collector.
///
- private bool isDisposed = false;
+ private bool isDisposed;
///
/// The current pixel
diff --git a/src/ImageSharp/Formats/Gif/PackedField.cs b/src/ImageSharp/Formats/Gif/PackedField.cs
index cabf4f5ab..21d8f91f2 100644
--- a/src/ImageSharp/Formats/Gif/PackedField.cs
+++ b/src/ImageSharp/Formats/Gif/PackedField.cs
@@ -74,9 +74,7 @@ namespace ImageSharp.Formats
{
if (index < 0 || index > 7)
{
- string message
- = "Index must be between 0 and 7. Supplied index: "
- + index;
+ string message = $"Index must be between 0 and 7. Supplied index: {index}";
throw new ArgumentOutOfRangeException(nameof(index), message);
}