diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index d5e806716..da10061fb 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -33,14 +33,9 @@ namespace ImageSharp.Formats
private byte[] globalColorTable;
///
- /// The next frame.
+ /// The current frame.
///
- private ImageFrame nextFrame;
-
- ///
- /// The area to restore.
- ///
- private Rectangle? restoreArea;
+ private TColor[] currentFrame;
///
/// The logical screen descriptor.
@@ -258,13 +253,10 @@ namespace ImageSharp.Formats
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
{
int dataSize = this.currentStream.ReadByte();
- byte[] indices;
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;
}
///
@@ -292,171 +284,141 @@ namespace ImageSharp.Formats
/// The indexed pixels.
/// The color table containing the available colors.
/// The
- 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 imageHeight = this.logicalScreenDescriptor.Height;
- ImageFrame previousFrame = null;
-
- ImageFrame currentFrame = null;
-
- ImageBase image;
-
- if (this.nextFrame == null)
+ if (this.currentFrame == null)
{
- image = this.decodedImage;
-
- image.Quality = colorTable.Length / 3;
-
- // This initializes the image to become fully transparent because the alpha channel is zero.
- image.InitPixels(imageWidth, imageHeight);
+ this.currentFrame = new TColor[imageWidth * imageHeight];
}
- else
- {
- if (this.graphicsControlExtension != null &&
- this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
- {
- previousFrame = this.nextFrame;
- }
-
- currentFrame = this.nextFrame.Clone();
- image = currentFrame;
+ TColor[] lastFrame = null;
- this.RestoreToBackground(image);
-
- this.decodedImage.Frames.Add(currentFrame);
- }
-
- if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
+ if (this.graphicsControlExtension != null &&
+ this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{
- image.FrameDelay = this.graphicsControlExtension.DelayTime;
+ lastFrame = new TColor[imageWidth * imageHeight];
+
+ Array.Copy(this.currentFrame, lastFrame, lastFrame.Length);
}
- int i = 0;
+ int offset, i = 0;
int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment
int interlaceY = 0; // The current interlaced line
- using (PixelAccessor pixelAccessor = image.Lock())
+ for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{
- using (PixelArea pixelRow = new PixelArea(imageWidth, ComponentOrder.XYZW))
+ // Check if this image is interlaced.
+ int writeY; // the target y offset to write to
+ if (descriptor.InterlaceFlag)
{
- for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
+ // If so then we read lines at predetermined offsets.
+ // When an entire image height worth of offset lines has been read we consider this a pass.
+ // With each pass the number of offset lines changes and the starting line changes.
+ if (interlaceY >= descriptor.Height)
{
- // Check if this image is interlaced.
- int writeY; // the target y offset to write to
- if (descriptor.InterlaceFlag)
- {
- // If so then we read lines at predetermined offsets.
- // When an entire image height worth of offset lines has been read we consider this a pass.
- // With each pass the number of offset lines changes and the starting line changes.
- if (interlaceY >= descriptor.Height)
- {
- interlacePass++;
- switch (interlacePass)
- {
- case 1:
- interlaceY = 4;
- break;
- case 2:
- interlaceY = 2;
- interlaceIncrement = 4;
- break;
- case 3:
- interlaceY = 1;
- interlaceIncrement = 2;
- break;
- }
- }
-
- writeY = interlaceY + descriptor.Top;
-
- interlaceY += interlaceIncrement;
- }
- else
+ interlacePass++;
+ switch (interlacePass)
{
- writeY = y;
+ case 1:
+ interlaceY = 4;
+ break;
+ case 2:
+ interlaceY = 2;
+ interlaceIncrement = 4;
+ break;
+ case 3:
+ interlaceY = 1;
+ interlaceIncrement = 2;
+ break;
}
+ }
- pixelRow.Reset();
+ writeY = interlaceY + descriptor.Top;
- byte* pixelBase = pixelRow.PixelBase;
- for (int x = 0; x < descriptor.Width; x++)
- {
- int index = indices[i];
-
- if (this.graphicsControlExtension == null ||
- this.graphicsControlExtension.TransparencyFlag == false ||
- this.graphicsControlExtension.TransparencyIndex != index)
- {
- int indexOffset = index * 3;
- *(pixelBase + 0) = colorTable[indexOffset];
- *(pixelBase + 1) = colorTable[indexOffset + 1];
- *(pixelBase + 2) = colorTable[indexOffset + 2];
- *(pixelBase + 3) = 255;
- }
-
- i++;
- pixelBase += 4;
- }
+ interlaceY += interlaceIncrement;
+ }
+ else
+ {
+ writeY = y;
+ }
- pixelAccessor.CopyFrom(pixelRow, writeY, descriptor.Left);
+ for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
+ {
+ offset = (writeY * imageWidth) + x;
+ int index = indices[i];
+
+ if (this.graphicsControlExtension == null ||
+ this.graphicsControlExtension.TransparencyFlag == false ||
+ this.graphicsControlExtension.TransparencyIndex != index)
+ {
+ // Stored in r-> g-> b-> a order.
+ int indexOffset = index * 3;
+ TColor pixel = default(TColor);
+ pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255);
+ this.currentFrame[offset] = pixel;
}
+
+ i++;
}
}
- if (previousFrame != null)
- {
- this.nextFrame = previousFrame;
- return;
- }
+ TColor[] pixels = new TColor[imageWidth * imageHeight];
- this.nextFrame = currentFrame == null ? this.decodedImage.ToFrame() : currentFrame.Clone();
+ Array.Copy(this.currentFrame, pixels, pixels.Length);
- if (this.graphicsControlExtension != null &&
- this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
- {
- this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height);
- }
- }
+ ImageBase currentImage;
- ///
- /// Restores the current frame background.
- ///
- /// The frame.
- private void RestoreToBackground(ImageBase frame)
- {
- if (this.restoreArea == null)
+ if (this.decodedImage.Pixels == null)
{
- return;
- }
+ currentImage = this.decodedImage;
+ currentImage.SetPixels(imageWidth, imageHeight, pixels);
+ currentImage.Quality = colorTable.Length / 3;
- // Optimization for when the size of the frame is the same as the image size.
- if (this.restoreArea.Value.Width == this.decodedImage.Width &&
- this.restoreArea.Value.Height == this.decodedImage.Height)
- {
- using (PixelAccessor pixelAccessor = frame.Lock())
+ if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
- pixelAccessor.Reset();
+ this.decodedImage.FrameDelay = this.graphicsControlExtension.DelayTime;
}
}
else
{
- using (PixelArea emptyRow = new PixelArea(this.restoreArea.Value.Width, ComponentOrder.XYZW))
+ ImageFrame frame = new ImageFrame();
+
+ currentImage = frame;
+ currentImage.SetPixels(imageWidth, imageHeight, pixels);
+ currentImage.Quality = colorTable.Length / 3;
+
+ if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
+ {
+ currentImage.FrameDelay = this.graphicsControlExtension.DelayTime;
+ }
+
+ this.decodedImage.Frames.Add(frame);
+ }
+
+ if (this.graphicsControlExtension != null)
+ {
+ if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
{
- using (PixelAccessor 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;
}
}
}