From 81d68e244da5e2db5cb48992cd54b5709c8068f9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 17 Apr 2018 10:35:15 +1000 Subject: [PATCH] Add identifier tests and begin cleanup --- .../PdfJsPort/Components/PdfJsComponent.cs | 43 ------- .../Components/PdfJsComponentBlocks.cs | 32 ----- .../Components/PdfJsJpegPixelArea.cs | 98 +++++++------- .../Components/PdfJsQuantizationTables.cs | 67 ---------- .../PdfJsPort/Components/PdfJsScanDecoder.cs | 35 +++-- .../Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 121 ++++-------------- .../Formats/Jpg/JpegDecoderTests.cs | 22 +++- .../ImageComparison/ImageComparer.cs | 6 +- 8 files changed, 121 insertions(+), 303 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs deleted file mode 100644 index 0742293c7..000000000 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.Memory; - -namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components -{ - /// - /// Represents a component block - /// - internal class PdfJsComponent : IDisposable - { -#pragma warning disable SA1401 - /// - /// Gets or sets the output - /// - public IBuffer Output; - - /// - /// Gets or sets the scaling factors - /// - public Vector2 Scale; - - /// - /// Gets or sets the number of blocks per line - /// - public int BlocksPerLine; - - /// - /// Gets or sets the number of blocks per column - /// - public int BlocksPerColumn; - - /// - public void Dispose() - { - this.Output?.Dispose(); - this.Output = null; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs deleted file mode 100644 index 86a0c6b31..000000000 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; - -namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components -{ - /// - /// Contains all the decoded component blocks - /// - internal sealed class PdfJsComponentBlocks : IDisposable - { - /// - /// Gets or sets the component blocks - /// - public PdfJsComponent[] Components { get; set; } - - /// - public void Dispose() - { - if (this.Components != null) - { - for (int i = 0; i < this.Components.Length; i++) - { - this.Components[i].Dispose(); - } - - this.Components = null; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs index 6a8548a3a..f37c5d903 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs @@ -54,55 +54,55 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components this.componentData = this.memoryManager.Allocate(this.Width * this.Height * this.NumberOfComponents); } - /// - /// Organsizes the decoded jpeg components into a linear array ordered by component. - /// This must be called before attempting to retrieve the data. - /// - /// The jpeg component blocks - public void LinearizeBlockData(PdfJsComponentBlocks components) - { - ref byte componentDataRef = ref MemoryMarshal.GetReference(this.componentData.Span); - const uint Mask3Lsb = 0xFFFFFFF8; // Used to clear the 3 LSBs - - using (IBuffer xScaleBlockOffset = this.memoryManager.Allocate(this.Width)) - { - ref int xScaleBlockOffsetRef = ref MemoryMarshal.GetReference(xScaleBlockOffset.Span); - int numberOfComponents = this.NumberOfComponents; - int width = this.Width; - int height = this.Height; - - for (int i = 0; i < numberOfComponents; i++) - { - ref PdfJsComponent component = ref components.Components[i]; - ref short outputRef = ref MemoryMarshal.GetReference(component.Output.Span); - Vector2 componentScale = component.Scale; - float cX = componentScale.X; - float cY = componentScale.Y; - int blocksPerScanline = (component.BlocksPerLine + 1) << 3; - - // Precalculate the xScaleBlockOffset - int j; - for (int x = 0; x < width; x++) - { - j = (int)(x * cX); - Unsafe.Add(ref xScaleBlockOffsetRef, x) = (int)((j & Mask3Lsb) << 3) | (j & 7); - } - - // Linearize the blocks of the component - int offset = i; - for (int y = 0; y < height; y++) - { - j = (int)(y * cY); - int index = blocksPerScanline * (int)(j & Mask3Lsb) | ((j & 7) << 3); - for (int x = 0; x < width; x++) - { - Unsafe.Add(ref componentDataRef, offset) = (byte)Unsafe.Add(ref outputRef, index + Unsafe.Add(ref xScaleBlockOffsetRef, x)); - offset += numberOfComponents; - } - } - } - } - } + //// + //// Organsizes the decoded jpeg components into a linear array ordered by component. + //// This must be called before attempting to retrieve the data. + //// + //// The jpeg component blocks + // public void LinearizeBlockData(PdfJsComponentBlocks components) + // { + // ref byte componentDataRef = ref MemoryMarshal.GetReference(this.componentData.Span); + // const uint Mask3Lsb = 0xFFFFFFF8; // Used to clear the 3 LSBs + + // using (IBuffer xScaleBlockOffset = this.memoryManager.Allocate(this.Width)) + // { + // ref int xScaleBlockOffsetRef = ref MemoryMarshal.GetReference(xScaleBlockOffset.Span); + // int numberOfComponents = this.NumberOfComponents; + // int width = this.Width; + // int height = this.Height; + // + // for (int i = 0; i < numberOfComponents; i++) + // { + // ref PdfJsComponent component = ref components.Components[i]; + // ref short outputRef = ref MemoryMarshal.GetReference(component.Output.Span); + // Vector2 componentScale = component.Scale; + // float cX = componentScale.X; + // float cY = componentScale.Y; + // int blocksPerScanline = (component.BlocksPerLine + 1) << 3; + // + // // Precalculate the xScaleBlockOffset + // int j; + // for (int x = 0; x < width; x++) + // { + // j = (int)(x * cX); + // Unsafe.Add(ref xScaleBlockOffsetRef, x) = (int)((j & Mask3Lsb) << 3) | (j & 7); + // } + // + // // Linearize the blocks of the component + // int offset = i; + // for (int y = 0; y < height; y++) + // { + // j = (int)(y * cY); + // int index = blocksPerScanline * (int)(j & Mask3Lsb) | ((j & 7) << 3); + // for (int x = 0; x < width; x++) + // { + // Unsafe.Add(ref componentDataRef, offset) = (byte)Unsafe.Add(ref outputRef, index + Unsafe.Add(ref xScaleBlockOffsetRef, x)); + // offset += numberOfComponents; + // } + // } + // } + // } + // } /// /// Gets a representing the row 'y' beginning from the the first byte on that row. diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs deleted file mode 100644 index afe0b3007..000000000 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Memory; - -namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components -{ - /// - /// Contains the quantization tables. - /// - internal sealed class PdfJsQuantizationTables : IDisposable - { - public PdfJsQuantizationTables(MemoryManager memoryManager) - { - this.Tables = memoryManager.Allocate2D(64, 4); - } - - /// - /// Gets the ZigZag scan table - /// - public static byte[] DctZigZag - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get; - } - - = - { - 0, - 1, 8, - 16, 9, 2, - 3, 10, 17, 24, - 32, 25, 18, 11, 4, - 5, 12, 19, 26, 33, 40, - 48, 41, 34, 27, 20, 13, 6, - 7, 14, 21, 28, 35, 42, 49, 56, - 57, 50, 43, 36, 29, 22, 15, - 23, 30, 37, 44, 51, 58, - 59, 52, 45, 38, 31, - 39, 46, 53, 60, - 61, 54, 47, - 55, 62, - 63 - }; - - /// - /// Gets or sets the quantization tables. - /// - public Buffer2D Tables - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get; set; - } - - /// - public void Dispose() - { - if (this.Tables != null) - { - this.Tables.Dispose(); - this.Tables = null; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs index b2c80ce9a..9e9fdf0fe 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +#if DEBUG using System.Diagnostics; +#endif using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -15,6 +17,28 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components /// internal struct PdfJsScanDecoder { + /// + /// Gets the ZigZag scan table + /// + private static readonly byte[] DctZigZag = + { + 0, + 1, 8, + 16, 9, 2, + 3, 10, 17, 24, + 32, 25, 18, 11, 4, + 5, 12, 19, 26, 33, 40, + 48, 41, 34, 27, 20, 13, 6, + 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, + 23, 30, 37, 44, 51, 58, + 59, 52, 45, 38, 31, + 39, 46, 53, 60, + 61, 54, 47, + 55, 62, + 63 + }; + private byte[] markerBuffer; private int bitsData; @@ -203,11 +227,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components if (componentsLength == 1) { PdfJsFrameComponent component = components[this.compIndex]; - - // TODO: This is where our error is happening. - // We can't simply cast the span as I think the scan decoder expects data to be laid out in linear order - // rather than in the column major order expected by the Block8x8 struct and anything reading it down the pipeline. - // Ask Anton about this. It might be a lost cause. ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span)); ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId]; ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId]; @@ -765,7 +784,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components break; } - ref byte z = ref PdfJsQuantizationTables.DctZigZag[k]; + ref byte z = ref DctZigZag[k]; short re = (short)this.ReceiveAndExtend(s, stream); Unsafe.Add(ref blockDataRef, offset + z) = re; k++; @@ -833,7 +852,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components k += r; - ref byte z = ref PdfJsQuantizationTables.DctZigZag[k]; + ref byte z = ref DctZigZag[k]; Unsafe.Add(ref blockDataRef, offset + z) = (short)(this.ReceiveAndExtend(s, stream) * (1 << this.successiveState)); k++; } @@ -848,7 +867,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components while (k <= e) { - int offsetZ = offset + PdfJsQuantizationTables.DctZigZag[k]; + int offsetZ = offset + DctZigZag[k]; ref short blockOffsetZRef = ref Unsafe.Add(ref blockDataRef, offsetZ); int sign = blockOffsetZRef < 0 ? -1 : 1; diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index 87d58a6ba..07c909e33 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -39,19 +39,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort private readonly Configuration configuration; /// - /// Gets the temporary buffer used to store bytes read from the stream. + /// The buffer used to temporarily store bytes read from the stream. /// private readonly byte[] temp = new byte[2 * 16 * 4]; + /// + /// The buffer used to read markers from the stream. + /// private readonly byte[] markerBuffer = new byte[2]; - // private PdfJsQuantizationTables quantizationTables; + /// + /// The DC HUffman tables + /// private PdfJsHuffmanTables dcHuffmanTables; + /// + /// The AC HUffman tables + /// private PdfJsHuffmanTables acHuffmanTables; - private PdfJsComponentBlocks components; - private PdfJsJpegPixelArea pixelArea; private ushort resetInterval; @@ -185,14 +191,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort where TPixel : struct, IPixel { this.ParseStream(stream); - - Image image = this.PostProcessIntoImage(); - - // this.QuantizeAndInverseAllComponents(); - // var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); - // this.FillPixelData(image.Frames.RootFrame); - this.AssignResolution(); - return image; + return this.PostProcessIntoImage(); } /// @@ -321,12 +320,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort break; case PdfJsJpegConstants.Markers.SOS: - if (metadataOnly) + if (!metadataOnly) { - return; + this.ProcessStartOfScanMarker(); } - this.ProcessStartOfScanMarker(); break; } @@ -336,58 +334,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort this.ImageWidth = this.Frame.SamplesPerLine; this.ImageHeight = this.Frame.Scanlines; - this.components = new PdfJsComponentBlocks { Components = new PdfJsComponent[this.Frame.ComponentCount] }; - - for (int i = 0; i < this.components.Components.Length; i++) - { - PdfJsFrameComponent frameComponent = this.Frame.Components[i]; - var component = new PdfJsComponent - { - Scale = new System.Numerics.Vector2( - frameComponent.HorizontalSamplingFactor / (float)this.Frame.MaxHorizontalFactor, - frameComponent.VerticalSamplingFactor / (float)this.Frame.MaxVerticalFactor), - BlocksPerLine = frameComponent.WidthInBlocks, - BlocksPerColumn = frameComponent.HeightInBlocks - }; - - // this.QuantizeAndInverseComponentData(ref component, frameComponent); - this.components.Components[i] = component; - } - - this.ComponentCount = this.components.Components.Length; + this.ComponentCount = this.Frame.ComponentCount; } /// public void Dispose() { this.Frame?.Dispose(); - this.components?.Dispose(); - - // this.quantizationTables?.Dispose(); this.pixelArea.Dispose(); // Set large fields to null. this.Frame = null; - this.components = null; - - // this.quantizationTables = null; this.dcHuffmanTables = null; this.acHuffmanTables = null; } - internal void QuantizeAndInverseAllComponents() - { - for (int i = 0; i < this.components.Components.Length; i++) - { - PdfJsFrameComponent frameComponent = this.Frame.Components[i]; - PdfJsComponent component = this.components.Components[i]; - - this.QuantizeAndInverseComponentData(component, frameComponent); - } - } - /// - /// Fills the given image with the color data + /// Fills the given image with the color data. TODO: Delete ME!! /// /// The pixel format. /// The image @@ -400,8 +363,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } this.pixelArea = new PdfJsJpegPixelArea(this.configuration.MemoryManager, image.Width, image.Height, this.ComponentCount); - this.pixelArea.LinearizeBlockData(this.components); + // this.pixelArea.LinearizeBlockData(this.components); if (this.ComponentCount == 1) { this.FillGrayScaleImage(image); @@ -433,6 +396,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } } + /// + /// Returns the correct colorspace based on the image component count + /// + /// The private JpegColorSpace DeduceJpegColorSpace() { if (this.ComponentCount == 1) @@ -536,12 +503,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort byte[] profile = new byte[remaining]; this.InputStream.Read(profile, 0, remaining); - if (profile[0] == PdfJsJpegConstants.Markers.Exif.E && - profile[1] == PdfJsJpegConstants.Markers.Exif.X && - profile[2] == PdfJsJpegConstants.Markers.Exif.I && - profile[3] == PdfJsJpegConstants.Markers.Exif.F && - profile[4] == PdfJsJpegConstants.Markers.Exif.Null && - profile[5] == PdfJsJpegConstants.Markers.Exif.Null) + if (ProfileResolver.IsProfile(profile, ProfileResolver.ExifMarker)) { this.isExif = true; this.MetaData.ExifProfile = new ExifProfile(profile); @@ -566,18 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort this.InputStream.Read(identifier, 0, Icclength); remaining -= Icclength; // We have read it by this point - if (identifier[0] == PdfJsJpegConstants.Markers.ICC.I && - identifier[1] == PdfJsJpegConstants.Markers.ICC.C && - identifier[2] == PdfJsJpegConstants.Markers.ICC.C && - identifier[3] == PdfJsJpegConstants.Markers.ICC.UnderScore && - identifier[4] == PdfJsJpegConstants.Markers.ICC.P && - identifier[5] == PdfJsJpegConstants.Markers.ICC.R && - identifier[6] == PdfJsJpegConstants.Markers.ICC.O && - identifier[7] == PdfJsJpegConstants.Markers.ICC.F && - identifier[8] == PdfJsJpegConstants.Markers.ICC.I && - identifier[9] == PdfJsJpegConstants.Markers.ICC.L && - identifier[10] == PdfJsJpegConstants.Markers.ICC.E && - identifier[11] == PdfJsJpegConstants.Markers.ICC.Null) + if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker)) { byte[] profile = new byte[remaining]; this.InputStream.Read(profile, 0, remaining); @@ -880,33 +831,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort successiveApproximation & 15); } - /// - /// Build the data for the given component - /// - /// The component - /// The frame component - private void QuantizeAndInverseComponentData(PdfJsComponent component, PdfJsFrameComponent frameComponent) - { - int blocksPerLine = component.BlocksPerLine; - int blocksPerColumn = component.BlocksPerColumn; - using (IBuffer computationBuffer = this.configuration.MemoryManager.Allocate(64, true)) - { - // ref short quantizationTableRef = ref MemoryMarshal.GetReference(this.quantizationTables.Tables.GetRowSpan(frameComponent.QuantizationTableIndex)); - // ref short computationBufferSpan = ref MemoryMarshal.GetReference(computationBuffer.Span); - // - // for (int blockRow = 0; blockRow < blocksPerColumn; blockRow++) - // { - // for (int blockCol = 0; blockCol < blocksPerLine; blockCol++) - // { - // int offset = 64 * (((blocksPerLine + 1) * blockRow) + blockCol); - // PdfJsIDCT.QuantizeAndInverse(frameComponent, offset, ref computationBufferSpan, ref quantizationTableRef); - // } - // } - } - - // component.Output = frameComponent.BlockData; - } - /// /// Builds the huffman tables /// @@ -1029,6 +953,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort where TPixel : struct, IPixel { this.ColorSpace = this.DeduceJpegColorSpace(); + this.AssignResolution(); using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this)) { var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 4bce4a1f6..51f113521 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -453,12 +453,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(TestImages.Jpeg.Baseline.Ycck, 32)] [InlineData(TestImages.Jpeg.Baseline.Jpeg400, 8)] [InlineData(TestImages.Jpeg.Baseline.Snake, 24)] - public void DetectPixelSize(string imagePath, int expectedPixelSize) + public void DetectPixelSizeGolang(string imagePath, int expectedPixelSize) { - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, ((IImageInfoDetector)OrigJpegDecoder).Identify(Configuration.Default, stream)?.PixelType?.BitsPerPixel); + } + } + + [Theory] + [InlineData(TestImages.Jpeg.Progressive.Progress, 24)] + [InlineData(TestImages.Jpeg.Progressive.Fb, 24)] + [InlineData(TestImages.Jpeg.Baseline.Cmyk, 32)] + [InlineData(TestImages.Jpeg.Baseline.Ycck, 32)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg400, 8)] + [InlineData(TestImages.Jpeg.Baseline.Snake, 24)] + public void DetectPixelSizePdfJs(string imagePath, int expectedPixelSize) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + Assert.Equal(expectedPixelSize, ((IImageInfoDetector)PdfJsJpegDecoder).Identify(Configuration.Default, stream)?.PixelType?.BitsPerPixel); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index b708673c7..bb5d0e6dd 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -117,10 +117,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison IEnumerable> reports = comparer.CompareImages(expected, actual); if (reports.Any()) { - List> cleanedReports = new List>(reports.Count()); - foreach (var r in reports) + var cleanedReports = new List>(reports.Count()); + foreach (ImageSimilarityReport r in reports) { - var outsideChanges = r.Differences.Where(x => !( + IEnumerable outsideChanges = r.Differences.Where(x => !( ignoredRegion.X <= x.Position.X && x.Position.X <= ignoredRegion.Right && ignoredRegion.Y <= x.Position.Y &&