Browse Source

Fixed byte flush order, fixed last byte padding

pull/1761/head
Dmitry Pentin 5 years ago
parent
commit
8a08259e09
  1. 45
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

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

@ -41,10 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private const int BytesPerCodingUnit = 256 * 3;
/// <summary>
/// Number of filled bytes in <see cref="emitBuffer"/> buffer
/// </summary>
private int emitLen = 0;
private int emitWriteIndex = (EmitBufferSizeInBytes / 4);
/// <summary>
/// Emmited bits 'micro buffer' before being transfered to the <see cref="emitBuffer"/>.
@ -123,14 +120,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref chrominanceQuantTable,
ref unzig);
if (this.emitLen + (BytesPerCodingUnit / 4) > EmitBufferSizeInBytes / 4)
if (this.emitWriteIndex < this.emitBuffer.Length / 2)
{
this.WriteToStream();
}
}
}
this.FlushInternalBuffer();
this.EmitFinalBits();
}
/// <summary>
@ -311,6 +308,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
return dc;
}
[MethodImpl(InliningOptions.ShortMethod)]
private void EmitFinalBits()
{
// Bytes count we want to write to the output stream
int valuableBytesCount = (int)Numerics.DivideCeil((uint)this.bitCount, 8);
// Padding all 4 bytes with 1's while not corrupting initial bits stored in accumulatedBits
uint packedBytes = (this.accumulatedBits | (uint.MaxValue >> this.bitCount)) >> ((4 - valuableBytesCount) * 8);
// 2x size due to possible stuff bytes, max out to 8
Span<byte> tempBuffer = stackalloc byte[valuableBytesCount * 2];
// Write bytes to temporal buffer
int writeCount = 0;
for (int i = 0; i < valuableBytesCount; i++)
{
byte value = (byte)(packedBytes >> (i * 8));
tempBuffer[writeCount++] = value;
if (value == 0xff)
{
tempBuffer[writeCount++] = 0;
}
}
// Write temporal buffer to the output stream
this.target.Write(tempBuffer, 0, writeCount);
}
/// <summary>
/// Emits the least significant count of bits to the stream write buffer.
/// The precondition is bits
@ -332,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
if (count >= 32)
{
this.emitBuffer[this.emitLen++] = this.accumulatedBits;
this.emitBuffer[--this.emitWriteIndex] = this.accumulatedBits;
this.accumulatedBits = correctedBits << (32 - this.bitCount);
count -= 32;
@ -514,7 +539,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
Span<byte> emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan());
int writeIdx = 0;
for (int i = 0; i < this.emitLen * 4; i++)
int start = emitBytes.Length - 1;
int end = (this.emitWriteIndex * 4) - 1;
for (int i = start; i > end; i--)
{
byte value = emitBytes[i];
this.streamWriteBuffer[writeIdx++] = value;
@ -525,7 +552,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
}
this.target.Write(this.streamWriteBuffer, 0, writeIdx);
this.emitLen = 0;
this.emitWriteIndex = this.emitBuffer.Length;
}
}
}

Loading…
Cancel
Save