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.