Browse Source

Reduce memory used during LZW decoding

pull/56/head
James Jackson-South 10 years ago
parent
commit
3f2b6c984d
  1. 14
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 13
      src/ImageSharp/Formats/Gif/LzwDecoder.cs

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

@ -252,7 +252,7 @@ namespace ImageSharp.Formats
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor(); GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();
byte[] localColorTable = null; byte[] localColorTable = null;
byte[] indices = null;
try try
{ {
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
@ -264,7 +264,9 @@ namespace ImageSharp.Formats
this.currentStream.Read(localColorTable, 0, length); this.currentStream.Read(localColorTable, 0, length);
} }
byte[] indices = this.ReadFrameIndices(imageDescriptor); indices = ArrayPool<byte>.Shared.Rent(imageDescriptor.Width * imageDescriptor.Height);
this.ReadFrameIndices(imageDescriptor, indices);
this.ReadFrameColors(indices, localColorTable ?? this.globalColorTable, length, imageDescriptor); this.ReadFrameColors(indices, localColorTable ?? this.globalColorTable, length, imageDescriptor);
// Skip any remaining blocks // Skip any remaining blocks
@ -276,6 +278,8 @@ namespace ImageSharp.Formats
{ {
ArrayPool<byte>.Shared.Return(localColorTable); ArrayPool<byte>.Shared.Return(localColorTable);
} }
ArrayPool<byte>.Shared.Return(indices);
} }
} }
@ -283,13 +287,13 @@ namespace ImageSharp.Formats
/// Reads the frame indices marking the color to use for each pixel. /// Reads the frame indices marking the color to use for each pixel.
/// </summary> /// </summary>
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param> /// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
/// <returns>The <see cref="T:byte[]"/></returns> /// <param name="indices">The pixel array to write to.</param>
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor) private void ReadFrameIndices(GifImageDescriptor imageDescriptor, byte[] indices)
{ {
int dataSize = this.currentStream.ReadByte(); int dataSize = this.currentStream.ReadByte();
using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream)) using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream))
{ {
return lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize); lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices);
} }
} }

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

@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
using System; using System;
@ -83,13 +84,13 @@ namespace ImageSharp.Formats
/// <param name="width">The width of the pixel index array.</param> /// <param name="width">The width of the pixel index array.</param>
/// <param name="height">The height of the pixel index array.</param> /// <param name="height">The height of the pixel index array.</param>
/// <param name="dataSize">Size of the data.</param> /// <param name="dataSize">Size of the data.</param>
/// <returns>The decoded and uncompressed array.</returns> /// <param name="pixels">The pixel array to decode to.</param>
public byte[] DecodePixels(int width, int height, int dataSize) public void DecodePixels(int width, int height, int dataSize, byte[] pixels)
{ {
Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize)); Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize));
// The resulting index table. // The resulting index table length.
byte[] pixels = new byte[width * height]; int length = width * height;
// Calculate the clear code. The value of the clear code is 2 ^ dataSize // Calculate the clear code. The value of the clear code is 2 ^ dataSize
int clearCode = 1 << dataSize; int clearCode = 1 << dataSize;
@ -124,7 +125,7 @@ namespace ImageSharp.Formats
} }
byte[] buffer = new byte[255]; byte[] buffer = new byte[255];
while (xyz < pixels.Length) while (xyz < length)
{ {
if (top == 0) if (top == 0)
{ {
@ -221,8 +222,6 @@ namespace ImageSharp.Formats
// Clear missing pixels // Clear missing pixels
pixels[xyz++] = (byte)this.pixelStack[top]; pixels[xyz++] = (byte)this.pixelStack[top];
} }
return pixels;
} }
/// <inheritdoc /> /// <inheritdoc />

Loading…
Cancel
Save