コード例 #1
0
        private static void BackwardReferencesHashChainFollowChosenPath(ReadOnlySpan <uint> bgra, int cacheBits, Span <ushort> chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
        {
            bool useColorCache = cacheBits > 0;
            var  colorCache    = new ColorCache();
            int  i             = 0;

            if (useColorCache)
            {
                colorCache.Init(cacheBits);
            }

            backwardRefs.Refs.Clear();
            for (int ix = 0; ix < chosenPathSize; ix++)
            {
                int len = chosenPath[ix];
                if (len != 1)
                {
                    int offset = hashChain.FindOffset(i);
                    backwardRefs.Add(PixOrCopy.CreateCopy((uint)offset, (ushort)len));

                    if (useColorCache)
                    {
                        for (int k = 0; k < len; k++)
                        {
                            colorCache.Insert(bgra[i + k]);
                        }
                    }

                    i += len;
                }
                else
                {
                    PixOrCopy v;
                    int       idx = useColorCache ? colorCache.Contains(bgra[i]) : -1;
                    if (idx >= 0)
                    {
                        // useColorCache is true and color cache contains bgra[i]
                        // Push pixel as a color cache index.
                        v = PixOrCopy.CreateCacheIdx(idx);
                    }
                    else
                    {
                        if (useColorCache)
                        {
                            colorCache.Insert(bgra[i]);
                        }

                        v = PixOrCopy.CreateLiteral(bgra[i]);
                    }

                    backwardRefs.Add(v);
                    i++;
                }
            }
        }
コード例 #2
0
        private static void BackwardReferencesRle(int xSize, int ySize, ReadOnlySpan <uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
        {
            int  pixelCount    = xSize * ySize;
            bool useColorCache = cacheBits > 0;
            var  colorCache    = new ColorCache();

            if (useColorCache)
            {
                colorCache.Init(cacheBits);
            }

            refs.Refs.Clear();

            // Add first pixel as literal.
            AddSingleLiteral(bgra[0], useColorCache, colorCache, refs);
            int i = 1;

            while (i < pixelCount)
            {
                int maxLen     = LosslessUtils.MaxFindCopyLength(pixelCount - i);
                int rleLen     = LosslessUtils.FindMatchLength(bgra.Slice(i), bgra.Slice(i - 1), 0, maxLen);
                int prevRowLen = i < xSize ? 0 : LosslessUtils.FindMatchLength(bgra.Slice(i), bgra.Slice(i - xSize), 0, maxLen);
                if (rleLen >= prevRowLen && rleLen >= MinLength)
                {
                    refs.Add(PixOrCopy.CreateCopy(1, (ushort)rleLen));

                    // We don't need to update the color cache here since it is always the
                    // same pixel being copied, and that does not change the color cache state.
                    i += rleLen;
                }
                else if (prevRowLen >= MinLength)
                {
                    refs.Add(PixOrCopy.CreateCopy((uint)xSize, (ushort)prevRowLen));
                    if (useColorCache)
                    {
                        for (int k = 0; k < prevRowLen; ++k)
                        {
                            colorCache.Insert(bgra[i + k]);
                        }
                    }

                    i += prevRowLen;
                }
                else
                {
                    AddSingleLiteral(bgra[i], useColorCache, colorCache, refs);
                    i++;
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Update (in-place) backward references for the specified cacheBits.
        /// </summary>
        private static void BackwardRefsWithLocalCache(ReadOnlySpan <uint> bgra, int cacheBits, Vp8LBackwardRefs refs)
        {
            int pixelIndex = 0;
            var colorCache = new ColorCache();

            colorCache.Init(cacheBits);
            for (int idx = 0; idx < refs.Refs.Count; idx++)
            {
                PixOrCopy v = refs.Refs[idx];
                if (v.IsLiteral())
                {
                    uint bgraLiteral = v.BgraOrDistance;
                    int  ix          = colorCache.Contains(bgraLiteral);
                    if (ix >= 0)
                    {
                        // Color cache contains bgraLiteral
                        v.Mode           = PixOrCopyMode.CacheIdx;
                        v.BgraOrDistance = (uint)ix;
                        v.Len            = 1;
                    }
                    else
                    {
                        colorCache.Insert(bgraLiteral);
                    }

                    pixelIndex++;
                }
                else
                {
                    // refs was created without local cache, so it can not have cache indexes.
                    for (int k = 0; k < v.Len; ++k)
                    {
                        colorCache.Insert(bgra[pixelIndex++]);
                    }
                }
            }
        }
コード例 #4
0
        private void AdvanceByOne(ref int col, ref int row, int width, ColorCache colorCache, ref int decodedPixels, Span <uint> pixelData, ref int lastCached)
        {
            col++;
            decodedPixels++;
            if (col >= width)
            {
                col = 0;
                row++;

                if (colorCache != null)
                {
                    while (lastCached < decodedPixels)
                    {
                        colorCache.Insert(pixelData[lastCached]);
                        lastCached++;
                    }
                }
            }
        }
コード例 #5
0
        private static void AddSingleLiteralWithCostModel(
            ReadOnlySpan <uint> bgra,
            ColorCache colorCache,
            CostModel costModel,
            int idx,
            bool useColorCache,
            float prevCost,
            Span <float> cost,
            Span <ushort> distArray)
        {
            double costVal = prevCost;
            uint   color   = bgra[idx];
            int    ix      = useColorCache ? colorCache.Contains(color) : -1;

            if (ix >= 0)
            {
                double mul0 = 0.68;
                costVal += costModel.GetCacheCost((uint)ix) * mul0;
            }
            else
            {
                double mul1 = 0.82;
                if (useColorCache)
                {
                    colorCache.Insert(color);
                }

                costVal += costModel.GetLiteralCost(color) * mul1;
            }

            if (cost[idx] > costVal)
            {
                cost[idx]      = (float)costVal;
                distArray[idx] = 1;  // only one is inserted.
            }
        }
コード例 #6
0
        private static void BackwardReferencesLz77(int xSize, int ySize, ReadOnlySpan <uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
        {
            int  iLastCheck    = -1;
            bool useColorCache = cacheBits > 0;
            int  pixCount      = xSize * ySize;
            var  colorCache    = new ColorCache();

            if (useColorCache)
            {
                colorCache.Init(cacheBits);
            }

            refs.Refs.Clear();
            for (int i = 0; i < pixCount;)
            {
                // Alternative #1: Code the pixels starting at 'i' using backward reference.
                int j;
                int offset = hashChain.FindOffset(i);
                int len    = hashChain.FindLength(i);
                if (len >= MinLength)
                {
                    int lenIni   = len;
                    int maxReach = 0;
                    int jMax     = i + lenIni >= pixCount ? pixCount - 1 : i + lenIni;

                    // Only start from what we have not checked already.
                    iLastCheck = i > iLastCheck ? i : iLastCheck;

                    // We know the best match for the current pixel but we try to find the
                    // best matches for the current pixel AND the next one combined.
                    // The naive method would use the intervals:
                    // [i,i+len) + [i+len, length of best match at i+len)
                    // while we check if we can use:
                    // [i,j) (where j<=i+len) + [j, length of best match at j)
                    for (j = iLastCheck + 1; j <= jMax; j++)
                    {
                        int lenJ  = hashChain.FindLength(j);
                        int reach = j + (lenJ >= MinLength ? lenJ : 1); // 1 for single literal.
                        if (reach > maxReach)
                        {
                            len      = j - i;
                            maxReach = reach;
                            if (maxReach >= pixCount)
                            {
                                break;
                            }
                        }
                    }
                }
                else
                {
                    len = 1;
                }

                // Go with literal or backward reference.
                if (len == 1)
                {
                    AddSingleLiteral(bgra[i], useColorCache, colorCache, refs);
                }
                else
                {
                    refs.Add(PixOrCopy.CreateCopy((uint)offset, (ushort)len));
                    if (useColorCache)
                    {
                        for (j = i; j < i + len; j++)
                        {
                            colorCache.Insert(bgra[j]);
                        }
                    }
                }

                i += len;
            }
        }
コード例 #7
0
        public void DecodeImageData(Vp8LDecoder decoder, Span <uint> pixelData)
        {
            int               lastPixel       = 0;
            int               width           = decoder.Width;
            int               height          = decoder.Height;
            int               row             = lastPixel / width;
            int               col             = lastPixel % width;
            const int         lenCodeLimit    = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes;
            int               colorCacheSize  = decoder.Metadata.ColorCacheSize;
            ColorCache        colorCache      = decoder.Metadata.ColorCache;
            int               colorCacheLimit = lenCodeLimit + colorCacheSize;
            int               mask            = decoder.Metadata.HuffmanMask;
            Span <HTreeGroup> hTreeGroup      = GetHTreeGroupForPos(decoder.Metadata, col, row);

            int totalPixels   = width * height;
            int decodedPixels = 0;
            int lastCached    = decodedPixels;

            while (decodedPixels < totalPixels)
            {
                int code;
                if ((col & mask) == 0)
                {
                    hTreeGroup = GetHTreeGroupForPos(decoder.Metadata, col, row);
                }

                if (hTreeGroup[0].IsTrivialCode)
                {
                    pixelData[decodedPixels] = hTreeGroup[0].LiteralArb;
                    this.AdvanceByOne(ref col, ref row, width, colorCache, ref decodedPixels, pixelData, ref lastCached);
                    continue;
                }

                this.bitReader.FillBitWindow();
                if (hTreeGroup[0].UsePackedTable)
                {
                    code = (int)this.ReadPackedSymbols(hTreeGroup, pixelData, decodedPixels);
                    if (this.bitReader.IsEndOfStream())
                    {
                        break;
                    }

                    if (code == PackedNonLiteralCode)
                    {
                        this.AdvanceByOne(ref col, ref row, width, colorCache, ref decodedPixels, pixelData, ref lastCached);
                        continue;
                    }
                }
                else
                {
                    code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green]);
                }

                if (this.bitReader.IsEndOfStream())
                {
                    break;
                }

                // Literal
                if (code < WebpConstants.NumLiteralCodes)
                {
                    if (hTreeGroup[0].IsTrivialLiteral)
                    {
                        pixelData[decodedPixels] = hTreeGroup[0].LiteralArb | ((uint)code << 8);
                    }
                    else
                    {
                        uint red = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Red]);
                        this.bitReader.FillBitWindow();
                        uint blue  = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Blue]);
                        uint alpha = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Alpha]);
                        if (this.bitReader.IsEndOfStream())
                        {
                            break;
                        }

                        pixelData[decodedPixels] = (uint)(((byte)alpha << 24) | ((byte)red << 16) | ((byte)code << 8) | (byte)blue);
                    }

                    this.AdvanceByOne(ref col, ref row, width, colorCache, ref decodedPixels, pixelData, ref lastCached);
                }
                else if (code < lenCodeLimit)
                {
                    // Backward reference is used.
                    int  lengthSym  = code - WebpConstants.NumLiteralCodes;
                    int  length     = this.GetCopyLength(lengthSym);
                    uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist]);
                    this.bitReader.FillBitWindow();
                    int distCode = this.GetCopyDistance((int)distSymbol);
                    int dist     = PlaneCodeToDistance(width, distCode);
                    if (this.bitReader.IsEndOfStream())
                    {
                        break;
                    }

                    CopyBlock(pixelData, decodedPixels, dist, length);
                    decodedPixels += length;
                    col           += length;
                    while (col >= width)
                    {
                        col -= width;
                        row++;
                    }

                    if ((col & mask) != 0)
                    {
                        hTreeGroup = GetHTreeGroupForPos(decoder.Metadata, col, row);
                    }

                    if (colorCache != null)
                    {
                        while (lastCached < decodedPixels)
                        {
                            colorCache.Insert(pixelData[lastCached]);
                            lastCached++;
                        }
                    }
                }
                else if (code < colorCacheLimit)
                {
                    // Color cache should be used.
                    int key = code - lenCodeLimit;
                    while (lastCached < decodedPixels)
                    {
                        colorCache.Insert(pixelData[lastCached]);
                        lastCached++;
                    }

                    pixelData[decodedPixels] = colorCache.Lookup(key);
                    this.AdvanceByOne(ref col, ref row, width, colorCache, ref decodedPixels, pixelData, ref lastCached);
                }
                else
                {
                    WebpThrowHelper.ThrowImageFormatException("Webp parsing error");
                }
            }
        }