Browse Source

Made frame configs internal

pull/2120/head
Dmitry Pentin 4 years ago
parent
commit
3d31a16a88
  1. 7
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  2. 5
      src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs
  3. 5
      src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs
  4. 22
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  5. 201
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  6. 112
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  7. 6
      src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs
  8. 2
      src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
  9. 2
      src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs
  10. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs
  11. 6
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs
  12. 30
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs
  13. 82
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  14. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs
  15. 10
      tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs

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

@ -138,15 +138,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
tables[tableConfig.DestinationIndex] = new HuffmanLut(tableConfig.Table);
}
public void EncodeInterleavedScan<TPixel>(JpegFrame frame, Image<TPixel> image, Block8x8F[] quantTables, Configuration configuration, CancellationToken cancellationToken)
public void EncodeInterleavedBaselineScan<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
// DEBUG INITIALIZATION SETUP
frame.AllocateComponents(fullScan: false);
var spectralConverter = new SpectralConverter<TPixel>(configuration);
spectralConverter.InjectFrameData(frame, image, quantTables);
// DEBUG ENCODING SETUP
int mcu = 0;
int mcusPerColumn = frame.McusPerColumn;
@ -157,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
cancellationToken.ThrowIfCancellationRequested();
// Convert from pixels to spectral via given converter
spectralConverter.ConvertStrideBaseline();
converter.ConvertStrideBaseline();
// decode from binary to spectral
for (int i = 0; i < mcusPerLine; i++)

5
src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs

@ -29,11 +29,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private JpegColorConverterBase colorConverter;
public SpectralConverter(Configuration configuration) =>
public SpectralConverter(JpegFrame frame, Image<TPixel> image, Block8x8F[] dequantTables, Configuration configuration)
{
this.configuration = configuration;
public void InjectFrameData(JpegFrame frame, Image<TPixel> image, Block8x8F[] dequantTables)
{
MemoryAllocator allocator = this.configuration.MemoryAllocator;
// iteration data

5
src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs

@ -14,10 +14,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Defaults to <value>75</value>.
/// </summary>
public int? Quality { get; set; }
/// <summary>
/// Gets the color type, that will be used to encode the image.
/// </summary>
JpegEncodingMode? ColorType { get; }
}
}

22
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -545,57 +545,57 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Returns the jpeg color type based on the colorspace and subsampling used.
/// </summary>
/// <returns>Jpeg color type.</returns>
private JpegEncodingMode DeduceJpegColorType()
private JpegEncodingColor DeduceJpegColorType()
{
switch (this.ColorSpace)
{
case JpegColorSpace.Grayscale:
return JpegEncodingMode.Luminance;
return JpegEncodingColor.Luminance;
case JpegColorSpace.RGB:
return JpegEncodingMode.Rgb;
return JpegEncodingColor.Rgb;
case JpegColorSpace.YCbCr:
if (this.Frame.Components[0].HorizontalSamplingFactor == 1 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingMode.YCbCrRatio444;
return JpegEncodingColor.YCbCrRatio444;
}
else if (this.Frame.Components[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingMode.YCbCrRatio420;
return JpegEncodingColor.YCbCrRatio420;
}
else if (this.Frame.Components[0].HorizontalSamplingFactor == 1 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 2 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 2)
{
return JpegEncodingMode.YCbCrRatio422;
return JpegEncodingColor.YCbCrRatio422;
}
else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingMode.YCbCrRatio411;
return JpegEncodingColor.YCbCrRatio411;
}
else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingMode.YCbCrRatio410;
return JpegEncodingColor.YCbCrRatio410;
}
else
{
return JpegEncodingMode.YCbCrRatio420;
return JpegEncodingColor.YCbCrRatio420;
}
case JpegColorSpace.Cmyk:
return JpegEncodingMode.Cmyk;
return JpegEncodingColor.Cmyk;
default:
return JpegEncodingMode.YCbCrRatio420;
return JpegEncodingColor.YCbCrRatio420;
}
}

201
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -16,15 +16,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions
{
/// <summary>
/// The available encodable frame configs.
/// </summary>
private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs();
/// <inheritdoc/>
public int? Quality { get; set; }
/// <inheritdoc/>
public JpegEncodingMode? ColorType { get; set; }
public JpegEncodingColor ColorType
{
set
{
JpegFrameConfig frameConfig = Array.Find(
FrameConfigs,
cfg => cfg.EncodingColor == value);
if (frameConfig is null)
{
throw new ArgumentException(nameof(value));
}
this.FrameConfig = frameConfig;
}
}
public JpegFrameConfig JpegFrameConfig { get; set; }
internal JpegFrameConfig FrameConfig { get; set; }
public JpegScanConfig JpegScanConfig { get; set; }
public JpegScanConfig ScanConfig { get; set; }
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
@ -35,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new JpegEncoderCore(this, this.JpegFrameConfig, this.JpegScanConfig);
var encoder = new JpegEncoderCore(this, this.FrameConfig, this.ScanConfig);
encoder.Encode(image, stream);
}
@ -50,81 +69,153 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new JpegEncoderCore(this, this.JpegFrameConfig, this.JpegScanConfig);
var encoder = new JpegEncoderCore(this, this.FrameConfig, this.ScanConfig);
return encoder.EncodeAsync(image, stream, cancellationToken);
}
private static JpegFrameConfig[] CreateFrameConfigs() => new JpegFrameConfig[]
{
// YCbCr 4:4:4
new JpegFrameConfig(
JpegColorSpace.YCbCr,
JpegEncodingColor.YCbCrRatio444,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
}),
// YCbCr 4:2:2
new JpegFrameConfig(
JpegColorSpace.YCbCr,
JpegEncodingColor.YCbCrRatio422,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 2, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
}),
// YCbCr 4:2:0
new JpegFrameConfig(
JpegColorSpace.YCbCr,
JpegEncodingColor.YCbCrRatio420,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 2, vsf: 2, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
}),
// YCbCr 4:1:1
new JpegFrameConfig(
JpegColorSpace.YCbCr,
JpegEncodingColor.YCbCrRatio411,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 4, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
}),
// YCbCr 4:1:0
new JpegFrameConfig(
JpegColorSpace.YCbCr,
JpegEncodingColor.YCbCrRatio410,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 4, vsf: 2, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 1, dcIndex: 1, acIndex: 1),
}),
// Luminance
new JpegFrameConfig(
JpegColorSpace.Grayscale,
JpegEncodingColor.Luminance,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 0, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
}),
// Rgb
new JpegFrameConfig(
JpegColorSpace.RGB,
JpegEncodingColor.Rgb,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 82, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 71, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 66, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
}),
// Cmyk
new JpegFrameConfig(
JpegColorSpace.Cmyk,
JpegEncodingColor.Cmyk,
new JpegComponentConfig[]
{
new JpegComponentConfig(id: 1, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 2, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 3, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
new JpegComponentConfig(id: 4, hsf: 1, vsf: 1, quantIndex: 0, dcIndex: 0, acIndex: 0),
}),
};
}
public class JpegFrameConfig
internal class JpegFrameConfig
{
public JpegFrameConfig(JpegEncodingMode colorType)
public JpegFrameConfig(JpegColorSpace colorType, JpegEncodingColor encodingColor, JpegComponentConfig[] components)
{
this.ColorType = colorType;
this.EncodingColor = encodingColor;
this.Components = components;
int componentCount = GetComponentCountFromColorType(colorType);
this.Components = new JpegComponentConfig[componentCount];
static int GetComponentCountFromColorType(JpegEncodingMode colorType)
this.MaxHorizontalSamplingFactor = components[0].HorizontalSampleFactor;
this.MaxVerticalSamplingFactor = components[0].VerticalSampleFactor;
for (int i = 1; i < components.Length; i++)
{
switch (colorType)
{
case JpegEncodingMode.Luminance:
return 1;
case JpegEncodingMode.YCbCrRatio444:
case JpegEncodingMode.YCbCrRatio422:
case JpegEncodingMode.YCbCrRatio420:
case JpegEncodingMode.YCbCrRatio411:
case JpegEncodingMode.YCbCrRatio410:
case JpegEncodingMode.Rgb:
return 3;
case JpegEncodingMode.Cmyk:
return 4;
default:
throw new ArgumentException($"Unknown jpeg color space: {colorType}");
}
JpegComponentConfig component = components[i];
this.MaxHorizontalSamplingFactor = Math.Max(this.MaxHorizontalSamplingFactor, component.HorizontalSampleFactor);
this.MaxVerticalSamplingFactor = Math.Max(this.MaxVerticalSamplingFactor, component.VerticalSampleFactor);
}
}
public JpegEncodingMode ColorType { get; }
public JpegColorSpace ColorType { get; }
public JpegEncodingColor EncodingColor { get; }
public JpegComponentConfig[] Components { get; }
public int MaxHorizontalSamplingFactor { get; set; } = 1;
public int MaxHorizontalSamplingFactor { get; }
public int MaxVerticalSamplingFactor { get; set; } = 1;
public int MaxVerticalSamplingFactor { get; }
}
public JpegFrameConfig PopulateComponent(int index, byte id, int hsf, int vsf, int quantIndex, int dcIndex, int acIndex)
internal class JpegComponentConfig
{
public JpegComponentConfig(byte id, int hsf, int vsf, int quantIndex, int dcIndex, int acIndex)
{
this.Components[index] = new JpegComponentConfig
{
Id = id,
HorizontalSampleFactor = hsf,
VerticalSampleFactor = vsf,
QuantizatioTableIndex = quantIndex,
dcTableSelector = dcIndex,
acTableSelector = acIndex,
};
this.MaxHorizontalSamplingFactor = Math.Max(this.MaxHorizontalSamplingFactor, hsf);
this.MaxVerticalSamplingFactor = Math.Max(this.MaxVerticalSamplingFactor, vsf);
return this;
this.Id = id;
this.HorizontalSampleFactor = hsf;
this.VerticalSampleFactor = vsf;
this.QuantizatioTableIndex = quantIndex;
this.dcTableSelector = dcIndex;
this.acTableSelector = acIndex;
}
}
public class JpegComponentConfig
{
public byte Id { get; set; }
public byte Id { get; }
public int HorizontalSampleFactor { get; set; }
public int HorizontalSampleFactor { get; }
public int VerticalSampleFactor { get; set; }
public int VerticalSampleFactor { get; }
public int QuantizatioTableIndex { get; set; }
public int QuantizatioTableIndex { get; }
public int dcTableSelector { get; set; }
public int dcTableSelector { get; }
public int acTableSelector { get; set; }
public int acTableSelector { get; }
}
public class JpegHuffmanTableConfig

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

@ -8,7 +8,6 @@ using System.Linq;
using System.Threading;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -42,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// Gets or sets the colorspace to use.
/// </summary>
private JpegEncodingMode? colorType;
private JpegEncodingColor? colorType;
private JpegFrameConfig frameConfig;
@ -66,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.quality = options.Quality;
this.frameConfig = frameConfig;
this.colorType = frameConfig.ColorType;
this.colorType = frameConfig.EncodingColor;
this.scanConfig = scanConfig;
}
@ -91,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
cancellationToken.ThrowIfCancellationRequested();
var frame = new Components.Encoder.JpegFrame(this.frameConfig, Configuration.Default.MemoryAllocator, image, GetTargetColorSpace(this.frameConfig.ColorType));
var frame = new JpegFrame(this.frameConfig, Configuration.Default.MemoryAllocator, image, GetTargetColorSpace(this.frameConfig.EncodingColor));
this.scanEncoder = new HuffmanScanEncoder(frame.BlocksPerMcu, stream);
this.outputStream = stream;
@ -102,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.WriteStartOfImage();
// Do not write APP0 marker for RGB colorspace.
if (this.colorType != JpegEncodingMode.Rgb)
if (this.colorType != JpegEncodingColor.Rgb)
{
this.WriteJfifApplicationHeader(metadata);
}
@ -110,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// Write Exif, XMP, ICC and IPTC profiles
this.WriteProfiles(metadata);
if (this.colorType == JpegEncodingMode.Rgb)
if (this.colorType == JpegEncodingColor.Rgb)
{
// Write App14 marker to indicate RGB color space.
this.WriteApp14Marker();
@ -128,28 +127,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// Write the scan header.
this.WriteStartOfScan(this.frameConfig.Components.Length, this.frameConfig.Components);
this.scanEncoder.EncodeInterleavedScan(frame, image, this.QuantizationTables, Configuration.Default, cancellationToken);
var spectralConverter = new SpectralConverter<TPixel>(frame, image, this.QuantizationTables, Configuration.Default);
this.scanEncoder.EncodeInterleavedBaselineScan(frame, spectralConverter, cancellationToken);
// Write the End Of Image marker.
this.WriteEndOfImageMarker();
stream.Flush();
static JpegColorSpace GetTargetColorSpace(JpegEncodingMode colorType)
static JpegColorSpace GetTargetColorSpace(JpegEncodingColor colorType)
{
switch (colorType)
{
case JpegEncodingMode.YCbCrRatio444:
case JpegEncodingMode.YCbCrRatio422:
case JpegEncodingMode.YCbCrRatio420:
case JpegEncodingMode.YCbCrRatio411:
case JpegEncodingMode.YCbCrRatio410:
case JpegEncodingColor.YCbCrRatio444:
case JpegEncodingColor.YCbCrRatio422:
case JpegEncodingColor.YCbCrRatio420:
case JpegEncodingColor.YCbCrRatio411:
case JpegEncodingColor.YCbCrRatio410:
return JpegColorSpace.YCbCr;
case JpegEncodingMode.Rgb:
case JpegEncodingColor.Rgb:
return JpegColorSpace.RGB;
case JpegEncodingMode.Cmyk:
case JpegEncodingColor.Cmyk:
return JpegColorSpace.Cmyk;
case JpegEncodingMode.Luminance:
case JpegEncodingColor.Luminance:
return JpegColorSpace.Grayscale;
default:
throw new NotImplementedException($"Unknown output color space: {colorType}");
@ -163,11 +163,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// returns <see langword="null"/> defering the field assignment
/// to <see cref="InitQuantizationTables(int, JpegMetadata, out Block8x8F, out Block8x8F)"/>.
/// </summary>
private static JpegEncodingMode? GetFallbackColorType<TPixel>(Image<TPixel> image)
private static JpegEncodingColor? GetFallbackColorType<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
// First inspect the image metadata.
JpegEncodingMode? colorType = null;
JpegEncodingColor? colorType = null;
JpegMetadata metadata = image.Metadata.GetJpegMetadata();
if (IsSupportedColorType(metadata.ColorType))
{
@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// the quality in InitQuantizationTables.
if (isGrayscale)
{
colorType = JpegEncodingMode.Luminance;
colorType = JpegEncodingColor.Luminance;
}
return colorType;
@ -195,11 +195,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
/// <param name="colorType">The color type.</param>
/// <returns>true, if color type is supported.</returns>
private static bool IsSupportedColorType(JpegEncodingMode? colorType)
=> colorType == JpegEncodingMode.YCbCrRatio444
|| colorType == JpegEncodingMode.YCbCrRatio420
|| colorType == JpegEncodingMode.Luminance
|| colorType == JpegEncodingMode.Rgb;
private static bool IsSupportedColorType(JpegEncodingColor? colorType)
=> colorType == JpegEncodingColor.YCbCrRatio444
|| colorType == JpegEncodingColor.YCbCrRatio420
|| colorType == JpegEncodingColor.Luminance
|| colorType == JpegEncodingColor.Rgb;
/// <summary>
/// Writes data to "Define Quantization Tables" block for QuantIndex.
@ -301,33 +301,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
}
/// <summary>
/// Writes the Define Quantization Marker and tables.
/// </summary>
private void WriteDefineQuantizationTables(ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable)
{
// Marker + quantization table lengths.
int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size));
this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen);
// Loop through and collect the tables as one array.
// This allows us to reduce the number of writes to the stream.
int dqtCount = (QuantizationTableCount * Block8x8F.Size) + QuantizationTableCount;
byte[] dqt = new byte[dqtCount];
int offset = 0;
WriteDataToDqt(dqt, ref offset, QuantIndex.Luminance, ref luminanceQuantTable);
WriteDataToDqt(dqt, ref offset, QuantIndex.Chrominance, ref chrominanceQuantTable);
this.outputStream.Write(dqt, 0, dqtCount);
}
/// <summary>
/// Writes the APP14 marker to indicate the image is in RGB color space.
/// </summary>
private void WriteApp14Marker()
{
this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + AdobeMarker.Length);
this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + Components.Decoder.AdobeMarker.Length);
// Identifier: ASCII "Adobe".
this.buffer[0] = 0x41;
@ -373,14 +352,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
// We can write up to a maximum of 64 data to the initial marker so calculate boundaries.
int exifMarkerLength = ProfileResolver.ExifMarker.Length;
int exifMarkerLength = Components.Decoder.ProfileResolver.ExifMarker.Length;
int remaining = exifMarkerLength + data.Length;
int bytesToWrite = remaining > MaxBytesApp1 ? MaxBytesApp1 : remaining;
int app1Length = bytesToWrite + 2;
// Write the app marker, EXIF marker, and data
this.WriteApp1Header(app1Length);
this.outputStream.Write(ProfileResolver.ExifMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength);
remaining -= bytesToWrite;
@ -393,7 +372,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.WriteApp1Header(app1Length);
// Write Exif00 marker
this.outputStream.Write(ProfileResolver.ExifMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
// Write the exif data
this.outputStream.Write(data, idx, bytesToWrite);
@ -429,14 +408,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
throw new ImageFormatException($"Iptc profile size exceeds limit of {Max} bytes");
}
int app13Length = 2 + ProfileResolver.AdobePhotoshopApp13Marker.Length +
ProfileResolver.AdobeImageResourceBlockMarker.Length +
ProfileResolver.AdobeIptcMarker.Length +
int app13Length = 2 + Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker.Length +
Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker.Length +
Components.Decoder.ProfileResolver.AdobeIptcMarker.Length +
2 + 4 + data.Length;
this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13);
this.outputStream.Write(ProfileResolver.AdobePhotoshopApp13Marker);
this.outputStream.Write(ProfileResolver.AdobeImageResourceBlockMarker);
this.outputStream.Write(ProfileResolver.AdobeIptcMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker);
this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even)
this.outputStream.WriteByte(0);
BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length);
@ -483,9 +462,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
dataLength -= length;
int app1Length = 2 + ProfileResolver.XmpMarker.Length + length;
int app1Length = 2 + Components.Decoder.ProfileResolver.XmpMarker.Length + length;
this.WriteApp1Header(app1Length);
this.outputStream.Write(ProfileResolver.XmpMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.XmpMarker);
this.outputStream.Write(data, offset, length);
offset += length;
@ -729,23 +708,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
/// <summary>
/// Initializes quantization tables.
/// Writes the Define Quantization Marker and prepares tables for encoding.
/// </summary>
/// <remarks>
/// <para>
/// Zig-zag ordering is NOT applied to the resulting tables.
/// </para>
/// <para>
/// We take quality values in a hierarchical order:
/// 1. Check if encoder has set quality
/// 2. Check if metadata has set quality
/// 3. Take default quality value - 75
/// </para>
/// <list type = "number" >
/// <item>Check if encoder has set quality.</item>
/// <item>Check if metadata has set quality.</item>
/// <item>Take default quality value from <see cref="Quantization.DefaultQualityFactor"/></item>
/// </list>
/// </remarks>
/// <param name="componentCount">Color components count.</param>
/// <param name="configs">Quantization tables configs.</param>
/// <param name="metadata">Jpeg metadata instance.</param>
/// <param name="luminanceQuantTable">Output luminance quantization table.</param>
/// <param name="chrominanceQuantTable">Output chrominance quantization table.</param>
private void InitQuantizationTables(JpegQuantizationTableConfig[] configs, JpegMetadata metadata)
{
int dataLen = configs.Length * (1 + Block8x8.Size);

6
src/ImageSharp/Formats/Jpeg/JpegEncodingMode.cs → src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// Provides enumeration of available JPEG color types.
/// </summary>
public enum JpegEncodingMode : byte
public enum JpegEncodingColor : byte
{
/// <summary>
/// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification.
@ -25,16 +25,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification.
/// The two chroma components are sampled at half the horizontal sample rate of luma while vertically it has full resolution.
///
/// Note: Not supported by the encoder.
/// </summary>
YCbCrRatio422 = 2,
/// <summary>
/// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification.
/// In 4:1:1 chroma subsampling, the horizontal color resolution is quartered.
///
/// Note: Not supported by the encoder.
/// </summary>
YCbCrRatio411 = 3,

2
src/ImageSharp/Formats/Jpeg/JpegMetadata.cs

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// Gets or sets the color type.
/// </summary>
public JpegEncodingMode? ColorType { get; set; }
public JpegEncodingColor? ColorType { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new JpegMetadata(this);

2
src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
var image = Image.LoadPixelData<Rgb24>(rows, width, height);
image.Save(memoryStream, new JpegEncoder()
{
ColorType = JpegEncodingMode.Rgb
ColorType = JpegEncodingColor.Rgb
});
memoryStream.Position = 0;
memoryStream.WriteTo(this.Output);

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
using FileStream imageBinaryStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage));
this.imageImageSharp = Image.Load<Rgba32>(imageBinaryStream);
this.encoderImageSharp = new JpegEncoder { Quality = this.Quality, ColorType = JpegEncodingMode.YCbCrRatio420 };
this.encoderImageSharp = new JpegEncoder { Quality = this.Quality, ColorType = JpegEncodingColor.YCbCrRatio420 };
this.destinationStream = new MemoryStream();
}

6
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs

@ -22,14 +22,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
// No metadata
private const string TestImage = TestImages.Jpeg.Baseline.Calliphora;
public static IEnumerable<JpegEncodingMode> ColorSpaceValues =>
new[] { JpegEncodingMode.Luminance, JpegEncodingMode.Rgb, JpegEncodingMode.YCbCrRatio420, JpegEncodingMode.YCbCrRatio444 };
public static IEnumerable<JpegEncodingColor> ColorSpaceValues =>
new[] { JpegEncodingColor.Luminance, JpegEncodingColor.Rgb, JpegEncodingColor.YCbCrRatio420, JpegEncodingColor.YCbCrRatio444 };
[Params(75, 90, 100)]
public int Quality;
[ParamsSource(nameof(ColorSpaceValues), Priority = -100)]
public JpegEncodingMode TargetColorSpace;
public JpegEncodingColor TargetColorSpace;
private Image<Rgb24> bmpCore;
private JpegEncoder encoder;

30
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs

@ -139,15 +139,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
[InlineData(TestImages.Jpeg.Baseline.Floorplan, JpegEncodingMode.Luminance)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegEncodingMode.YCbCrRatio420)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegEncodingMode.YCbCrRatio444)]
[InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegEncodingMode.Rgb)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegEncodingMode.Cmyk)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg410, JpegEncodingMode.YCbCrRatio410)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg422, JpegEncodingMode.YCbCrRatio422)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegEncodingMode.YCbCrRatio411)]
public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingMode expectedColorType)
[InlineData(TestImages.Jpeg.Baseline.Floorplan, JpegEncodingColor.Luminance)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegEncodingColor.YCbCrRatio420)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegEncodingColor.YCbCrRatio444)]
[InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegEncodingColor.Rgb)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegEncodingColor.Cmyk)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg410, JpegEncodingColor.YCbCrRatio410)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg422, JpegEncodingColor.YCbCrRatio422)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegEncodingColor.YCbCrRatio411)]
public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingColor expectedColorType)
{
var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
@ -159,12 +159,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
[WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingMode.Luminance)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegEncodingMode.YCbCrRatio420)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingMode.YCbCrRatio444)]
[WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegEncodingMode.Rgb)]
[WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgb24, JpegEncodingMode.Cmyk)]
public void Decode_DetectsCorrectColorType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode expectedColorType)
[WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingColor.Luminance)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio420)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)]
[WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegEncodingColor.Rgb)]
[WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgb24, JpegEncodingColor.Cmyk)]
public void Decode_DetectsCorrectColorType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor expectedColorType)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(JpegDecoder))

82
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -33,18 +33,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ TestImages.Jpeg.Progressive.Fb, 75 }
};
public static readonly TheoryData<JpegEncodingMode, int> BitsPerPixel_Quality =
public static readonly TheoryData<JpegEncodingColor, int> BitsPerPixel_Quality =
new()
{
{ JpegEncodingMode.YCbCrRatio420, 40 },
{ JpegEncodingMode.YCbCrRatio420, 60 },
{ JpegEncodingMode.YCbCrRatio420, 100 },
{ JpegEncodingMode.YCbCrRatio444, 40 },
{ JpegEncodingMode.YCbCrRatio444, 60 },
{ JpegEncodingMode.YCbCrRatio444, 100 },
{ JpegEncodingMode.Rgb, 40 },
{ JpegEncodingMode.Rgb, 60 },
{ JpegEncodingMode.Rgb, 100 }
{ JpegEncodingColor.YCbCrRatio420, 40 },
{ JpegEncodingColor.YCbCrRatio420, 60 },
{ JpegEncodingColor.YCbCrRatio420, 100 },
{ JpegEncodingColor.YCbCrRatio444, 40 },
{ JpegEncodingColor.YCbCrRatio444, 60 },
{ JpegEncodingColor.YCbCrRatio444, 100 },
{ JpegEncodingColor.Rgb, 40 },
{ JpegEncodingColor.Rgb, 60 },
{ JpegEncodingColor.Rgb, 100 }
};
public static readonly TheoryData<int> Grayscale_Quality =
@ -64,11 +64,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
};
[Theory]
[WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegEncodingMode.Luminance)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegEncodingMode.YCbCrRatio444)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegEncodingMode.YCbCrRatio420)]
[WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegEncodingMode.Rgb)]
public void Encode_PreservesColorType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode expectedColorType)
[WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegEncodingColor.Luminance)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio444)]
[WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio420)]
[WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegEncodingColor.Rgb)]
public void Encode_PreservesColorType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor expectedColorType)
where TPixel : unmanaged, IPixel<TPixel>
{
// arrange
@ -107,15 +107,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
memoryStream.Position = 0;
using var output = Image.Load<Rgba32>(memoryStream);
JpegMetadata meta = output.Metadata.GetJpegMetadata();
Assert.Equal(JpegEncodingMode.YCbCrRatio420, meta.ColorType);
Assert.Equal(JpegEncodingColor.YCbCrRatio420, meta.ColorType);
}
[Theory]
[InlineData(JpegEncodingMode.Cmyk)]
[InlineData(JpegEncodingMode.YCbCrRatio410)]
[InlineData(JpegEncodingMode.YCbCrRatio411)]
[InlineData(JpegEncodingMode.YCbCrRatio422)]
public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(JpegEncodingMode colorType)
[InlineData(JpegEncodingColor.Cmyk)]
[InlineData(JpegEncodingColor.YCbCrRatio410)]
[InlineData(JpegEncodingColor.YCbCrRatio411)]
[InlineData(JpegEncodingColor.YCbCrRatio422)]
public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(JpegEncodingColor colorType)
{
// arrange
var jpegEncoder = new JpegEncoder() { ColorType = colorType };
@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
memoryStream.Position = 0;
using var output = Image.Load<Rgba32>(memoryStream);
JpegMetadata meta = output.Metadata.GetJpegMetadata();
Assert.Equal(JpegEncodingMode.YCbCrRatio420, meta.ColorType);
Assert.Equal(JpegEncodingColor.YCbCrRatio420, meta.ColorType);
}
[Theory]
@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)]
public void EncodeBaseline_CalliphoraPartial<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType, int quality)
public void EncodeBaseline_CalliphoraPartial<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, colorType, quality);
[Theory]
@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 153, 21, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 600, 400, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 138, 24, PixelTypes.Rgba32)]
public void EncodeBaseline_WorksWithDifferentSizes<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType, int quality)
public void EncodeBaseline_WorksWithDifferentSizes<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, colorType, quality);
[Theory]
@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 24, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 46, 8, PixelTypes.Rgba32)]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 51, 7, PixelTypes.Rgba32)]
public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType, int quality)
public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.12f));
[Theory]
@ -188,27 +188,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[WithSolidFilledImages(1, 1, 100, 100, 100, 255, PixelTypes.La16, 100)]
[WithSolidFilledImages(1, 1, 100, 100, 100, 255, PixelTypes.La32, 100)]
public void EncodeBaseline_Grayscale<TPixel>(TestImageProvider<TPixel> provider, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, JpegEncodingMode.Luminance, quality);
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, JpegEncodingColor.Luminance, quality);
[Theory]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 96, PixelTypes.Rgba32 | PixelTypes.Bgra32)]
public void EncodeBaseline_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType, int quality)
public void EncodeBaseline_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, colorType, quality);
[Theory]
[WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)]
public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType, int quality)
public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality)
where TPixel : unmanaged, IPixel<TPixel> => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.06f));
[Theory]
[WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegEncodingMode.YCbCrRatio444)]
[WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegEncodingMode.YCbCrRatio444)]
[WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegEncodingMode.YCbCrRatio420)]
[WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegEncodingMode.YCbCrRatio420)]
public void EncodeBaseline_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingMode colorType)
[WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio444)]
[WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegEncodingColor.YCbCrRatio444)]
[WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegEncodingColor.YCbCrRatio420)]
[WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegEncodingColor.YCbCrRatio420)]
public void EncodeBaseline_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType)
where TPixel : unmanaged, IPixel<TPixel>
{
ImageComparer comparer = colorType == JpegEncodingMode.YCbCrRatio444
ImageComparer comparer = colorType == JpegEncodingColor.YCbCrRatio444
? ImageComparer.TolerantPercentage(0.1f)
: ImageComparer.TolerantPercentage(5f);
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
/// <summary>
/// Anton's SUPER-SCIENTIFIC tolerance threshold calculation
/// </summary>
private static ImageComparer GetComparer(int quality, JpegEncodingMode? colorType)
private static ImageComparer GetComparer(int quality, JpegEncodingColor? colorType)
{
float tolerance = 0.015f; // ~1.5%
@ -227,10 +227,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
tolerance *= 4.5f;
}
else if (quality < 75 || colorType == JpegEncodingMode.YCbCrRatio420)
else if (quality < 75 || colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
if (colorType == JpegEncodingMode.YCbCrRatio420)
if (colorType == JpegEncodingColor.YCbCrRatio420)
{
tolerance *= 2.0f;
}
@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private static void TestJpegEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
JpegEncodingMode colorType = JpegEncodingMode.YCbCrRatio420,
JpegEncodingColor colorType = JpegEncodingColor.YCbCrRatio420,
int quality = 100,
ImageComparer comparer = null)
where TPixel : unmanaged, IPixel<TPixel>
@ -396,9 +396,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Theory]
[InlineData(JpegEncodingMode.YCbCrRatio420)]
[InlineData(JpegEncodingMode.YCbCrRatio444)]
public async Task Encode_IsCancellable(JpegEncodingMode colorType)
[InlineData(JpegEncodingColor.YCbCrRatio420)]
[InlineData(JpegEncodingColor.YCbCrRatio444)]
public async Task Encode_IsCancellable(JpegEncodingColor colorType)
{
var cts = new CancellationTokenSource();
using var pausedStream = new PausedStream(new MemoryStream());

4
tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs

@ -12,11 +12,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void CloneIsDeep()
{
var meta = new JpegMetadata { Quality = 50, ColorType = JpegEncodingMode.Luminance };
var meta = new JpegMetadata { Quality = 50, ColorType = JpegEncodingColor.Luminance };
var clone = (JpegMetadata)meta.DeepClone();
clone.Quality = 99;
clone.ColorType = JpegEncodingMode.YCbCrRatio420;
clone.ColorType = JpegEncodingColor.YCbCrRatio420;
Assert.False(meta.Quality.Equals(clone.Quality));
Assert.False(meta.ColorType.Equals(clone.ColorType));

10
tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs

@ -91,11 +91,11 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks
// Benchmark, enable manually!
[Theory(Skip = ProfilingSetup.SkipProfilingTests)]
[InlineData(1, 75, JpegEncodingMode.YCbCrRatio420)]
[InlineData(30, 75, JpegEncodingMode.YCbCrRatio420)]
[InlineData(30, 75, JpegEncodingMode.YCbCrRatio444)]
[InlineData(30, 100, JpegEncodingMode.YCbCrRatio444)]
public void EncodeJpeg(int executionCount, int quality, JpegEncodingMode colorType)
[InlineData(1, 75, JpegEncodingColor.YCbCrRatio420)]
[InlineData(30, 75, JpegEncodingColor.YCbCrRatio420)]
[InlineData(30, 75, JpegEncodingColor.YCbCrRatio444)]
[InlineData(30, 100, JpegEncodingColor.YCbCrRatio444)]
public void EncodeJpeg(int executionCount, int quality, JpegEncodingColor colorType)
{
// do not run this on CI even by accident
if (TestEnvironment.RunsOnCI)

Loading…
Cancel
Save