diff --git a/ImageSharp.sln.DotSettings b/ImageSharp.sln.DotSettings index 5e9cc2abd..a3055c07e 100644 --- a/ImageSharp.sln.DotSettings +++ b/ImageSharp.sln.DotSettings @@ -1,4 +1,7 @@  + DC + FDCT + IDCT JPEG PNG RGB diff --git a/Settings.StyleCop b/Settings.StyleCop index 3fa9874cf..0eabc6cf3 100644 --- a/Settings.StyleCop +++ b/Settings.StyleCop @@ -26,6 +26,11 @@ zig-zag crc zlib + xff + xda + ss + Vol + pp diff --git a/src/ImageSharp/Formats/Jpg/Components/FDCT.cs b/src/ImageSharp/Formats/Jpg/Components/FDCT.cs index 460dc61c9..cd27b9e73 100644 --- a/src/ImageSharp/Formats/Jpg/Components/FDCT.cs +++ b/src/ImageSharp/Formats/Jpg/Components/FDCT.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Formats { /// - /// Performs a fast, forward descrete cosine transform against the given block + /// Performs a fast, forward discrete cosine transform against the given block /// decomposing it into 64 orthogonal basis signals. /// internal class FDCT @@ -42,10 +42,9 @@ namespace ImageSharp.Formats private const int CenterJSample = 128; /// - /// Performs a forward DCT on an 8x8 block of coefficients, including a - /// level shift. + /// Performs a forward DCT on an 8x8 block of coefficients, including a level shift. /// - /// The block. + /// The block of coefficients. public static void Transform(Block block) { // Pass 1: process rows. diff --git a/src/ImageSharp/Formats/Jpg/Components/IDCT.cs b/src/ImageSharp/Formats/Jpg/Components/IDCT.cs index c6bc279d5..bc145779a 100644 --- a/src/ImageSharp/Formats/Jpg/Components/IDCT.cs +++ b/src/ImageSharp/Formats/Jpg/Components/IDCT.cs @@ -5,6 +5,9 @@ namespace ImageSharp.Formats { + /// + /// Performs a 2-D Inverse Discrete Cosine Transformation. + /// internal class IDCT { private const int w1 = 2841; // 2048*sqrt(2)*cos(1*pi/16) @@ -23,16 +26,19 @@ namespace ImageSharp.Formats private const int r2 = 181; // 256/sqrt(2) - // idct performs a 2-D Inverse Discrete Cosine Transformation. - // - // The input coefficients should already have been multiplied by the - // appropriate quantization table. We use fixed-point computation, with the - // number of bits for the fractional component varying over the intermediate - // stages. - // - // For more on the actual algorithm, see Z. Wang, "Fast algorithms for the - // discrete W transform and for the discrete Fourier transform", IEEE Trans. on - // ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984. + /// + /// Performs a 2-D Inverse Discrete Cosine Transformation. + /// + /// The input coefficients should already have been multiplied by the + /// appropriate quantization table. We use fixed-point computation, with the + /// number of bits for the fractional component varying over the intermediate + /// stages. + /// + /// For more on the actual algorithm, see Z. Wang, "Fast algorithms for the + /// discrete W transform and for the discrete Fourier transform", IEEE Trans. on + /// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984. + /// + /// The source block of coefficients public static void Transform(Block src) { // Horizontal 1-D IDCT. diff --git a/src/ImageSharp/Formats/Jpg/JpegConstants.cs b/src/ImageSharp/Formats/Jpg/JpegConstants.cs index 3991cf3ea..19d726e70 100644 --- a/src/ImageSharp/Formats/Jpg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpg/JpegConstants.cs @@ -26,24 +26,24 @@ namespace ImageSharp.Formats public static readonly byte[] ChromaFourFourFourVertical = { 0x11, 0x11, 0x11 }; /// - /// Represents medium detail chroma horizontal subsampling. + /// Represents medium detail chroma vertical subsampling. /// - public static readonly byte[] ChromaFourTwoTwoHorizontal = { 0x22, 0x11, 0x11 }; + public static readonly byte[] ChromaFourTwoTwoVertical = { 0x11, 0x11, 0x11 }; /// - /// Represents medium detail chroma vertical subsampling. + /// Represents low detail chroma vertical subsampling. /// - public static readonly byte[] ChromaFourTwoTwoVertical = { 0x11, 0x11, 0x11 }; + public static readonly byte[] ChromaFourTwoZeroVertical = { 0x22, 0x11, 0x11 }; /// - /// Represents low detail chroma horizontal subsampling. + /// Represents medium detail chroma horizontal subsampling. /// - public static readonly byte[] ChromaFourTwoZeroHorizontal = { 0x22, 0x11, 0x11 }; + public static readonly byte[] ChromaFourTwoTwoHorizontal = { 0x22, 0x11, 0x11 }; /// - /// Represents low detail chroma vertical subsampling. + /// Represents low detail chroma horizontal subsampling. /// - public static readonly byte[] ChromaFourTwoZeroVertical = { 0x22, 0x11, 0x11 }; + public static readonly byte[] ChromaFourTwoZeroHorizontal = { 0x22, 0x11, 0x11 }; /// /// Describes component ids for start of frame components. diff --git a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs index 371e71522..f13481882 100644 --- a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs @@ -2,6 +2,7 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // + namespace ImageSharp.Formats { using System; @@ -12,6 +13,9 @@ namespace ImageSharp.Formats /// internal class JpegEncoderCore { + /// + /// The number of quantization tables. + /// private const int NQuantIndex = 2; /// @@ -74,7 +78,7 @@ namespace ImageSharp.Formats /// The Huffman encoding specifications. /// This encoder uses the same Huffman encoding for all images. /// - private readonly HuffmanSpec[] theHuffmanSpec = + private readonly HuffmanSpec[] huffmanSpec = { // Luminance DC. new HuffmanSpec( @@ -153,13 +157,40 @@ namespace ImageSharp.Formats /// /// The scaled quantization tables, in zig-zag order. /// - private readonly byte[][] quant = new byte[NQuantIndex][]; // [Block.blockSize]; + 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", + /// - the number of components "\x03", + /// - component 1 uses DC table 0 and AC table 0 "\x01\x00", + /// - component 2 uses DC table 1 and AC table 1 "\x02\x11", + /// - component 3 uses DC table 1 and AC table 1 "\x03\x11", + /// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for + /// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) + /// should be 0x00, 0x3f, 0x00<<4 | 0x00. + /// + private readonly byte[] sosHeaderYCbCr = + { + JpegConstants.Markers.XFF, JpegConstants.Markers.SOS, // Marker + 0x00, 0x0c, // Length (high byte, low byte), must be 6 + 2 * (number of components in scan) + 0x03, // Number of components in a scan, 3 + 0x01, // Component Id Y + 0x00, // DC/AC Huffman table + 0x02, // Component Id Cb + 0x11, // DC/AC Huffman table + 0x03, // Component Id Cr + 0x11, // DC/AC Huffman table + 0x00, // Ss - Start of spectral selection. + 0x3f, // Se - End of spectral selection. + 0x00 // Ah + Ah (Successive approximation bit position high + low) + }; + /// /// The accumulated bits to write to the stream. /// @@ -180,6 +211,174 @@ namespace ImageSharp.Formats /// private JpegSubsample subsample; + /// + /// Enumerates the Huffman tables + /// + private enum HuffIndex + { + /// + /// The DC luminance huffman table index + /// + LuminanceDC = 0, + + /// + /// The AC luminance huffman table index + /// + + LuminanceAC = 1, + // ReSharper restore UnusedMember.Local + + /// + /// The DC chrominance huffman table index + /// + ChrominanceDC = 2, + + /// + /// The AC chrominance huffman table index + /// + ChrominanceAC = 3, + } + + /// + /// Enumerates the quantization tables + /// + private enum QuantIndex + { + /// + /// The luminance quantization table index + /// + Luminance = 0, + + /// + /// The chrominance quantization table index + /// + Chrominance = 1, + } + + /// + /// Encode writes the image to the jpeg baseline format with the given options. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The image to write from. + /// The stream to write to. + /// The quality. + /// The subsampling mode. + public void Encode(Image image, Stream stream, int quality, JpegSubsample sample) + where TColor : struct, IPackedPixel + where TPacked : struct + { + Guard.NotNull(image, nameof(image)); + Guard.NotNull(stream, nameof(stream)); + + ushort max = JpegConstants.MaxLength; + if (image.Width >= max || image.Height >= max) + { + throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); + } + + 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]; + } + + if (quality < 1) + { + quality = 1; + } + + if (quality > 100) + { + quality = 100; + } + + // Convert from a quality rating to a scaling factor. + int scale; + if (quality < 50) + { + scale = 5000 / quality; + } + else + { + scale = 200 - (quality * 2); + } + + // Initialize the quantization tables. + for (int i = 0; i < NQuantIndex; i++) + { + for (int j = 0; j < Block.BlockSize; j++) + { + int x = this.unscaledQuant[i, j]; + x = ((x * scale) + 50) / 100; + if (x < 1) + { + x = 1; + } + + if (x > 255) + { + x = 255; + } + + this.quant[i][j] = (byte)x; + } + } + + // Compute number of components based on input image type. + int componentCount = 3; + + // Write the Start Of Image marker. + this.WriteApplicationHeader((short)image.HorizontalResolution, (short)image.VerticalResolution); + + this.WriteProfiles(image); + + // Write the quantization tables. + this.WriteDescreteQuantizationTables(); + + // Write the image dimensions. + this.WriteStartOfFrame(image.Width, image.Height, componentCount); + + // Write the Huffman tables. + this.WriteDefineHuffmanTables(componentCount); + + // Write the image data. + using (PixelAccessor pixels = image.Lock()) + { + this.WriteStartOfScan(pixels); + } + + // Write the End Of Image marker. + this.buffer[0] = JpegConstants.Markers.XFF; + this.buffer[1] = JpegConstants.Markers.EOI; + stream.Write(this.buffer, 0, 2); + stream.Flush(); + } + + /// + /// Gets the quotient of the two numbers rounded to the nearest integer, instead of rounded to zero. + /// + /// The value to divide. + /// The value to divide by. + /// The + private static int Round(int dividend, int divisor) + { + if (dividend >= 0) + { + return (dividend + (divisor >> 1)) / divisor; + } + + return -((-dividend + (divisor >> 1)) / divisor); + } + /// /// Writes the given byte to the stream. /// @@ -313,19 +512,32 @@ namespace ImageSharp.Formats return dc; } - // toYCbCr converts the 8x8 region of m whose top-left corner is p to its - // YCbCr values. + /// + /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The pixel accessor. + /// The x-position within the image. + /// The y-position within the image. + /// The luminance block. + /// The red chroma block. + /// The blue chroma block. + // ReSharper disable StyleCop.SA1305 private void ToYCbCr(PixelAccessor pixels, int x, int y, Block yBlock, Block cbBlock, Block crBlock) + // ReSharper restore StyleCop.SA1305 where TColor : struct, IPackedPixel where TPacked : struct { int xmax = pixels.Width - 1; int ymax = pixels.Height - 1; + byte[] b = new byte[3]; for (int j = 0; j < 8; j++) { for (int i = 0; i < 8; i++) { - YCbCr color = new Color(pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToVector4()); + pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToBytes(b, 0, ComponentOrder.XYZ); + YCbCr color = new Color(b[0], b[1], b[2]); int index = (8 * j) + i; yBlock[index] = (int)color.Y; cbBlock[index] = (int)color.Cb; @@ -335,12 +547,12 @@ namespace ImageSharp.Formats } /// - /// Scales the 16x16 region represented by the 4 src blocks to the 8x8 - /// dst block. + /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 + /// DST block. /// /// The destination block array /// The source block array. - private void Scale16X16_8X8(Block destination, Block[] source) + private void Scale16X16To8X8(Block destination, Block[] source) { for (int i = 0; i < 4; i++) { @@ -357,174 +569,6 @@ namespace ImageSharp.Formats } } - // The SOS marker "\xff\xda" followed by 8 bytes: - // - the marker length "\x00\x08", - // - the number of components "\x01", - // - component 1 uses DC table 0 and AC table 0 "\x01\x00", - // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for - // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) - // should be 0x00, 0x3f, 0x00<<4 | 0x00. - private readonly byte[] SOSHeaderY = - { - JpegConstants.Markers.XFF, JpegConstants.Markers.SOS, - 0x00, 0x08, // Length (high byte, low byte), must be 6 + 2 * (number of components in scan) - 0x01, // Number of components in a scan, 1 - 0x01, // Component Id Y - 0x00, // DC/AC Huffman table - 0x00, // Ss - Start of spectral selection. - 0x3f, // Se - End of spectral selection. - 0x00 // Ah + Ah (Successive approximation bit position high + low) - }; - - // The SOS marker "\xff\xda" followed by 12 bytes: - // - the marker length "\x00\x0c", - // - the number of components "\x03", - // - component 1 uses DC table 0 and AC table 0 "\x01\x00", - // - component 2 uses DC table 1 and AC table 1 "\x02\x11", - // - component 3 uses DC table 1 and AC table 1 "\x03\x11", - // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for - // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) - // should be 0x00, 0x3f, 0x00<<4 | 0x00. - private readonly byte[] SOSHeaderYCbCr = - { - JpegConstants.Markers.XFF, JpegConstants.Markers.SOS, - 0x00, 0x0c, // Length (high byte, low byte), must be 6 + 2 * (number of components in scan) - 0x03, // Number of components in a scan, 3 - 0x01, // Component Id Y - 0x00, // DC/AC Huffman table - 0x02, // Component Id Cb - 0x11, // DC/AC Huffman table - 0x03, // Component Id Cr - 0x11, // DC/AC Huffman table - 0x00, // Ss - Start of spectral selection. - 0x3f, // Se - End of spectral selection. - 0x00 // Ah + Ah (Successive approximation bit position high + low) - }; - - /// - /// Encode writes the image to the jpeg baseline format with the given options. - /// - /// The pixel format. - /// The packed format. uint, long, float. - /// The image to write from. - /// The stream to write to. - /// The quality. - /// The subsampling mode. - public void Encode(Image image, Stream stream, int quality, JpegSubsample sample) - where TColor : struct, IPackedPixel - where TPacked : struct - { - Guard.NotNull(image, nameof(image)); - Guard.NotNull(stream, nameof(stream)); - - ushort max = JpegConstants.MaxLength; - if (image.Width >= max || image.Height >= max) - { - throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); - } - - this.outputStream = stream; - this.subsample = sample; - - // TODO: This should be static should it not? - for (int i = 0; i < this.theHuffmanSpec.Length; i++) - { - this.theHuffmanLut[i] = new HuffmanLut(this.theHuffmanSpec[i]); - } - - for (int i = 0; i < NQuantIndex; i++) - { - this.quant[i] = new byte[Block.BlockSize]; - } - - if (quality < 1) - { - quality = 1; - } - - if (quality > 100) - { - quality = 100; - } - - // Convert from a quality rating to a scaling factor. - int scale; - if (quality < 50) - { - scale = 5000 / quality; - } - else - { - scale = 200 - (quality * 2); - } - - // Initialize the quantization tables. - for (int i = 0; i < NQuantIndex; i++) - { - for (int j = 0; j < Block.BlockSize; j++) - { - int x = this.unscaledQuant[i, j]; - x = ((x * scale) + 50) / 100; - if (x < 1) - { - x = 1; - } - - if (x > 255) - { - x = 255; - } - - this.quant[i][j] = (byte)x; - } - } - - // Compute number of components based on input image type. - int componentCount = 3; - - // Write the Start Of Image marker. - this.WriteApplicationHeader((short)image.HorizontalResolution, (short)image.VerticalResolution); - - this.WriteProfiles(image); - - // Write the quantization tables. - this.WriteDQT(); - - // Write the image dimensions. - this.WriteSOF0(image.Width, image.Height, componentCount); - - // Write the Huffman tables. - this.WriteDHT(componentCount); - - // Write the image data. - using (PixelAccessor pixels = image.Lock()) - { - this.WriteSOS(pixels); - } - - // Write the End Of Image marker. - this.buffer[0] = 0xff; - this.buffer[1] = 0xd9; - stream.Write(this.buffer, 0, 2); - stream.Flush(); - } - - /// - /// Gets the quotient of the two numbers rounded to the nearest integer, instead of rounded to zero. - /// - /// The value to divide. - /// The value to divide by. - /// The - private static int Round(int dividend, int divisor) - { - if (dividend >= 0) - { - return (dividend + (divisor >> 1)) / divisor; - } - - return -((-dividend + (divisor >> 1)) / divisor); - } - /// /// Writes the application header containing the JFIF identifier plus extra data. /// @@ -565,6 +609,12 @@ namespace ImageSharp.Formats this.outputStream.Write(this.buffer, 0, 4); } + /// + /// Writes the metadata profiles to the image. + /// + /// The image. + /// The pixel format. + /// The packed format. uint, long, float. private void WriteProfiles(Image image) where TColor : struct, IPackedPixel where TPacked : struct @@ -572,17 +622,25 @@ namespace ImageSharp.Formats this.WriteProfile(image.ExifProfile); } + /// + /// Writes the EXIF profile. + /// + /// The exif profile. + /// + /// Thrown if the EXIF profile size exceeds the limit + /// private void WriteProfile(ExifProfile exifProfile) { + const int Max = 65533; byte[] data = exifProfile?.ToByteArray(); if (data == null || data.Length == 0) { return; } - if (data.Length > 65533) + if (data.Length > Max) { - throw new ImageFormatException("Exif profile size exceeds limit."); + throw new ImageFormatException($"Exif profile size exceeds limit. nameof{Max}"); } int length = data.Length + 2; @@ -599,7 +657,7 @@ namespace ImageSharp.Formats /// /// Writes the Define Quantization Marker and tables. /// - private void WriteDQT() + private void WriteDescreteQuantizationTables() { int markerlen = 2 + (NQuantIndex * (1 + Block.BlockSize)); this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen); @@ -615,8 +673,8 @@ namespace ImageSharp.Formats /// /// The width of the image /// The height of the image - /// - private void WriteSOF0(int width, int height, int componentCount) + /// The number of components in a pixel + private void WriteStartOfFrame(int width, int height, int componentCount) { // "default" to 4:2:0 byte[] subsamples = { 0x22, 0x11, 0x11 }; @@ -667,17 +725,17 @@ namespace ImageSharp.Formats /// /// Writes the Define Huffman Table marker and tables. /// - /// The number of components to write. - private void WriteDHT(int nComponent) + /// The number of components to write. + private void WriteDefineHuffmanTables(int componentCount) { byte[] headers = { 0x00, 0x10, 0x01, 0x11 }; int markerlen = 2; - HuffmanSpec[] specs = this.theHuffmanSpec; + HuffmanSpec[] specs = this.huffmanSpec; - if (nComponent == 1) + if (componentCount == 1) { // Drop the Chrominance tables. - specs = new[] { this.theHuffmanSpec[0], this.theHuffmanSpec[1] }; + specs = new[] { this.huffmanSpec[0], this.huffmanSpec[1] }; } foreach (HuffmanSpec s in specs) @@ -699,21 +757,25 @@ namespace ImageSharp.Formats /// /// Writes the StartOfScan marker. /// - /// The pixel accessor providing access to the image pixels. - private void WriteSOS(PixelAccessor pixels) + /// The pixel format. + /// The packed format. uint, long, float. + /// + /// The pixel accessor providing access to the image pixels. + /// + private void WriteStartOfScan(PixelAccessor pixels) where TColor : struct, IPackedPixel where TPacked : struct { // TODO: We should allow grayscale writing. - this.outputStream.Write(this.SOSHeaderYCbCr, 0, this.SOSHeaderYCbCr.Length); + this.outputStream.Write(this.sosHeaderYCbCr, 0, this.sosHeaderYCbCr.Length); switch (this.subsample) { case JpegSubsample.Ratio444: - this.Encode444(pixels); + this.Encode444(pixels); break; case JpegSubsample.Ratio420: - this.Encode420(pixels); + this.Encode420(pixels); break; } @@ -724,7 +786,9 @@ namespace ImageSharp.Formats /// /// Encodes the image with no subsampling. /// - /// The pixel accessor providing acces to the image pixels. + /// The pixel format. + /// The packed format. uint, long, float. + /// The pixel accessor providing access to the image pixels. private void Encode444(PixelAccessor pixels) where TColor : struct, IPackedPixel where TPacked : struct @@ -732,13 +796,14 @@ namespace ImageSharp.Formats Block b = new Block(); Block cb = new Block(); Block cr = new Block(); + // ReSharper disable once InconsistentNaming int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; for (int y = 0; y < pixels.Height; y += 8) { for (int x = 0; x < pixels.Width; x += 8) { - this.ToYCbCr(pixels, x, y, b, cb, cr); + this.ToYCbCr(pixels, x, y, b, cb, cr); prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY); prevDCCb = this.WriteBlock(cb, QuantIndex.Chrominance, prevDCCb); prevDCCr = this.WriteBlock(cr, QuantIndex.Chrominance, prevDCCr); @@ -750,7 +815,9 @@ namespace ImageSharp.Formats /// Encodes the image with subsampling. The Cb and Cr components are each subsampled /// at a factor of 2 both horizontally and vertically. /// - /// The pixel accessor providing acces to the image pixels. + /// The pixel format. + /// The packed format. uint, long, float. + /// The pixel accessor providing access to the image pixels. private void Encode420(PixelAccessor pixels) where TColor : struct, IPackedPixel where TPacked : struct @@ -758,6 +825,7 @@ namespace ImageSharp.Formats Block b = new Block(); Block[] cb = new Block[4]; Block[] cr = new Block[4]; + // ReSharper disable once InconsistentNaming int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; for (int i = 0; i < 4; i++) @@ -783,9 +851,9 @@ namespace ImageSharp.Formats prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY); } - this.Scale16X16_8X8(b, cb); + this.Scale16X16To8X8(b, cb); prevDCCb = this.WriteBlock(b, QuantIndex.Chrominance, prevDCCb); - this.Scale16X16_8X8(b, cr); + this.Scale16X16To8X8(b, cr); prevDCCr = this.WriteBlock(b, QuantIndex.Chrominance, prevDCCr); } } @@ -806,36 +874,6 @@ namespace ImageSharp.Formats this.outputStream.Write(this.buffer, 0, 4); } - /// - /// Enumerates the Huffman tables - /// - private enum HuffIndex - { - LuminanceDC = 0, - - LuminanceAC = 1, - - ChrominanceDC = 2, - - ChrominanceAC = 3, - } - - /// - /// Enumerates the quantization tables - /// - private enum QuantIndex - { - /// - /// Luminance - /// - Luminance = 0, - - /// - /// Chrominance - /// - Chrominance = 1, - } - /// /// The Huffman encoding specifications. ///