From 2fb000ae6e5ca0b387eab5ecda078f9fe91b7db9 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Wed, 15 Jan 2020 18:14:31 +0100 Subject: [PATCH] move some methods from LosslessDecoder to base class Implementing WebPLossyDecoder.DecodeAlphaData these methods are called from there containing the same code than in the lossless decoder, so we move them to an abstract base class. (not sure if it's a good idea to move the BitReader itself as well, so passing it as a parameter for now) --- .../Formats/WebP/WebPDecoderBase.cs | 86 +++++++++++++++++++ .../Formats/WebP/WebPLosslessDecoder.cs | 76 +--------------- .../Formats/WebP/WebPLossyDecoder.cs | 2 +- 3 files changed, 90 insertions(+), 74 deletions(-) create mode 100644 src/ImageSharp/Formats/WebP/WebPDecoderBase.cs diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs b/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs new file mode 100644 index 000000000..607dbc1c3 --- /dev/null +++ b/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs @@ -0,0 +1,86 @@ +// // Copyright (c) Six Labors and contributors. +// // Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; + +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Formats.WebP +{ + abstract class WebPDecoderBase + { + protected HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y) + { + uint metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y); + return metadata.HTreeGroups.AsSpan((int)metaIndex).ToArray(); + } + + private uint GetMetaIndex(IMemoryOwner huffmanImage, int xSize, int bits, int x, int y) + { + if (bits is 0) + { + return 0; + } + + Span huffmanImageSpan = huffmanImage.GetSpan(); + return huffmanImageSpan[(xSize * (y >> bits)) + (x >> bits)]; + } + + // TODO: copied from WebPLosslessDecoder + protected int GetCopyDistance(int distanceSymbol, Vp8LBitReader bitReader) + { + if (distanceSymbol < 4) + { + return distanceSymbol + 1; + } + + int extraBits = (distanceSymbol - 2) >> 1; + int offset = (2 + (distanceSymbol & 1)) << extraBits; + + return (int)(offset + bitReader.ReadBits(extraBits) + 1); + } + + // TODO: copied from WebPLosslessDecoder + protected int GetCopyLength(int lengthSymbol, Vp8LBitReader bitReader) + { + // Length and distance prefixes are encoded the same way. + return this.GetCopyDistance(lengthSymbol, bitReader); + } + + // TODO: copied from LosslessDecoder + protected static readonly int[] KCodeToPlane = + { + 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a, + 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a, + 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b, + 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03, + 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c, + 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e, + 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b, + 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f, + 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b, + 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41, + 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f, + 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70 + }; + + protected static readonly int CodeToPlaneCodes = KCodeToPlane.Length; + + protected int PlaneCodeToDistance(int xSize, int planeCode) + { + if (planeCode > CodeToPlaneCodes) + { + return planeCode - CodeToPlaneCodes; + } + + int distCode = KCodeToPlane[planeCode - 1]; + int yOffset = distCode >> 4; + int xOffset = 8 - (distCode & 0xf); + int dist = (yOffset * xSize) + xOffset; + + // dist < 1 can happen if xSize is very small. + return (dist >= 1) ? dist : 1; + } + } +} diff --git a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs index 3b0a06e5b..851ac213b 100644 --- a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.WebP /// The lossless specification can be found here: /// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification /// - internal sealed class WebPLosslessDecoder + internal sealed class WebPLosslessDecoder : WebPDecoderBase { private readonly Vp8LBitReader bitReader; @@ -50,24 +50,6 @@ namespace SixLabors.ImageSharp.Formats.WebP private static readonly byte[] KCodeLengthCodeOrder = { 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; private static readonly int NumCodeLengthCodes = KCodeLengthCodeOrder.Length; - private static readonly int[] KCodeToPlane = - { - 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a, - 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a, - 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b, - 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03, - 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c, - 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e, - 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b, - 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f, - 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b, - 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41, - 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f, - 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70 - }; - - private static readonly int CodeToPlaneCodes = KCodeToPlane.Length; - private static readonly byte[] KLiteralMap = { 0, 1, 1, 1, 0 @@ -289,10 +271,10 @@ namespace SixLabors.ImageSharp.Formats.WebP { // Backward reference is used. int lengthSym = code - WebPConstants.NumLiteralCodes; - int length = this.GetCopyLength(lengthSym); + int length = this.GetCopyLength(lengthSym, this.bitReader); uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist]); this.bitReader.FillBitWindow(); - int distCode = this.GetCopyDistance((int)distSymbol); + int distCode = this.GetCopyDistance((int)distSymbol, this.bitReader); int dist = this.PlaneCodeToDistance(width, distCode); if (this.bitReader.IsEndOfStream()) { @@ -767,41 +749,6 @@ namespace SixLabors.ImageSharp.Formats.WebP } } - private int GetCopyDistance(int distanceSymbol) - { - if (distanceSymbol < 4) - { - return distanceSymbol + 1; - } - - int extraBits = (distanceSymbol - 2) >> 1; - int offset = (2 + (distanceSymbol & 1)) << extraBits; - - return (int)(offset + this.bitReader.ReadBits(extraBits) + 1); - } - - private int GetCopyLength(int lengthSymbol) - { - // Length and distance prefixes are encoded the same way. - return this.GetCopyDistance(lengthSymbol); - } - - private int PlaneCodeToDistance(int xSize, int planeCode) - { - if (planeCode > CodeToPlaneCodes) - { - return planeCode - CodeToPlaneCodes; - } - - int distCode = KCodeToPlane[planeCode - 1]; - int yOffset = distCode >> 4; - int xOffset = 8 - (distCode & 0xf); - int dist = (yOffset * xSize) + xOffset; - - // dist < 1 can happen if xSize is very small. - return (dist >= 1) ? dist : 1; - } - private void BuildPackedTable(HTreeGroup hTreeGroup) { for (uint code = 0; code < HuffmanUtils.HuffmanPackedTableSize; ++code) @@ -832,22 +779,5 @@ namespace SixLabors.ImageSharp.Formats.WebP huff.Value |= hCode.Value << shift; return hCode.BitsUsed; } - - private uint GetMetaIndex(IMemoryOwner huffmanImage, int xSize, int bits, int x, int y) - { - if (bits is 0) - { - return 0; - } - - Span huffmanImageSpan = huffmanImage.GetSpan(); - return huffmanImageSpan[(xSize * (y >> bits)) + (x >> bits)]; - } - - private HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y) - { - uint metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y); - return metadata.HTreeGroups.AsSpan((int)metaIndex).ToArray(); - } } } diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs index 484f5071f..c1293ff49 100644 --- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs @@ -10,7 +10,7 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Formats.WebP { - internal sealed class WebPLossyDecoder + internal sealed class WebPLossyDecoder : WebPDecoderBase { private readonly Configuration configuration;