Browse Source

Moved encode method choice to the JpegEncoderCore

pull/1632/head
Dmitry Pentin 5 years ago
parent
commit
7e0a317461
  1. 41
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  2. 35
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

41
src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param> /// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param>
/// <param name="chrominanceQuantTable">Chrominance quantization table provided by the callee</param> /// <param name="chrominanceQuantTable">Chrominance quantization table provided by the callee</param>
/// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param>
private void Encode444<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) public void Encode444<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var unzig = ZigZag.CreateUnzigTable(); var unzig = ZigZag.CreateUnzigTable();
@ -129,6 +129,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref unzig); ref unzig);
} }
} }
// Pad the last byte with 1's.
this.Emit(0x7f, 7);
this.target.Write(this.emitBuffer, 0, this.emitLen);
} }
/// <summary> /// <summary>
@ -140,7 +144,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param> /// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param>
/// <param name="chrominanceQuantTable">Chrominance quantization table provided by the callee</param> /// <param name="chrominanceQuantTable">Chrominance quantization table provided by the callee</param>
/// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param>
private void Encode420<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) public void Encode420<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> 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); 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
/// <param name="pixels">The pixel accessor providing access to the image pixels.</param> /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param> /// <param name="luminanceQuantTable">Luminance quantization table provided by the callee</param>
/// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param>
private void EncodeGrayscale<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken) public void EncodeGrayscale<TPixel>(Image<TPixel> pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var unzig = ZigZag.CreateUnzigTable(); var unzig = ZigZag.CreateUnzigTable();
@ -239,33 +247,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref unzig); ref unzig);
} }
} }
}
public void WriteStartOfScan<TPixel>(
Image<TPixel> image,
JpegColorType? colorType,
JpegSubsample? subsample,
ref Block8x8F luminanceQuantTable,
ref Block8x8F chrominanceTable,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
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. // Pad the last byte with 1's.
this.Emit(0x7f, 7); this.Emit(0x7f, 7);

35
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -86,9 +86,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private readonly int? quality; private readonly int? quality;
/// <summary> /// <summary>
/// Gets or sets the subsampling method to use. /// Component count.
/// </summary> /// </summary>
private readonly JpegColorType? colorType; private readonly int componentCount;
/// <summary> /// <summary>
/// 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.
@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
this.quality = options.Quality; this.quality = options.Quality;
this.subsample = options.Subsample; this.subsample = options.Subsample;
this.colorType = options.ColorType; this.componentCount = (options.ColorType == JpegColorType.Luminance) ? 1 : 3;
} }
/// <summary> /// <summary>
@ -129,9 +129,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.outputStream = stream; this.outputStream = stream;
ImageMetadata metadata = image.Metadata; 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. // 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); int qlty = Numerics.Clamp(this.quality ?? metadata.GetJpegMetadata().Quality, 1, 100);
this.subsample ??= qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420; this.subsample ??= qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420;
@ -153,7 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
Block8x8F luminanceQuantTable = default; Block8x8F luminanceQuantTable = default;
Block8x8F chrominanceQuantTable = default; Block8x8F chrominanceQuantTable = default;
InitQuantizationTable(0, scale, ref luminanceQuantTable); InitQuantizationTable(0, scale, ref luminanceQuantTable);
if (componentCount > 1) if (this.componentCount > 1)
{ {
InitQuantizationTable(1, scale, ref chrominanceQuantTable); InitQuantizationTable(1, scale, ref chrominanceQuantTable);
} }
@ -177,13 +174,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.WriteStartOfScan(image, componentCount, cancellationToken); this.WriteStartOfScan(image, componentCount, cancellationToken);
// Write the scan compressed data. // Write the scan compressed data.
new HuffmanScanEncoder(stream).WriteStartOfScan( var scanEncoder = new HuffmanScanEncoder(stream);
image, if (this.componentCount == 1)
this.colorType, {
this.subsample, scanEncoder.EncodeGrayscale(image, ref luminanceQuantTable, cancellationToken);
ref luminanceQuantTable, }
ref chrominanceQuantTable, else
cancellationToken); {
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. // Write the End Of Image marker.
this.buffer[0] = JpegConstants.Markers.XFF; this.buffer[0] = JpegConstants.Markers.XFF;

Loading…
Cancel
Save