Browse Source

Optimized byte emition, ouput images are corrupted due to msb-lsb invalid order

pull/1761/head
Dmitry Pentin 5 years ago
parent
commit
739f520640
  1. 55
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

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

@ -1,8 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS #if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
@ -33,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <summary> /// <summary>
/// A buffer for reducing the number of stream writes when emitting Huffman tables. /// A buffer for reducing the number of stream writes when emitting Huffman tables.
/// </summary> /// </summary>
private readonly byte[] emitBuffer = new byte[EmitBufferSizeInBytes]; private readonly uint[] emitBuffer = new uint[EmitBufferSizeInBytes / 4];
private readonly byte[] streamWriteBuffer = new byte[EmitBufferSizeInBytes * 2]; private readonly byte[] streamWriteBuffer = new byte[EmitBufferSizeInBytes * 2];
@ -47,7 +49,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <summary> /// <summary>
/// Emmited bits 'micro buffer' before being transfered to the <see cref="emitBuffer"/>. /// Emmited bits 'micro buffer' before being transfered to the <see cref="emitBuffer"/>.
/// </summary> /// </summary>
private int accumulatedBits; private uint accumulatedBits;
/// <summary> /// <summary>
/// Number of jagged bits stored in <see cref="accumulatedBits"/> /// Number of jagged bits stored in <see cref="accumulatedBits"/>
@ -121,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref chrominanceQuantTable, ref chrominanceQuantTable,
ref unzig); ref unzig);
if (this.emitLen + BytesPerCodingUnit > EmitBufferSizeInBytes) if (this.emitLen + (BytesPerCodingUnit / 4) > EmitBufferSizeInBytes / 4)
{ {
this.WriteToStream(); this.WriteToStream();
} }
@ -320,27 +322,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <param name="bits">The packed bits.</param> /// <param name="bits">The packed bits.</param>
/// <param name="count">The number of bits</param> /// <param name="count">The number of bits</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private void Emit(int bits, int count) private void Emit(uint bits, int count)
{ {
uint correctedBits = bits << (32 - count);
this.accumulatedBits |= correctedBits >> this.bitCount;
count += this.bitCount; count += this.bitCount;
bits <<= 32 - count;
bits |= this.accumulatedBits;
// Only write if more than 8 bits. if (count >= 32)
if (count >= 8)
{ {
// Track length this.emitBuffer[this.emitLen++] = this.accumulatedBits;
while (count >= 8) this.accumulatedBits = correctedBits << (32 - this.bitCount);
{
byte b = (byte)(bits >> 24);
this.emitBuffer[this.emitLen++] = b;
bits <<= 8; count -= 32;
count -= 8;
}
} }
this.accumulatedBits = bits;
this.bitCount = count; this.bitCount = count;
} }
@ -353,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private void EmitHuff(int[] table, int value) private void EmitHuff(int[] table, int value)
{ {
int x = table[value]; int x = table[value];
this.Emit(x >> 8, x & 0xff); this.Emit((uint)x >> 8, x & 0xff);
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
@ -372,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.EmitHuff(table, bt); this.EmitHuff(table, bt);
if (bt > 0) if (bt > 0)
{ {
this.Emit(b & ((1 << bt) - 1), bt); this.Emit((uint)(b & ((1 << bt) - 1)), bt);
} }
} }
@ -396,7 +393,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
int bt = GetHuffmanEncodingLength((uint)a); int bt = GetHuffmanEncodingLength((uint)a);
this.EmitHuff(table, (runLength << 4) | bt); this.EmitHuff(table, (runLength << 4) | bt);
this.Emit(b & ((1 << bt) - 1), bt); this.Emit((uint)(b & ((1 << bt) - 1)), bt);
} }
/// <summary> /// <summary>
@ -406,12 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private void FlushInternalBuffer() private void FlushInternalBuffer()
{ {
// pad last byte with 1's // pad last byte with 1's
int padBitsCount = 8 - (this.bitCount % 8); //int padBitsCount = 8 - (this.bitCount % 8);
if (padBitsCount != 0) //if (padBitsCount != 0)
{ //{
this.Emit((1 << padBitsCount) - 1, padBitsCount); // this.Emit((1 << padBitsCount) - 1, padBitsCount);
this.target.Write(this.emitBuffer, 0, this.emitLen); // this.target.Write(this.emitBuffer, 0, this.emitLen);
} //}
} }
/// <summary> /// <summary>
@ -514,10 +511,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private void WriteToStream() private void WriteToStream()
{ {
Span<byte> emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan());
int writeIdx = 0; int writeIdx = 0;
for (int i = 0; i < this.emitLen; i++) for (int i = 0; i < this.emitLen * 4; i++)
{ {
byte value = this.emitBuffer[i]; byte value = emitBytes[i];
this.streamWriteBuffer[writeIdx++] = value; this.streamWriteBuffer[writeIdx++] = value;
if (value == 0xff) if (value == 0xff)
{ {

Loading…
Cancel
Save