Browse Source

update write block in huffman encoder, add test

pull/2740/head
Alexandr Ivanov 2 years ago
parent
commit
490c0d3a31
  1. 41
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  2. 32
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

41
src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

@ -263,7 +263,6 @@ internal class HuffmanScanEncoder
ref Unsafe.Add(ref blockRef, k),
ref dcHuffmanTable);
if (this.IsStreamFlushNeeded)
{
this.FlushToStream();
@ -492,6 +491,7 @@ internal class HuffmanScanEncoder
}
}
// if mcu block contains trailing zeros - we must write end of block (EOB) value indicating that current block is over
if (runLength > 0)
{
this.EmitHuff(acHuffTable, 0x00);
@ -505,44 +505,7 @@ internal class HuffmanScanEncoder
ref HuffmanLut acTable)
{
this.WriteDc(component, ref block, ref dcTable);
// Emit the AC components.
int[] acHuffTable = acTable.Values;
nint lastValuableIndex = block.GetLastNonZeroIndex();
int runLength = 0;
ref short blockRef = ref Unsafe.As<Block8x8, short>(ref block);
for (nint zig = 1; zig <= lastValuableIndex; zig++)
{
const int zeroRun1 = 1 << 4;
const int zeroRun16 = 16 << 4;
int ac = Unsafe.Add(ref blockRef, zig);
if (ac == 0)
{
runLength += zeroRun1;
}
else
{
while (runLength >= zeroRun16)
{
this.EmitHuff(acHuffTable, 0xf0);
runLength -= zeroRun16;
}
this.EmitHuffRLE(acHuffTable, runLength, ac);
runLength = 0;
}
}
// if mcu block contains trailing zeros - we must write end of block (EOB) value indicating that current block is over
// this can be done for any number of trailing zeros, even when all 63 ac values are zero
// (Block8x8F.Size - 1) == 63 - last index of the mcu elements
if (lastValuableIndex != Block8x8F.Size - 1)
{
this.EmitHuff(acHuffTable, 0x00);
}
this.WriteAcBlock(ref block, 1, 64, ref acTable);
}
/// <summary>

32
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -14,13 +14,6 @@ public partial class JpegEncoderTests
{
private static JpegEncoder JpegEncoder => new();
private static readonly TheoryData<int> TestQualities = new()
{
40,
80,
100,
};
public static readonly TheoryData<JpegEncodingColor, int, float> NonSubsampledEncodingSetups = new()
{
{ JpegEncodingColor.Rgb, 100, 0.0238f / 100 },
@ -160,6 +153,31 @@ public partial class JpegEncoderTests
TestJpegEncoderCore(provider, colorType, 100, comparer);
}
[Theory]
[WithFile(TestImages.Png.CalliphoraPartial, nameof(NonSubsampledEncodingSetups), PixelTypes.Rgb24)]
[WithFile(TestImages.Png.CalliphoraPartial, nameof(SubsampledEncodingSetups), PixelTypes.Rgb24)]
[WithFile(TestImages.Png.BikeGrayscale, nameof(LuminanceEncodingSetups), PixelTypes.L8)]
[WithFile(TestImages.Jpeg.Baseline.Cmyk, nameof(CmykEncodingSetups), PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.Ycck, nameof(YcckEncodingSetups), PixelTypes.Rgb24)]
public void EncodeProgressive_DefaultNumberOfScans<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality, float tolerance)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
JpegEncoder encoder = new()
{
Quality = quality,
ColorType = colorType,
Progressive = true
};
string info = $"{colorType}-Q{quality}";
ImageComparer comparer = new TolerantImageComparer(tolerance);
// Does DebugSave & load reference CompareToReferenceInput():
image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "jpg");
}
[Theory]
[InlineData(JpegEncodingColor.YCbCrRatio420)]
[InlineData(JpegEncodingColor.YCbCrRatio444)]

Loading…
Cancel
Save