diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
index 72300e6fb1..0b05b955d2 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
@@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// Luminance quantization table provided by the callee
/// Chrominance quantization table provided by the callee
/// The token to monitor for cancellation.
- private void Encode444(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
+ public void Encode444(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
var unzig = ZigZag.CreateUnzigTable();
@@ -129,6 +129,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref unzig);
}
}
+
+ // Pad the last byte with 1's.
+ this.Emit(0x7f, 7);
+ this.target.Write(this.emitBuffer, 0, this.emitLen);
}
///
@@ -140,7 +144,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// Luminance quantization table provided by the callee
/// Chrominance quantization table provided by the callee
/// The token to monitor for cancellation.
- private void Encode420(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
+ public void Encode420(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
// TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
@@ -199,6 +203,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref unzig);
}
}
+
+ // Pad the last byte with 1's.
+ this.Emit(0x7f, 7);
+ this.target.Write(this.emitBuffer, 0, this.emitLen);
}
@@ -209,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// The pixel accessor providing access to the image pixels.
/// Luminance quantization table provided by the callee
/// The token to monitor for cancellation.
- private void EncodeGrayscale(Image pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken)
+ public void EncodeGrayscale(Image pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
var unzig = ZigZag.CreateUnzigTable();
@@ -239,33 +247,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref unzig);
}
}
- }
-
- public void WriteStartOfScan(
- Image image,
- JpegColorType? colorType,
- JpegSubsample? subsample,
- ref Block8x8F luminanceQuantTable,
- ref Block8x8F chrominanceTable,
- CancellationToken cancellationToken)
- where TPixel : unmanaged, IPixel
- {
- if (colorType == JpegColorType.Luminance)
- {
- this.EncodeGrayscale(image, ref luminanceQuantTable, cancellationToken);
- }
- else
- {
- switch (subsample)
- {
- case JpegSubsample.Ratio444:
- this.Encode444(image, ref luminanceQuantTable, ref chrominanceTable, cancellationToken);
- break;
- case JpegSubsample.Ratio420:
- this.Encode420(image, ref luminanceQuantTable, ref chrominanceTable, cancellationToken);
- break;
- }
- }
// Pad the last byte with 1's.
this.Emit(0x7f, 7);
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index e9a5f7e02a..9ff3344531 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -86,9 +86,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private readonly int? quality;
///
- /// Gets or sets the subsampling method to use.
+ /// Component count.
///
- private readonly JpegColorType? colorType;
+ private readonly int componentCount;
///
/// The output stream. All attempted writes after the first error become no-ops.
@@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
this.quality = options.Quality;
this.subsample = options.Subsample;
- this.colorType = options.ColorType;
+ this.componentCount = (options.ColorType == JpegColorType.Luminance) ? 1 : 3;
}
///
@@ -129,9 +129,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.outputStream = stream;
ImageMetadata metadata = image.Metadata;
- // Compute number of components based on color type in options.
- int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3;
-
// System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1.
int qlty = Numerics.Clamp(this.quality ?? metadata.GetJpegMetadata().Quality, 1, 100);
this.subsample ??= qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420;
@@ -153,7 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
Block8x8F luminanceQuantTable = default;
Block8x8F chrominanceQuantTable = default;
InitQuantizationTable(0, scale, ref luminanceQuantTable);
- if (componentCount > 1)
+ if (this.componentCount > 1)
{
InitQuantizationTable(1, scale, ref chrominanceQuantTable);
}
@@ -177,13 +174,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.WriteStartOfScan(image, componentCount, cancellationToken);
// Write the scan compressed data.
- new HuffmanScanEncoder(stream).WriteStartOfScan(
- image,
- this.colorType,
- this.subsample,
- ref luminanceQuantTable,
- ref chrominanceQuantTable,
- cancellationToken);
+ var scanEncoder = new HuffmanScanEncoder(stream);
+ if (this.componentCount == 1)
+ {
+ scanEncoder.EncodeGrayscale(image, ref luminanceQuantTable, cancellationToken);
+ }
+ else
+ {
+ switch (subsample)
+ {
+ case JpegSubsample.Ratio444:
+ scanEncoder.Encode444(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken);
+ break;
+ case JpegSubsample.Ratio420:
+ scanEncoder.Encode420(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken);
+ break;
+ }
+ }
// Write the End Of Image marker.
this.buffer[0] = JpegConstants.Markers.XFF;