Browse Source

Revert decoder optimizations touch #54

pull/56/head
James Jackson-South 10 years ago
parent
commit
2f439592ef
  1. 142
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs

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

@ -33,14 +33,9 @@ namespace ImageSharp.Formats
private byte[] globalColorTable; private byte[] globalColorTable;
/// <summary> /// <summary>
/// The next frame. /// The current frame.
/// </summary> /// </summary>
private ImageFrame<TColor, TPacked> nextFrame; private TColor[] currentFrame;
/// <summary>
/// The area to restore.
/// </summary>
private Rectangle? restoreArea;
/// <summary> /// <summary>
/// The logical screen descriptor. /// The logical screen descriptor.
@ -258,13 +253,10 @@ namespace ImageSharp.Formats
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor) private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
{ {
int dataSize = this.currentStream.ReadByte(); int dataSize = this.currentStream.ReadByte();
byte[] indices;
using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream)) using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream))
{ {
indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize); return lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize);
} }
return indices;
} }
/// <summary> /// <summary>
@ -292,57 +284,31 @@ namespace ImageSharp.Formats
/// <param name="indices">The indexed pixels.</param> /// <param name="indices">The indexed pixels.</param>
/// <param name="colorTable">The color table containing the available colors.</param> /// <param name="colorTable">The color table containing the available colors.</param>
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param> /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
{ {
int imageWidth = this.logicalScreenDescriptor.Width; int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height; int imageHeight = this.logicalScreenDescriptor.Height;
ImageFrame<TColor, TPacked> previousFrame = null; if (this.currentFrame == null)
ImageFrame<TColor, TPacked> currentFrame = null;
ImageBase<TColor, TPacked> image;
if (this.nextFrame == null)
{ {
image = this.decodedImage; this.currentFrame = new TColor[imageWidth * imageHeight];
}
image.Quality = colorTable.Length / 3; TColor[] lastFrame = null;
// This initializes the image to become fully transparent because the alpha channel is zero.
image.InitPixels(imageWidth, imageHeight);
}
else
{
if (this.graphicsControlExtension != null && if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{ {
previousFrame = this.nextFrame; lastFrame = new TColor[imageWidth * imageHeight];
}
currentFrame = this.nextFrame.Clone();
image = currentFrame; Array.Copy(this.currentFrame, lastFrame, lastFrame.Length);
this.RestoreToBackground(image);
this.decodedImage.Frames.Add(currentFrame);
}
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
image.FrameDelay = this.graphicsControlExtension.DelayTime;
} }
int i = 0; int offset, i = 0;
int interlacePass = 0; // The interlace pass int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment int interlaceIncrement = 8; // The interlacing line increment
int interlaceY = 0; // The current interlaced line int interlaceY = 0; // The current interlaced line
using (PixelAccessor<TColor, TPacked> pixelAccessor = image.Lock())
{
using (PixelArea<TColor, TPacked> pixelRow = new PixelArea<TColor, TPacked>(imageWidth, ComponentOrder.XYZW))
{
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{ {
// Check if this image is interlaced. // Check if this image is interlaced.
@ -380,83 +346,79 @@ namespace ImageSharp.Formats
writeY = y; writeY = y;
} }
pixelRow.Reset(); for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
byte* pixelBase = pixelRow.PixelBase;
for (int x = 0; x < descriptor.Width; x++)
{ {
offset = (writeY * imageWidth) + x;
int index = indices[i]; int index = indices[i];
if (this.graphicsControlExtension == null || if (this.graphicsControlExtension == null ||
this.graphicsControlExtension.TransparencyFlag == false || this.graphicsControlExtension.TransparencyFlag == false ||
this.graphicsControlExtension.TransparencyIndex != index) this.graphicsControlExtension.TransparencyIndex != index)
{ {
// Stored in r-> g-> b-> a order.
int indexOffset = index * 3; int indexOffset = index * 3;
*(pixelBase + 0) = colorTable[indexOffset]; TColor pixel = default(TColor);
*(pixelBase + 1) = colorTable[indexOffset + 1]; pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255);
*(pixelBase + 2) = colorTable[indexOffset + 2]; this.currentFrame[offset] = pixel;
*(pixelBase + 3) = 255;
} }
i++; i++;
pixelBase += 4;
}
pixelAccessor.CopyFrom(pixelRow, writeY, descriptor.Left);
}
} }
} }
if (previousFrame != null) TColor[] pixels = new TColor[imageWidth * imageHeight];
{
this.nextFrame = previousFrame;
return;
}
this.nextFrame = currentFrame == null ? this.decodedImage.ToFrame() : currentFrame.Clone(); Array.Copy(this.currentFrame, pixels, pixels.Length);
if (this.graphicsControlExtension != null && ImageBase<TColor, TPacked> currentImage;
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
{
this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height);
}
}
/// <summary> if (this.decodedImage.Pixels == null)
/// Restores the current frame background.
/// </summary>
/// <param name="frame">The frame.</param>
private void RestoreToBackground(ImageBase<TColor, TPacked> frame)
{ {
if (this.restoreArea == null) currentImage = this.decodedImage;
currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3;
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{ {
return; this.decodedImage.FrameDelay = this.graphicsControlExtension.DelayTime;
} }
}
// Optimization for when the size of the frame is the same as the image size. else
if (this.restoreArea.Value.Width == this.decodedImage.Width &&
this.restoreArea.Value.Height == this.decodedImage.Height)
{ {
using (PixelAccessor<TColor, TPacked> pixelAccessor = frame.Lock()) ImageFrame<TColor, TPacked> frame = new ImageFrame<TColor, TPacked>();
currentImage = frame;
currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3;
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{ {
pixelAccessor.Reset(); currentImage.FrameDelay = this.graphicsControlExtension.DelayTime;
} }
this.decodedImage.Frames.Add(frame);
} }
else
if (this.graphicsControlExtension != null)
{ {
using (PixelArea<TColor, TPacked> emptyRow = new PixelArea<TColor, TPacked>(this.restoreArea.Value.Width, ComponentOrder.XYZW)) if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
{ {
using (PixelAccessor<TColor, TPacked> pixelAccessor = frame.Lock()) for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{ {
for (int y = this.restoreArea.Value.Top; y < this.restoreArea.Value.Top + this.restoreArea.Value.Height; y++) for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
{ {
pixelAccessor.CopyFrom(emptyRow, y, this.restoreArea.Value.Left); offset = (y * imageWidth) + x;
// Stored in r-> g-> b-> a order.
this.currentFrame[offset] = default(TColor);
} }
} }
} }
else if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{
this.currentFrame = lastFrame;
}
} }
this.restoreArea = null;
} }
} }
} }

Loading…
Cancel
Save