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