From 308e02eb2f5940e9c5bbef9c68a62318e654f1a2 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 8 Dec 2018 13:04:39 +1030 Subject: [PATCH 01/15] Adds more to the AoT compiler. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 9e7624480d..9f20704cf7 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -15,6 +18,20 @@ namespace SixLabors.ImageSharp.Advanced /// public static class AotCompilerTools { + /// + /// Seeds the calls. + /// + public static void SeedUnsafe() + { + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + } + /// /// Seeds the compiler using the given pixel format. /// @@ -27,6 +44,13 @@ namespace SixLabors.ImageSharp.Advanced AotCompileWuQuantizer(); AotCompileDithering(); + System.Runtime.CompilerServices.Unsafe.SizeOf(); + + AotDecoder(new Formats.Png.PngDecoder()); + AotDecoder(new Formats.Bmp.BmpDecoder()); + AotDecoder(new Formats.Gif.GifDecoder()); + AotDecoder(new Formats.Jpeg.JpegDecoder()); + // TODO: Do the discovery work to figure out what works and what doesn't. } @@ -99,5 +123,22 @@ namespace SixLabors.ImageSharp.Advanced TPixel pixel = default; test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); } + + /// + /// This method pre-seeds the decoder for a given pixel format in the AoT compiler for iOS. + /// + /// The image decoder to seed.. + /// The pixel format. + private static void AotDecoder(IImageDecoder decoder) + where TPixel : struct, IPixel + { + try + { + decoder.Decode(Configuration.Default, null); + } + catch + { + } + } } } \ No newline at end of file From 1b2e794c5b08d16c9b94a844352f389763321e06 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 13 Dec 2018 10:32:12 +1100 Subject: [PATCH 02/15] Use correct Kernel dimensions and optimize. Fix #786 --- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 33 +++++-- .../Convolution/BoxBlurProcessor.cs | 18 ++-- .../Convolution/GaussianBlurProcessor.cs | 51 +++-------- .../Convolution/GaussianSharpenProcessor.cs | 86 +++++-------------- .../Primitives/DenseMatrixTests.cs | 24 ++++++ 5 files changed, 89 insertions(+), 123 deletions(-) diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 7cfa98ec1b..170292e29e 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.Primitives /// The at the specified position. public ref T this[int row, int column] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get { this.CheckCoordinates(row, column); @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// The representation on the source data. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator DenseMatrix(T[,] data) => new DenseMatrix(data); /// @@ -135,9 +135,9 @@ namespace SixLabors.ImageSharp.Primitives /// /// The representation on the source data. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] #pragma warning disable SA1008 // Opening parenthesis should be spaced correctly - public static implicit operator T[,] (DenseMatrix data) + public static implicit operator T[,] (in DenseMatrix data) #pragma warning restore SA1008 // Opening parenthesis should be spaced correctly { var result = new T[data.Rows, data.Columns]; @@ -154,17 +154,38 @@ namespace SixLabors.ImageSharp.Primitives return result; } + /// + /// Transposes the rows and columns of the dense matrix. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public DenseMatrix Transpose() + { + var result = new DenseMatrix(this.Rows, this.Columns); + + for (int y = 0; y < this.Rows; y++) + { + for (int x = 0; x < this.Columns; x++) + { + ref T value = ref result[x, y]; + value = this[y, x]; + } + } + + return result; + } + /// /// Fills the matrix with the given value /// /// The value to fill each item with - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Fill(T value) => this.Span.Fill(value); /// /// Clears the matrix setting each value to the default value for the element type /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Clear() => this.Span.Clear(); /// diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 38dc638b90..644d6c9e17 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -29,8 +29,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { this.Radius = radius; this.kernelSize = (radius * 2) + 1; - this.KernelX = this.CreateBoxKernel(true); - this.KernelY = this.CreateBoxKernel(false); + this.KernelX = this.CreateBoxKernel(); + this.KernelY = this.KernelX.Transpose(); } /// @@ -49,24 +49,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public DenseMatrix KernelY { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); - } + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) => new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); /// /// Create a 1 dimensional Box kernel. /// - /// Whether to calculate a horizontal kernel. /// The - private DenseMatrix CreateBoxKernel(bool horizontal) + private DenseMatrix CreateBoxKernel() { int size = this.kernelSize; - DenseMatrix kernel = horizontal - ? new DenseMatrix(size, 1) - : new DenseMatrix(1, size); + var kernel = new DenseMatrix(size, 1); - kernel.Fill(1.0F / size); + kernel.Fill(1F / size); return kernel; } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index 3045b9993f..b3bc15d391 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution @@ -26,11 +25,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// The 'sigma' value representing the weight of the blur. public GaussianBlurProcessor(float sigma = 3F) + : this(sigma, (int)MathF.Ceiling(sigma * 3)) { - this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; - this.Sigma = sigma; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); + // Kernel radius is calculated using the minimum viable value. + // http://chemaguerra.com/gaussian-filter-radius/ } /// @@ -40,11 +38,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The 'radius' value representing the size of the area to sample. /// public GaussianBlurProcessor(int radius) + : this(radius / 3F, radius) { - this.kernelSize = (radius * 2) + 1; - this.Sigma = radius; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); } /// @@ -61,8 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { this.kernelSize = (radius * 2) + 1; this.Sigma = sigma; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); + this.KernelX = this.CreateGaussianKernel(); + this.KernelY = this.KernelX.Transpose(); } /// @@ -82,22 +77,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); - } + => new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); /// /// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function /// - /// Whether to calculate a horizontal kernel. /// The - private DenseMatrix CreateGaussianKernel(bool horizontal) + private DenseMatrix CreateGaussianKernel() { int size = this.kernelSize; float weight = this.Sigma; - DenseMatrix kernel = horizontal - ? new DenseMatrix(size, 1) - : new DenseMatrix(1, size); + var kernel = new DenseMatrix(size, 1); float sum = 0F; float midpoint = (size - 1) / 2F; @@ -107,30 +97,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution float x = i - midpoint; float gx = ImageMaths.Gaussian(x, weight); sum += gx; - if (horizontal) - { - kernel[0, i] = gx; - } - else - { - kernel[i, 0] = gx; - } + kernel[0, i] = gx; } // Normalize kernel so that the sum of all weights equals 1 - if (horizontal) - { - for (int i = 0; i < size; i++) - { - kernel[0, i] = kernel[0, i] / sum; - } - } - else + for (int i = 0; i < size; i++) { - for (int i = 0; i < size; i++) - { - kernel[i, 0] = kernel[i, 0] / sum; - } + kernel[0, i] /= sum; } return kernel; diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 18963c73c0..786bf7757a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -27,11 +27,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The 'sigma' value representing the weight of the sharpening. /// public GaussianSharpenProcessor(float sigma = 3F) + : this(sigma, (int)MathF.Ceiling(sigma * 3)) { - this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; - this.Sigma = sigma; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); + // Kernel radius is calculated using the minimum viable value. + // http://chemaguerra.com/gaussian-filter-radius/ } /// @@ -41,11 +40,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The 'radius' value representing the size of the area to sample. /// public GaussianSharpenProcessor(int radius) + : this(radius / 3F, radius) { - this.kernelSize = (radius * 2) + 1; - this.Sigma = radius; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); } /// @@ -62,8 +58,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { this.kernelSize = (radius * 2) + 1; this.Sigma = sigma; - this.KernelX = this.CreateGaussianKernel(true); - this.KernelY = this.CreateGaussianKernel(false); + this.KernelX = this.CreateGaussianKernel(); + this.KernelY = this.KernelX.Transpose(); } /// @@ -83,91 +79,49 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); - } + => new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); /// /// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function /// - /// Whether to calculate a horizontal kernel. /// The - private DenseMatrix CreateGaussianKernel(bool horizontal) + private DenseMatrix CreateGaussianKernel() { int size = this.kernelSize; float weight = this.Sigma; - DenseMatrix kernel = horizontal - ? new DenseMatrix(size, 1) - : new DenseMatrix(1, size); + var kernel = new DenseMatrix(size, 1); float sum = 0; - float midpoint = (size - 1) / 2f; + float midpoint = (size - 1) / 2F; for (int i = 0; i < size; i++) { float x = i - midpoint; float gx = ImageMaths.Gaussian(x, weight); sum += gx; - if (horizontal) - { - kernel[0, i] = gx; - } - else - { - kernel[i, 0] = gx; - } + kernel[0, i] = gx; } // Invert the kernel for sharpening. int midpointRounded = (int)midpoint; - - if (horizontal) + for (int i = 0; i < size; i++) { - for (int i = 0; i < size; i++) + if (i == midpointRounded) { - if (i == midpointRounded) - { - // Calculate central value - kernel[0, i] = (2F * sum) - kernel[0, i]; - } - else - { - // invert value - kernel[0, i] = -kernel[0, i]; - } + // Calculate central value + kernel[0, i] = (2F * sum) - kernel[0, i]; } - } - else - { - for (int i = 0; i < size; i++) + else { - if (i == midpointRounded) - { - // Calculate central value - kernel[i, 0] = (2 * sum) - kernel[i, 0]; - } - else - { - // invert value - kernel[i, 0] = -kernel[i, 0]; - } + // invert value + kernel[0, i] = -kernel[0, i]; } } // Normalize kernel so that the sum of all weights equals 1 - if (horizontal) - { - for (int i = 0; i < size; i++) - { - kernel[0, i] /= sum; - } - } - else + for (int i = 0; i < size; i++) { - for (int i = 0; i < size; i++) - { - kernel[i, 0] /= sum; - } + kernel[0, i] /= sum; } return kernel; diff --git a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs index fa4862293f..0af8ae45f9 100644 --- a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs +++ b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs @@ -106,5 +106,29 @@ namespace SixLabors.ImageSharp.Tests.Primitives Assert.Equal(0, dense.Data[i]); } } + + [Fact] + public void DenseMatrixCorrectlyCasts() + { + float[,] actual = new DenseMatrix(FloydSteinbergMatrix); + Assert.Equal(FloydSteinbergMatrix, actual); + } + + [Fact] + public void DenseMatrixCanTranspose() + { + var dense = new DenseMatrix(3, 1); + dense[0, 0] = 1; + dense[0, 1] = 2; + dense[0, 2] = 3; + + DenseMatrix transposed = dense.Transpose(); + + Assert.Equal(dense.Columns, transposed.Rows); + Assert.Equal(dense.Rows, transposed.Columns); + Assert.Equal(1, transposed[0, 0]); + Assert.Equal(2, transposed[1, 0]); + Assert.Equal(3, transposed[2, 0]); + } } } \ No newline at end of file From 83d52d5f79f0f14b57e90346bd40de9012b3b1bc Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Thu, 13 Dec 2018 18:42:16 +1030 Subject: [PATCH 03/15] Seed unsafe calls from the static constructor. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 9f20704cf7..c9c0e40146 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -18,10 +18,7 @@ namespace SixLabors.ImageSharp.Advanced /// public static class AotCompilerTools { - /// - /// Seeds the calls. - /// - public static void SeedUnsafe() + static AotCompilerTools() { System.Runtime.CompilerServices.Unsafe.SizeOf(); System.Runtime.CompilerServices.Unsafe.SizeOf(); From 520d181b0dcbb11a5b8226c4d38e1438178599a7 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Fri, 14 Dec 2018 20:16:20 +1030 Subject: [PATCH 04/15] AoT seed image encoders as well as decoders --- src/ImageSharp/Advanced/AotCompilerTools.cs | 22 ++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index c9c0e40146..db46ab4ad3 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -43,10 +43,10 @@ namespace SixLabors.ImageSharp.Advanced System.Runtime.CompilerServices.Unsafe.SizeOf(); - AotDecoder(new Formats.Png.PngDecoder()); - AotDecoder(new Formats.Bmp.BmpDecoder()); - AotDecoder(new Formats.Gif.GifDecoder()); - AotDecoder(new Formats.Jpeg.JpegDecoder()); + AotCodec(new Formats.Png.PngDecoder(), new Formats.Png.PngEncoder()); + AotCodec(new Formats.Bmp.BmpDecoder(), new Formats.Bmp.BmpEncoder()); + AotCodec(new Formats.Gif.GifDecoder(), new Formats.Gif.GifEncoder()); + AotCodec(new Formats.Jpeg.JpegDecoder(), new Formats.Jpeg.JpegEncoder()); // TODO: Do the discovery work to figure out what works and what doesn't. } @@ -122,11 +122,12 @@ namespace SixLabors.ImageSharp.Advanced } /// - /// This method pre-seeds the decoder for a given pixel format in the AoT compiler for iOS. + /// This method pre-seeds the decoder and encoder for a given pixel format in the AoT compiler for iOS. /// - /// The image decoder to seed.. + /// The image decoder to seed. + /// The image encoder to seed. /// The pixel format. - private static void AotDecoder(IImageDecoder decoder) + private static void AotCodec(IImageDecoder decoder, IImageEncoder encoder) where TPixel : struct, IPixel { try @@ -136,6 +137,13 @@ namespace SixLabors.ImageSharp.Advanced catch { } + try + { + encoder.Encode(null, null); + } + catch + { + } } } } \ No newline at end of file From 50c3d7fd7a41a018a6ea856b2a8c95e285b18284 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Fri, 14 Dec 2018 20:38:18 +1030 Subject: [PATCH 05/15] Code sanity --- src/ImageSharp/Advanced/AotCompilerTools.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index db46ab4ad3..eb6991e6a1 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -137,6 +137,7 @@ namespace SixLabors.ImageSharp.Advanced catch { } + try { encoder.Encode(null, null); From eb7d60b681b2c5ad49de2066e6bc4a9c440458bc Mon Sep 17 00:00:00 2001 From: popow Date: Sat, 15 Dec 2018 16:18:55 +0100 Subject: [PATCH 06/15] added parsing of the OS22XBITMAPHEADER short variant (16 bytes) --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 5 ++++ src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 24 +++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index ef3ca24ee8..f6eb78ea9d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -510,6 +510,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp // 12 bytes this.infoHeader = BmpInfoHeader.ParseCore(buffer); } + else if (headerSize == BmpInfoHeader.Os2Short) + { + // 16 bytes + this.infoHeader = BmpInfoHeader.ParseOs2Short(buffer); + } else if (headerSize >= BmpInfoHeader.Size) { // >= 40 bytes diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index 4dd63a9626..a32f806a94 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public const int CoreSize = 12; + /// + /// Defines the size of the short variant of the OS22XBITMAPHEADER data structure in the bitmap file. + /// + public const int Os2Short = 16; + /// /// Defines the size of the biggest supported header data structure in the bitmap file. /// @@ -143,7 +148,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Parses the BITMAPCOREHEADER consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes). /// - /// The data to parse, + /// The data to parse. /// Parsed header /// public static BmpInfoHeader ParseCore(ReadOnlySpan data) @@ -156,6 +161,23 @@ namespace SixLabors.ImageSharp.Formats.Bmp bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2))); } + /// + /// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height + /// are 4 bytes instead of 2. + /// + /// The data to parse. + /// Parsed header + /// + public static BmpInfoHeader ParseOs2Short(ReadOnlySpan data) + { + return new BmpInfoHeader( + headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), + width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), + height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), + planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), + bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2))); + } + public unsafe void WriteTo(Span buffer) { ref BmpInfoHeader dest = ref Unsafe.As(ref MemoryMarshal.GetReference(buffer)); From c25c34b4768a15f32f2c8c92b9b276d4f61df5ef Mon Sep 17 00:00:00 2001 From: popow Date: Sat, 15 Dec 2018 17:20:48 +0100 Subject: [PATCH 07/15] added unit test for decoding OS2 bitmap with 16 bytes header --- .../Formats/Bmp/BmpDecoderTests.cs | 30 +++++++++++++----- tests/Images/Input/Bmp/pal8os2v2-16.bmp | Bin 0 -> 9246 bytes 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 tests/Images/Input/Bmp/pal8os2v2-16.bmp diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 5f2de9f51e..dc858f9500 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -88,19 +88,33 @@ namespace SixLabors.ImageSharp.Tests } } - [Theory] - [MemberData(nameof(RatioFiles))] - public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) + [Fact] + public void DecodeOs22XShortHeader_VeryfyDimensions() { + string imagePath = @"Bmp/pal8os2v2-16.bmp"; var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { var decoder = new BmpDecoder(); - IImageInfo image = decoder.Identify(Configuration.Default, stream); - ImageMetaData meta = image.MetaData; - Assert.Equal(xResolution, meta.HorizontalResolution); - Assert.Equal(yResolution, meta.VerticalResolution); - Assert.Equal(resolutionUnit, meta.ResolutionUnits); + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + Assert.Equal(127, image.Width); + Assert.Equal(64, image.Height); + } + } + } + + [Fact] + public void IdentifyOs22XShortHeader_VeryfyDimensions() + { + string imagePath = @"Bmp/pal8os2v2-16.bmp"; + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.Equal(127, imageInfo.Width); + Assert.Equal(64, imageInfo.Height); + Assert.Equal(8, imageInfo.PixelType.BitsPerPixel); } } } diff --git a/tests/Images/Input/Bmp/pal8os2v2-16.bmp b/tests/Images/Input/Bmp/pal8os2v2-16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..95a1d2345aa1dd29cd03b29d0ea50879e24be9e3 GIT binary patch literal 9246 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 z zs~Ja*;NRX)1BMtW8i4-?@dx0T%uf8J{W5u-xw5n}Ha7Od*f`_vUHm7fXh4#oub-Qn zGs!D^p65PF{>9w?)!hF_xc}R^|NEgIN+p+5Y!ILrP!#_sKZH=seM>#tla5hIA*DT3Hc)@@L!=f9U}J(@A~3 z_=|DAm1IAeu(r_tg8;Mua1Mas_M!fN4GDcJwF&^$%TDa0`6oF4odnQH^KWqeQ?x&| zvNTWop8>D{z)JuYCzDgZC8c|EJ^qrvWG}g|EjcA>SvmP@f1N)8Wcbs8HGew5puF*D`QhW|_Q7k@gCT9)gz zzs@~h2gDzM>Vw?>EzRd>e}Dh*&@k;!3BZTdwezp@m-ed;$N@0<12F!K`+woyOWHp* zwU}I_{V4&MTQ%O=e*LEjBAx%yP4gFfrt!yK`9HxQyVR=5|JRS_FXlS=+@IE#EyY_t z!~bB*k(QQo&F9Wt>mME_fLQ{V6@L}L2?fx3k$Llm1R(7PVP$oGer*01{GTn{U08T| z@8!!^Q;UlPuuK5U_`5h~El^y&_?Ed@{+$1;{L}uFU-MTT*d%|>e@6b(%AW6)#y;Z_ z|1F(`QMf_XP$Nyi$=rc0?FMhSI|Kz6l(*fmA{)`3jUqB!K-xkql@cL%iCn?UNKJ5pf z1pvyo44)gmM)_e?9st#T0-(GCxOwsBP0A|(2|%?UfCT_3zp(gn@fGD4Re1m;d%gHx JfN{>U{tG?^9{2zN literal 0 HcmV?d00001 From 10af2ed98c206271457a40d0999c3a6a51c30655 Mon Sep 17 00:00:00 2001 From: popow Date: Sun, 16 Dec 2018 19:06:08 +0100 Subject: [PATCH 08/15] fix for Windows 2.0 or OS/2 1.x bitmaps only use 3 bytes per color palette entry --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 29 ++++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index ef3ca24ee8..b11f7934d2 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { try { - this.ReadImageHeaders(stream, out bool inverted, out byte[] palette); + int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette); var image = new Image(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metaData); @@ -137,6 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.infoHeader.Width, this.infoHeader.Height, this.infoHeader.BitsPerPixel, + bytesPerColorMapEntry, inverted); } @@ -329,18 +330,20 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The containing the colors. /// The width of the bitmap. /// The height of the bitmap. - /// The number of bits per pixel. + /// The number of bits per pixel. + /// Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps + /// the bytes per color palette entry's can be 3 bytes instead of 4. /// Whether the bitmap is inverted. - private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int width, int height, int bits, bool inverted) + private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted) where TPixel : struct, IPixel { // Pixels per byte (bits per pixel) - int ppb = 8 / bits; + int ppb = 8 / bitsPerPixel; int arrayWidth = (width + ppb - 1) / ppb; // Bit mask - int mask = 0xFF >> (8 - bits); + int mask = 0xFF >> (8 - bitsPerPixel); // Rows are aligned on 4 byte boundaries int padding = arrayWidth % 4; @@ -366,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp int colOffset = x * ppb; for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++) { - int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; + int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; color.FromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; @@ -571,7 +574,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Reads the and from the stream and sets the corresponding fields. /// - private void ReadImageHeaders(Stream stream, out bool inverted, out byte[] palette) + /// Bytes per color palette entry. Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps + /// the bytes per color palette entry's can be 3 bytes instead of 4. + private int ReadImageHeaders(Stream stream, out bool inverted, out byte[] palette) { this.stream = stream; @@ -591,6 +596,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp } int colorMapSize = -1; + int bytesPerColorMapEntry = 4; if (this.infoHeader.ClrUsed == 0) { @@ -598,12 +604,15 @@ namespace SixLabors.ImageSharp.Formats.Bmp || this.infoHeader.BitsPerPixel == 4 || this.infoHeader.BitsPerPixel == 8) { - colorMapSize = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel) * 4; + int colorMapSizeBytes = this.fileHeader.Offset - BmpFileHeader.Size - this.infoHeader.HeaderSize; + int colorCountForBitDepth = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel); + bytesPerColorMapEntry = colorMapSizeBytes / colorCountForBitDepth; + colorMapSize = colorMapSizeBytes; } } else { - colorMapSize = this.infoHeader.ClrUsed * 4; + colorMapSize = this.infoHeader.ClrUsed * bytesPerColorMapEntry; } palette = null; @@ -622,6 +631,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp } this.infoHeader.VerifyDimensions(); + + return bytesPerColorMapEntry; } } } \ No newline at end of file From 377a2e50a2e8c1afb0c53f4cdfe1ac4aa9f18648 Mon Sep 17 00:00:00 2001 From: popow Date: Sun, 16 Dec 2018 21:36:29 +0100 Subject: [PATCH 09/15] Os2Short -> Os22ShortSize --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++-- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index f6eb78ea9d..2226a1ec98 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -510,10 +510,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp // 12 bytes this.infoHeader = BmpInfoHeader.ParseCore(buffer); } - else if (headerSize == BmpInfoHeader.Os2Short) + else if (headerSize == BmpInfoHeader.Os22ShortSize) { // 16 bytes - this.infoHeader = BmpInfoHeader.ParseOs2Short(buffer); + this.infoHeader = BmpInfoHeader.ParseOs22Short(buffer); } else if (headerSize >= BmpInfoHeader.Size) { diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index a32f806a94..5177bc325c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Defines the size of the short variant of the OS22XBITMAPHEADER data structure in the bitmap file. /// - public const int Os2Short = 16; + public const int Os22ShortSize = 16; /// /// Defines the size of the biggest supported header data structure in the bitmap file. @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The data to parse. /// Parsed header /// - public static BmpInfoHeader ParseOs2Short(ReadOnlySpan data) + public static BmpInfoHeader ParseOs22Short(ReadOnlySpan data) { return new BmpInfoHeader( headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), From 0e41c13d3ccef2792db6fad809375f0a2d845f20 Mon Sep 17 00:00:00 2001 From: popow Date: Tue, 18 Dec 2018 19:34:28 +0100 Subject: [PATCH 10/15] added Test for decoding windows BMPv2 and one for a bitmap which has 4 bytes per color palette --- .../Formats/Bmp/BmpDecoderTests.cs | 24 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 +++ tests/Images/Input/Bmp/pal8-0.bmp | Bin 0 -> 9270 bytes tests/Images/Input/Bmp/pal8os2v1_winv2.bmp | Bin 0 -> 8986 bytes 4 files changed, 27 insertions(+) create mode 100644 tests/Images/Input/Bmp/pal8-0.bmp create mode 100644 tests/Images/Input/Bmp/pal8os2v1_winv2.bmp diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 5f2de9f51e..d60d9d918a 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -55,6 +55,30 @@ namespace SixLabors.ImageSharp.Tests } } + [Theory] + [WithFile(WinBmpv2, PixelTypes.Rgba32)] + public void BmpDecoder_CanDecodeBmpv2(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new BmpDecoder())) + { + image.DebugSave(provider, "png"); + image.CompareToOriginal(provider); + } + } + + [Theory] + [WithFile(Bit8Palette4, PixelTypes.Rgba32)] + public void BmpDecoder_CanDecode4BytePerEntryPalette(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new BmpDecoder())) + { + image.DebugSave(provider, "png"); + image.CompareToOriginal(provider); + } + } + [Theory] [InlineData(Car, 24)] [InlineData(F, 24)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1144a3f7c0..9c747dcb8a 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -201,6 +201,9 @@ namespace SixLabors.ImageSharp.Tests public const string Bit16 = "Bmp/test16.bmp"; public const string Bit16Inverted = "Bmp/test16-inverted.bmp"; public const string Bit32Rgb = "Bmp/rgb32.bmp"; + // Note: This format can be called OS/2 BMPv1, or Windows BMPv2 + public const string WinBmpv2 = "Bmp/pal8os2v1_winv2.bmp"; + public const string Bit8Palette4 = "Bmp/pal8-0.bmp"; public static readonly string[] All = { diff --git a/tests/Images/Input/Bmp/pal8-0.bmp b/tests/Images/Input/Bmp/pal8-0.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ab8815a360d315ed119604c5a60feb81bfa65625 GIT binary patch literal 9270 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 IIA>Y^1(tjtKmY&$ literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Bmp/pal8os2v1_winv2.bmp b/tests/Images/Input/Bmp/pal8os2v1_winv2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..14901b3882cea0679832e4f45a49f6b10034d3ce GIT binary patch literal 8986 zcmbuDPiU0a-p5Z&O!`M%h=N>;i{5UU**H0BMoZ(%D=7#mU6|>jW??3JGKrvFNG=r2 zJB3OXH-gSYlanmWyAZ=rt{_xgB+@#$RmW$c!qB=X6$HgaZti{YPpgabetzdXNhbfi zeR+R}XP%ko$$5U?&-Z)IIQXBR{^`%k*Pm*YTF1NpQvac9)LY@AR>~-4m5P*dDxp+D ztAtSrs}hk)IF(i^tyS8nv{mUyrJc$tmD4I`RL-hgq;gIbl`3jgG^%J-F;YdRDoRzf zsu)$VsuHP+wA0!d?W}f@ zcIW_G8)b~LMn%Xn31t%6B#cQ|lZZ^hnY1!#ZPLc1tw~2F?MzOYoHjXQa@OP`lXIr1 zOi`PnF-2>NktsS;QKq6z#h8jUmB>__amqMtoH5QC7a4~IIIgWSR#~ee9I**y6WS(> zO<0?VY{J>JvT1G8#-^=JM>g$jPT8EcIb(Cy<|3POwy11T+oG{WYm1RBI$Ke;qHV?4 zinW!%BBV{6GBNY)wlu%JZM+p-pY?O$igp1NDO6w?XqO^_D zQIvL3PDME#8&pI6 z`i2b+8`f{yK>JNwH@~;_eFXgZ{SOh4ZO&%0opVP%lkZ$~c)WVyKP3F(0Q}#d_xOwW zrM;BkOM9unuj++=gYb(3@V~d!QR`4 zzXSdb+7BS$3IeXs{ucx^`uPnFDFn12pcVd4;BUkJ1HvEE=Q)RCkpseCoqymD`4hmh z`~yD@2z|_7oqymD`4hk!@*l*3!3_LK_>=H=!hhDBHN)`VJb&~1f5HC}e(tLz{0!(B z@H3!i!0+e7pMrnyroEe5;cwg8_TH!P9}xa{K%XJ|#X})L`TRRW{%6j{`AY!8?*m}{ z6Ts&L@bv)s6Tr7V0M=h4^CkaO$ba+RIDZL1__JhPedPHZjzP|}Z>Zw$CV%0_fgf+i z{N90>-#ZZVdk5g(F7spl7V;N<9C*LY^A|jIHWSWy&cT8BEc^)Ap4{HNtMgDd_Mbg7 ze0~`Fy?_@lRee1IlF39e+3|Tt2lfvPd_6F5<=ZP)5b(<{@FSoh+0eW`wV?(3_ik?8 z+KT;Nz=sEx(9b!MCwn>K{G0!u`8WTY{FkI2d%#syQ=@7c;7@k$>g?=3)ZGpLFag|z z|K`gVFTt;`hdkD^ejE_`z~8vNG0cab+Pk-vYQum} z+YTHM{>5Wa6od3n)`)$b$TTyNA#IFnkjMv`4@?p|5XFW*8kEr)5BYZQ$A! z=&wA&|74@YmrACZTT**l_O`U{{iL-G0klWJsw+S21mP!ts#Ewo!H55cVeqMH{y2Y$ ze{uee3kU>Be0VD9=K)@~9|K|C{ zfxw^X$asF};TH!U{nC#82N94#Ko$YV;r|i=eY8J`fH!0>4lK?8Y*qe&e_cHSk}~Gn zpB^~v+autYM~&cD!5E&UD zgeL_*<5&Ek$sGT+Yfpv0J>)O9eE#x=1=xoGpMN%9|4Yw#t`8RIzvitqO;joczi7;l zP`7TZ(BDHY<8S|>{oouw>reV0Ki-D{@SmK^f2Hij0QxtrX?iQwlxfPO_8?d&zzNfL!t~*#A`USIM6M$lsGMI51Bh9DrZLui@{4AEj9f|Lr;cCF>vi z=lOm9O0}P=;*X^*nxz6gPxelPGuAU?{nxSqH2HUtKLK!gWTZ5ofAy0j{Ve!%{MWBP zmD?C_DmcQw?BPxIEO|elyR3ml4#59*6@L%;3qKCXla>_i#i4lplYi(|#h+hc7OKTH z;T8v2gmL!bfbb)rNjL3Ib!B?wPx5xej@iqg&DSsd&w}nw9V@lQ5uBm++e%+Po>gvh#^uTWkAl`qAlAK!r zq4Dxp`90^qqZZBbS72Y!fmQOKU;n>t*|=rnzK#1nJ~p@i=K1||pZ3QcMH~OTgipuE z+5hA0|4S#4;$>U-Eh6G0&pBTr|JvHxw`(=EdpG=4pO(?EjuZk1eqJ zZS4Q=p5F5x3(ub8mxkA8pZ52M#U~&6r4#<<_&5S+-*@R!d`0MG1<+E+Wk8>o{4qfI zyM(_BeE3UtF8|-Rz`q6heY6j3fnWMf&kBEVAn*@{zZtdQQ}D;Lcx-;9L)Bsb4g?%V zKraGD;h#o8IXr3kN{abCJ^T~>-}GOWzvaRtzvsNhm1Zr^ex>{gU{U^yp5&XbI6{-@ z>FL>7;r}L%U?KnIvsR|(tE8@W2mE{BKMem+&rr`O{N=#EcwdsCYU{{<2l*c+e*)+kf}a3Z`u>&n$2>pTO9}r3 z23$VHB4qtf`utaDzhd^X9^iim{v9!YFZs{&%OjW8u?q;`qAk<@IRYm7{|5i%Q&+h- zIXJoW@5AT3{Hx**??IsV4hTO2^bWme_u;PIo?iG_y|&E$UtY&3&u=|_%#VOmmroJF z;3VsBdBM4A#reQ@8^3o6Y8fkK@AI##tF3zn{vC&RA3ogM)jI_L=(L?Kmv5KLuYP~EW!si5wBJYj zW5-T_e*pu^@cRJpf1-clZ}4Bf`q!&h31DifP%8QPI%K@bScaiej#4zC~>`1 zP;0S&CjyQj;3xvddPj%;J}TSm{{#V?!2AoW|1$QMpU>XM{s#zn zh=9ikn3*h1{i7uA$$a=Ff5~2QpFd=k_(LtpKk$eA380D}2j=;4fTF$Uug*X4hx`e^ z^V538fgIuA3I9&`kHCMf_gwE7{C7t0K=-=*8h+>r0Dc5Of5O|30NNwq{=@_LAHe?* z{wI@9CTHM(R(clZ3xA-;Y;nMkg|qN4%75tJ;MME-^&j#V`@I9Q0OI@+aQOlI|KZig*grKjQ<}m4 zvIw~MI_3`a3$JkybNPR?YW_mci20%S{CDApuKYUA|JOI?FXSQlrLSu3+Pbyx!oTy# zo+C$&9zJ^X+|bw<0o);gJHqb+*zX0L_=<7yf&?J;BjNe$`}ZgA{|x_whu=MX`1tDM z$4{naW(eRJ0X&1>!o27}iVX+9GFQu=^}i_pIeyyD^LqzY$)ELKmH)J-=XYgHUv-9m z?YnDtQXhQ;KXvZh7H4f$;$p;8}I**;{AUv-v4)G|Nnvf@5lT9*LeRwiTD4ru>M!gUfd9V z@~4gn{}J%v|N9vDR5kxspDp0uy(s)R;Q7g)dMNx4!H54JGvHI)UoHC*%{l0g{RlXM z0NNiJJ34lb_G7+10=)eMKzlFX;#U_h(%uV@0KEMOc!&VnKb(0y^Mv*@zC8jY`*85P J0OBQw`d{xg9_j!9 literal 0 HcmV?d00001 From 0f5df545be7d314f25fb6cb3d96bbf4c382ed053 Mon Sep 17 00:00:00 2001 From: popow Date: Tue, 18 Dec 2018 20:29:21 +0100 Subject: [PATCH 11/15] updated unit test to be in line with the other tests --- .../Formats/Bmp/BmpDecoderTests.cs | 33 +++++-------------- tests/ImageSharp.Tests/TestImages.cs | 1 + 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index dc858f9500..2d6a5474d6 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -11,6 +11,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests { using SixLabors.ImageSharp.MetaData; + using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using static TestImages.Bmp; public class BmpDecoderTests @@ -88,33 +89,15 @@ namespace SixLabors.ImageSharp.Tests } } - [Fact] - public void DecodeOs22XShortHeader_VeryfyDimensions() - { - string imagePath = @"Bmp/pal8os2v2-16.bmp"; - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - var decoder = new BmpDecoder(); - using (Image image = decoder.Decode(Configuration.Default, stream)) - { - Assert.Equal(127, image.Width); - Assert.Equal(64, image.Height); - } - } - } - - [Fact] - public void IdentifyOs22XShortHeader_VeryfyDimensions() + [Theory] + [WithFile(Os2v2Short, PixelTypes.Rgba32)] + public void BmpDecoder_CanDecode_Os2v2XShortHeader(TestImageProvider provider) + where TPixel : struct, IPixel { - string imagePath = @"Bmp/pal8os2v2-16.bmp"; - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) + using (Image image = provider.GetImage(new BmpDecoder())) { - IImageInfo imageInfo = Image.Identify(stream); - Assert.Equal(127, imageInfo.Width); - Assert.Equal(64, imageInfo.Height); - Assert.Equal(8, imageInfo.PixelType.BitsPerPixel); + image.DebugSave(provider, "png"); + image.CompareToOriginal(provider); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1144a3f7c0..8e226d337d 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -201,6 +201,7 @@ namespace SixLabors.ImageSharp.Tests public const string Bit16 = "Bmp/test16.bmp"; public const string Bit16Inverted = "Bmp/test16-inverted.bmp"; public const string Bit32Rgb = "Bmp/rgb32.bmp"; + public const string Os2v2Short = "Bmp/pal8os2v2-16.bmp"; public static readonly string[] All = { From 7e55d2277f405d8243c881187b411e5833fb88de Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Dec 2018 20:30:07 +1100 Subject: [PATCH 12/15] Disable comparison since the reference decoders cannpt decode the image. --- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 2d6a5474d6..98c3c194df 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -11,7 +11,6 @@ using Xunit; namespace SixLabors.ImageSharp.Tests { using SixLabors.ImageSharp.MetaData; - using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using static TestImages.Bmp; public class BmpDecoderTests @@ -97,7 +96,10 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage(new BmpDecoder())) { image.DebugSave(provider, "png"); - image.CompareToOriginal(provider); + + // TODO: Neither System.Drawing not MagickReferenceDecoder + // can correctly decode this file. + // image.CompareToOriginal(provider); } } } From 5ef46927fcdb71f16db8a526349c7146f6d8f43c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Dec 2018 20:59:38 +1100 Subject: [PATCH 13/15] Use MagickReferenceDecoder for bmp. --- .../TestUtilities/TestEnvironment.Formats.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 334b6552ac..34a075ac7f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -34,8 +34,7 @@ namespace SixLabors.ImageSharp.Tests { string extension = Path.GetExtension(filePath); - IImageFormat format = Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); - return format; + return Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); } private static void ConfigureCodecs( @@ -69,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests cfg.ConfigureCodecs( BmpFormat.Instance, - SystemDrawingReferenceDecoder.Instance, + MagickReferenceDecoder.Instance, bmpEncoder, new BmpImageFormatDetector()); From 890134cec61a6c65a11562046635a248fd4d4158 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Dec 2018 21:54:59 +1100 Subject: [PATCH 14/15] Fix reference tests --- .../TestUtilities/Tests/TestEnvironmentTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 30bb16c2a0..8abbd94bda 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests [Theory] [InlineData("lol/foo.png", typeof(MagickReferenceDecoder))] - [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))] + [InlineData("lol/Rofl.bmp", typeof(MagickReferenceDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(string fileName, Type expectedDecoderType) @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests [Theory] [InlineData("lol/foo.png", typeof(MagickReferenceDecoder))] - [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))] + [InlineData("lol/Rofl.bmp", typeof(MagickReferenceDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] public void GetReferenceDecoder_ReturnsCorrectDecoders_Linux(string fileName, Type expectedDecoderType) From 2f3c0fce47c8636c7f2102b0b89705eaa778f217 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Dec 2018 23:25:23 +1100 Subject: [PATCH 15/15] Use S.D in Windows. --- tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs | 2 +- .../TestUtilities/Tests/TestEnvironmentTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 34a075ac7f..7d06847223 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests cfg.ConfigureCodecs( BmpFormat.Instance, - MagickReferenceDecoder.Instance, + IsWindows ? (IImageDecoder)SystemDrawingReferenceDecoder.Instance : MagickReferenceDecoder.Instance, bmpEncoder, new BmpImageFormatDetector()); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 8abbd94bda..122234ae89 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests [Theory] [InlineData("lol/foo.png", typeof(MagickReferenceDecoder))] - [InlineData("lol/Rofl.bmp", typeof(MagickReferenceDecoder))] + [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(string fileName, Type expectedDecoderType)