Browse Source

DecodeHuffmanUnsafe, DecodeBitUnsafe

pull/90/head
Anton Firszov 9 years ago
parent
commit
1f824a39be
  1. 29
      src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
  2. 2
      src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
  3. 26
      src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
  4. 57
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
  5. 62
      src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs

29
src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs

@ -94,24 +94,45 @@ namespace ImageSharp.Formats.Jpg
/// <param name="t">Byte</param>
/// <param name="decoder">Jpeg decoder</param>
/// <returns>Read bits value</returns>
internal int ReceiveExtend(byte t, JpegDecoderCore decoder)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReceiveExtend(byte t, JpegDecoderCore decoder)
{
int x;
DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, decoder, out x);
errorCode.EnsureNoError();
return x;
}
/// <summary>
/// Receive extend
/// </summary>
/// <param name="t">Byte</param>
/// <param name="decoder">Jpeg decoder</param>
/// <param name="x">Read bits value</param>
/// <returns>The <see cref="DecoderErrorCode"/></returns>
public DecoderErrorCode ReceiveExtendUnsafe(byte t, JpegDecoderCore decoder, out int x)
{
if (this.UnreadBits < t)
{
this.EnsureNBits(t, decoder);
DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, decoder);
if (errorCode != DecoderErrorCode.NoError)
{
x = int.MaxValue;
return errorCode;
}
}
this.UnreadBits -= t;
this.Mask >>= t;
int s = 1 << t;
int x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1));
x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1));
if (x < (s >> 1))
{
x += ((-1) << t) + 1;
}
return x;
return DecoderErrorCode.NoError;
}
}
}

2
src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs

@ -101,6 +101,7 @@ namespace ImageSharp.Formats.Jpg
{
return errorCode;
}
if (x != JpegConstants.Markers.XFF)
{
return DecoderErrorCode.NoError;
@ -112,6 +113,7 @@ namespace ImageSharp.Formats.Jpg
{
return errorCode;
}
if (x != 0x00)
{
return DecoderErrorCode.MissingFF00;

26
src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs

@ -46,18 +46,40 @@ namespace ImageSharp.Formats.Jpg
}
}
/// <summary>
/// Throws an exception if the given <see cref="DecoderErrorCode"/> is <see cref="DecoderErrorCode.UnexpectedEndOfStream"/>.
/// </summary>
/// <param name="errorCode">The <see cref="DecoderErrorCode"/></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureNoEOF(this DecoderErrorCode errorCode)
{
if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
{
errorCode.ThrowExceptionForErrorCode();
}
}
/// <summary>
/// Encapsulates methods throwing different flavours of <see cref="ImageFormatException"/>-s.
/// </summary>
public static class ThrowImageFormatException
{
/// <summary>
/// Throws "Fill called when unread bytes exist."
/// Throws "Fill called when unread bytes exist".
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void FillCalledWhenUnreadBytesExist()
{
throw new ImageFormatException("Fill called when unread bytes exist.");
throw new ImageFormatException("Fill called when unread bytes exist!");
}
/// <summary>
/// Throws "Bad Huffman code".
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void BadHuffmanCode()
{
throw new ImageFormatException("Bad Huffman code!");
}
}
}

57
src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs

@ -308,7 +308,7 @@ namespace ImageSharp.Formats.Jpg
private void ProcessBlockImpl(JpegDecoderCore decoder, int scanIndex)
{
var b = this.pointers.Block;
DecoderErrorCode errorCode;
int huffmannIdx = (AcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0)
{
@ -322,9 +322,13 @@ namespace ImageSharp.Formats.Jpg
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
byte value =
decoder.DecodeHuffman(
ref decoder.HuffmanTrees[(DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector]);
byte value;
int huffmanIndex = (DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
errorCode = decoder.DecodeHuffmanUnsafe(
ref decoder.HuffmanTrees[huffmanIndex],
out value);
errorCode.EnsureNoEOF();
if (value > 16)
{
throw new ImageFormatException("Excessive DC component");
@ -347,7 +351,10 @@ namespace ImageSharp.Formats.Jpg
// Decode the AC coefficients, as specified in section F.2.2.2.
for (; zig <= this.zigEnd; zig++)
{
byte value = decoder.DecodeHuffman(ref decoder.HuffmanTrees[huffmannIdx]);
byte value;
errorCode = decoder.DecodeHuffmanUnsafe(ref decoder.HuffmanTrees[huffmannIdx], out value);
errorCode.EnsureNoEOF();
byte val0 = (byte)(value >> 4);
byte val1 = (byte)(value & 0x0f);
if (val1 != 0)
@ -370,7 +377,8 @@ namespace ImageSharp.Formats.Jpg
this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
this.eobRun |= (ushort)decoder.DecodeBits(val0);
errorCode = this.DecodeEobRun(val0, decoder);
errorCode.EnsureNoError();
}
this.eobRun--;
@ -409,6 +417,19 @@ namespace ImageSharp.Formats.Jpg
destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2);
}
private DecoderErrorCode DecodeEobRun(int count, JpegDecoderCore decoder)
{
uint bitsResult;
DecoderErrorCode errorCode = decoder.DecodeBitsUnsafe(count, out bitsResult);
if (errorCode != DecoderErrorCode.NoError)
{
return errorCode;
}
this.eobRun |= (ushort)bitsResult;
return DecoderErrorCode.NoError;
}
/// <summary>
/// Gets the block index used to retieve blocks from in <see cref="JpegDecoderCore.DecodedBlocks"/>
/// </summary>
@ -496,7 +517,9 @@ namespace ImageSharp.Formats.Jpg
throw new ImageFormatException("Invalid state for zig DC component");
}
bool bit = decoder.DecodeBit();
bool bit;
DecoderErrorCode errorCode = decoder.DecodeBitUnsafe(out bit);
errorCode.EnsureNoError();
if (bit)
{
int stuff = (int)Block8x8F.GetScalarAt(b, 0);
@ -519,7 +542,11 @@ namespace ImageSharp.Formats.Jpg
{
bool done = false;
int z = 0;
byte val = decoder.DecodeHuffman(ref h);
byte val;
DecoderErrorCode errorCode = decoder.DecodeHuffmanUnsafe(ref h, out val);
errorCode.EnsureNoEOF();
int val0 = val >> 4;
int val1 = val & 0x0f;
@ -531,7 +558,8 @@ namespace ImageSharp.Formats.Jpg
this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
this.eobRun |= (ushort)decoder.DecodeBits(val0);
errorCode = this.DecodeEobRun(val0, decoder);
errorCode.EnsureNoError();
}
done = true;
@ -540,7 +568,11 @@ namespace ImageSharp.Formats.Jpg
break;
case 1:
z = delta;
bool bit = decoder.DecodeBit();
bool bit;
errorCode = decoder.DecodeBitUnsafe(out bit);
errorCode.EnsureNoError();
if (!bit)
{
z = -z;
@ -606,7 +638,10 @@ namespace ImageSharp.Formats.Jpg
continue;
}
bool bit = decoder.DecodeBit();
bool bit;
DecoderErrorCode errorCode = decoder.DecodeBitUnsafe(out bit);
errorCode.EnsureNoError();
if (!bit)
{
continue;

62
src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs

@ -435,25 +435,31 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte()
{
byte result = this.Bytes.ReadByte(this.InputStream);
return result;
return this.Bytes.ReadByte(this.InputStream);
}
/// <summary>
/// Decodes a single bit
/// TODO: This method (and also the usages) could be optimized by batching!
/// </summary>
/// <returns>The <see cref="bool" /></returns>
public bool DecodeBit()
/// <param name="result">The decoded bit as a <see cref="bool"/></param>
/// <returns>The <see cref="DecoderErrorCode" /></returns>
public DecoderErrorCode DecodeBitUnsafe(out bool result)
{
if (this.Bits.UnreadBits == 0)
{
this.Bits.EnsureNBits(1, this);
DecoderErrorCode errorCode = this.Bits.EnsureNBitsUnsafe(1, this);
if (errorCode != DecoderErrorCode.NoError)
{
result = false;
return errorCode;
}
}
bool ret = (this.Bits.Accumulator & this.Bits.Mask) != 0;
result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--;
this.Bits.Mask >>= 1;
return ret;
return DecoderErrorCode.NoError;
}
/// <summary>
@ -517,28 +523,32 @@ namespace ImageSharp.Formats
/// Decodes the given number of bits
/// </summary>
/// <param name="count">The number of bits to decode.</param>
/// <returns>The <see cref="uint" /></returns>
public uint DecodeBits(int count)
/// <param name="result">The <see cref="uint" /> result</param>
/// <returns>The <see cref="DecoderErrorCode"/></returns>
public DecoderErrorCode DecodeBitsUnsafe(int count, out uint result)
{
if (this.Bits.UnreadBits < count)
{
this.Bits.EnsureNBits(count, this);
}
uint ret = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
ret = (uint)(ret & ((1 << count) - 1));
result = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
result = (uint)(result & ((1 << count) - 1));
this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count;
return ret;
return DecoderErrorCode.NoError;
}
/// <summary>
/// Returns the next Huffman-coded value from the bit-stream, decoded according to the given value.
/// Extracts the next Huffman-coded value from the bit-stream into result, decoded according to the given value.
/// </summary>
/// <param name="huffmanTree">The huffman value</param>
/// <returns>The <see cref="byte" /></returns>
public byte DecodeHuffman(ref HuffmanTree huffmanTree)
/// <param name="result">The decoded <see cref="byte" /></param>
/// <returns>The <see cref="DecoderErrorCode"/></returns>
public DecoderErrorCode DecodeHuffmanUnsafe(ref HuffmanTree huffmanTree, out byte result)
{
result = 0;
// Copy stuff to the stack:
if (huffmanTree.Length == 0)
{
@ -558,16 +568,19 @@ namespace ImageSharp.Formats
int n = (v & 0xFF) - 1;
this.Bits.UnreadBits -= n;
this.Bits.Mask >>= n;
return (byte)(v >> 8);
result = (byte)(v >> 8);
return errorCode;
}
}
else if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
{
errorCode.ThrowExceptionForErrorCode();
}
// else if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
// {
// errorCode.ThrowExceptionForErrorCode();
// }
else
{
this.UnreadByteStuffedByte();
return errorCode;
}
}
@ -589,13 +602,18 @@ namespace ImageSharp.Formats
if (code <= huffmanTree.MaxCodes[i])
{
return huffmanTree.Values[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
result = huffmanTree.Values[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
return DecoderErrorCode.NoError;
}
code <<= 1;
}
throw new ImageFormatException("Bad Huffman code");
// Unrecoverable error, throwing:
DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode();
// DUMMY RETURN! C# doesn't know we have thrown an exception!
return DecoderErrorCode.NoError;
}
/// <summary>

Loading…
Cancel
Save