Esempio n. 1
0
        /// <summary>
        /// Stores code in table[0], table[step], table[2*step], ..., table[end-step].
        /// Assumes that end is an integer multiple of step.
        /// </summary>
        private static void ReplicateValue(Span <HuffmanCode> table, int step, int end, HuffmanCode code)
        {
            DebugGuard.IsTrue(end % step == 0, nameof(end), "end must be a multiple of step");

            do
            {
                end       -= step;
                table[end] = code;
            }while (end > 0);
        }
Esempio n. 2
0
        private uint ReadPackedSymbols(Span <HTreeGroup> group, Span <uint> pixelData, int decodedPixels)
        {
            uint        val  = (uint)(this.bitReader.PrefetchBits() & (HuffmanUtils.HuffmanPackedTableSize - 1));
            HuffmanCode code = group[0].PackedTable[val];

            if (code.BitsUsed < BitsSpecialMarker)
            {
                this.bitReader.AdvanceBitPosition(code.BitsUsed);
                pixelData[decodedPixels] = code.Value;
                return(PackedNonLiteralCode);
            }

            this.bitReader.AdvanceBitPosition(code.BitsUsed - BitsSpecialMarker);

            return(code.Value);
        }
Esempio n. 3
0
 private void BuildPackedTable(HTreeGroup hTreeGroup)
 {
     for (uint code = 0; code < HuffmanUtils.HuffmanPackedTableSize; code++)
     {
         uint            bits  = code;
         ref HuffmanCode huff  = ref hTreeGroup.PackedTable[bits];
         HuffmanCode     hCode = hTreeGroup.HTrees[HuffIndex.Green][bits];
         if (hCode.Value >= WebpConstants.NumLiteralCodes)
         {
             huff.BitsUsed = hCode.BitsUsed + BitsSpecialMarker;
             huff.Value    = hCode.Value;
         }
         else
         {
             huff.BitsUsed = 0;
             huff.Value    = 0;
             bits        >>= AccumulateHCode(hCode, 8, ref huff);
             bits        >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Red][bits], 16, ref huff);
             bits        >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Blue][bits], 0, ref huff);
             bits        >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Alpha][bits], 24, ref huff);
         }
     }
Esempio n. 4
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;
                    }
                }
            }
        }
Esempio n. 5
0
        private void ReadHuffmanCodes(Vp8LDecoder decoder, int xSize, int ySize, int colorCacheBits, bool allowRecursion)
        {
            int maxAlphabetSize   = 0;
            int numHTreeGroups    = 1;
            int numHTreeGroupsMax = 1;

            // If the next bit is zero, there is only one meta Huffman code used everywhere in the image. No more data is stored.
            // If this bit is one, the image uses multiple meta Huffman codes. These meta Huffman codes are stored as an entropy image.
            if (allowRecursion && this.bitReader.ReadBit())
            {
                // Use meta Huffman codes.
                int huffmanPrecision = (int)(this.bitReader.ReadValue(3) + 2);
                int huffmanXSize     = LosslessUtils.SubSampleSize(xSize, huffmanPrecision);
                int huffmanYSize     = LosslessUtils.SubSampleSize(ySize, huffmanPrecision);
                int huffmanPixels    = huffmanXSize * huffmanYSize;

                IMemoryOwner <uint> huffmanImage     = this.DecodeImageStream(decoder, huffmanXSize, huffmanYSize, false);
                Span <uint>         huffmanImageSpan = huffmanImage.GetSpan();
                decoder.Metadata.HuffmanSubSampleBits = huffmanPrecision;

                // TODO: Isn't huffmanPixels the length of the span?
                for (int i = 0; i < huffmanPixels; i++)
                {
                    // The huffman data is stored in red and green bytes.
                    uint group = (huffmanImageSpan[i] >> 8) & 0xffff;
                    huffmanImageSpan[i] = group;
                    if (group >= numHTreeGroupsMax)
                    {
                        numHTreeGroupsMax = (int)group + 1;
                    }
                }

                numHTreeGroups = numHTreeGroupsMax;
                decoder.Metadata.HuffmanImage = huffmanImage;
            }

            // Find maximum alphabet size for the hTree group.
            for (int j = 0; j < WebpConstants.HuffmanCodesPerMetaCode; j++)
            {
                int alphabetSize = WebpConstants.AlphabetSize[j];
                if (j == 0 && colorCacheBits > 0)
                {
                    alphabetSize += 1 << colorCacheBits;
                }

                if (maxAlphabetSize < alphabetSize)
                {
                    maxAlphabetSize = alphabetSize;
                }
            }

            int tableSize     = TableSize[colorCacheBits];
            var huffmanTables = new HuffmanCode[numHTreeGroups * tableSize];
            var hTreeGroups   = new HTreeGroup[numHTreeGroups];
            Span <HuffmanCode> huffmanTable = huffmanTables.AsSpan();

            int[] codeLengths = new int[maxAlphabetSize];
            for (int i = 0; i < numHTreeGroupsMax; i++)
            {
                hTreeGroups[i] = new HTreeGroup(HuffmanUtils.HuffmanPackedTableSize);
                HTreeGroup hTreeGroup       = hTreeGroups[i];
                int        totalSize        = 0;
                bool       isTrivialLiteral = true;
                int        maxBits          = 0;
                codeLengths.AsSpan().Clear();
                for (int j = 0; j < WebpConstants.HuffmanCodesPerMetaCode; j++)
                {
                    int alphabetSize = WebpConstants.AlphabetSize[j];
                    if (j == 0 && colorCacheBits > 0)
                    {
                        alphabetSize += 1 << colorCacheBits;
                    }

                    int size = this.ReadHuffmanCode(alphabetSize, codeLengths, huffmanTable);
                    if (size == 0)
                    {
                        WebpThrowHelper.ThrowImageFormatException("Huffman table size is zero");
                    }

                    // TODO: Avoid allocation.
                    hTreeGroup.HTrees.Add(huffmanTable.Slice(0, size).ToArray());

                    HuffmanCode huffTableZero = huffmanTable[0];
                    if (isTrivialLiteral && LiteralMap[j] == 1)
                    {
                        isTrivialLiteral = huffTableZero.BitsUsed == 0;
                    }

                    totalSize   += huffTableZero.BitsUsed;
                    huffmanTable = huffmanTable.Slice(size);

                    if (j <= HuffIndex.Alpha)
                    {
                        int localMaxBits = codeLengths[0];
                        int k;
                        for (k = 1; k < alphabetSize; ++k)
                        {
                            int codeLengthK = codeLengths[k];
                            if (codeLengthK > localMaxBits)
                            {
                                localMaxBits = codeLengthK;
                            }
                        }

                        maxBits += localMaxBits;
                    }
                }

                hTreeGroup.IsTrivialLiteral = isTrivialLiteral;
                hTreeGroup.IsTrivialCode    = false;
                if (isTrivialLiteral)
                {
                    uint red   = hTreeGroup.HTrees[HuffIndex.Red][0].Value;
                    uint blue  = hTreeGroup.HTrees[HuffIndex.Blue][0].Value;
                    uint green = hTreeGroup.HTrees[HuffIndex.Green][0].Value;
                    uint alpha = hTreeGroup.HTrees[HuffIndex.Alpha][0].Value;
                    hTreeGroup.LiteralArb = (alpha << 24) | (red << 16) | blue;
                    if (totalSize == 0 && green < WebpConstants.NumLiteralCodes)
                    {
                        hTreeGroup.IsTrivialCode = true;
                        hTreeGroup.LiteralArb   |= green << 8;
                    }
                }

                hTreeGroup.UsePackedTable = !hTreeGroup.IsTrivialCode && maxBits < HuffmanUtils.HuffmanPackedBits;
                if (hTreeGroup.UsePackedTable)
                {
                    this.BuildPackedTable(hTreeGroup);
                }
            }

            decoder.Metadata.NumHTreeGroups = numHTreeGroups;
            decoder.Metadata.HTreeGroups    = hTreeGroups;
            decoder.Metadata.HuffmanTables  = huffmanTables;
        }
Esempio n. 6
0
        public static int BuildHuffmanTable(Span <HuffmanCode> table, int rootBits, int[] codeLengths, int codeLengthsSize)
        {
            DebugGuard.MustBeGreaterThan(rootBits, 0, nameof(rootBits));
            DebugGuard.NotNull(codeLengths, nameof(codeLengths));
            DebugGuard.MustBeGreaterThan(codeLengthsSize, 0, nameof(codeLengthsSize));

            // sorted[codeLengthsSize] is a pre-allocated array for sorting symbols by code length.
            int[] sorted    = new int[codeLengthsSize];
            int   totalSize = 1 << rootBits;                                 // total size root table + 2nd level table.
            int   len;                                                       // current code length.
            int   symbol;                                                    // symbol index in original or sorted table.

            int[] counts  = new int[WebpConstants.MaxAllowedCodeLength + 1]; // number of codes of each length.
            int[] offsets = new int[WebpConstants.MaxAllowedCodeLength + 1]; // offsets in sorted table for each length.

            // Build histogram of code lengths.
            for (symbol = 0; symbol < codeLengthsSize; ++symbol)
            {
                int codeLengthOfSymbol = codeLengths[symbol];
                if (codeLengthOfSymbol > WebpConstants.MaxAllowedCodeLength)
                {
                    return(0);
                }

                counts[codeLengthOfSymbol]++;
            }

            // Error, all code lengths are zeros.
            if (counts[0] == codeLengthsSize)
            {
                return(0);
            }

            // Generate offsets into sorted symbol table by code length.
            offsets[1] = 0;
            for (len = 1; len < WebpConstants.MaxAllowedCodeLength; ++len)
            {
                int codesOfLength = counts[len];
                if (codesOfLength > 1 << len)
                {
                    return(0);
                }

                offsets[len + 1] = offsets[len] + codesOfLength;
            }

            // Sort symbols by length, by symbol order within each length.
            for (symbol = 0; symbol < codeLengthsSize; ++symbol)
            {
                int symbolCodeLength = codeLengths[symbol];
                if (symbolCodeLength > 0)
                {
                    sorted[offsets[symbolCodeLength]++] = symbol;
                }
            }

            // Special case code with only one value.
            if (offsets[WebpConstants.MaxAllowedCodeLength] == 1)
            {
                var huffmanCode = new HuffmanCode()
                {
                    BitsUsed = 0,
                    Value    = (uint)sorted[0]
                };
                ReplicateValue(table, 1, totalSize, huffmanCode);
                return(totalSize);
            }

            int step;                       // step size to replicate values in current table
            int low       = -1;             // low bits for current root entry
            int mask      = totalSize - 1;  // mask for low bits
            int key       = 0;              // reversed prefix code
            int numNodes  = 1;              // number of Huffman tree nodes
            int numOpen   = 1;              // number of open branches in current tree level
            int tableBits = rootBits;       // key length of current table
            int tableSize = 1 << tableBits; // size of current table

            symbol = 0;

            // Fill in root table.
            for (len = 1, step = 2; len <= rootBits; ++len, step <<= 1)
            {
                int countsLen = counts[len];
                numOpen <<= 1;
                numNodes += numOpen;
                numOpen  -= counts[len];
                if (numOpen < 0)
                {
                    return(0);
                }

                for (; countsLen > 0; countsLen--)
                {
                    var huffmanCode = new HuffmanCode()
                    {
                        BitsUsed = len,
                        Value    = (uint)sorted[symbol++]
                    };
                    ReplicateValue(table.Slice(key), step, tableSize, huffmanCode);
                    key = GetNextKey(key, len);
                }

                counts[len] = countsLen;
            }

            // Fill in 2nd level tables and add pointers to root table.
            Span <HuffmanCode> tableSpan = table;
            int tablePos = 0;

            for (len = rootBits + 1, step = 2; len <= WebpConstants.MaxAllowedCodeLength; ++len, step <<= 1)
            {
                numOpen <<= 1;
                numNodes += numOpen;
                numOpen  -= counts[len];
                if (numOpen < 0)
                {
                    return(0);
                }

                for (; counts[len] > 0; --counts[len])
                {
                    if ((key & mask) != low)
                    {
                        tableSpan  = tableSpan.Slice(tableSize);
                        tablePos  += tableSize;
                        tableBits  = NextTableBitSize(counts, len, rootBits);
                        tableSize  = 1 << tableBits;
                        totalSize += tableSize;
                        low        = key & mask;
                        table[low] = new HuffmanCode
                        {
                            BitsUsed = tableBits + rootBits,
                            Value    = (uint)(tablePos - low)
                        };
                    }

                    var huffmanCode = new HuffmanCode
                    {
                        BitsUsed = len - rootBits,
                        Value    = (uint)sorted[symbol++]
                    };
                    ReplicateValue(tableSpan.Slice(key >> rootBits), step, tableSize, huffmanCode);
                    key = GetNextKey(key, len);
                }
            }

            return(totalSize);
        }