diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/SubsampleRatio.cs b/src/ImageSharp/Formats/Jpeg/Common/ComponentUtils.cs similarity index 74% rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/SubsampleRatio.cs rename to src/ImageSharp/Formats/Jpeg/Common/ComponentUtils.cs index 86fde5e72..3b3f302a4 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/SubsampleRatio.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/ComponentUtils.cs @@ -1,54 +1,18 @@ using System.Collections.Generic; using System.Linq; -using SixLabors.ImageSharp.Formats.Jpeg.Common; using SixLabors.Primitives; -namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common { - /// - /// Provides enumeration of the various available subsample ratios. - /// https://en.wikipedia.org/wiki/Chroma_subsampling - /// - internal enum SubsampleRatio - { - Undefined, - - /// - /// 4:4:4 - /// - Ratio444, - - /// - /// 4:2:2 - /// - Ratio422, - - /// - /// 4:2:0 - /// - Ratio420, - - /// - /// 4:4:0 - /// - Ratio440, - - /// - /// 4:1:1 - /// - Ratio411, - - /// - /// 4:1:0 - /// - Ratio410, - } + using System; /// - /// Various utilities for + /// Various utilities for and . /// - internal static class Subsampling + internal static class ComponentUtils { + public static Size SizeInBlocks(this IJpegComponent component) => new Size(component.WidthInBlocks, component.HeightInBlocks); + public static SubsampleRatio GetSubsampleRatio(int horizontalRatio, int verticalRatio) { switch ((horizontalRatio << 4) | verticalRatio) @@ -113,5 +77,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder return new Size(width, height); } } + + public static bool IsChromaComponent(this IJpegComponent component) => + component.Index > 0 && component.Index < 3; + + public static Size CalculateJpegChannelSize(this IJpegComponent component, SubsampleRatio ratio = SubsampleRatio.Undefined) + { + Size size = new Size(component.WidthInBlocks, component.HeightInBlocks) * 8; + + if (component.IsChromaComponent()) + { + return ratio.CalculateChrominanceSize(size.Width, size.Height); + } + else + { + return size; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs index 5a5b95e30..07dba0bdb 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs @@ -2,6 +2,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common { internal interface IJpegComponent { + /// + /// Gets the component's position in the components array. + /// + int Index { get; } + /// /// Gets the number of blocks per line /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/SubsampleRatio.cs b/src/ImageSharp/Formats/Jpeg/Common/SubsampleRatio.cs new file mode 100644 index 000000000..f6f5fbd68 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Common/SubsampleRatio.cs @@ -0,0 +1,41 @@ +namespace SixLabors.ImageSharp.Formats.Jpeg.Common +{ + /// + /// Provides enumeration of the various available subsample ratios. + /// https://en.wikipedia.org/wiki/Chroma_subsampling + /// + internal enum SubsampleRatio + { + Undefined, + + /// + /// 4:4:4 + /// + Ratio444, + + /// + /// 4:2:2 + /// + Ratio422, + + /// + /// 4:2:0 + /// + Ratio420, + + /// + /// 4:4:0 + /// + Ratio440, + + /// + /// 4:1:1 + /// + Ratio411, + + /// + /// 4:1:0 + /// + Ratio410, + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs index e416bbc19..035a7ddd8 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs @@ -25,9 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// public byte Identifier { get; } - /// - /// Gets the component's position in - /// + /// public int Index { get; } /// @@ -44,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// /// Gets the storing the "raw" frequency-domain decoded blocks. /// We need to apply IDCT, dequantiazition and unzigging to transform them into color-space blocks. - /// This is done by . + /// This is done by . /// When us true, we are touching these blocks multiple times - each time we process a Scan. /// public Buffer2D SpectralBlocks { get; private set; } @@ -224,20 +222,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder this.VerticalSamplingFactor = v; } - public Size CalculateJpegChannelSize(SubsampleRatio ratio) - { - Size size = new Size(this.WidthInBlocks, this.HeightInBlocks) * 8; - - if (this.Index > 0 && this.Index < 3) // Chroma component: - { - return ratio.CalculateChrominanceSize(size.Width, size.Height); - } - else - { - return size; - } - } - public void Dispose() { this.SpectralBlocks.Dispose(); diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegPixelArea.cs index 0fd2b5a61..b724ecb1e 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegPixelArea.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegPixelArea.cs @@ -5,9 +5,11 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F; +using SixLabors.ImageSharp.Formats.Jpeg.Common; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder -{ +{ /// /// Represents an area of a Jpeg subimage (channel) /// @@ -36,6 +38,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { } + public OrigJpegPixelArea(Size size) + : this(Buffer2D.CreateClean(size)) + { + } + /// /// Gets the pixels buffer. /// @@ -76,6 +83,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder } } + public static OrigJpegPixelArea CreateForComponent(IJpegComponent component, SubsampleRatio ratio = SubsampleRatio.Undefined) + { + Size size = component.CalculateJpegChannelSize(ratio); + return new OrigJpegPixelArea(size); + } + /// /// Gets the subarea that belongs to the Block8x8 defined by block indices /// diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/YCbCrImage.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/YCbCrImage.cs index 7260784ff..72a25ecd7 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/YCbCrImage.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/YCbCrImage.cs @@ -7,6 +7,8 @@ using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { + using SixLabors.ImageSharp.Formats.Jpeg.Common; + /// /// Represents an image made up of three color components (luminance, blue chroma, red chroma) /// diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs index 6fb367edc..b8eea6f37 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs @@ -17,6 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort { using System.Linq; + using SixLabors.ImageSharp.Formats.Jpeg.Common; + using SixLabors.Primitives; + /// /// Performs the jpeg decoding operation. /// @@ -112,7 +115,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } /// - /// Gets the ratio. + /// Gets the ratio. /// public SubsampleRatio SubsampleRatio { get; private set; } @@ -775,29 +778,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } /// - /// Makes the image from the buffer. + /// Initializes the image channels. /// private void InitJpegImageChannels() { if (this.ComponentCount == 1) { - var buffer = Buffer2D.CreateClean(8 * this.MCUCountX, 8 * this.MCUCountY); - this.grayImage = new OrigJpegPixelArea(buffer); + this.grayImage = OrigJpegPixelArea.CreateForComponent(this.Components[0]); } else { - int h0 = this.Components[0].HorizontalSamplingFactor; - int v0 = this.Components[0].VerticalSamplingFactor; + Size size = this.Components[0].CalculateJpegChannelSize(); - this.ycbcrImage = new YCbCrImage(8 * h0 * this.MCUCountX, 8 * v0 * this.MCUCountY, this.SubsampleRatio); + this.ycbcrImage = new YCbCrImage(size.Width, size.Height, this.SubsampleRatio); if (this.ComponentCount == 4) { - int h3 = this.Components[3].HorizontalSamplingFactor; - int v3 = this.Components[3].VerticalSamplingFactor; - - var buffer = Buffer2D.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY); - this.blackImage = new OrigJpegPixelArea(buffer); + this.blackImage = OrigJpegPixelArea.CreateForComponent(this.Components[3]); } } } @@ -1198,7 +1195,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort this.Components[i].InitializeBlocks(this); } - this.SubsampleRatio = Subsampling.GetSubsampleRatio(this.Components); + this.SubsampleRatio = ComponentUtils.GetSubsampleRatio(this.Components); } } } diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs index 8f424143a..2363d9600 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs @@ -16,13 +16,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components { #pragma warning disable SA1401 // Fields should be private - public PdfJsFrameComponent(PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationIdentifier) + public PdfJsFrameComponent(PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationIdentifier, int index) { this.Frame = frame; this.Id = id; this.HorizontalSamplingFactor = horizontalFactor; this.VerticalSamplingFactor = verticalFactor; this.QuantizationIdentifier = quantizationIdentifier; + this.Index = index; } /// @@ -35,14 +36,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components /// public int Pred { get; set; } - /// - /// Gets the horizontal sampling factor. - /// + /// public int HorizontalSamplingFactor { get; } - /// - /// Gets the vertical sampling factor. - /// + /// public int VerticalSamplingFactor { get; } /// @@ -55,6 +52,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components /// public Buffer BlockData { get; private set; } + /// + public int Index { get; } + /// /// Gets the number of blocks per line /// diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs index 56814843a..e705073fa 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs @@ -676,7 +676,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort maxV = v; } - var component = new PdfJsFrameComponent(this.Frame, this.temp[index], h, v, this.temp[index + 2]); + var component = new PdfJsFrameComponent(this.Frame, this.temp[index], h, v, this.temp[index + 2], i); this.Frame.Components[i] = component; this.Frame.ComponentIds[i] = component.Id; diff --git a/src/ImageSharp/Memory/Buffer2D.cs b/src/ImageSharp/Memory/Buffer2D.cs index d86eb5b26..8c7b104cf 100644 --- a/src/ImageSharp/Memory/Buffer2D.cs +++ b/src/ImageSharp/Memory/Buffer2D.cs @@ -5,6 +5,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { + using SixLabors.Primitives; + /// /// Represents a buffer of value type objects /// interpreted as a 2D region of x elements. @@ -71,5 +73,12 @@ namespace SixLabors.ImageSharp.Memory buffer.Clear(); return buffer; } + + /// + /// Creates a clean instance of initializing it's elements with 'default(T)'. + /// + /// The size of the buffer + /// The instance + public static Buffer2D CreateClean(Size size) => CreateClean(size.Width, size.Height); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index edf3162d2..3f643344b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using Xunit; using Xunit.Abstractions; - public class Block8x8FTests : JpegUtilityTestFixture + public class Block8x8FTests : JpegFixture { #if BENCHMARKING public const int Times = 1000000; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs index 8c1d5fb90..d1a128b53 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using Xunit; using Xunit.Abstractions; - public class Block8x8Tests : JpegUtilityTestFixture + public class Block8x8Tests : JpegFixture { public Block8x8Tests(ITestOutputHelper output) : base(output) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ComponentUtilsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ComponentUtilsTests.cs new file mode 100644 index 000000000..a2e349d8a --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Jpg/ComponentUtilsTests.cs @@ -0,0 +1,124 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Jpg +{ + using SixLabors.ImageSharp.Formats.Jpeg.Common; + using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; + using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; + using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; + using SixLabors.Primitives; + + using Xunit; + using Xunit.Abstractions; + + public class ComponentUtilsTests + { + public ComponentUtilsTests(ITestOutputHelper output) + { + this.Output = output; + } + + private ITestOutputHelper Output { get; } + + [Theory] + [InlineData(SubsampleRatio.Ratio410, 4, 2)] + [InlineData(SubsampleRatio.Ratio411, 4, 1)] + [InlineData(SubsampleRatio.Ratio420, 2, 2)] + [InlineData(SubsampleRatio.Ratio422, 2, 1)] + [InlineData(SubsampleRatio.Ratio440, 1, 2)] + [InlineData(SubsampleRatio.Ratio444, 1, 1)] + internal void CalculateChrominanceSize( + SubsampleRatio ratio, + int expectedDivX, + int expectedDivY) + { + //this.Output.WriteLine($"RATIO: {ratio}"); + Size size = ratio.CalculateChrominanceSize(400, 400); + //this.Output.WriteLine($"Ch Size: {size}"); + + Assert.Equal(new Size(400 / expectedDivX, 400 / expectedDivY), size); + } + + [Theory] + [InlineData(SubsampleRatio.Ratio410, 4)] + [InlineData(SubsampleRatio.Ratio411, 4)] + [InlineData(SubsampleRatio.Ratio420, 2)] + [InlineData(SubsampleRatio.Ratio422, 2)] + [InlineData(SubsampleRatio.Ratio440, 1)] + [InlineData(SubsampleRatio.Ratio444, 1)] + internal void Create(SubsampleRatio ratio, int expectedCStrideDiv) + { + this.Output.WriteLine($"RATIO: {ratio}"); + + YCbCrImage img = new YCbCrImage(400, 400, ratio); + + //this.PrintChannel("Y", img.YChannel); + //this.PrintChannel("Cb", img.CbChannel); + //this.PrintChannel("Cr", img.CrChannel); + + Assert.Equal(400, img.YChannel.Width); + Assert.Equal(img.CbChannel.Width, 400 / expectedCStrideDiv); + Assert.Equal(img.CrChannel.Width, 400 / expectedCStrideDiv); + } + + private void PrintChannel(string name, OrigJpegPixelArea channel) + { + this.Output.WriteLine($"{name}: Stride={channel.Stride}"); + } + + [Fact] + public void CalculateJpegChannelSize_Grayscale() + { + using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(TestImages.Jpeg.Baseline.Jpeg400)) + { + Assert.Equal(1, decoder.ComponentCount); + Size expected = decoder.Components[0].SizeInBlocks() * 8; + Size actual = decoder.Components[0].CalculateJpegChannelSize(decoder.SubsampleRatio); + + Assert.Equal(expected, actual); + } + } + + [Theory] + [InlineData(TestImages.Jpeg.Baseline.Calliphora, 1)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg444, 1)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg420, 2)] + public void CalculateJpegChannelSize_YCbCr( + string imageFile, + int chromaDiv) + { + using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile)) + { + Size ySize = decoder.Components[0].SizeInBlocks() * 8; + Size cSize = decoder.Components[1].SizeInBlocks() * 8 / chromaDiv; + + Size s0 = decoder.Components[0].CalculateJpegChannelSize(decoder.SubsampleRatio); + Size s1 = decoder.Components[1].CalculateJpegChannelSize(decoder.SubsampleRatio); + Size s2 = decoder.Components[2].CalculateJpegChannelSize(decoder.SubsampleRatio); + + Assert.Equal(ySize, s0); + Assert.Equal(cSize, s1); + Assert.Equal(cSize, s2); + } + } + + [Theory] + [InlineData(TestImages.Jpeg.Baseline.Ycck)] + [InlineData(TestImages.Jpeg.Baseline.Cmyk)] + public void CalculateJpegChannelSize_4Chan(string imageFile) + { + using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile)) + { + Size expected = decoder.Components[0].SizeInBlocks() * 8; + + foreach (OrigComponent component in decoder.Components) + { + Size actual = component.CalculateJpegChannelSize(decoder.SubsampleRatio); + Assert.Equal(expected, actual); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index bf0563b67..ee6f5305f 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public static class DCTTests { - public class FastFloatingPoint : JpegUtilityTestFixture + public class FastFloatingPoint : JpegFixture { public FastFloatingPoint(ITestOutputHelper output) : base(output) @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Fact] public void iDCT2D8x4_LeftPart() { - float[] sourceArray = JpegUtilityTestFixture.Create8x8FloatData(); + float[] sourceArray = JpegFixture.Create8x8FloatData(); float[] expectedDestArray = new float[64]; ReferenceImplementations.LLM_FloatingPoint_DCT.iDCT2D8x4_32f(sourceArray, expectedDestArray); @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Fact] public void iDCT2D8x4_RightPart() { - float[] sourceArray = JpegUtilityTestFixture.Create8x8FloatData(); + float[] sourceArray = JpegFixture.Create8x8FloatData(); float[] expectedDestArray = new float[64]; ReferenceImplementations.LLM_FloatingPoint_DCT.iDCT2D8x4_32f(sourceArray.AsSpan().Slice(4), expectedDestArray.AsSpan().Slice(4)); @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(3)] public void LLM_TransformIDCT_CompareToNonOptimized(int seed) { - float[] sourceArray = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); + float[] sourceArray = JpegFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); var source = Block8x8F.Load(sourceArray); @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(3)] public void LLM_TransformIDCT_CompareToAccurate(int seed) { - float[] sourceArray = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); + float[] sourceArray = JpegFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); var source = Block8x8F.Load(sourceArray); @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2)] public void FDCT8x4_LeftPart(int seed) { - Span src = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); + Span src = JpegFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); Block8x8F srcBlock = new Block8x8F(); srcBlock.LoadFrom(src); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2)] public void FDCT8x4_RightPart(int seed) { - Span src = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); + Span src = JpegFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); Block8x8F srcBlock = new Block8x8F(); srcBlock.LoadFrom(src); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2)] public void TransformFDCT(int seed) { - Span src = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); + Span src = JpegFixture.Create8x8RoundedRandomFloatData(-200, 200, seed); Block8x8F srcBlock = new Block8x8F(); srcBlock.LoadFrom(src); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 15be5b771..6dd1da351 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -65,12 +65,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Fact(Skip = "Doesn't really matter")] public void ParseStream_BasicPropertiesAreCorrect1_Orig() { - byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes; - using (var ms = new MemoryStream(bytes)) + using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(TestImages.Jpeg.Progressive.Progress)) { - var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder()); - decoder.ParseStream(ms); - VerifyJpeg.Components3(decoder.Components, 43, 61, 22, 31, 22, 31); } } @@ -95,7 +91,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void DecodeBaselineJpeg_PdfJs(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(PdfJsJpegDecoder)) { image.DebugSave(provider); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs index b716146e8..6b9e98d66 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class ReferenceImplementationsTests { - public class AccurateDCT : JpegUtilityTestFixture + public class AccurateDCT : JpegFixture { public AccurateDCT(ITestOutputHelper output) : base(output) @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2)] public void ForwardThenInverse(int seed) { - float[] data = JpegUtilityTestFixture.Create8x8RandomFloatData(-1000, 1000, seed); + float[] data = JpegFixture.Create8x8RandomFloatData(-1000, 1000, seed); var b0 = default(Block8x8F); b0.LoadFrom(data); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs index 1babb4f14..7ff2a3923 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class ReferenceImplementationsTests { - public class FastFloatingPointDCT : JpegUtilityTestFixture + public class FastFloatingPointDCT : JpegFixture { public FastFloatingPointDCT(ITestOutputHelper output) : base(output) @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2, 0)] public void LLM_ForwardThenInverse(int seed, int startAt) { - int[] data = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed); + int[] data = JpegFixture.Create8x8RandomIntData(-1000, 1000, seed); float[] original = data.ConvertAllToFloat(); float[] src = data.ConvertAllToFloat(); float[] dest = new float[64]; @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2, 200)] public void LLM_IDCT_IsEquivalentTo_AccurateImplementation(int seed, int range) { - float[] sourceArray = JpegUtilityTestFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); + float[] sourceArray = JpegFixture.Create8x8RoundedRandomFloatData(-1000, 1000, seed); var source = Block8x8F.Load(sourceArray); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2)] public void LLM_FDCT_IsEquivalentTo_AccurateImplementation(int seed) { - float[] floatData = JpegUtilityTestFixture.Create8x8RandomFloatData(-1000, 1000); + float[] floatData = JpegFixture.Create8x8RandomFloatData(-1000, 1000); Block8x8F source = default(Block8x8F); source.LoadFrom(floatData); @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2, 200)] public void GT_IDCT_IsEquivalentTo_AccurateImplementation(int seed, int range) { - int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-range, range, seed); + int[] intData = JpegFixture.Create8x8RandomIntData(-range, range, seed); float[] floatSrc = intData.ConvertAllToFloat(); ReferenceImplementations.AccurateDCT.TransformIDCTInplace(intData); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs index e9e0503ed..f384a76c4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class ReferenceImplementationsTests { - public class StandardIntegerDCT : JpegUtilityTestFixture + public class StandardIntegerDCT : JpegFixture { public StandardIntegerDCT(ITestOutputHelper output) : base(output) @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(2, 0)] public void ForwardThenInverse(int seed, int startAt) { - Span original = JpegUtilityTestFixture.Create8x8RandomIntData(-200, 200, seed); + Span original = JpegFixture.Create8x8RandomIntData(-200, 200, seed); Span block = original.AddScalarToAllValues(128); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs index 8b97f1208..26ec454f9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; - public partial class ReferenceImplementationsTests : JpegUtilityTestFixture + public partial class ReferenceImplementationsTests : JpegFixture { public ReferenceImplementationsTests(ITestOutputHelper output) : base(output) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SubsampleRatioTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SubsampleRatioTests.cs deleted file mode 100644 index 6e30e6f80..000000000 --- a/tests/ImageSharp.Tests/Formats/Jpg/SubsampleRatioTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Tests.Formats.Jpg -{ - using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; - using SixLabors.Primitives; - - using Xunit; - using Xunit.Abstractions; - - public class SubsampleRatioTests - { - public SubsampleRatioTests(ITestOutputHelper output) - { - this.Output = output; - } - - private ITestOutputHelper Output { get; } - - [Theory] - [InlineData(SubsampleRatio.Ratio410, 4, 2)] - [InlineData(SubsampleRatio.Ratio411, 4, 1)] - [InlineData(SubsampleRatio.Ratio420, 2, 2)] - [InlineData(SubsampleRatio.Ratio422, 2, 1)] - [InlineData(SubsampleRatio.Ratio440, 1, 2)] - [InlineData(SubsampleRatio.Ratio444, 1, 1)] - internal void CalculateChrominanceSize( - SubsampleRatio ratio, - int expectedDivX, - int expectedDivY) - { - //this.Output.WriteLine($"RATIO: {ratio}"); - Size size = ratio.CalculateChrominanceSize(400, 400); - //this.Output.WriteLine($"Ch Size: {size}"); - - Assert.Equal(new Size(400 / expectedDivX, 400 / expectedDivY), size); - } - - [Theory] - [InlineData(SubsampleRatio.Ratio410, 4)] - [InlineData(SubsampleRatio.Ratio411, 4)] - [InlineData(SubsampleRatio.Ratio420, 2)] - [InlineData(SubsampleRatio.Ratio422, 2)] - [InlineData(SubsampleRatio.Ratio440, 1)] - [InlineData(SubsampleRatio.Ratio444, 1)] - internal void Create(SubsampleRatio ratio, int expectedCStrideDiv) - { - this.Output.WriteLine($"RATIO: {ratio}"); - - YCbCrImage img = new YCbCrImage(400, 400, ratio); - - //this.PrintChannel("Y", img.YChannel); - //this.PrintChannel("Cb", img.CbChannel); - //this.PrintChannel("Cr", img.CrChannel); - - Assert.Equal(400, img.YChannel.Width); - Assert.Equal(img.CbChannel.Width, 400 / expectedCStrideDiv); - Assert.Equal(img.CrChannel.Width, 400 / expectedCStrideDiv); - } - - private void PrintChannel(string name, OrigJpegPixelArea channel) - { - this.Output.WriteLine($"{name}: Stride={channel.Stride}"); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs similarity index 88% rename from tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs rename to tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index 1ecfeacef..ab5d072a4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -9,16 +9,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { using System; using System.Diagnostics; + using System.IO; using System.Text; + using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Common; + using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using Xunit; using Xunit.Abstractions; - public class JpegUtilityTestFixture : MeasureFixture + public class JpegFixture : MeasureFixture { - public JpegUtilityTestFixture(ITestOutputHelper output) : base(output) + public JpegFixture(ITestOutputHelper output) : base(output) { } @@ -166,5 +169,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils this.Output.WriteLine("TOTAL DIFF: "+totalDifference); Assert.False(failed); } + + internal static OrigJpegDecoderCore ParseStream(string testFileName) + { + byte[] bytes = TestFile.Create(testFileName).Bytes; + using (var ms = new MemoryStream(bytes)) + { + var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder()); + decoder.ParseStream(ms); + return decoder; + } + } } } \ No newline at end of file