diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs index f2f1175897..1f72f38078 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs @@ -1164,18 +1164,37 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless if (paletteSize < ApplyPaletteGreedyMax) { - // TODO: APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); + uint prevPix = palette[0]; + uint prevIdx = 0; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + uint pix = src[x]; + if (pix != prevPix) + { + prevIdx = SearchColorGreedy(palette, pix); + prevPix = pix; + } + + tmpRow[x] = (byte)prevIdx; + } + + BundleColorMap(tmpRow, width, xBits, dst); + src = src.Slice(srcStride); + dst = dst.Slice(dstStride); + } } else { - uint[] buffer = new uint[PaletteInvSize]; + var buffer = new uint[PaletteInvSize]; // Try to find a perfect hash function able to go from a color to an index // within 1 << PaletteInvSize in order to build a hash map to go from color to index in palette. int i; for (i = 0; i < 3; i++) { - bool useLUT = true; + bool useLut = true; // Set each element in buffer to max value. buffer.AsSpan().Fill(uint.MaxValue); @@ -1198,7 +1217,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless if (buffer[ind] != uint.MaxValue) { - useLUT = false; + useLut = false; break; } else @@ -1207,7 +1226,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless } } - if (useLUT) + if (useLut) { break; } @@ -1513,6 +1532,38 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless (histoBits > WebPConstants.MaxHuffmanBits) ? WebPConstants.MaxHuffmanBits : histoBits; } + /// + /// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. + /// + private static void BundleColorMap(Span row, int width, int xBits, Span dst) + { + int x; + if (xBits > 0) + { + int bitDepth = 1 << (3 - xBits); + int mask = (1 << xBits) - 1; + uint code = 0xff000000; + for (x = 0; x < width; ++x) + { + int xSub = x & mask; + if (xSub == 0) + { + code = 0xff000000; + } + + code |= (uint)(row[x] << (8 + (bitDepth * xSub))); + dst[x >> xBits] = code; + } + } + else + { + for (x = 0; x < width; ++x) + { + dst[x] = (uint)(0xff000000 | (row[x] << 8)); + } + } + } + /// /// Calculates the bits used for the transformation. /// @@ -1551,6 +1602,27 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless b[(int)((p >> 0) - green) & 0xff]++; } + [MethodImpl(InliningOptions.ShortMethod)] + private static uint SearchColorGreedy(Span palette, uint color) + { + if (color == palette[0]) + { + return 0; + } + + if (color == palette[1]) + { + return 1; + } + + if (color == palette[2]) + { + return 2; + } + + return 3; + } + [MethodImpl(InliningOptions.ShortMethod)] private static uint ApplyPaletteHash0(uint color) {