public static void EnsureNoEOF(this DecoderErrorCode errorCode) { if (errorCode == DecoderErrorCode.UnexpectedEndOfStream) { errorCode.ThrowExceptionForErrorCode(); } }
public void Skip(int count) { this.positionIndex += count; DecoderErrorCode errorCode = this.positionIndex >= this.InputStream.Length ? DecoderErrorCode.UnexpectedEndOfStream : DecoderErrorCode.NoError; errorCode.EnsureNoError(); }
public static void EnsureNoError(this DecoderErrorCode errorCode) { if (errorCode != DecoderErrorCode.NoError) { ThrowExceptionForErrorCode(errorCode); } }
/// <summary> /// Receive extend /// </summary> /// <param name="t">Byte</param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <param name="x">Read bits value</param> /// <returns>The <see cref="DecoderErrorCode"/></returns> public DecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x) { if (this.UnreadBits < t) { DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor); if (errorCode != DecoderErrorCode.NoError) { x = int.MaxValue; return(errorCode); } } this.UnreadBits -= t; this.Mask >>= t; int s = 1 << t; x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1)); if (x < (s >> 1)) { x += ((-1) << t) + 1; } return(DecoderErrorCode.NoError); }
public int ReceiveExtend(int t, ref InputProcessor inputProcessor) { int x; DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out x); errorCode.EnsureNoError(); return(x); }
public byte ReadByte(Stream inputStream) { byte result; DecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out result); errorCode.EnsureNoError(); return(result); }
/// <summary> /// If errorCode indicates unexpected EOF, sets <see cref="UnexpectedEndOfStreamReached"/> to true and returns false. /// Returns true otherwise. /// </summary> /// <param name="errorCode">The <see cref="DecoderErrorCode"/></param> /// <returns><see cref="bool"/> indicating whether everything is OK</returns> public bool CheckEOF(DecoderErrorCode errorCode) { if (errorCode == DecoderErrorCode.UnexpectedEndOfStream) { this.UnexpectedEndOfStreamReached = true; return(false); } return(true); }
/// <summary> /// ReadByteStuffedByte is like ReadByte but is for byte-stuffed Huffman data. /// </summary> /// <param name="inputStream">Input stream</param> /// <param name="x">The result byte as <see cref="int"/></param> /// <returns>The <see cref="DecoderErrorCode"/></returns> 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.BufferAsInt[this.I]; this.I++; this.UnreadableBytes = 1; if (x != JpegConstants.Markers.XFFInt) { return(DecoderErrorCode.NoError); } if (this.BufferAsInt[this.I] != 0x00) { return(DecoderErrorCode.MissingFF00); } this.I++; this.UnreadableBytes = 2; x = JpegConstants.Markers.XFF; return(DecoderErrorCode.NoError); } this.UnreadableBytes = 0; DecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x); this.UnreadableBytes = 1; if (errorCode != DecoderErrorCode.NoError) { return(errorCode); } if (x != JpegConstants.Markers.XFF) { return(DecoderErrorCode.NoError); } errorCode = this.ReadByteAsIntUnsafe(inputStream, out x); this.UnreadableBytes = 2; if (errorCode != DecoderErrorCode.NoError) { return(errorCode); } if (x != 0x00) { return(DecoderErrorCode.MissingFF00); } x = JpegConstants.Markers.XFF; return(DecoderErrorCode.NoError); }
/// <summary> /// 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. /// This method does not throw. Returns <see cref="DecoderErrorCode"/> instead. /// </summary> /// <param name="n">The number of bits to ensure.</param> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <returns>Error code</returns> public DecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor) { while (true) { DecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor); if (errorCode != DecoderErrorCode.NoError || this.UnreadBits >= n) { return(errorCode); } } }
private DecoderErrorCode DecodeEobRun(int count, ref InputProcessor decoder) { int bitsResult; DecoderErrorCode errorCode = decoder.DecodeBitsUnsafe(count, out bitsResult); if (errorCode != DecoderErrorCode.NoError) { return(errorCode); } this.eobRun |= bitsResult; return(DecoderErrorCode.NoError); }
public Span <byte> ReadFull(int offset, int length) { DecoderErrorCode errorCode = DecoderErrorCode.NoError; if (this.InputStream.Length < this.positionIndex + offset + length) { errorCode = DecoderErrorCode.UnexpectedEndOfStream; } errorCode.EnsureNoError(); Span <byte> span = this.InputStream.Slice(this.positionIndex + offset, length); this.positionIndex += length; return(span); }
/// <summary> /// Refines non-zero entries of b in zig-zag order. /// If <paramref name="nz" /> >= 0, the first <paramref name="nz" /> zero entries are skipped over. /// </summary> /// <param name="bp">The <see cref="InputProcessor"/></param> /// <param name="zig">The zig-zag start index</param> /// <param name="nz">The non-zero entry</param> /// <param name="delta">The low transform offset</param> /// <returns>The <see cref="int" /></returns> private int RefineNonZeroes(ref InputProcessor bp, int zig, int nz, int delta) { var b = this.pointers.Block; for (; zig <= this.zigEnd; zig++) { int u = this.pointers.Unzig[zig]; float bu = Block8x8F.GetScalarAt(b, u); // TODO: Are the equality comparsions OK with floating point values? Isn't an epsilon value necessary? if (bu == 0) { if (nz == 0) { break; } nz--; continue; } bool bit; DecoderErrorCode errorCode = bp.DecodeBitUnsafe(out bit); if (!bp.CheckEOFEnsureNoError(errorCode)) { return(int.MinValue); } if (!bit) { continue; } if (bu >= 0) { // b[u] += delta; Block8x8F.SetScalarAt(b, u, bu + delta); } else { // b[u] -= delta; Block8x8F.SetScalarAt(b, u, bu - delta); } } return(zig); }
public static void ThrowExceptionForErrorCode(this DecoderErrorCode errorCode) { switch (errorCode) { case DecoderErrorCode.NoError: throw new ArgumentException("ThrowExceptionForErrorCode() called with NoError!", nameof(errorCode)); case DecoderErrorCode.MissingFF00: throw new MissingFF00Exception(); case DecoderErrorCode.UnexpectedEndOfStream: throw new EOFException(); default: throw new ArgumentOutOfRangeException(nameof(errorCode), errorCode, null); } }
/// <summary> /// Decodes a single bit /// TODO: This method (and also the usages) could be optimized by batching! /// </summary> /// <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) { DecoderErrorCode errorCode = this.Bits.Ensure1BitUnsafe(ref this); if (errorCode != DecoderErrorCode.NoError) { result = false; return(errorCode); } } result = (this.Bits.Accumulator & this.Bits.Mask) != 0; this.Bits.UnreadBits--; this.Bits.Mask >>= 1; return(DecoderErrorCode.NoError); }
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); }
private DecoderErrorCode EnsureBitsStepImpl(ref InputProcessor inputProcessor) { int c; DecoderErrorCode errorCode = inputProcessor.Bytes.ReadByteStuffedByteUnsafe(inputProcessor.InputStream, out c); if (errorCode != DecoderErrorCode.NoError) { return(errorCode); } this.Accumulator = (this.Accumulator << 8) | c; this.UnreadBits += 8; if (this.Mask == 0) { this.Mask = 1 << 7; } else { this.Mask <<= 8; } return(errorCode); }
/// <summary> /// Skips the next n bytes. /// Does not throw, returns <see cref="DecoderErrorCode"/> instead! /// </summary> /// <param name="count">The number of bytes to ignore.</param> /// <returns>The <see cref="DecoderErrorCode"/></returns> public DecoderErrorCode SkipUnsafe(int count) { // Unread the overshot bytes, if any. if (this.Bytes.UnreadableBytes != 0) { if (this.Bits.UnreadBits >= 8) { this.UnreadByteStuffedByte(); } this.Bytes.UnreadableBytes = 0; } while (true) { int m = this.Bytes.J - this.Bytes.I; if (m > count) { m = count; } this.Bytes.I += m; count -= m; if (count == 0) { break; } DecoderErrorCode errorCode = this.Bytes.FillUnsafe(this.InputStream); if (errorCode != DecoderErrorCode.NoError) { return(errorCode); } } return(DecoderErrorCode.NoError); }
/// <summary> /// Reads exactly length bytes into data. It does not care about byte stuffing. /// Does not throw on errors, returns <see cref="JpegDecoderCore"/> instead! /// </summary> /// <param name="data">The data to write to.</param> /// <param name="offset">The offset in the source buffer</param> /// <param name="length">The number of bytes to read</param> /// <returns>The <see cref="DecoderErrorCode"/></returns> public DecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length) { // Unread the overshot bytes, if any. if (this.Bytes.UnreadableBytes != 0) { if (this.Bits.UnreadBits >= 8) { this.UnreadByteStuffedByte(); } this.Bytes.UnreadableBytes = 0; } DecoderErrorCode errorCode = DecoderErrorCode.NoError; while (length > 0) { if (this.Bytes.J - this.Bytes.I >= length) { Array.Copy(this.Bytes.Buffer, this.Bytes.I, data, offset, length); this.Bytes.I += length; length -= length; } else { Array.Copy(this.Bytes.Buffer, this.Bytes.I, data, offset, this.Bytes.J - this.Bytes.I); offset += this.Bytes.J - this.Bytes.I; length -= this.Bytes.J - this.Bytes.I; this.Bytes.I += this.Bytes.J - this.Bytes.I; errorCode = this.Bytes.FillUnsafe(this.InputStream); } } return(errorCode); }
public void EnsureNBits(int n, ref InputProcessor inputProcessor) { DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor); errorCode.EnsureNoError(); }
/// <summary> /// Decodes a successive approximation refinement block, as specified in section G.1.2. /// </summary> /// <param name="bp">The <see cref="InputProcessor"/> instance</param> /// <param name="h">The Huffman tree</param> /// <param name="delta">The low transform offset</param> private void Refine(ref InputProcessor bp, ref HuffmanTree h, int delta) { Block8x8F *b = this.pointers.Block; // Refining a DC component is trivial. if (this.zigStart == 0) { if (this.zigEnd != 0) { throw new ImageFormatException("Invalid state for zig DC component"); } bool bit; DecoderErrorCode errorCode = bp.DecodeBitUnsafe(out bit); if (!bp.CheckEOFEnsureNoError(errorCode)) { return; } if (bit) { int stuff = (int)Block8x8F.GetScalarAt(b, 0); // int stuff = (int)b[0]; stuff |= delta; // b[0] = stuff; Block8x8F.SetScalarAt(b, 0, stuff); } return; } // Refining AC components is more complicated; see sections G.1.2.2 and G.1.2.3. int zig = this.zigStart; if (this.eobRun == 0) { for (; zig <= this.zigEnd; zig++) { bool done = false; int z = 0; int val; DecoderErrorCode errorCode = bp.DecodeHuffmanUnsafe(ref h, out val); if (!bp.CheckEOF(errorCode)) { return; } int val0 = val >> 4; int val1 = val & 0x0f; switch (val1) { case 0: if (val0 != 0x0f) { this.eobRun = 1 << val0; if (val0 != 0) { errorCode = this.DecodeEobRun(val0, ref bp); if (!bp.CheckEOFEnsureNoError(errorCode)) { return; } } done = true; } break; case 1: z = delta; bool bit; errorCode = bp.DecodeBitUnsafe(out bit); if (!bp.CheckEOFEnsureNoError(errorCode)) { return; } if (!bit) { z = -z; } break; default: throw new ImageFormatException("Unexpected Huffman code"); } if (done) { break; } zig = this.RefineNonZeroes(ref bp, zig, val0, delta); if (bp.UnexpectedEndOfStreamReached) { return; } if (zig > this.zigEnd) { throw new ImageFormatException($"Too many coefficients {zig} > {this.zigEnd}"); } if (z != 0) { // b[Unzig[zig]] = z; Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], z); } } } if (this.eobRun > 0) { this.eobRun--; this.RefineNonZeroes(ref bp, zig, -1, delta); } }
public void Skip(int count) { DecoderErrorCode errorCode = this.SkipUnsafe(count); errorCode.EnsureNoError(); }
public void Fill(Stream inputStream) { DecoderErrorCode errorCode = this.FillUnsafe(inputStream); errorCode.EnsureNoError(); }
public void ReadFull(byte[] data, int offset, int length) { DecoderErrorCode errorCode = this.ReadFullUnsafe(data, offset, length); errorCode.EnsureNoError(); }
/// <summary> /// 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> /// <param name="result">The decoded <see cref="byte" /></param> /// <returns>The <see cref="DecoderErrorCode"/></returns> public DecoderErrorCode DecodeHuffmanUnsafe(ref HuffmanTree huffmanTree, out int result) { result = 0; if (huffmanTree.Length == 0) { DecoderThrowHelper.ThrowImageFormatException.UninitializedHuffmanTable(); } if (this.Bits.UnreadBits < 8) { DecoderErrorCode errorCode = this.Bits.Ensure8BitsUnsafe(ref this); if (errorCode == DecoderErrorCode.NoError) { 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 = v >> 8; return(errorCode); } } else { this.UnreadByteStuffedByte(); return(errorCode); } } int code = 0; for (int i = 0; i < HuffmanTree.MaxCodeLength; i++) { if (this.Bits.UnreadBits == 0) { this.Bits.EnsureNBits(1, ref this); } if ((this.Bits.Accumulator & this.Bits.Mask) != 0) { code |= 1; } this.Bits.UnreadBits--; this.Bits.Mask >>= 1; if (code <= huffmanTree.MaxCodes[i]) { result = huffmanTree.GetValue(code, i); return(DecoderErrorCode.NoError); } code <<= 1; } // Unrecoverable error, throwing: DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode(); // DUMMY RETURN! C# doesn't know we have thrown an exception! return(DecoderErrorCode.NoError); }
/// <summary> /// Read Huffman data from Jpeg scans in <see cref="JpegDecoderCore.InputStream"/>, /// and decode it as <see cref="Block8x8F"/> into <see cref="JpegDecoderCore.DecodedBlocks"/>. /// /// The blocks are traversed one MCU at a time. For 4:2:0 chroma /// subsampling, there are four Y 8x8 blocks in every 16x16 MCU. /// For a baseline 32x16 pixel image, the Y blocks visiting order is: /// 0 1 4 5 /// 2 3 6 7 /// For progressive images, the interleaved scans (those with component count > 1) /// are traversed as above, but non-interleaved scans are traversed left /// to right, top to bottom: /// 0 1 2 3 /// 4 5 6 7 /// Only DC scans (zigStart == 0) can be interleave AC scans must have /// only one component. /// To further complicate matters, for non-interleaved scans, there is no /// data for any blocks that are inside the image at the MCU level but /// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0 /// progressive image consists of two 16x16 MCUs. The interleaved scans /// will process 8 Y blocks: /// 0 1 4 5 /// 2 3 6 7 /// The non-interleaved scans will process only 6 Y blocks: /// 0 1 2 /// 3 4 5 /// </summary> /// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param> public void DecodeBlocks(JpegDecoderCore decoder) { int blockCount = 0; int mcu = 0; byte expectedRst = JpegConstants.Markers.RST0; for (int my = 0; my < decoder.MCUCountY; my++) { for (int mx = 0; mx < decoder.MCUCountX; mx++) { for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++) { this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex; this.hi = decoder.ComponentArray[this.ComponentIndex].HorizontalFactor; int vi = decoder.ComponentArray[this.ComponentIndex].VerticalFactor; for (int j = 0; j < this.hi * vi; j++) { if (this.componentScanCount != 1) { this.bx = (this.hi * mx) + (j % this.hi); this.by = (vi * my) + (j / this.hi); } else { int q = decoder.MCUCountX * this.hi; this.bx = blockCount % q; this.by = blockCount / q; blockCount++; if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight) { continue; } } // Take an existing block (required when progressive): int blockIndex = this.GetBlockIndex(decoder); this.data.Block = decoder.DecodedBlocks[this.ComponentIndex].Buffer[blockIndex].Block; if (!decoder.InputProcessor.UnexpectedEndOfStreamReached) { this.DecodeBlock(decoder, scanIndex); } // Store the decoded block DecodedBlockArray blocks = decoder.DecodedBlocks[this.ComponentIndex]; blocks.Buffer[blockIndex].SaveBlock(this.bx, this.by, ref this.data.Block); } // for j } // for i mcu++; if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < decoder.TotalMCUCount) { // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input, // but this one assumes well-formed input, and hence the restart marker follows immediately. if (!decoder.InputProcessor.UnexpectedEndOfStreamReached) { DecoderErrorCode errorCode = decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2); if (decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) { if (decoder.Temp[0] != 0xff || decoder.Temp[1] != expectedRst) { throw new ImageFormatException("Bad RST marker"); } expectedRst++; if (expectedRst == JpegConstants.Markers.RST7 + 1) { expectedRst = JpegConstants.Markers.RST0; } } } // Reset the Huffman decoder. decoder.InputProcessor.Bits = default(Bits); // Reset the DC components, as per section F.2.1.3.1. this.ResetDc(); // Reset the progressive decoder state, as per section G.1.2.2. this.eobRun = 0; } } // for mx } }