From 62d475506f385fd6e084cc81f269190cd86fd63b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 24 Apr 2020 15:13:01 +0200 Subject: [PATCH] Review changes --- src/ImageSharp/Formats/WebP/AlphaDecoder.cs | 4 +- src/ImageSharp/Formats/WebP/LosslessUtils.cs | 6 ++- .../Formats/WebP/WebPDecoderCore.cs | 11 +++-- .../Formats/WebP/WebPLosslessDecoder.cs | 23 ++++++++-- .../Formats/WebP/WebPLossyDecoder.cs | 8 ++-- .../Codecs/DecodeWebp.cs | 44 ++++++------------- 6 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs index 756c1d645..7a23ad6e5 100644 --- a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs @@ -273,10 +273,10 @@ namespace SixLabors.ImageSharp.Formats.WebP int bitsPerPixel = 8 >> transform.Bits; int width = transform.XSize; Span colorMap = transform.Data.Memory.Span; - int srcOffset = 0; - int dstOffset = 0; if (bitsPerPixel < 8) { + int srcOffset = 0; + int dstOffset = 0; int pixelsPerByte = 1 << transform.Bits; int countMask = pixelsPerByte - 1; int bitMask = (1 << bitsPerPixel) - 1; diff --git a/src/ImageSharp/Formats/WebP/LosslessUtils.cs b/src/ImageSharp/Formats/WebP/LosslessUtils.cs index f49000c6e..6279a5d12 100644 --- a/src/ImageSharp/Formats/WebP/LosslessUtils.cs +++ b/src/ImageSharp/Formats/WebP/LosslessUtils.cs @@ -279,14 +279,16 @@ namespace SixLabors.ImageSharp.Formats.WebP newColorMap[0] = transformData[0]; Span data = MemoryMarshal.Cast(transformData); Span newData = MemoryMarshal.Cast(newColorMap); + int numColorsX4 = 4 * numColors; int i; - for (i = 4; i < 4 * numColors; ++i) + for (i = 4; i < numColorsX4; i++) { // Equivalent to AddPixelEq(), on a byte-basis. newData[i] = (byte)((data[i] + newData[i - 4]) & 0xff); } - for (; i < 4 * newColorMap.Length; ++i) + int colorMapLength4 = 4 * newColorMap.Length; + for (; i < colorMapLength4; i++) { newData[i] = 0; // black tail. } diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs index 180c7c960..b8d450c33 100644 --- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs +++ b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs @@ -235,7 +235,6 @@ namespace SixLabors.ImageSharp.Formats.WebP return new WebPImageInfo() { Width = width, Height = height, Features = features }; } - // TODO: check if VP8 or VP8L info about the dimensions match VP8X info switch (chunkType) { case WebPChunkType.Vp8: @@ -415,7 +414,11 @@ namespace SixLabors.ImageSharp.Formats.WebP { case WebPChunkType.Iccp: uint iccpChunkSize = this.ReadChunkSize(); - if (!this.IgnoreMetadata) + if (this.IgnoreMetadata) + { + this.currentStream.Skip((int)iccpChunkSize); + } + else { var iccpData = new byte[iccpChunkSize]; this.currentStream.Read(iccpData, 0, (int)iccpChunkSize); @@ -425,10 +428,6 @@ namespace SixLabors.ImageSharp.Formats.WebP this.Metadata.IccProfile = profile; } } - else - { - this.currentStream.Skip((int)iccpChunkSize); - } break; diff --git a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs index b517a06f3..cbe2fec0f 100644 --- a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs @@ -929,9 +929,17 @@ namespace SixLabors.ImageSharp.Formats.WebP return (dist >= 1) ? dist : 1; } + /// + /// Copies pixels when a backward reference is used. + /// Copy 'length' number of pixels (in scan-line order) from the sequence of pixels prior to them by 'dist' pixels. + /// + /// The pixel data. + /// The number of so far decoded pixels. + /// The backward reference distance prior to the current decoded pixel. + /// The number of pixels to copy. private static void CopyBlock(Span pixelData, int decodedPixels, int dist, int length) { - if (dist >= length) + if (dist >= length) // no overlap. { Span src = pixelData.Slice(decodedPixels - dist, length); Span dest = pixelData.Slice(decodedPixels); @@ -939,18 +947,27 @@ namespace SixLabors.ImageSharp.Formats.WebP } else { + // There is overlap between the backward reference distance and the pixels to copy. Span src = pixelData.Slice(decodedPixels - dist); Span dest = pixelData.Slice(decodedPixels); - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; i++) { dest[i] = src[i]; } } } + /// + /// Copies alpha values when a backward reference is used. + /// Copy 'length' number of alpha values from the sequence of alpha values prior to them by 'dist'. + /// + /// The alpha values. + /// The position of the so far decoded pixels. + /// The backward reference distance prior to the current decoded pixel. + /// The number of pixels to copy. private static void CopyBlock8B(Span data, int pos, int dist, int length) { - if (dist >= length) + if (dist >= length) // no overlap. { data.Slice(pos - dist, length).CopyTo(data.Slice(pos)); } diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs index ac5981600..1c524b83b 100644 --- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs @@ -699,15 +699,17 @@ namespace SixLabors.ImageSharp.Formats.WebP } // Loop over each output pairs of row. + var bufferStride2 = 2 * bufferStride; + var ioStride2 = 2 * io.YStride; for (; y + 2 < yEnd; y += 2) { topU = curU; topV = curV; curU = curU.Slice(io.UvStride); curV = curV.Slice(io.UvStride); - this.UpSample(curY.Slice(io.YStride), curY.Slice(2 * io.YStride), topU, topV, curU, curV, dst.Slice(bufferStride), dst.Slice(2 * bufferStride), mbw); - curY = curY.Slice(2 * io.YStride); - dst = dst.Slice(2 * bufferStride); + this.UpSample(curY.Slice(io.YStride), curY.Slice(ioStride2), topU, topV, curU, curV, dst.Slice(bufferStride), dst.Slice(bufferStride2), mbw); + curY = curY.Slice(ioStride2); + dst = dst.Slice(bufferStride2); } // Move to last row. diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs index 0bd0c4e8d..b6631727d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs @@ -15,6 +15,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public class DecodeWebp : BenchmarkBase { private byte[] webpLossyBytes; + private byte[] webpLosslessBytes; private string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImageLossy); @@ -30,59 +31,40 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs [GlobalSetup] public void ReadImages() { - if (this.webpLossyBytes is null) - { - this.webpLossyBytes = File.ReadAllBytes(this.TestImageLossyFullPath); - } - - if (this.webpLosslessBytes is null) - { - this.webpLosslessBytes = File.ReadAllBytes(this.TestImageLosslessFullPath); - } + this.webpLossyBytes ??= File.ReadAllBytes(this.TestImageLossyFullPath); + this.webpLosslessBytes ??= File.ReadAllBytes(this.TestImageLosslessFullPath); } [Benchmark(Description = "Magick Lossy WebP")] public int WebpLossyMagick() { var settings = new MagickReadSettings { Format = MagickFormat.WebP }; - using (var image = new MagickImage(new MemoryStream(this.webpLossyBytes), settings)) - { - return image.Width; - } + using var image = new MagickImage(new MemoryStream(this.webpLossyBytes), settings); + return image.Width; } [Benchmark(Description = "ImageSharp Lossy Webp")] public int WebpLossy() { - using (var memoryStream = new MemoryStream(this.webpLossyBytes)) - { - using (var image = Image.Load(memoryStream)) - { - return image.Height; - } - } + using var memoryStream = new MemoryStream(this.webpLossyBytes); + using var image = Image.Load(memoryStream); + return image.Height; } [Benchmark(Description = "Magick Lossless WebP")] public int WebpLosslessMagick() { var settings = new MagickReadSettings { Format = MagickFormat.WebP }; - using (var image = new MagickImage(new MemoryStream(this.webpLosslessBytes), settings)) - { - return image.Width; - } + using var image = new MagickImage(new MemoryStream(this.webpLosslessBytes), settings); + return image.Width; } [Benchmark(Description = "ImageSharp Lossless Webp")] public int WebpLossless() { - using (var memoryStream = new MemoryStream(this.webpLosslessBytes)) - { - using (var image = Image.Load(memoryStream)) - { - return image.Height; - } - } + using var memoryStream = new MemoryStream(this.webpLosslessBytes); + using var image = Image.Load(memoryStream); + return image.Height; } /* Results 18.03.2020