private static void AddSingleLiteral(uint pixel, bool useColorCache, ColorCache colorCache, Vp8LBackwardRefs refs) { PixOrCopy v; if (useColorCache) { int key = colorCache.GetIndex(pixel); if (colorCache.Lookup(key) == pixel) { v = PixOrCopy.CreateCacheIdx(key); } else { v = PixOrCopy.CreateLiteral(pixel); colorCache.Set((uint)key, pixel); } } else { v = PixOrCopy.CreateLiteral(pixel); } refs.Add(v); }
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"); } } }