Browse Source

Build Huffman tables once only.

af/merge-core
James Jackson-South 9 years ago
parent
commit
be028ed1b5
  1. 122
      src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
  2. 10
      tests/ImageSharp.Tests/FileTestBase.cs

122
src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs

@ -31,54 +31,11 @@ namespace ImageSharp.Formats
39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
};
/// <summary>
/// Counts the number of bits needed to hold an integer.
/// </summary>
private readonly byte[] bitCountLut =
{
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8,
};
/// <summary>
/// The unscaled quantization tables in zig-zag order. Each
/// encoder copies and scales the tables according to its quality parameter.
/// The values are derived from section K.1 after converting from natural to
/// zig-zag order.
/// </summary>
private readonly byte[,] unscaledQuant =
{
{
// Luminance.
16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81,
87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92,
101, 103, 99,
},
{
// Chrominance.
17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
}
};
/// <summary>
/// The Huffman encoding specifications.
/// This encoder uses the same Huffman encoding for all images.
/// </summary>
private readonly HuffmanSpec[] huffmanSpec =
private static readonly HuffmanSpec[] TheHuffmanSpecs =
{
// Luminance DC.
new HuffmanSpec(
@ -149,6 +106,54 @@ namespace ImageSharp.Formats
})
};
/// <summary>
/// The compiled representations of theHuffmanSpec.
/// </summary>
private static readonly HuffmanLut[] TheHuffmanLut = new HuffmanLut[4];
/// <summary>
/// Counts the number of bits needed to hold an integer.
/// </summary>
private readonly byte[] bitCountLut =
{
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8,
};
/// <summary>
/// The unscaled quantization tables in zig-zag order. Each
/// encoder copies and scales the tables according to its quality parameter.
/// The values are derived from section K.1 after converting from natural to
/// zig-zag order.
/// </summary>
private readonly byte[,] unscaledQuant =
{
{
// Luminance.
16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81,
87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92,
101, 103, 99,
},
{
// Chrominance.
17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
}
};
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
@ -159,11 +164,6 @@ namespace ImageSharp.Formats
/// </summary>
private readonly byte[][] quant = new byte[NQuantIndex][];
/// <summary>
/// The compiled representations of theHuffmanSpec.
/// </summary>
private readonly HuffmanLut[] theHuffmanLut = new HuffmanLut[4];
/// <summary>
/// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
/// - the marker length "\x00\x0c",
@ -211,6 +211,18 @@ namespace ImageSharp.Formats
/// </summary>
private JpegSubsample subsample;
/// <summary>
/// Initializes static members of the <see cref="JpegEncoderCore"/> class.
/// </summary>
static JpegEncoderCore()
{
// Initialize the Huffman tables
for (int i = 0; i < TheHuffmanSpecs.Length; i++)
{
TheHuffmanLut[i] = new HuffmanLut(TheHuffmanSpecs[i]);
}
}
/// <summary>
/// Enumerates the Huffman tables
/// </summary>
@ -280,12 +292,6 @@ namespace ImageSharp.Formats
this.outputStream = stream;
this.subsample = sample;
// TODO: This should be static should it not?
for (int i = 0; i < this.huffmanSpec.Length; i++)
{
this.theHuffmanLut[i] = new HuffmanLut(this.huffmanSpec[i]);
}
for (int i = 0; i < NQuantIndex; i++)
{
this.quant[i] = new byte[Block.BlockSize];
@ -425,7 +431,7 @@ namespace ImageSharp.Formats
/// <param name="value">The value to encode.</param>
private void EmitHuff(HuffIndex index, int value)
{
uint x = this.theHuffmanLut[(int)index].Values[value];
uint x = TheHuffmanLut[(int)index].Values[value];
this.Emit(x & ((1 << 24) - 1), x >> 24);
}
@ -730,12 +736,12 @@ namespace ImageSharp.Formats
{
byte[] headers = { 0x00, 0x10, 0x01, 0x11 };
int markerlen = 2;
HuffmanSpec[] specs = this.huffmanSpec;
HuffmanSpec[] specs = TheHuffmanSpecs;
if (componentCount == 1)
{
// Drop the Chrominance tables.
specs = new[] { this.huffmanSpec[0], this.huffmanSpec[1] };
specs = new[] { TheHuffmanSpecs[0], TheHuffmanSpecs[1] };
}
foreach (HuffmanSpec s in specs)

10
tests/ImageSharp.Tests/FileTestBase.cs

@ -22,11 +22,11 @@ namespace ImageSharp.Tests
//new TestFile(TestImages.Png.Pd),
new TestFile(TestImages.Jpeg.Floorplan), // Perf: Enable for local testing only
new TestFile(TestImages.Jpeg.Calliphora),
//new TestFile(TestImages.Jpg.Cmyk), // Perf: Enable for local testing only
//new TestFile(TestImages.Jpg.Turtle),
//new TestFile(TestImages.Jpg.Fb), // Perf: Enable for local testing only
//new TestFile(TestImages.Jpg.Progress), // Perf: Enable for local testing only
//new TestFile(TestImages.Jpg.Gamma_dalai_lama_gray). // Perf: Enable for local testing only
//new TestFile(TestImages.Jpeg.Cmyk), // Perf: Enable for local testing only
new TestFile(TestImages.Jpeg.Turtle),
//new TestFile(TestImages.Jpeg.Fb), // Perf: Enable for local testing only
//new TestFile(TestImages.Jpeg.Progress), // Perf: Enable for local testing only
//new TestFile(TestImages.Jpeg.Gamma_dalai_lama_gray). // Perf: Enable for local testing only
new TestFile(TestImages.Bmp.Car),
//new TestFile(TestImages.Bmp.Neg_height), // Perf: Enable for local testing only
//new TestFile(TestImages.Png.Blur), // Perf: Enable for local testing only

Loading…
Cancel
Save