コード例 #1
0
 public static void EnsureNoEOF(this DecoderErrorCode errorCode)
 {
     if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
     {
         errorCode.ThrowExceptionForErrorCode();
     }
 }
コード例 #2
0
        public void Skip(int count)
        {
            this.positionIndex += count;
            DecoderErrorCode errorCode = this.positionIndex >= this.InputStream.Length ? DecoderErrorCode.UnexpectedEndOfStream : DecoderErrorCode.NoError;

            errorCode.EnsureNoError();
        }
コード例 #3
0
 public static void EnsureNoError(this DecoderErrorCode errorCode)
 {
     if (errorCode != DecoderErrorCode.NoError)
     {
         ThrowExceptionForErrorCode(errorCode);
     }
 }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
        public int ReceiveExtend(int t, ref InputProcessor inputProcessor)
        {
            int x;
            DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out x);

            errorCode.EnsureNoError();
            return(x);
        }
コード例 #6
0
        public byte ReadByte(Stream inputStream)
        {
            byte             result;
            DecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out result);

            errorCode.EnsureNoError();
            return(result);
        }
コード例 #7
0
        /// <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);
        }
コード例 #8
0
        /// <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);
        }
コード例 #9
0
 /// <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 &lt; 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);
         }
     }
 }
コード例 #10
0
        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);
        }
コード例 #11
0
        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);
        }
コード例 #12
0
        /// <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);
        }
コード例 #13
0
        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);
            }
        }
コード例 #14
0
        /// <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);
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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);
        }
コード例 #17
0
        /// <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);
        }
コード例 #18
0
        /// <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);
        }
コード例 #19
0
        public void EnsureNBits(int n, ref InputProcessor inputProcessor)
        {
            DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);

            errorCode.EnsureNoError();
        }
コード例 #20
0
        /// <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);
            }
        }
コード例 #21
0
        public void Skip(int count)
        {
            DecoderErrorCode errorCode = this.SkipUnsafe(count);

            errorCode.EnsureNoError();
        }
コード例 #22
0
        public void Fill(Stream inputStream)
        {
            DecoderErrorCode errorCode = this.FillUnsafe(inputStream);

            errorCode.EnsureNoError();
        }
コード例 #23
0
        public void ReadFull(byte[] data, int offset, int length)
        {
            DecoderErrorCode errorCode = this.ReadFullUnsafe(data, offset, length);

            errorCode.EnsureNoError();
        }
コード例 #24
0
        /// <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);
        }
コード例 #25
0
        /// <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 &gt; 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
            }
        }