diff --git a/src/ImageSharp/Formats/Jpg/Components/Bits.cs b/src/ImageSharp/Formats/Jpg/Components/Bits.cs
index 68278e69bf..9bec6cd167 100644
--- a/src/ImageSharp/Formats/Jpg/Components/Bits.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/Bits.cs
@@ -3,6 +3,8 @@
// Licensed under the Apache License, Version 2.0.
//
+using System.Runtime.CompilerServices;
+
namespace ImageSharp.Formats
{
///
@@ -10,22 +12,88 @@ namespace ImageSharp.Formats
/// The n least significant bits of a form the unread bits, to be read in MSB to
/// LSB order.
///
- internal class Bits
+ internal struct Bits
{
///
/// Gets or sets the accumulator.
///
- public uint Accumulator { get; set; }
+ public uint Accumulator;
///
/// Gets or sets the mask.
/// 0, with mask==0 when unreadbits==0.]]>
///
- public uint Mask { get; set; }
+ public uint Mask;
///
/// Gets or sets the number of unread bits in the accumulator.
///
- public int UnreadBits { get; set; }
+ public int UnreadBits;
+
+
+ ///
+ /// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
+ /// least n. For best performance (avoiding function calls inside hot loops),
+ /// the caller is the one responsible for first checking that bits.UnreadBits < n.
+ ///
+ /// The number of bits to ensure.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal JpegDecoderCore.ErrorCodes EnsureNBits(int n, JpegDecoderCore decoder)
+ {
+ while (true)
+ {
+ JpegDecoderCore.ErrorCodes errorCode;
+
+ byte c = decoder.bytes.ReadByteStuffedByte(decoder.inputStream, out errorCode);
+
+ if (errorCode != JpegDecoderCore.ErrorCodes.NoError)
+ {
+ return errorCode;
+ }
+
+ Accumulator = (Accumulator << 8) | c;
+ UnreadBits += 8;
+ if (Mask == 0)
+ {
+ Mask = 1 << 7;
+ }
+ else
+ {
+ Mask <<= 8;
+ }
+
+ if (UnreadBits >= n)
+ {
+ return JpegDecoderCore.ErrorCodes.NoError;
+ //break;
+ }
+ }
+ }
+
+ internal int ReceiveExtend(byte t, JpegDecoderCore decoder)
+ {
+ if (UnreadBits < t)
+ {
+ var errorCode = EnsureNBits(t, decoder);
+ if (errorCode != JpegDecoderCore.ErrorCodes.NoError)
+ {
+ throw new JpegDecoderCore.MissingFF00Exception();
+ }
+ }
+
+ UnreadBits -= t;
+ Mask >>= t;
+ int s = 1 << t;
+ int x = (int)((Accumulator >> UnreadBits) & (s - 1));
+
+ if (x < (s >> 1))
+ {
+ x += ((-1) << t) + 1;
+ }
+
+ return x;
+ }
+
+
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
index 73d71b2829..4b9830aa73 100644
--- a/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
@@ -491,6 +491,19 @@ namespace ImageSharp.Formats
}
}
-
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe void UnZig(Block8x8F* block, Block8x8F* qt, int* unzigPtr)
+ {
+ float* b = (float*)block;
+ float* qtp = (float*)qt;
+ for (int zig = 0; zig < BlockF.BlockSize; zig++)
+ {
+ float* unzigPos = b + unzigPtr[zig];
+ float val = *unzigPos;
+ val *= qtp[zig];
+ *unzigPos = val;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpg/Components/Bytes.cs b/src/ImageSharp/Formats/Jpg/Components/Bytes.cs
index d4159e9963..3377b61558 100644
--- a/src/ImageSharp/Formats/Jpg/Components/Bytes.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/Bytes.cs
@@ -3,6 +3,11 @@
// Licensed under the Apache License, Version 2.0.
//
+using System;
+using System.Buffers;
+using System.IO;
+using System.Runtime.CompilerServices;
+
namespace ImageSharp.Formats
{
///
@@ -10,17 +15,27 @@ namespace ImageSharp.Formats
/// has to be able to unread more than 1 byte, due to byte stuffing.
/// Byte stuffing is specified in section F.1.2.3.
///
- internal class Bytes
+ internal struct Bytes : IDisposable
{
///
/// Initializes a new instance of the class.
///
- public Bytes()
+ //public Bytes()
+ //{
+ // this.Buffer = new byte[4096];
+ // this.I = 0;
+ // this.J = 0;
+ // this.UnreadableBytes = 0;
+ //}
+
+ private static readonly ArrayPool ArrayPool = ArrayPool.Create(4096, 50);
+
+ public static Bytes Create()
{
- this.Buffer = new byte[4096];
- this.I = 0;
- this.J = 0;
- this.UnreadableBytes = 0;
+ return new Bytes
+ {
+ Buffer = ArrayPool.Rent(4096)
+ };
}
///
@@ -28,16 +43,128 @@ namespace ImageSharp.Formats
/// buffer[i:j] are the buffered bytes read from the underlying
/// stream that haven't yet been passed further on.
///
- public byte[] Buffer { get; set; }
+ public byte[] Buffer;
- public int I { get; set; }
+ public int I;
- public int J { get; set; }
+ public int J;
///
/// Gets or sets the unreadable bytes. The number of bytes to back up i after
/// overshooting. It can be 0, 1 or 2.
///
- public int UnreadableBytes { get; set; }
+ public int UnreadableBytes;
+
+ public void Dispose()
+ {
+ if (Buffer!= null) ArrayPool.Return(Buffer);
+ Buffer = null;
+ }
+
+ ///
+ /// ReadByteStuffedByte is like ReadByte but is for byte-stuffed Huffman data.
+ ///
+ /// The
+ //[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal byte ReadByteStuffedByte(Stream inputStream, out JpegDecoderCore.ErrorCodes errorCode)
+ {
+ byte x;
+
+ errorCode = JpegDecoderCore.ErrorCodes.NoError;
+
+ // Take the fast path if bytes.buf contains at least two bytes.
+ if (this.I + 2 <= this.J)
+ {
+ x = this.Buffer[this.I];
+ this.I++;
+ this.UnreadableBytes = 1;
+ if (x != JpegConstants.Markers.XFF)
+ {
+ return x;
+ }
+
+ if (this.Buffer[this.I] != 0x00)
+ {
+ errorCode = JpegDecoderCore.ErrorCodes.MissingFF00;
+ return 0;
+ //throw new MissingFF00Exception();
+ }
+
+ this.I++;
+ this.UnreadableBytes = 2;
+ return JpegConstants.Markers.XFF;
+ }
+
+ this.UnreadableBytes = 0;
+
+ x = this.ReadByte(inputStream);
+ this.UnreadableBytes = 1;
+ if (x != JpegConstants.Markers.XFF)
+ {
+ return x;
+ }
+
+ x = this.ReadByte(inputStream);
+ this.UnreadableBytes = 2;
+ if (x != 0x00)
+ {
+ errorCode = JpegDecoderCore.ErrorCodes.MissingFF00;
+ return 0;
+ //throw new MissingFF00Exception();
+ }
+
+ return JpegConstants.Markers.XFF;
+ }
+
+ ///
+ /// Returns the next byte, whether buffered or not buffered. It does not care about byte stuffing.
+ ///
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal byte ReadByte(Stream inputStream)
+ {
+ while (this.I == this.J)
+ {
+ this.Fill(inputStream);
+ }
+
+ byte x = this.Buffer[this.I];
+ this.I++;
+ this.UnreadableBytes = 0;
+ return x;
+ }
+
+ ///
+ /// Fills up the bytes buffer from the underlying stream.
+ /// It should only be called when there are no unread bytes in bytes.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void Fill(Stream inputStream)
+ {
+ if (this.I != this.J)
+ {
+ throw new ImageFormatException("Fill called when unread bytes exist.");
+ }
+
+ // Move the last 2 bytes to the start of the buffer, in case we need
+ // to call UnreadByteStuffedByte.
+ if (this.J > 2)
+ {
+ this.Buffer[0] = this.Buffer[this.J - 2];
+ this.Buffer[1] = this.Buffer[this.J - 1];
+ this.I = 2;
+ this.J = 2;
+ }
+
+ // Fill in the rest of the buffer.
+ int n = inputStream.Read(this.Buffer, this.J, this.Buffer.Length - this.J);
+ if (n == 0)
+ {
+ throw new JpegDecoderCore.EOFException();
+ }
+
+ this.J += n;
+ }
+
}
}
diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
index a2a570aed4..e66d3ca219 100644
--- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace ImageSharp.Formats
{
@@ -107,7 +108,7 @@ namespace ImageSharp.Formats
///
/// The byte buffer.
///
- private readonly Bytes bytes;
+ internal Bytes bytes;
///
/// The image width
@@ -137,12 +138,12 @@ namespace ImageSharp.Formats
///
/// The input stream.
///
- private Stream inputStream;
+ internal Stream inputStream;
///
/// Holds the unprocessed bits that have been taken from the byte-stream.
///
- private Bits bits;
+ internal Bits bits;
///
/// The array of keyline pixels in a CMYK image
@@ -209,7 +210,7 @@ namespace ImageSharp.Formats
this.componentArray = new Component[MaxComponents];
this.progCoeffs = new Block8x8F[MaxComponents][];
this.bits = new Bits();
- this.bytes = new Bytes();
+ this.bytes = Bytes.Create();
// TODO: This looks like it could be static.
@@ -421,61 +422,7 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Missing SOS marker.");
}
}
-
- ///
- /// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
- /// least n. For best performance (avoiding function calls inside hot loops),
- /// the caller is the one responsible for first checking that bits.UnreadBits < n.
- ///
- /// The number of bits to ensure.
- private void EnsureNBits(int n)
- {
- while (true)
- {
- byte c = this.ReadByteStuffedByte();
- this.bits.Accumulator = (this.bits.Accumulator << 8) | c;
- this.bits.UnreadBits += 8;
- if (this.bits.Mask == 0)
- {
- this.bits.Mask = 1 << 7;
- }
- else
- {
- this.bits.Mask <<= 8;
- }
-
- if (this.bits.UnreadBits >= n)
- {
- break;
- }
- }
- }
-
- ///
- /// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
- ///
- /// The byte
- /// The
- private int ReceiveExtend(byte t)
- {
- if (this.bits.UnreadBits < t)
- {
- this.EnsureNBits(t);
- }
-
- this.bits.UnreadBits -= t;
- this.bits.Mask >>= t;
- int s = 1 << t;
- int x = (int)((this.bits.Accumulator >> this.bits.UnreadBits) & (s - 1));
-
- if (x < (s >> 1))
- {
- x += ((-1) << t) + 1;
- }
-
- return x;
- }
-
+
///
/// Processes a Define Huffman Table marker, and initializes a huffman
/// struct from its contents. Specified in section B.2.4.2.
@@ -604,6 +551,8 @@ namespace ImageSharp.Formats
/// The
private byte DecodeHuffman(ref Huffman huffman)
{
+ // Copy stuff to the stack:
+
if (huffman.Length == 0)
{
throw new ImageFormatException("Uninitialized Huffman table");
@@ -611,34 +560,35 @@ namespace ImageSharp.Formats
if (this.bits.UnreadBits < 8)
{
- try
- {
- this.EnsureNBits(8);
-
- ushort v = huffman.Lut[(this.bits.Accumulator >> (this.bits.UnreadBits - LutSize)) & 0xff];
+ //try
+ //{
+ var errorCode = bits.EnsureNBits(8, this);
- if (v != 0)
+ if (errorCode == ErrorCodes.NoError)
{
- byte n = (byte)((v & 0xff) - 1);
- this.bits.UnreadBits -= n;
- this.bits.Mask >>= n;
- return (byte)(v >> 8);
- }
- }
- catch (MissingFF00Exception)
- {
- if (this.bytes.UnreadableBytes != 0)
- {
- this.UnreadByteStuffedByte();
+ ushort v = huffman.Lut[(this.bits.Accumulator >> (this.bits.UnreadBits - LutSize)) & 0xff];
+
+ if (v != 0)
+ {
+ byte n = (byte)((v & 0xff) - 1);
+ this.bits.UnreadBits -= n;
+ this.bits.Mask >>= n;
+ return (byte)(v >> 8);
+ }
}
- }
- catch (ShortHuffmanDataException)
- {
- if (this.bytes.UnreadableBytes != 0)
+ else
{
this.UnreadByteStuffedByte();
}
- }
+
+ //}
+ //catch (ShortHuffmanDataException) // TODO: This is actually never thrown!
+ //{
+ // if (this.bytes.UnreadableBytes != 0)
+ // {
+ // this.UnreadByteStuffedByte();
+ // }
+ //}
}
int code = 0;
@@ -646,7 +596,11 @@ namespace ImageSharp.Formats
{
if (this.bits.UnreadBits == 0)
{
- this.EnsureNBits(1);
+ var errorCode = this.bits.EnsureNBits(1, this);
+ if (errorCode != ErrorCodes.NoError)
+ {
+ throw new MissingFF00Exception();
+ }
}
if ((this.bits.Accumulator & this.bits.Mask) != 0)
@@ -676,7 +630,11 @@ namespace ImageSharp.Formats
{
if (this.bits.UnreadBits == 0)
{
- this.EnsureNBits(1);
+ var errorCode = this.bits.EnsureNBits(1, this);
+ if (errorCode != ErrorCodes.NoError)
+ {
+ throw new MissingFF00Exception();
+ }
}
bool ret = (this.bits.Accumulator & this.bits.Mask) != 0;
@@ -694,7 +652,11 @@ namespace ImageSharp.Formats
{
if (this.bits.UnreadBits < count)
{
- this.EnsureNBits(count);
+ var errorCode = this.bits.EnsureNBits(count, this);
+ if (errorCode != ErrorCodes.NoError)
+ {
+ throw new MissingFF00Exception();
+ }
}
uint ret = this.bits.Accumulator >> (this.bits.UnreadBits - count);
@@ -708,32 +670,32 @@ namespace ImageSharp.Formats
/// Fills up the bytes buffer from the underlying stream.
/// It should only be called when there are no unread bytes in bytes.
///
- private void Fill()
- {
- if (this.bytes.I != this.bytes.J)
- {
- throw new ImageFormatException("Fill called when unread bytes exist.");
- }
-
- // Move the last 2 bytes to the start of the buffer, in case we need
- // to call UnreadByteStuffedByte.
- if (this.bytes.J > 2)
- {
- this.bytes.Buffer[0] = this.bytes.Buffer[this.bytes.J - 2];
- this.bytes.Buffer[1] = this.bytes.Buffer[this.bytes.J - 1];
- this.bytes.I = 2;
- this.bytes.J = 2;
- }
-
- // Fill in the rest of the buffer.
- int n = this.inputStream.Read(this.bytes.Buffer, this.bytes.J, this.bytes.Buffer.Length - this.bytes.J);
- if (n == 0)
- {
- throw new EOFException();
- }
-
- this.bytes.J += n;
- }
+ //private void Fill()
+ //{
+ // if (this.bytes.I != this.bytes.J)
+ // {
+ // throw new ImageFormatException("Fill called when unread bytes exist.");
+ // }
+
+ // // Move the last 2 bytes to the start of the buffer, in case we need
+ // // to call UnreadByteStuffedByte.
+ // if (this.bytes.J > 2)
+ // {
+ // this.bytes.Buffer[0] = this.bytes.Buffer[this.bytes.J - 2];
+ // this.bytes.Buffer[1] = this.bytes.Buffer[this.bytes.J - 1];
+ // this.bytes.I = 2;
+ // this.bytes.J = 2;
+ // }
+
+ // // Fill in the rest of the buffer.
+ // int n = this.inputStream.Read(this.bytes.Buffer, this.bytes.J, this.bytes.Buffer.Length - this.bytes.J);
+ // if (n == 0)
+ // {
+ // throw new EOFException();
+ // }
+
+ // this.bytes.J += n;
+ //}
///
/// Undoes the most recent ReadByteStuffedByte call,
@@ -754,70 +716,81 @@ namespace ImageSharp.Formats
}
}
+
///
/// Returns the next byte, whether buffered or not buffered. It does not care about byte stuffing.
///
/// The
- private byte ReadByte()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal byte ReadByte()
{
- while (this.bytes.I == this.bytes.J)
- {
- this.Fill();
- }
-
- byte x = this.bytes.Buffer[this.bytes.I];
- this.bytes.I++;
- this.bytes.UnreadableBytes = 0;
- return x;
+ return bytes.ReadByte(inputStream);
+ //while (this.bytes.I == this.bytes.J)
+ //{
+ // this.Fill();
+ //}
+
+ //byte x = this.bytes.Buffer[this.bytes.I];
+ //this.bytes.I++;
+ //this.bytes.UnreadableBytes = 0;
+ //return x;
}
+
+
///
/// ReadByteStuffedByte is like ReadByte but is for byte-stuffed Huffman data.
///
/// The
- private byte ReadByteStuffedByte()
- {
- byte x;
-
- // Take the fast path if bytes.buf contains at least two bytes.
- if (this.bytes.I + 2 <= this.bytes.J)
- {
- x = this.bytes.Buffer[this.bytes.I];
- this.bytes.I++;
- this.bytes.UnreadableBytes = 1;
- if (x != JpegConstants.Markers.XFF)
- {
- return x;
- }
-
- if (this.bytes.Buffer[this.bytes.I] != 0x00)
- {
- throw new MissingFF00Exception();
- }
-
- this.bytes.I++;
- this.bytes.UnreadableBytes = 2;
- return JpegConstants.Markers.XFF;
- }
-
- this.bytes.UnreadableBytes = 0;
-
- x = this.ReadByte();
- this.bytes.UnreadableBytes = 1;
- if (x != JpegConstants.Markers.XFF)
- {
- return x;
- }
-
- x = this.ReadByte();
- this.bytes.UnreadableBytes = 2;
- if (x != 0x00)
- {
- throw new MissingFF00Exception();
- }
-
- return JpegConstants.Markers.XFF;
- }
+ //internal byte ReadByteStuffedByte(out ErrorCodes errorCode)
+ //{
+ // byte x;
+
+ // errorCode = ErrorCodes.NoError;
+
+ // // Take the fast path if bytes.buf contains at least two bytes.
+ // if (this.bytes.I + 2 <= this.bytes.J)
+ // {
+ // x = this.bytes.Buffer[this.bytes.I];
+ // this.bytes.I++;
+ // this.bytes.UnreadableBytes = 1;
+ // if (x != JpegConstants.Markers.XFF)
+ // {
+ // return x;
+ // }
+
+ // if (this.bytes.Buffer[this.bytes.I] != 0x00)
+ // {
+ // errorCode = ErrorCodes.MissingFF00;
+ // return 0;
+ // //throw new MissingFF00Exception();
+ // }
+
+ // this.bytes.I++;
+ // this.bytes.UnreadableBytes = 2;
+ // return JpegConstants.Markers.XFF;
+ // }
+
+ // this.bytes.UnreadableBytes = 0;
+
+ // x = this.ReadByte();
+ // this.bytes.UnreadableBytes = 1;
+ // if (x != JpegConstants.Markers.XFF)
+ // {
+ // return x;
+ // }
+
+ // x = this.ReadByte();
+ // this.bytes.UnreadableBytes = 2;
+ // if (x != 0x00)
+ // {
+ // errorCode = ErrorCodes.MissingFF00;
+ // return 0;
+ // //throw new MissingFF00Exception();
+ // }
+
+ // return JpegConstants.Markers.XFF;
+ //}
///
/// Reads exactly length bytes into data. It does not care about byte stuffing.
@@ -832,7 +805,7 @@ namespace ImageSharp.Formats
{
if (this.bits.UnreadBits >= 8)
{
- this.UnreadByteStuffedByte();
+ UnreadByteStuffedByte();
}
this.bytes.UnreadableBytes = 0;
@@ -853,7 +826,7 @@ namespace ImageSharp.Formats
length -= this.bytes.J - this.bytes.I;
this.bytes.I += this.bytes.J - this.bytes.I;
- this.Fill();
+ this.bytes.Fill(inputStream);
}
}
}
@@ -890,7 +863,7 @@ namespace ImageSharp.Formats
break;
}
- this.Fill();
+ this.bytes.Fill(inputStream);
}
}
@@ -1401,6 +1374,7 @@ namespace ImageSharp.Formats
this.AssignResolution(image);
}
+
///
/// Converts the image from the original RBG image pixels.
///
@@ -1460,7 +1434,10 @@ namespace ImageSharp.Formats
}
}
- private BlockF scanWorkerBlock = BlockF.Create();
+ struct StackallocUnzigData
+ {
+ internal fixed int Data [64];
+ }
///
/// Processes the SOS (Start of scan marker).
@@ -1593,6 +1570,11 @@ namespace ImageSharp.Formats
Block8x8F temp1 = new Block8x8F();
Block8x8F temp2 = new Block8x8F();
+ // Tricky way to copy contents of the Unzig static variable to the stack:
+ StackallocUnzigData unzigOnStack = new StackallocUnzigData();
+ int* unzigPtr = unzigOnStack.Data;
+ Marshal.Copy(Unzig, 0, (IntPtr) unzigPtr, 64);
+
for (int my = 0; my < myy; my++)
{
for (int mx = 0; mx < mxx; mx++)
@@ -1648,11 +1630,13 @@ namespace ImageSharp.Formats
var qtIndex = this.componentArray[compIndex].Selector;
// TODO: Find a way to clean up this mess
+
fixed (Block8x8F* qtp = &this.quantizationTables[qtIndex])
{
- if (this.isProgressive) // Load the previous partially decoded coefficients, if applicable.
+ if (this.isProgressive)
+ // Load the previous partially decoded coefficients, if applicable.
{
- blockIndex = ((@by * mxx) * hi) + bx;
+ blockIndex = ((@by*mxx)*hi) + bx;
fixed (Block8x8F* bp = &this.progCoeffs[compIndex][blockIndex])
{
@@ -1660,6 +1644,7 @@ namespace ImageSharp.Formats
bp,
&temp1,
&temp2,
+ unzigPtr,
scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi, bx,
qtp
);
@@ -1668,16 +1653,19 @@ namespace ImageSharp.Formats
else
{
b.Clear();
- ProcessBlockImpl(ah,
- &b,
+ ProcessBlockImpl(ah,
+ &b,
&temp1,
&temp2,
+ unzigPtr,
scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi,
bx, qtp
- );
+ );
}
}
+
+
}
@@ -1725,14 +1713,16 @@ namespace ImageSharp.Formats
Block8x8F* b,
Block8x8F* temp1,
Block8x8F* temp2,
+ int* unzigPtr,
Scan[] scan,
int i, int zigStart, int zigEnd, int al,
int[] dc, int compIndex, int @by, int mxx, int hi, int bx,
Block8x8F* qt)
{
+ var huffmannIdx = AcTable * ThRowSize + scan[i].AcTableSelector;
if (ah != 0)
{
- this.Refine(b, ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector], zigStart, zigEnd, 1 << al);
+ this.Refine(b, ref this.huffmanTrees[huffmannIdx], unzigPtr, zigStart, zigEnd, 1 << al);
}
else
{
@@ -1748,7 +1738,7 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Excessive DC component");
}
- int deltaDC = this.ReceiveExtend(value);
+ int deltaDC = this.bits.ReceiveExtend(value, this);
dc[compIndex] += deltaDC;
//b[0] = dc[compIndex] << al;
@@ -1765,7 +1755,7 @@ namespace ImageSharp.Formats
//Huffman huffv = ;
for (; zig <= zigEnd; zig++)
{
- byte value = this.DecodeHuffman(ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector]);
+ byte value = this.DecodeHuffman(ref this.huffmanTrees[huffmannIdx]);
byte val0 = (byte)(value >> 4);
byte val1 = (byte)(value & 0x0f);
if (val1 != 0)
@@ -1776,10 +1766,10 @@ namespace ImageSharp.Formats
break;
}
- int ac = this.ReceiveExtend(val1);
+ int ac = this.bits.ReceiveExtend(val1, this);
//b[Unzig[zig]] = ac << al;
- Block8x8F.SetScalarAt(b, Unzig[zig], ac << al);
+ Block8x8F.SetScalarAt(b, unzigPtr[zig], ac << al);
}
else
{
@@ -1822,22 +1812,8 @@ namespace ImageSharp.Formats
}
// Dequantize, perform the inverse DCT and store the block to the image.
- for (int zig = 0; zig < BlockF.BlockSize; zig++)
- {
- // TODO: We really need the fancy new corefxlab Span here ...
- //b[Unzig[zig]] *= qt[zig];
-
- int unzigIdx = Unzig[zig];
- float value = Block8x8F.GetScalarAt(b, unzigIdx);
- value *= Block8x8F.GetScalarAt(qt, zig);
- Block8x8F.SetScalarAt(b, unzigIdx, value);
- }
-
- //IDCT.Transform(ref b);
- //FloatIDCT.Transform(ref b);
- //ReferenceDCT.IDCT(ref b);
- //Block8x8F.SuchIDCT(ref b);
- //b->IDCTInplace();
+ Block8x8F.UnZig(b, qt, unzigPtr);
+
b->IDCTInto(ref *temp1, ref *temp2);
byte[] dst;
@@ -1885,9 +1861,7 @@ namespace ImageSharp.Formats
}
// Level shift by +128, clip to [0, 255], and write to dst.
-
-
- //temp1->CopyColorsPlz(new MutableSpan(dst, offset), stride);
+
temp1->CopyColorsTo(new MutableSpan(dst, offset), stride, temp2);
}
@@ -1954,7 +1928,7 @@ namespace ImageSharp.Formats
/// The zig-zag start index
/// The zig-zag end index
/// The low transform offset
- private void Refine(Block8x8F* b, ref Huffman h, int zigStart, int zigEnd, int delta)
+ private void Refine(Block8x8F* b, ref Huffman h, int* unzigPtr, int zigStart, int zigEnd, int delta)
{
// Refining a DC component is trivial.
if (zigStart == 0)
@@ -2034,7 +2008,7 @@ namespace ImageSharp.Formats
if (z != 0)
{
//b[Unzig[zig]] = z;
- Block8x8F.SetScalarAt(b, Unzig[zig], z);
+ Block8x8F.SetScalarAt(b, unzigPtr[zig], z);
}
}
}
@@ -2256,10 +2230,21 @@ namespace ImageSharp.Formats
public byte AcTableSelector { get; set; }
}
+ ///
+ /// ReadByteStuffedByte was throwing exceptions on normal execution path (very inefficent)
+ /// It's better tho have an error code for this!
+ ///
+ internal enum ErrorCodes
+ {
+ NoError,
+ // ReSharper disable once InconsistentNaming
+ MissingFF00
+ }
+
///
/// The missing ff00 exception.
///
- private class MissingFF00Exception : Exception
+ internal class MissingFF00Exception : Exception
{
}
@@ -2274,18 +2259,17 @@ namespace ImageSharp.Formats
/// The EOF (End of File exception).
/// Thrown when the decoder encounters an EOF marker without a proceeding EOI (End Of Image) marker
///
- private class EOFException : Exception
+ internal class EOFException : Exception
{
}
public void Dispose()
{
- scanWorkerBlock.Dispose();
-
for (int i = 0; i < huffmanTrees.Length; i++)
{
huffmanTrees[i].Dispose();
}
+ bytes.Dispose();
}
}
}
diff --git a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
index 81ab5dcac3..75e00bc763 100644
--- a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
@@ -246,6 +246,7 @@ namespace ImageSharp.Formats
///
/// The AC luminance huffman table index
///
+
LuminanceAC = 1,
// ReSharper restore UnusedMember.Local
@@ -851,7 +852,6 @@ namespace ImageSharp.Formats
Block b = Block.Create();
Block cb = Block.Create();
Block cr = Block.Create();
-
// ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
@@ -884,7 +884,6 @@ namespace ImageSharp.Formats
Block b = Block.Create();
Block[] cb = Block.CreateArray(4);
Block[] cr = Block.CreateArray(4);
-
// ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;