/// <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> /// 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> /// Decodes a successive approximation refinement block, as specified in section G.1.2. /// </summary> /// <param name="decoder">The decoder instance</param> /// <param name="h">The Huffman tree</param> /// <param name="delta">The low transform offset</param> private void Refine(JpegDecoderCore decoder, 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 = decoder.DecodeBit(); 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; byte val = decoder.DecodeHuffman(ref h); int val0 = val >> 4; int val1 = val & 0x0f; switch (val1) { case 0: if (val0 != 0x0f) { this.eobRun = (ushort)(1 << val0); if (val0 != 0) { this.eobRun |= (ushort)decoder.DecodeBits(val0); } done = true; } break; case 1: z = delta; bool bit = decoder.DecodeBit(); if (!bit) { z = -z; } break; default: throw new ImageFormatException("Unexpected Huffman code"); } if (done) { break; } zig = this.RefineNonZeroes(decoder, zig, val0, delta); 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(decoder, zig, -1, delta); } }