Browse Source

Faster decoding

pull/527/head
James Jackson-South 8 years ago
parent
commit
c43957951b
  1. 14
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 36
      src/ImageSharp/Formats/Gif/LzwDecoder.cs

14
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -5,6 +5,7 @@ using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
@ -410,13 +411,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame, Span<byte> indices, Span<byte> colorTable, GifImageDescriptor descriptor)
where TPixel : struct, IPixel<TPixel>
{
ref byte indicesRef = ref MemoryMarshal.GetReference(indices);
int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height;
ImageFrame<TPixel> prevFrame = null;
ImageFrame<TPixel> currentFrame = null;
ImageFrame<TPixel> imageFrame;
if (previousFrame == null)
@ -479,7 +479,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
writeY = interlaceY + descriptor.Top;
interlaceY += interlaceIncrement;
}
else
@ -487,14 +486,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
writeY = y;
}
Span<TPixel> rowSpan = imageFrame.GetPixelRowSpan(writeY);
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
var rgba = new Rgba32(0, 0, 0, 255);
// #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < rowSpan.Length; x++)
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{
int index = indices[i];
int index = Unsafe.Add(ref indicesRef, i);
if (this.graphicsControlExtension == null ||
this.graphicsControlExtension.TransparencyFlag == false ||
@ -502,7 +500,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
int indexOffset = index * 3;
ref TPixel pixel = ref rowSpan[x];
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
rgba.Rgb = colorTable.GetRgb24(indexOffset);
pixel.PackFromRgba32(rgba);

36
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -4,7 +4,8 @@
using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
@ -115,14 +116,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
int data = 0;
int first = 0;
Span<int> prefixSpan = this.prefix.Span;
Span<int> suffixSpan = this.suffix.Span;
Span<int> pixelStackSpan = this.pixelStack.Span;
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.Span);
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.Span);
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.Span);
ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels);
for (code = 0; code < clearCode; code++)
{
prefixSpan[code] = 0;
suffixSpan[code] = (byte)code;
Unsafe.Add(ref suffixRef, code) = (byte)code;
}
byte[] buffer = new byte[255];
@ -176,7 +177,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (oldCode == NullCode)
{
pixelStackSpan[top++] = suffixSpan[code];
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code);
oldCode = code;
first = code;
continue;
@ -185,27 +186,27 @@ namespace SixLabors.ImageSharp.Formats.Gif
int inCode = code;
if (code == availableCode)
{
pixelStackSpan[top++] = (byte)first;
Unsafe.Add(ref pixelStackRef, top++) = (byte)first;
code = oldCode;
}
while (code > clearCode)
{
pixelStackSpan[top++] = suffixSpan[code];
code = prefixSpan[code];
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code);
code = Unsafe.Add(ref prefixRef, code);
}
first = suffixSpan[code];
pixelStackSpan[top++] = suffixSpan[code];
int suffixCode = Unsafe.Add(ref suffixRef, code);
first = suffixCode;
Unsafe.Add(ref pixelStackRef, top++) = suffixCode;
// Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize)
{
prefixSpan[availableCode] = oldCode;
suffixSpan[availableCode] = first;
Unsafe.Add(ref prefixRef, availableCode) = oldCode;
Unsafe.Add(ref suffixRef, availableCode) = first;
availableCode++;
if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
@ -221,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
top--;
// Clear missing pixels
pixels[xyz++] = (byte)pixelStackSpan[top];
Unsafe.Add(ref pixelsRef, xyz++) = (byte)Unsafe.Add(ref pixelStackRef, top);
}
}
@ -238,8 +239,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
/// <param name="buffer">The buffer to store the block in.</param>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// The <see cref="int"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int ReadBlock(byte[] buffer)
{
int bufferSize = this.stream.ReadByte();

Loading…
Cancel
Save