diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 991f7ff32..014a06c16 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/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(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); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 5842c8e1a..ee3cc674d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -14,13 +14,6 @@ public partial class JpegEncoderTests { private static JpegEncoder JpegEncoder => new(); - private static readonly TheoryData TestQualities = new() - { - 40, - 80, - 100, - }; - public static readonly TheoryData 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(TestImageProvider provider, JpegEncodingColor colorType, int quality, float tolerance) + where TPixel : unmanaged, IPixel + { + using Image 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)]