From 7e0a317461e8eba128c97bb205396d71ae687a6d Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 21 May 2021 16:54:09 +0300 Subject: [PATCH] Moved encode method choice to the JpegEncoderCore --- .../Components/Encoder/HuffmanScanEncoder.cs | 41 +++++-------------- .../Formats/Jpeg/JpegEncoderCore.cs | 35 +++++++++------- 2 files changed, 32 insertions(+), 44 deletions(-) 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;