From 775610d5a0221e11096bbe500adc5bd31d6cbe63 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Mon, 13 Sep 2021 00:35:29 +0300 Subject: [PATCH] Fixed tests, fixed compilation, added DHT marker decoding more meaningful exception messages, fixed invalid jpeg encoding --- .../Components/Encoder/HuffmanScanEncoder.cs | 22 ++++++++----------- .../Formats/Jpeg/JpegDecoderCore.cs | 4 ++-- .../ImageSharp.Tests/Formats/Jpg/DCTTests.cs | 20 +++++------------ 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 08f676e40c..3e6b0e5f4d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs @@ -561,13 +561,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// this method endianness dependent. /// [MethodImpl(InliningOptions.ShortMethod)] - private void FlushToStream() + private void FlushToStream(int endIndex) { Span emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan()); int writeIdx = 0; int startIndex = emitBytes.Length - 1; - int endIndex = this.emitWriteIndex * sizeof(uint); // Some platforms may fail to eliminate this if-else branching // Even if it happens - buffer is flushed in big packs, @@ -621,28 +620,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder } this.target.Write(this.streamWriteBuffer, 0, writeIdx); + } + + private void FlushToStream() + { + this.FlushToStream(this.emitWriteIndex * 4); this.emitWriteIndex = this.emitBuffer.Length; } [MethodImpl(InliningOptions.ShortMethod)] private void FlushRemainingBytes() { - // Flush full 4-byte blocks - this.FlushToStream(); - // Padding all 4 bytes with 1's while not corrupting initial bits stored in accumulatedBits // And writing only valuable count of bytes count we want to write to the output stream int valuableBytesCount = (int)Numerics.DivideCeil((uint)this.bitCount, 8); uint packedBytes = this.accumulatedBits | (uint.MaxValue >> this.bitCount); + this.emitBuffer[--this.emitWriteIndex] = packedBytes; - Span emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan()); - for (int i = 0; i < valuableBytesCount; i++) - { - emitBytes[i] = (byte)((packedBytes >> ((3 - i) * 8)) & 0xff); - } - - // Flush remaining 'tail' bytes - this.target.Write(emitBytes, 0, valuableBytesCount); + // Flush cached bytes to the output stream with padding bits + this.FlushToStream((this.emitWriteIndex * 4) - 4 + valuableBytesCount); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 024743ddbc..a0f69bb7bf 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1071,13 +1071,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Types 0..1 DC..AC if (tableType > 1) { - JpegThrowHelper.ThrowInvalidImageContentException("Bad Huffman Table type."); + JpegThrowHelper.ThrowInvalidImageContentException($"Bad huffman table type: {tableType}"); } // Max tables of each type if (tableIndex > 3) { - JpegThrowHelper.ThrowInvalidImageContentException("Bad Huffman Table index."); + JpegThrowHelper.ThrowInvalidImageContentException($"Bad huffman table index: {tableIndex}"); } stream.Read(huffmanDataSpan, 0, 16); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index 55d208c5af..b4d3769d74 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -2,9 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; #if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics.X86; #endif @@ -121,24 +118,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void IDCT8x8_Avx(int seed) { #if SUPPORTS_RUNTIME_INTRINSICS - var skip = !Avx.IsSupported; -#else - var skip = true; -#endif - - if (skip) + if (!Avx.IsSupported) { this.Output.WriteLine("No AVX present, skipping test!"); - return; } Span src = Create8x8RoundedRandomFloatData(-200, 200, seed); - var srcBlock = default(Block8x8F); + Block8x8F srcBlock = default; srcBlock.LoadFrom(src); - var destBlock = default(Block8x8F); + Block8x8F destBlock = default; - var expectedDest = new float[64]; + float[] expectedDest = new float[64]; // reference, left part ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src, expectedDest); @@ -149,10 +140,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // testee, whole 8x8 FastFloatingPointDCT.IDCT8x8_Avx(ref srcBlock, ref destBlock); - var actualDest = new float[64]; + float[] actualDest = new float[64]; destBlock.ScaledCopyTo(actualDest); Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); +#endif } [Theory]