📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

124 lines
4.5 KiB

// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
/// <summary>
/// Represents a Huffman Table
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct HuffmanTable
{
/// <summary>
/// Gets the max code array
/// </summary>
public FixedUInt32Buffer18 MaxCode;
/// <summary>
/// Gets the value offset array
/// </summary>
public FixedInt32Buffer18 ValOffset;
/// <summary>
/// Gets the huffman value array
/// </summary>
public FixedByteBuffer256 Values;
/// <summary>
/// Gets the lookahead array
/// </summary>
public FixedByteBuffer512 Lookahead;
/// <summary>
/// Gets the sizes array
/// </summary>
public FixedInt16Buffer257 Sizes;
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanTable"/> struct.
/// </summary>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="codeLengths">The code lengths</param>
/// <param name="values">The huffman values</param>
public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
{
const int Length = 257;
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(Length))
{
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths);
// Figure C.1: make table of Huffman code length for each symbol
ref short sizesRef = ref this.Sizes.Data[0];
short x = 0;
for (short i = 1; i < 17; i++)
{
byte length = Unsafe.Add(ref codeLengthsRef, i);
for (short j = 0; j < length; j++)
{
Unsafe.Add(ref sizesRef, x++) = i;
}
}
Unsafe.Add(ref sizesRef, x) = 0;
// Figure C.2: generate the codes themselves
int si = 0;
ref int valOffsetRef = ref this.ValOffset.Data[0];
ref uint maxcodeRef = ref this.MaxCode.Data[0];
uint code = 0;
int k;
for (k = 1; k < 17; k++)
{
// Compute delta to add to code to compute symbol id.
Unsafe.Add(ref valOffsetRef, k) = (int)(si - code);
if (Unsafe.Add(ref sizesRef, si) == k)
{
while (Unsafe.Add(ref sizesRef, si) == k)
{
Unsafe.Add(ref huffcodeRef, si++) = (short)code++;
}
}
// Figure F.15: generate decoding tables for bit-sequential decoding.
// Compute largest code + 1 for this size. preshifted as we need later.
Unsafe.Add(ref maxcodeRef, k) = code << (16 - k);
code <<= 1;
}
Unsafe.Add(ref maxcodeRef, k) = 0xFFFFFFFF;
// Generate non-spec lookup tables to speed up decoding.
const int FastBits = ScanDecoder.FastBits;
ref byte fastRef = ref this.Lookahead.Data[0];
new Span<byte>(Unsafe.AsPointer(ref fastRef), 1 << FastBits).Fill(0xFF); // Flag for non-accelerated
for (int i = 0; i < si; i++)
{
int size = Unsafe.Add(ref sizesRef, i);
if (size <= FastBits)
{
int c = Unsafe.Add(ref huffcodeRef, i) << (FastBits - size);
int m = 1 << (FastBits - size);
for (int l = 0; l < m; l++)
{
Unsafe.Add(ref fastRef, c + l) = (byte)i;
}
}
}
}
values.CopyTo(new Span<byte>(Unsafe.AsPointer(ref this.Values.Data[0]), 256));
}
}
}