diff --git a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs index f13481882..a5c9be547 100644 --- a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs @@ -31,54 +31,11 @@ namespace ImageSharp.Formats 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, }; - /// - /// Counts the number of bits needed to hold an integer. - /// - 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, - }; - - /// - /// 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. - /// - 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, - } - }; - /// /// The Huffman encoding specifications. /// This encoder uses the same Huffman encoding for all images. /// - private readonly HuffmanSpec[] huffmanSpec = + private static readonly HuffmanSpec[] TheHuffmanSpecs = { // Luminance DC. new HuffmanSpec( @@ -149,6 +106,54 @@ namespace ImageSharp.Formats }) }; + /// + /// The compiled representations of theHuffmanSpec. + /// + private static readonly HuffmanLut[] TheHuffmanLut = new HuffmanLut[4]; + + /// + /// Counts the number of bits needed to hold an integer. + /// + 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, + }; + + /// + /// 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. + /// + 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, + } + }; + /// /// A scratch buffer to reduce allocations. /// @@ -159,11 +164,6 @@ namespace ImageSharp.Formats /// private readonly byte[][] quant = new byte[NQuantIndex][]; - /// - /// The compiled representations of theHuffmanSpec. - /// - private readonly HuffmanLut[] theHuffmanLut = new HuffmanLut[4]; - /// /// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes: /// - the marker length "\x00\x0c", @@ -211,6 +211,18 @@ namespace ImageSharp.Formats /// private JpegSubsample subsample; + /// + /// Initializes static members of the class. + /// + static JpegEncoderCore() + { + // Initialize the Huffman tables + for (int i = 0; i < TheHuffmanSpecs.Length; i++) + { + TheHuffmanLut[i] = new HuffmanLut(TheHuffmanSpecs[i]); + } + } + /// /// Enumerates the Huffman tables /// @@ -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 /// The value to encode. 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) diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs index 2d36e2da8..855c3a7af 100644 --- a/tests/ImageSharp.Tests/FileTestBase.cs +++ b/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