mirror of https://github.com/SixLabors/ImageSharp
21 changed files with 275 additions and 177 deletions
@ -0,0 +1,41 @@ |
|||||
|
namespace SixLabors.ImageSharp.Formats.Jpeg.Common |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides enumeration of the various available subsample ratios.
|
||||
|
/// https://en.wikipedia.org/wiki/Chroma_subsampling
|
||||
|
/// </summary>
|
||||
|
internal enum SubsampleRatio |
||||
|
{ |
||||
|
Undefined, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:4:4
|
||||
|
/// </summary>
|
||||
|
Ratio444, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:2:2
|
||||
|
/// </summary>
|
||||
|
Ratio422, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:2:0
|
||||
|
/// </summary>
|
||||
|
Ratio420, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:4:0
|
||||
|
/// </summary>
|
||||
|
Ratio440, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:1:1
|
||||
|
/// </summary>
|
||||
|
Ratio411, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 4:1:0
|
||||
|
/// </summary>
|
||||
|
Ratio410, |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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}"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue