Exemple #1
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);
         }
     }
Exemple #2
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;
        }