From 2f439592ef568229df1e196cc9c38fa22737eb47 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 21 Dec 2016 12:13:48 +1100 Subject: [PATCH] Revert decoder optimizations touch #54 --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 226 ++++++++----------- 1 file changed, 94 insertions(+), 132 deletions(-) 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; } } }