예제 #1
0
        private int ReadHuffmanCode(int alphabetSize, int[] codeLengths, Span <HuffmanCode> table)
        {
            bool simpleCode = this.bitReader.ReadBit();

            for (int i = 0; i < alphabetSize; i++)
            {
                codeLengths[i] = 0;
            }

            if (simpleCode)
            {
                // (i) Simple Code Length Code.
                // This variant is used in the special case when only 1 or 2 Huffman code lengths are non-zero,
                // and are in the range of[0, 255]. All other Huffman code lengths are implicitly zeros.

                // Read symbols, codes & code lengths directly.
                uint numSymbols         = this.bitReader.ReadValue(1) + 1;
                uint firstSymbolLenCode = this.bitReader.ReadValue(1);

                // The first code is either 1 bit or 8 bit code.
                uint symbol = this.bitReader.ReadValue(firstSymbolLenCode == 0 ? 1 : 8);
                codeLengths[symbol] = 1;

                // The second code (if present), is always 8 bit long.
                if (numSymbols == 2)
                {
                    symbol = this.bitReader.ReadValue(8);
                    codeLengths[symbol] = 1;
                }
            }
            else
            {
                // (ii) Normal Code Length Code:
                // The code lengths of a Huffman code are read as follows: num_code_lengths specifies the number of code lengths;
                // the rest of the code lengths (according to the order in kCodeLengthCodeOrder) are zeros.
                int[] codeLengthCodeLengths = new int[NumCodeLengthCodes];
                uint  numCodes = this.bitReader.ReadValue(4) + 4;
                if (numCodes > NumCodeLengthCodes)
                {
                    WebpThrowHelper.ThrowImageFormatException("Bitstream error, numCodes has an invalid value");
                }

                for (int i = 0; i < numCodes; i++)
                {
                    codeLengthCodeLengths[CodeLengthCodeOrder[i]] = (int)this.bitReader.ReadValue(3);
                }

                this.ReadHuffmanCodeLengths(table, codeLengthCodeLengths, alphabetSize, codeLengths);
            }

            int size = HuffmanUtils.BuildHuffmanTable(table, HuffmanUtils.HuffmanTableBits, codeLengths, alphabetSize);

            return(size);
        }
예제 #2
0
        private void ReadHuffmanCodeLengths(Span <HuffmanCode> table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths)
        {
            int maxSymbol;
            int symbol      = 0;
            int prevCodeLen = WebpConstants.DefaultCodeLength;
            int size        = HuffmanUtils.BuildHuffmanTable(table, WebpConstants.LengthTableBits, codeLengthCodeLengths, NumCodeLengthCodes);

            if (size == 0)
            {
                WebpThrowHelper.ThrowImageFormatException("Error building huffman table");
            }

            if (this.bitReader.ReadBit())
            {
                int lengthNBits = 2 + (2 * (int)this.bitReader.ReadValue(3));
                maxSymbol = 2 + (int)this.bitReader.ReadValue(lengthNBits);
            }
            else
            {
                maxSymbol = numSymbols;
            }

            while (symbol < numSymbols)
            {
                if (maxSymbol-- == 0)
                {
                    break;
                }

                this.bitReader.FillBitWindow();
                ulong       prefetchBits = this.bitReader.PrefetchBits();
                int         idx          = (int)(prefetchBits & 127);
                HuffmanCode huffmanCode  = table[idx];
                this.bitReader.AdvanceBitPosition(huffmanCode.BitsUsed);
                uint codeLen = huffmanCode.Value;
                if (codeLen < WebpConstants.CodeLengthLiterals)
                {
                    codeLengths[symbol++] = (int)codeLen;
                    if (codeLen != 0)
                    {
                        prevCodeLen = (int)codeLen;
                    }
                }
                else
                {
                    bool usePrev      = codeLen == WebpConstants.CodeLengthRepeatCode;
                    uint slot         = codeLen - WebpConstants.CodeLengthLiterals;
                    int  extraBits    = WebpConstants.CodeLengthExtraBits[slot];
                    int  repeatOffset = WebpConstants.CodeLengthRepeatOffsets[slot];
                    int  repeat       = (int)(this.bitReader.ReadValue(extraBits) + repeatOffset);
                    if (symbol + repeat > numSymbols)
                    {
                        return;
                    }

                    int length = usePrev ? prevCodeLen : 0;
                    while (repeat-- > 0)
                    {
                        codeLengths[symbol++] = length;
                    }
                }
            }
        }