/// <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); }
/// <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); }
/// <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); }
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> /// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==1 /// </summary> /// <param name="inputProcessor">The <see cref="InputProcessor"/></param> /// <returns>A <see cref="DecoderErrorCode"/></returns> public DecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor) { return(this.EnsureBitsStepImpl(ref inputProcessor)); }
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); } }
/// <summary> /// Internal part of the DHT processor, whatever does it mean /// </summary> /// <param name="inputProcessor">The decoder instance</param> /// <param name="defineHuffmanTablesData">The temporal buffer that holds the data that has been read from the Jpeg stream</param> /// <param name="remaining">Remaining bits</param> public void ProcessDefineHuffmanTablesMarkerLoop( ref InputProcessor inputProcessor, byte[] defineHuffmanTablesData, ref int remaining) { // Read nCodes and huffman.Valuess (and derive h.Length). // nCodes[i] is the number of codes with code length i. // h.Length is the total number of codes. this.Length = 0; int[] ncodes = new int[MaxCodeLength]; for (int i = 0; i < ncodes.Length; i++) { ncodes[i] = defineHuffmanTablesData[i + 1]; this.Length += ncodes[i]; } if (this.Length == 0) { throw new ImageFormatException("Huffman table has zero length"); } if (this.Length > MaxNCodes) { throw new ImageFormatException("Huffman table has excessive length"); } remaining -= this.Length + 17; if (remaining < 0) { throw new ImageFormatException("DHT has wrong length"); } byte[] values = null; try { values = BytePool256.Rent(MaxNCodes); inputProcessor.ReadFull(values, 0, this.Length); for (int i = 0; i < values.Length; i++) { this.Values[i] = values[i]; } } finally { BytePool256.Return(values, true); } // Derive the look-up table. for (int i = 0; i < this.Lut.Length; i++) { this.Lut[i] = 0; } int x = 0, code = 0; for (int i = 0; i < LutSizeLog2; i++) { code <<= 1; for (int j = 0; j < ncodes[i]; j++) { // The codeLength is 1+i, so shift code by 8-(1+i) to // calculate the high bits for every 8-bit sequence // 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. int base2 = code << (7 - i); int lutValue = (this.Values[x] << 8) | (2 + i); for (int k = 0; k < 1 << (7 - i); k++) { this.Lut[base2 | k] = lutValue; } code++; x++; } } // Derive minCodes, maxCodes, and indices. int c = 0, index = 0; for (int i = 0; i < ncodes.Length; i++) { int nc = ncodes[i]; if (nc == 0) { this.MinCodes[i] = -1; this.MaxCodes[i] = -1; this.Indices[i] = -1; } else { this.MinCodes[i] = c; this.MaxCodes[i] = c + nc - 1; this.Indices[i] = index; c += nc; index += nc; } c <<= 1; } }