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;