diff --git a/src/ImageSharp/Formats/Jpg/Components/BlockQuad.cs b/src/ImageSharp/Formats/Jpg/Components/BlockQuad.cs new file mode 100644 index 000000000..63453da21 --- /dev/null +++ b/src/ImageSharp/Formats/Jpg/Components/BlockQuad.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +namespace ImageSharp.Formats.Jpg.Components +{ + /// + /// Poor man's stackalloc: Contains a value-type buffer sized for 4 instances. + /// Useful for decoder/encoder operations allocating a block for each Jpeg component. + /// + internal unsafe struct BlockQuad + { + /// + /// The value-type buffer sized for 4 instances. + /// + public fixed float Data[4 * Block8x8F.ScalarCount]; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs index 4413163d3..96e3f3071 100644 --- a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs @@ -11,19 +11,20 @@ namespace ImageSharp.Formats using System.Runtime.CompilerServices; using ImageSharp.Formats.Jpg; + using ImageSharp.Formats.Jpg.Components; /// - /// Image encoder for writing an image to a stream as a jpeg. + /// Image encoder for writing an image to a stream as a jpeg. /// internal unsafe class JpegEncoderCore { /// - /// The number of quantization tables. + /// The number of quantization tables. /// private const int QuantizationTableCount = 2; /// - /// Counts the number of bits needed to hold an integer. + /// Counts the number of bits needed to hold an integer. /// private static readonly uint[] BitCountLut = { @@ -43,15 +44,15 @@ namespace ImageSharp.Formats }; /// - /// 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. + /// 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 static readonly byte[] SosHeaderYCbCr = { @@ -76,10 +77,10 @@ namespace ImageSharp.Formats }; /// - /// 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. + /// 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 static readonly byte[,] UnscaledQuant = { @@ -102,69 +103,59 @@ namespace ImageSharp.Formats }; /// - /// A scratch buffer to reduce allocations. + /// A scratch buffer to reduce allocations. /// private readonly byte[] buffer = new byte[16]; /// - /// A buffer for reducing the number of stream writes when emitting Huffman tables. 64 seems to be enough. + /// A buffer for reducing the number of stream writes when emitting Huffman tables. 64 seems to be enough. /// private readonly byte[] emitBuffer = new byte[64]; /// - /// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths + - /// identifier. + /// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths + + /// identifier. /// private readonly byte[] huffmanBuffer = new byte[179]; /// - /// The accumulated bits to write to the stream. + /// The accumulated bits to write to the stream. /// private uint accumulatedBits; /// - /// The accumulated bit count. + /// The accumulated bit count. /// private uint bitCount; /// - /// The scaled chrominance table, in zig-zag order. + /// The scaled chrominance table, in zig-zag order. /// private Block8x8F chrominanceQuantTable; /// - /// The scaled luminance table, in zig-zag order. + /// The scaled luminance table, in zig-zag order. /// private Block8x8F luminanceQuantTable; /// - /// The output stream. All attempted writes after the first error become no-ops. + /// The output stream. All attempted writes after the first error become no-ops. /// private Stream outputStream; /// - /// The subsampling method to use. + /// The subsampling method to use. /// private JpegSubsample subsample; /// /// Encode writes the image to the jpeg baseline format with the given options. /// - /// - /// The pixel format. - /// - /// - /// The image to write from. - /// - /// - /// The stream to write to. - /// - /// - /// The quality. - /// - /// - /// The subsampling mode. - /// + /// The pixel format. + /// 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, IEquatable { @@ -258,30 +249,14 @@ namespace ImageSharp.Formats /// /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values. /// - /// - /// The pixel format. - /// - /// - /// 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. - /// - /// - /// Temporal provided by the caller - /// + /// The pixel format. + /// 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. + /// Temporal provided by the caller private static void ToYCbCr( PixelAccessor pixels, int x, @@ -326,18 +301,14 @@ namespace ImageSharp.Formats /// /// Emits the least significant count of bits of bits to the bit-stream. - /// The precondition is bits - /// + /// The precondition is bits + /// /// < 1<<nBits && nBits <= 16 /// /// . /// - /// - /// The packed bits. - /// - /// - /// The number of bits - /// + /// The packed bits. + /// The number of bits private void Emit(uint bits, uint count) { count += this.bitCount; @@ -375,12 +346,8 @@ namespace ImageSharp.Formats /// /// Emits the given value with the given Huffman encoder. /// - /// - /// The index of the Huffman encoder - /// - /// - /// The value to encode. - /// + /// The index of the Huffman encoder + /// The value to encode. [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EmitHuff(HuffIndex index, int value) { @@ -391,15 +358,9 @@ namespace ImageSharp.Formats /// /// Emits a run of runLength copies of value encoded with the given Huffman encoder. /// - /// - /// The index of the Huffman encoder - /// - /// - /// The number of copies to encode. - /// - /// - /// The value to encode. - /// + /// The index of the Huffman encoder + /// The number of copies to encode. + /// The value to encode. [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EmitHuffRLE(HuffIndex index, int runLength, int value) { @@ -431,12 +392,8 @@ namespace ImageSharp.Formats /// /// Encodes the image with no subsampling. /// - /// - /// The pixel format. - /// - /// - /// The pixel accessor providing access to the image pixels. - /// + /// The pixel format. + /// The pixel accessor providing access to the image pixels. private void Encode444(PixelAccessor pixels) where TColor : struct, IPackedPixel, IEquatable { @@ -496,12 +453,8 @@ namespace ImageSharp.Formats /// /// Writes the application header containing the JFIF identifier plus extra data. /// - /// - /// The resolution of the image in the x- direction. - /// - /// - /// The resolution of the image in the y- direction. - /// + /// The resolution of the image in the x- direction. + /// The resolution of the image in the y- direction. private void WriteApplicationHeader(short horizontalResolution, short verticalResolution) { // Write the start of image marker. Markers are always prefixed with with 0xff. @@ -539,30 +492,16 @@ namespace ImageSharp.Formats /// /// Writes a block of pixel data using the given quantization table, - /// returning the post-quantized DC value of the DCT-transformed block. - /// The block is in natural (not zig-zag) order. + /// returning the post-quantized DC value of the DCT-transformed block. + /// The block is in natural (not zig-zag) order. /// - /// - /// The quantization table index. - /// - /// - /// The previous DC value. - /// - /// - /// Source block - /// - /// - /// Temporal block to be used as FDCT Destination - /// - /// - /// Temporal block 2 - /// - /// - /// Quantization table - /// - /// - /// The 8x8 Unzig block ptr - /// + /// The quantization table index. + /// The previous DC value. + /// Source block + /// Temporal block to be used as FDCT Destination + /// Temporal block 2 + /// Quantization table + /// The 8x8 Unzig block ptr /// /// The /// @@ -622,9 +561,7 @@ namespace ImageSharp.Formats /// /// Writes the Define Huffman Table marker and tables. /// - /// - /// The number of components to write. - /// + /// The number of components to write. private void WriteDefineHuffmanTables(int componentCount) { // Table identifiers. @@ -671,7 +608,7 @@ namespace ImageSharp.Formats } /// - /// Writes the Define Quantization Marker and tables. + /// Writes the Define Quantization Marker and tables. /// private void WriteDefineQuantizationTables() { @@ -695,9 +632,7 @@ namespace ImageSharp.Formats /// /// Writes the EXIF profile. /// - /// - /// The exif profile. - /// + /// The exif profile. /// /// Thrown if the EXIF profile size exceeds the limit /// @@ -729,12 +664,8 @@ namespace ImageSharp.Formats /// /// Writes the metadata profiles to the image. /// - /// - /// The image. - /// - /// - /// The pixel format. - /// + /// The image. + /// The pixel format. private void WriteProfiles(Image image) where TColor : struct, IPackedPixel, IEquatable { @@ -744,15 +675,9 @@ namespace ImageSharp.Formats /// /// Writes the Start Of Frame (Baseline) marker /// - /// - /// The width of the image - /// - /// - /// The height of the image - /// - /// - /// The number of components in a pixel - /// + /// The width of the image + /// The height of the image + /// The number of components in a pixel private void WriteStartOfFrame(int width, int height, int componentCount) { // "default" to 4:2:0 @@ -806,12 +731,8 @@ namespace ImageSharp.Formats /// /// Writes the StartOfScan marker. /// - /// - /// The pixel format. - /// - /// - /// The pixel accessor providing access to the image pixels. - /// + /// The pixel format. + /// The pixel accessor providing access to the image pixels. private void WriteStartOfScan(PixelAccessor pixels) where TColor : struct, IPackedPixel, IEquatable { @@ -833,28 +754,12 @@ namespace ImageSharp.Formats this.Emit(0x7f, 7); } -#pragma warning disable SA1201 // MethodShouldNotFollowAStruct - - /// - /// Poor man's stackalloc for Encode420. - /// This struct belongs to Encode420. Much easeier to understand code if they are close to each other. Why should I - /// move it Up? :P - /// - private struct BlockQuad - { - public fixed float Data[4 * Block8x8F.ScalarCount]; - } - /// /// Encodes the image with subsampling. The Cb and Cr components are each subsampled - /// at a factor of 2 both horizontally and vertically. + /// at a factor of 2 both horizontally and vertically. /// - /// - /// The pixel format. - /// - /// - /// The pixel accessor providing access to the image pixels. - /// + /// The pixel format. + /// The pixel accessor providing access to the image pixels. private void Encode420(PixelAccessor pixels) where TColor : struct, IPackedPixel, IEquatable { @@ -923,17 +828,11 @@ namespace ImageSharp.Formats } } -#pragma warning restore SA1201 - /// /// Writes the header for a marker with the given length. /// - /// - /// The marker to write. - /// - /// - /// The marker length. - /// + /// The marker to write. + /// The marker length. private void WriteMarkerHeader(byte marker, int length) { // Markers are always prefixed with with 0xff.