diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
index 1eea1417f3..80787101b0 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
@@ -18,13 +18,13 @@ namespace ImageSharp.Formats.Jpg
///
/// Gets or sets the accumulator.
///
- public uint Accumulator;
+ public int Accumulator;
///
/// Gets or sets the mask.
/// 0, with mask==0 when unreadbits==0.]]>
///
- public uint Mask;
+ public int Mask;
///
/// Gets or sets the number of unread bits in the accumulator.
@@ -89,7 +89,7 @@ namespace ImageSharp.Formats.Jpg
private DecoderErrorCode EnsureBitsStepImpl(JpegDecoderCore decoder)
{
- byte c;
+ int c;
DecoderErrorCode errorCode = decoder.Bytes.ReadByteStuffedByteUnsafe(decoder.InputStream, out c);
if (errorCode != DecoderErrorCode.NoError)
@@ -117,7 +117,7 @@ namespace ImageSharp.Formats.Jpg
/// Jpeg decoder
/// Read bits value
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public int ReceiveExtend(byte t, JpegDecoderCore decoder)
+ public int ReceiveExtend(int t, JpegDecoderCore decoder)
{
int x;
DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, decoder, out x);
@@ -132,7 +132,7 @@ namespace ImageSharp.Formats.Jpg
/// Jpeg decoder
/// Read bits value
/// The
- public DecoderErrorCode ReceiveExtendUnsafe(byte t, JpegDecoderCore decoder, out int x)
+ public DecoderErrorCode ReceiveExtendUnsafe(int t, JpegDecoderCore decoder, out int x)
{
if (this.UnreadBits < t)
{
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
index 27f902aa15..b65df51dc4 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
@@ -16,6 +16,11 @@ namespace ImageSharp.Formats.Jpg
///
internal struct Bytes : IDisposable
{
+ ///
+ /// Specifies the buffer size for and
+ ///
+ public const int BufferSize = 4096;
+
///
/// Gets or sets the buffer.
/// buffer[i:j] are the buffered bytes read from the underlying
@@ -23,6 +28,11 @@ namespace ImageSharp.Formats.Jpg
///
public byte[] Buffer;
+ ///
+ /// Values of converted to -s
+ ///
+ public int[] BufferAsInt;
+
///
/// Start of bytes read
///
@@ -39,7 +49,9 @@ namespace ImageSharp.Formats.Jpg
///
public int UnreadableBytes;
- private static readonly ArrayPool ArrayPool = ArrayPool.Create(4096, 50);
+ private static readonly ArrayPool BytePool = ArrayPool.Create(BufferSize, 50);
+
+ private static readonly ArrayPool IntPool = ArrayPool.Create(BufferSize, 50);
///
/// Creates a new instance of the , and initializes it's buffer.
@@ -47,7 +59,11 @@ namespace ImageSharp.Formats.Jpg
/// The bytes created
public static Bytes Create()
{
- return new Bytes { Buffer = ArrayPool.Rent(4096) };
+ return new Bytes
+ {
+ Buffer = BytePool.Rent(BufferSize),
+ BufferAsInt = IntPool.Rent(BufferSize)
+ };
}
///
@@ -57,32 +73,34 @@ namespace ImageSharp.Formats.Jpg
{
if (this.Buffer != null)
{
- ArrayPool.Return(this.Buffer);
+ BytePool.Return(this.Buffer);
+ IntPool.Return(this.BufferAsInt);
}
this.Buffer = null;
+ this.BufferAsInt = null;
}
///
/// ReadByteStuffedByte is like ReadByte but is for byte-stuffed Huffman data.
///
/// Input stream
- /// The result
+ /// The result byte as
/// The
- public DecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out byte x)
+ public DecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
{
// Take the fast path if bytes.buf contains at least two bytes.
if (this.I + 2 <= this.J)
{
- x = this.Buffer[this.I];
+ x = this.BufferAsInt[this.I];
this.I++;
this.UnreadableBytes = 1;
- if (x != JpegConstants.Markers.XFF)
+ if (x != JpegConstants.Markers.XFFInt)
{
return DecoderErrorCode.NoError;
}
- if (this.Buffer[this.I] != 0x00)
+ if (this.BufferAsInt[this.I] != 0x00)
{
return DecoderErrorCode.MissingFF00;
}
@@ -95,7 +113,7 @@ namespace ImageSharp.Formats.Jpg
this.UnreadableBytes = 0;
- DecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out x);
+ DecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 1;
if (errorCode != DecoderErrorCode.NoError)
{
@@ -107,7 +125,7 @@ namespace ImageSharp.Formats.Jpg
return DecoderErrorCode.NoError;
}
- errorCode = this.ReadByteUnsafe(inputStream, out x);
+ errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 2;
if (errorCode != DecoderErrorCode.NoError)
{
@@ -164,6 +182,25 @@ namespace ImageSharp.Formats.Jpg
return errorCode;
}
+ public DecoderErrorCode ReadByteAsIntUnsafe(Stream inputStream, out int result)
+ {
+ DecoderErrorCode errorCode = DecoderErrorCode.NoError;
+ while (this.I == this.J)
+ {
+ errorCode = this.FillUnsafe(inputStream);
+ if (errorCode != DecoderErrorCode.NoError)
+ {
+ result = 0;
+ return errorCode;
+ }
+ }
+
+ result = this.BufferAsInt[this.I];
+ this.I++;
+ this.UnreadableBytes = 0;
+ return errorCode;
+ }
+
///
/// Fills up the bytes buffer from the underlying stream.
/// It should only be called when there are no unread bytes in bytes.
@@ -211,6 +248,12 @@ namespace ImageSharp.Formats.Jpg
}
this.J += n;
+
+ for (int i = 0; i < this.Buffer.Length; i++)
+ {
+ this.BufferAsInt[i] = this.Buffer[i];
+ }
+
return DecoderErrorCode.NoError;
}
}
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
index 84f7579c8a..9ce5ea4146 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
@@ -81,6 +81,15 @@ namespace ImageSharp.Formats.Jpg
{
throw new ImageFormatException("Bad Huffman code!");
}
+
+ ///
+ /// Throws "Uninitialized Huffman table".
+ ///
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void UninitializedHuffmanTable()
+ {
+ throw new ImageFormatException("Uninitialized Huffman table");
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs
index e06d644a7f..55cf8c77f6 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs
@@ -45,7 +45,7 @@ namespace ImageSharp.Formats.Jpg
///
/// The log-2 size of the Huffman decoder's look-up table.
///
- public const int LutSize = 8;
+ public const int LutSizeLog2 = 8;
///
/// Gets or sets the number of codes in the tree.
@@ -58,13 +58,18 @@ namespace ImageSharp.Formats.Jpg
/// are 1 plus the code length, or 0 if the value is too large to fit in
/// lutSize bits.
///
- public ushort[] Lut;
+ public int[] Lut;
///
/// Gets the the decoded values, sorted by their encoding.
///
public byte[] Values;
+ ///
+ /// Same as , converted to int-s
+ ///
+ public int[] ValuesAsInt;
+
///
/// Gets the array of minimum codes.
/// MinCodes[i] is the minimum code of length i, or -1 if there are no codes of that length.
@@ -82,11 +87,11 @@ namespace ImageSharp.Formats.Jpg
///
public int[] Indices;
- private static readonly ArrayPool UshortBuffer = ArrayPool.Create(1 << LutSize, 50);
+ private static readonly ArrayPool IntBuffer256 = ArrayPool.Create(MaxNCodes, 50);
- private static readonly ArrayPool ByteBuffer = ArrayPool.Create(MaxNCodes, 50);
+ private static readonly ArrayPool ByteBuffer256 = ArrayPool.Create(MaxNCodes, 50);
- private static readonly ArrayPool IntBuffer = ArrayPool.Create(MaxCodeLength, 50);
+ private static readonly ArrayPool CodesBuffer16 = ArrayPool.Create(MaxCodeLength, 50);
///
/// Creates and initializes an array of instances of size
@@ -111,11 +116,12 @@ namespace ImageSharp.Formats.Jpg
///
public void Dispose()
{
- UshortBuffer.Return(this.Lut, true);
- ByteBuffer.Return(this.Values, true);
- IntBuffer.Return(this.MinCodes, true);
- IntBuffer.Return(this.MaxCodes, true);
- IntBuffer.Return(this.Indices, true);
+ IntBuffer256.Return(this.Lut, true);
+ IntBuffer256.Return(this.ValuesAsInt, true);
+ ByteBuffer256.Return(this.Values, true);
+ CodesBuffer16.Return(this.MinCodes, true);
+ CodesBuffer16.Return(this.MaxCodes, true);
+ CodesBuffer16.Return(this.Indices, true);
}
///
@@ -159,15 +165,20 @@ namespace ImageSharp.Formats.Jpg
decoder.ReadFull(this.Values, 0, this.Length);
+ for (int i = 0; i < this.Values.Length; i++)
+ {
+ this.ValuesAsInt[i] = this.Values[i];
+ }
+
// Derive the look-up table.
for (int i = 0; i < this.Lut.Length; i++)
{
this.Lut[i] = 0;
}
- uint x = 0, code = 0;
+ int x = 0, code = 0;
- for (int i = 0; i < LutSize; i++)
+ for (int i = 0; i < LutSizeLog2; i++)
{
code <<= 1;
@@ -178,8 +189,8 @@ namespace ImageSharp.Formats.Jpg
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
- byte base2 = (byte)(code << (7 - i));
- ushort lutValue = (ushort)((this.Values[x] << 8) | (2 + i));
+ int base2 = (code << (7 - i));
+ int lutValue = (this.ValuesAsInt[x] << 8) | (2 + i);
for (int k = 0; k < 1 << (7 - i); k++)
{
@@ -215,16 +226,22 @@ namespace ImageSharp.Formats.Jpg
}
}
+ public int GetValue(int code, int i)
+ {
+ return this.ValuesAsInt[this.Indices[i] + code - this.MinCodes[i]];
+ }
+
///
/// Initializes the Huffman tree
///
private void Init()
{
- this.Lut = UshortBuffer.Rent(1 << LutSize);
- this.Values = ByteBuffer.Rent(MaxNCodes);
- this.MinCodes = IntBuffer.Rent(MaxCodeLength);
- this.MaxCodes = IntBuffer.Rent(MaxCodeLength);
- this.Indices = IntBuffer.Rent(MaxCodeLength);
+ this.Lut = IntBuffer256.Rent(MaxNCodes);
+ this.Values = ByteBuffer256.Rent(MaxNCodes);
+ this.ValuesAsInt = IntBuffer256.Rent(MaxNCodes);
+ this.MinCodes = CodesBuffer16.Rent(MaxCodeLength);
+ this.MaxCodes = CodesBuffer16.Rent(MaxCodeLength);
+ this.Indices = CodesBuffer16.Rent(MaxCodeLength);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
index 4dcf6def8f..86c558af7b 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
@@ -85,7 +85,7 @@ namespace ImageSharp.Formats.Jpg
///
/// End-of-Band run, specified in section G.1.2.2.
///
- private ushort eobRun;
+ private int eobRun;
///
/// Pointers to elements of
@@ -349,7 +349,7 @@ namespace ImageSharp.Formats.Jpg
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
- byte value;
+ int value;
int huffmanIndex = (DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
errorCode = decoder.DecodeHuffmanUnsafe(
ref decoder.HuffmanTrees[huffmanIndex],
@@ -378,12 +378,12 @@ namespace ImageSharp.Formats.Jpg
// Decode the AC coefficients, as specified in section F.2.2.2.
for (; zig <= this.zigEnd; zig++)
{
- byte value;
+ int value;
errorCode = decoder.DecodeHuffmanUnsafe(ref decoder.HuffmanTrees[huffmannIdx], out value);
errorCode.EnsureNoEOF();
- byte val0 = (byte)(value >> 4);
- byte val1 = (byte)(value & 0x0f);
+ int val0 = value >> 4;
+ int val1 = value & 0x0f;
if (val1 != 0)
{
zig += val0;
@@ -424,14 +424,14 @@ namespace ImageSharp.Formats.Jpg
private DecoderErrorCode DecodeEobRun(int count, JpegDecoderCore decoder)
{
- uint bitsResult;
+ int bitsResult;
DecoderErrorCode errorCode = decoder.DecodeBitsUnsafe(count, out bitsResult);
if (errorCode != DecoderErrorCode.NoError)
{
return errorCode;
}
- this.eobRun |= (ushort)bitsResult;
+ this.eobRun |= bitsResult;
return DecoderErrorCode.NoError;
}
@@ -548,7 +548,7 @@ namespace ImageSharp.Formats.Jpg
bool done = false;
int z = 0;
- byte val;
+ int val;
DecoderErrorCode errorCode = decoder.DecodeHuffmanUnsafe(ref h, out val);
errorCode.EnsureNoEOF();
@@ -560,7 +560,7 @@ namespace ImageSharp.Formats.Jpg
case 0:
if (val0 != 0x0f)
{
- this.eobRun = (ushort)(1 << val0);
+ this.eobRun = 1 << val0;
if (val0 != 0)
{
errorCode = this.DecodeEobRun(val0, decoder);
diff --git a/src/ImageSharp.Formats.Jpeg/JpegConstants.cs b/src/ImageSharp.Formats.Jpeg/JpegConstants.cs
index 19d726e708..74f9a3c07d 100644
--- a/src/ImageSharp.Formats.Jpeg/JpegConstants.cs
+++ b/src/ImageSharp.Formats.Jpeg/JpegConstants.cs
@@ -86,6 +86,11 @@ namespace ImageSharp.Formats
///
public const byte XFF = 0xff;
+ ///
+ /// Same as but of type
+ ///
+ public const int XFFInt = XFF;
+
///
/// Start of Image
///
diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
index 1a039191e4..64f19a3a29 100644
--- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
@@ -307,7 +307,7 @@ namespace ImageSharp.Formats
/// The number of bits to decode.
/// The result
/// The
- public DecoderErrorCode DecodeBitsUnsafe(int count, out uint result)
+ public DecoderErrorCode DecodeBitsUnsafe(int count, out int result)
{
if (this.Bits.UnreadBits < count)
{
@@ -315,7 +315,7 @@ namespace ImageSharp.Formats
}
result = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
- result = (uint)(result & ((1 << count) - 1));
+ result = result & ((1 << count) - 1);
this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count;
return DecoderErrorCode.NoError;
@@ -327,14 +327,13 @@ namespace ImageSharp.Formats
/// The huffman value
/// The decoded
/// The
- public DecoderErrorCode DecodeHuffmanUnsafe(ref HuffmanTree huffmanTree, out byte result)
+ public DecoderErrorCode DecodeHuffmanUnsafe(ref HuffmanTree huffmanTree, out int result)
{
result = 0;
- // Copy stuff to the stack:
if (huffmanTree.Length == 0)
{
- throw new ImageFormatException("Uninitialized Huffman table");
+ DecoderThrowHelper.ThrowImageFormatException.UninitializedHuffmanTable();
}
if (this.Bits.UnreadBits < 8)
@@ -344,14 +343,15 @@ namespace ImageSharp.Formats
if (errorCode == DecoderErrorCode.NoError)
{
- ushort v = huffmanTree.Lut[(this.Bits.Accumulator >> (this.Bits.UnreadBits - HuffmanTree.LutSize)) & 0xFF];
+ int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - HuffmanTree.LutSizeLog2)) & 0xFF;
+ int v = huffmanTree.Lut[lutIndex];
if (v != 0)
{
int n = (v & 0xFF) - 1;
this.Bits.UnreadBits -= n;
this.Bits.Mask >>= n;
- result = (byte)(v >> 8);
+ result = v >> 8;
return errorCode;
}
}
@@ -380,7 +380,8 @@ namespace ImageSharp.Formats
if (code <= huffmanTree.MaxCodes[i])
{
- result = huffmanTree.Values[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
+ // ValuesAsInt[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
+ result = huffmanTree.GetValue(code, i);
return DecoderErrorCode.NoError;
}