Browse Source

Change huffman code to a struct

pull/1846/head
Brian Popow 5 years ago
parent
commit
40b6f4e55b
  1. 4
      src/ImageSharp/Formats/Webp/Lossless/HTreeGroup.cs
  2. 2
      src/ImageSharp/Formats/Webp/Lossless/HuffmanCode.cs
  3. 45
      src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs
  4. 14
      src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
  5. 2
      tests/ImageSharp.Tests/Formats/WebP/ColorSpaceTransformUtilsTests.cs
  6. 2
      tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs
  7. 2
      tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs
  8. 2
      tests/ImageSharp.Tests/Formats/WebP/Vp8EncodingTests.cs

4
src/ImageSharp/Formats/Webp/Lossless/HTreeGroup.cs

@ -19,10 +19,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{ {
this.HTrees = new List<HuffmanCode[]>(WebpConstants.HuffmanCodesPerMetaCode); this.HTrees = new List<HuffmanCode[]>(WebpConstants.HuffmanCodesPerMetaCode);
this.PackedTable = new HuffmanCode[packedTableSize]; this.PackedTable = new HuffmanCode[packedTableSize];
for (int i = 0; i < packedTableSize; i++)
{
this.PackedTable[i] = new HuffmanCode();
}
} }
/// <summary> /// <summary>

2
src/ImageSharp/Formats/Webp/Lossless/HuffmanCode.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// A classic way to do entropy coding where a smaller number of bits are used for more frequent codes. /// A classic way to do entropy coding where a smaller number of bits are used for more frequent codes.
/// </summary> /// </summary>
[DebuggerDisplay("BitsUsed: {BitsUsed}, Value: {Value}")] [DebuggerDisplay("BitsUsed: {BitsUsed}, Value: {Value}")]
internal class HuffmanCode internal struct HuffmanCode
{ {
/// <summary> /// <summary>
/// Gets or sets the number of bits used for this symbol. /// Gets or sets the number of bits used for this symbol.

45
src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Webp.Lossless namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{ {
@ -307,9 +308,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public static int BuildHuffmanTable(Span<HuffmanCode> table, int rootBits, int[] codeLengths, int codeLengthsSize) public static int BuildHuffmanTable(Span<HuffmanCode> table, int rootBits, int[] codeLengths, int codeLengthsSize)
{ {
Guard.MustBeGreaterThan(rootBits, 0, nameof(rootBits)); DebugGuard.MustBeGreaterThan(rootBits, 0, nameof(rootBits));
Guard.NotNull(codeLengths, nameof(codeLengths)); DebugGuard.NotNull(codeLengths, nameof(codeLengths));
Guard.MustBeGreaterThan(codeLengthsSize, 0, nameof(codeLengthsSize)); DebugGuard.MustBeGreaterThan(codeLengthsSize, 0, nameof(codeLengthsSize));
// sorted[codeLengthsSize] is a pre-allocated array for sorting symbols by code length. // sorted[codeLengthsSize] is a pre-allocated array for sorting symbols by code length.
int[] sorted = new int[codeLengthsSize]; int[] sorted = new int[codeLengthsSize];
@ -467,27 +468,27 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
break; break;
} }
else if (repetitions < 11)
if (repetitions < 11)
{ {
tokens[pos].Code = 17; tokens[pos].Code = 17;
tokens[pos].ExtraBits = (byte)(repetitions - 3); tokens[pos].ExtraBits = (byte)(repetitions - 3);
pos++; pos++;
break; break;
} }
else if (repetitions < 139)
if (repetitions < 139)
{ {
tokens[pos].Code = 18; tokens[pos].Code = 18;
tokens[pos].ExtraBits = (byte)(repetitions - 11); tokens[pos].ExtraBits = (byte)(repetitions - 11);
pos++; pos++;
break; break;
} }
else
{ tokens[pos].Code = 18;
tokens[pos].Code = 18; tokens[pos].ExtraBits = 0x7f; // 138 repeated 0s
tokens[pos].ExtraBits = 0x7f; // 138 repeated 0s pos++;
pos++; repetitions -= 138;
repetitions -= 138;
}
} }
return pos; return pos;
@ -519,20 +520,19 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
break; break;
} }
else if (repetitions < 7)
if (repetitions < 7)
{ {
tokens[pos].Code = 16; tokens[pos].Code = 16;
tokens[pos].ExtraBits = (byte)(repetitions - 3); tokens[pos].ExtraBits = (byte)(repetitions - 3);
pos++; pos++;
break; break;
} }
else
{ tokens[pos].Code = 16;
tokens[pos].Code = 16; tokens[pos].ExtraBits = 3;
tokens[pos].ExtraBits = 3; pos++;
pos++; repetitions -= 6;
repetitions -= 6;
}
} }
return pos; return pos;
@ -541,7 +541,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary> /// <summary>
/// Get the actual bit values for a tree of bit depths. /// Get the actual bit values for a tree of bit depths.
/// </summary> /// </summary>
/// <param name="tree">The hiffman tree.</param> /// <param name="tree">The huffman tree.</param>
private static void ConvertBitDepthsToSymbols(HuffmanTreeCode tree) private static void ConvertBitDepthsToSymbols(HuffmanTreeCode tree)
{ {
// 0 bit-depth means that the symbol does not exist. // 0 bit-depth means that the symbol does not exist.
@ -628,7 +628,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary> /// </summary>
private static void ReplicateValue(Span<HuffmanCode> table, int step, int end, HuffmanCode code) private static void ReplicateValue(Span<HuffmanCode> table, int step, int end, HuffmanCode code)
{ {
Guard.IsTrue(end % step == 0, nameof(end), "end must be a multiple of step"); DebugGuard.IsTrue(end % step == 0, nameof(end), "end must be a multiple of step");
do do
{ {
@ -656,6 +656,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary> /// <summary>
/// Heuristics for selecting the stride ranges to collapse. /// Heuristics for selecting the stride ranges to collapse.
/// </summary> /// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private static bool ValuesShouldBeCollapsedToStrideAverage(int a, int b) => Math.Abs(a - b) < 4; private static bool ValuesShouldBeCollapsedToStrideAverage(int a, int b) => Math.Abs(a - b) < 4;
} }
} }

14
src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs

@ -834,10 +834,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private void BuildPackedTable(HTreeGroup hTreeGroup) private void BuildPackedTable(HTreeGroup hTreeGroup)
{ {
for (uint code = 0; code < HuffmanUtils.HuffmanPackedTableSize; ++code) for (uint code = 0; code < HuffmanUtils.HuffmanPackedTableSize; code++)
{ {
uint bits = code; uint bits = code;
HuffmanCode huff = hTreeGroup.PackedTable[bits]; ref HuffmanCode huff = ref hTreeGroup.PackedTable[bits];
HuffmanCode hCode = hTreeGroup.HTrees[HuffIndex.Green][bits]; HuffmanCode hCode = hTreeGroup.HTrees[HuffIndex.Green][bits];
if (hCode.Value >= WebpConstants.NumLiteralCodes) if (hCode.Value >= WebpConstants.NumLiteralCodes)
{ {
@ -848,10 +848,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{ {
huff.BitsUsed = 0; huff.BitsUsed = 0;
huff.Value = 0; huff.Value = 0;
bits >>= AccumulateHCode(hCode, 8, huff); bits >>= AccumulateHCode(hCode, 8, ref huff);
bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Red][bits], 16, huff); bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Red][bits], 16, ref huff);
bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Blue][bits], 0, huff); bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Blue][bits], 0, ref huff);
bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Alpha][bits], 24, huff); bits >>= AccumulateHCode(hTreeGroup.HTrees[HuffIndex.Alpha][bits], 24, ref huff);
} }
} }
} }
@ -992,7 +992,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static int AccumulateHCode(HuffmanCode hCode, int shift, HuffmanCode huff) private static int AccumulateHCode(HuffmanCode hCode, int shift, ref HuffmanCode huff)
{ {
huff.BitsUsed += hCode.BitsUsed; huff.BitsUsed += hCode.BitsUsed;
huff.Value |= hCode.Value << shift; huff.Value |= hCode.Value << shift;

2
tests/ImageSharp.Tests/Formats/WebP/ColorSpaceTransformUtilsTests.cs

@ -5,7 +5,7 @@ using SixLabors.ImageSharp.Formats.Webp.Lossless;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP namespace SixLabors.ImageSharp.Tests.Formats.Webp
{ {
[Trait("Format", "Webp")] [Trait("Format", "Webp")]
public class ColorSpaceTransformUtilsTests public class ColorSpaceTransformUtilsTests

2
tests/ImageSharp.Tests/Formats/WebP/LossyUtilsTests.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP namespace SixLabors.ImageSharp.Tests.Formats.Webp
{ {
[Trait("Format", "Webp")] [Trait("Format", "Webp")]
public class LossyUtilsTests public class LossyUtilsTests

2
tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP namespace SixLabors.ImageSharp.Tests.Formats.Webp
{ {
[Trait("Format", "Webp")] [Trait("Format", "Webp")]
public class QuantEncTests public class QuantEncTests

2
tests/ImageSharp.Tests/Formats/WebP/Vp8EncodingTests.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP namespace SixLabors.ImageSharp.Tests.Formats.Webp
{ {
[Trait("Format", "Webp")] [Trait("Format", "Webp")]
public class Vp8EncodingTests public class Vp8EncodingTests

Loading…
Cancel
Save