From 3d31a16a883f0350fffbd61b676c77531c15256c Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Tue, 10 May 2022 13:41:49 +0300 Subject: [PATCH] Made frame configs internal --- .../Components/Encoder/HuffmanScanEncoder.cs | 7 +- .../Encoder/SpectralConverter{TPixel}.cs | 5 +- .../Formats/Jpeg/IJpegEncoderOptions.cs | 5 - .../Formats/Jpeg/JpegDecoderCore.cs | 22 +- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 201 +++++++++++++----- .../Formats/Jpeg/JpegEncoderCore.cs | 112 ++++------ ...egEncodingMode.cs => JpegEncodingColor.cs} | 6 +- src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 2 +- .../Compressors/TiffJpegCompressor.cs | 2 +- .../Codecs/Jpeg/EncodeJpegComparison.cs | 2 +- .../Codecs/Jpeg/EncodeJpegFeatures.cs | 6 +- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 30 +-- .../Formats/Jpg/JpegEncoderTests.cs | 82 +++---- .../Formats/Jpg/JpegMetadataTests.cs | 4 +- .../JpegProfilingBenchmarks.cs | 10 +- 15 files changed, 274 insertions(+), 222 deletions(-) rename src/ImageSharp/Formats/Jpeg/{JpegEncodingMode.cs => JpegEncodingColor.cs} (93%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 4c1071a286..1dde766e78 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/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(JpegFrame frame, Image image, Block8x8F[] quantTables, Configuration configuration, CancellationToken cancellationToken) + public void EncodeInterleavedBaselineScan(JpegFrame frame, SpectralConverter converter, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // DEBUG INITIALIZATION SETUP frame.AllocateComponents(fullScan: false); - var spectralConverter = new SpectralConverter(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++) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs index 2877d8f65e..b9a98aace2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs +++ b/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 image, Block8x8F[] dequantTables, Configuration configuration) + { this.configuration = configuration; - public void InjectFrameData(JpegFrame frame, Image image, Block8x8F[] dequantTables) - { MemoryAllocator allocator = this.configuration.MemoryAllocator; // iteration data diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs index e8daeaf738..ff87d88eb5 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -14,10 +14,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Defaults to 75. /// public int? Quality { get; set; } - - /// - /// Gets the color type, that will be used to encode the image. - /// - JpegEncodingMode? ColorType { get; } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index b933ff6fed..10e52066d1 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/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. /// /// Jpeg color type. - 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; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 5e1bde3097..926c49b571 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -16,15 +16,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions { + /// + /// The available encodable frame configs. + /// + private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs(); + /// public int? Quality { get; set; } - /// - 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; } /// /// Encodes the image to the specified stream from the . @@ -35,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public void Encode(Image image, Stream stream) where TPixel : unmanaged, IPixel { - 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(Image image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - 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 diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 2adec881d0..452dae4e5f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/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 /// /// Gets or sets the colorspace to use. /// - 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(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 defering the field assignment /// to . /// - private static JpegEncodingMode? GetFallbackColorType(Image image) + private static JpegEncodingColor? GetFallbackColorType(Image image) where TPixel : unmanaged, IPixel { // 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 /// /// The color type. /// true, if color type is supported. - 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; /// /// Writes data to "Define Quantization Tables" block for QuantIndex. @@ -301,33 +301,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } - /// - /// Writes the Define Quantization Marker and tables. - /// - 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); - } - /// /// Writes the APP14 marker to indicate the image is in RGB color space. /// 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 } /// - /// Initializes quantization tables. + /// Writes the Define Quantization Marker and prepares tables for encoding. /// /// - /// - /// Zig-zag ordering is NOT applied to the resulting tables. - /// - /// /// 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 - /// + /// + /// Check if encoder has set quality. + /// Check if metadata has set quality. + /// Take default quality value from + /// /// - /// Color components count. + /// Quantization tables configs. /// Jpeg metadata instance. - /// Output luminance quantization table. - /// Output chrominance quantization table. private void InitQuantizationTables(JpegQuantizationTableConfig[] configs, JpegMetadata metadata) { int dataLen = configs.Length * (1 + Block8x8.Size); diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncodingMode.cs b/src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs similarity index 93% rename from src/ImageSharp/Formats/Jpeg/JpegEncodingMode.cs rename to src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs index d6105da490..995b6036c8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncodingMode.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncodingColor.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Provides enumeration of available JPEG color types. /// - public enum JpegEncodingMode : byte + public enum JpegEncodingColor : byte { /// /// 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 /// /// 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. /// YCbCrRatio422 = 2, /// /// 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. /// YCbCrRatio411 = 3, diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index be42151223..bb4cbeeee9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Gets or sets the color type. /// - public JpegEncodingMode? ColorType { get; set; } + public JpegEncodingColor? ColorType { get; set; } /// public IDeepCloneable DeepClone() => new JpegMetadata(this); diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs index f5eb5507df..231afa3d04 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors var image = Image.LoadPixelData(rows, width, height); image.Save(memoryStream, new JpegEncoder() { - ColorType = JpegEncodingMode.Rgb + ColorType = JpegEncodingColor.Rgb }); memoryStream.Position = 0; memoryStream.WriteTo(this.Output); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs index 344a00b030..1c05ca8ce6 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs +++ b/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(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(); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs index 2c5dd1f8ca..b115550f93 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs +++ b/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 ColorSpaceValues => - new[] { JpegEncodingMode.Luminance, JpegEncodingMode.Rgb, JpegEncodingMode.YCbCrRatio420, JpegEncodingMode.YCbCrRatio444 }; + public static IEnumerable 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 bmpCore; private JpegEncoder encoder; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 16bc6d6969..7a5dcedef9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/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(TestImageProvider 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(TestImageProvider provider, JpegEncodingColor expectedColorType) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(JpegDecoder)) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index db66015683..9f36fcc0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/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 BitsPerPixel_Quality = + public static readonly TheoryData 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 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(TestImageProvider 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(TestImageProvider provider, JpegEncodingColor expectedColorType) where TPixel : unmanaged, IPixel { // arrange @@ -107,15 +107,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg memoryStream.Position = 0; using var output = Image.Load(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(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(TestImageProvider provider, JpegEncodingMode colorType, int quality) + public void EncodeBaseline_CalliphoraPartial(TestImageProvider provider, JpegEncodingColor colorType, int quality) where TPixel : unmanaged, IPixel => 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(TestImageProvider provider, JpegEncodingMode colorType, int quality) + public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegEncodingColor colorType, int quality) where TPixel : unmanaged, IPixel => 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(TestImageProvider provider, JpegEncodingMode colorType, int quality) + public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes(TestImageProvider provider, JpegEncodingColor colorType, int quality) where TPixel : unmanaged, IPixel => 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(TestImageProvider provider, int quality) - where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegEncodingMode.Luminance, quality); + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegEncodingColor.Luminance, quality); [Theory] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 96, PixelTypes.Rgba32 | PixelTypes.Bgra32)] - public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingMode colorType, int quality) + public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingColor colorType, int quality) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)] - public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingMode colorType, int quality) + public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegEncodingColor colorType, int quality) where TPixel : unmanaged, IPixel => 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(TestImageProvider 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(TestImageProvider provider, JpegEncodingColor colorType) where TPixel : unmanaged, IPixel { - 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 /// /// Anton's SUPER-SCIENTIFIC tolerance threshold calculation /// - 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( TestImageProvider provider, - JpegEncodingMode colorType = JpegEncodingMode.YCbCrRatio420, + JpegEncodingColor colorType = JpegEncodingColor.YCbCrRatio420, int quality = 100, ImageComparer comparer = null) where TPixel : unmanaged, IPixel @@ -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()); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 0c229488aa..b72059b669 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/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)); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index ad1402105d..3ca4944eba 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/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)