diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index 4c81c58dd3..593937b929 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -102,18 +102,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// Compute number of components based on color type in options.
int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3;
- // Initialize the quantization tables.
// TODO: Right now encoder writes both quantization tables for grayscale images - we shouldn't do that
- int lumaQuality = Numerics.Clamp(this.luminanceQuality ?? jpegMetadata.LuminanceQuality, 1, 100);
- Block8x8F luminanceQuantTable = Quantization.ScaleLuminanceTable(lumaQuality);
- Block8x8F chrominanceQuantTable = default;
- if (componentCount > 1)
- {
- int chromaQuality = Numerics.Clamp(this.chrominanceQuality ?? jpegMetadata.ChrominanceQuality, 1, 100);
- this.subsample ??= chromaQuality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420;
-
- chrominanceQuantTable = Quantization.ScaleChrominanceTable(chromaQuality);
- }
+ // Initialize the quantization tables.
+ this.InitQuantizationTables(componentCount, jpegMetadata, out Block8x8F luminanceQuantTable, out Block8x8F chrominanceQuantTable);
// Write the Start Of Image marker.
this.WriteApplicationHeader(metadata);
@@ -651,5 +642,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.buffer[3] = (byte)(length & 0xff);
this.outputStream.Write(this.buffer, 0, 4);
}
+
+ ///
+ /// Initializes quntization tables.
+ ///
+ /// Color components count.
+ /// Jpeg metadata instance.
+ /// Output luminance quantization table.
+ /// Output chrominance quantization table.
+ private void InitQuantizationTables(int componentCount, JpegMetadata metadata, out Block8x8F luminanceQuantTable, out Block8x8F chrominanceQuantTable)
+ {
+ // We take quality values in a hierarchical order:
+ // 1. Check if encoder has set quality
+ // 2. Check if metadata has special table for encoding
+ // 3. Check if metadata has set quality
+ // 4. Take default quality value - 75
+ int lumaQuality = Numerics.Clamp(
+ this.luminanceQuality ?? metadata.LuminanceQuality ?? DefaultQualityValue,
+ min: 1,
+ max: 100);
+
+ luminanceQuantTable = Quantization.ScaleLuminanceTable(lumaQuality);
+ chrominanceQuantTable = default;
+ if (componentCount > 1)
+ {
+ int chromaQuality = Numerics.Clamp(
+ this.chrominanceQuality ?? metadata.ChrominanceQuality ?? DefaultQualityValue,
+ min: 1,
+ max: 100);
+
+ this.subsample ??= chromaQuality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420;
+
+ chrominanceQuantTable = Quantization.ScaleChrominanceTable(chromaQuality);
+ }
+ }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
index 0579e7b5e8..8b3332ef8b 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
@@ -24,7 +24,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// The metadata to create an instance from.
private JpegMetadata(JpegMetadata other)
{
- this.Quality = other.Quality;
this.ColorType = other.ColorType;
this.LumaQuantizationTable = other.LumaQuantizationTable;
@@ -56,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// This value might not be accurate if it was calculated during jpeg decoding
/// with non-complient ITU quantization tables.
///
- public int LuminanceQuality { get; set; }
+ public int? LuminanceQuality { get; set; }
///
/// Gets or sets the jpeg chrominance quality.
@@ -65,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// This value might not be accurate if it was calculated during jpeg decoding
/// with non-complient ITU quantization tables.
///
- public int ChrominanceQuality { get; set; }
+ public int? ChrominanceQuality { get; set; }
///
/// Gets a value indicating whether jpeg luminance data was encoded using ITU complient quantization table.
@@ -82,7 +81,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
public int Quality
{
- get => (int)Math.Round((this.LuminanceQuality + this.ChrominanceQuality) / 2f);
+ [Obsolete("This accessor will soon be deprecated. Use LuminanceQuality and ChrominanceQuality getters instead.", error: false)]
+ get
+ {
+ const int defaultQuality = 75;
+
+ int lumaQuality = this.LuminanceQuality ?? defaultQuality;
+ int chromaQuality = this.LuminanceQuality ?? lumaQuality;
+ return (int)Math.Round((lumaQuality + chromaQuality) / 2f);
+ }
+
set
{
this.LuminanceQuality = value;