From ea05900d3b93844c1b2b24c50aecc23289e0470f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 11 Aug 2021 12:36:27 +0200 Subject: [PATCH 01/32] Add decompressor for tiff's with jpeg compression --- .../Components/Decoder/HuffmanScanDecoder.cs | 12 ++- .../Formats/Jpeg/JpegDecoderCore.cs | 74 +++++++++++++++++-- .../Decompressors/JpegTiffCompression.cs | 70 ++++++++++++++++++ .../Compression/TiffDecoderCompressionType.cs | 5 ++ .../Compression/TiffDecompressorsFactory.cs | 6 ++ .../Formats/Tiff/TiffDecoderCore.cs | 9 +++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 7 ++ 7 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 70a4465121..28ef6a96f7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -38,10 +38,14 @@ internal class HuffmanScanDecoder /// private int restartInterval; - // How many mcu's are left to do. + /// + /// How many mcu's are left to do. + /// private int todo; - // The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero. + /// + /// The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero. + /// private int eobrun; /// @@ -54,7 +58,9 @@ internal class HuffmanScanDecoder /// private readonly HuffmanTable[] acHuffmanTables; - // The unzig data. + /// + /// The unzig data. + /// private ZigZag dctZigZag; private HuffmanScanBuffer scanBuffer; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 896e5f0aaf..4f54f5078a 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Buffers.Binary; +using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; @@ -136,8 +137,8 @@ public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options) /// /// Finds the next file marker within the byte stream. /// - /// The buffer to read file markers to - /// The input stream + /// The buffer to read file markers to. + /// The input stream. /// The public static JpegFileMarker FindNextFileMarker(byte[] marker, BufferedReadStream stream) { @@ -200,6 +201,67 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata); } + /// + /// Load quantization and/or Huffman tables for subsequent use for jpeg's embedded in tiff's, + /// so those tables do not need to be duplicated with segmented tiff's (tiff's with multiple strips). + /// + /// The table bytes. + /// The scan decoder. + public void LoadTables(byte[] tableBytes, HuffmanScanDecoder huffmanScanDecoder) + { + this.Metadata = new ImageMetadata(); + this.QuantizationTables = new Block8x8F[4]; + this.scanDecoder = huffmanScanDecoder; + using var ms = new MemoryStream(tableBytes); + using var stream = new BufferedReadStream(this.Configuration, ms); + + // Check for the Start Of Image marker. + stream.Read(this.markerBuffer, 0, 2); + var fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); + if (fileMarker.Marker != JpegConstants.Markers.SOI) + { + JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); + } + + // Read next marker. + stream.Read(this.markerBuffer, 0, 2); + byte marker = this.markerBuffer[1]; + fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2); + + while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) + { + if (!fileMarker.Invalid) + { + // Get the marker length. + int remaining = this.ReadUint16(stream) - 2; + + switch (fileMarker.Marker) + { + case JpegConstants.Markers.SOI: + break; + case JpegConstants.Markers.RST0: + case JpegConstants.Markers.RST7: + break; + case JpegConstants.Markers.DHT: + this.ProcessDefineHuffmanTablesMarker(stream, remaining); + break; + case JpegConstants.Markers.DQT: + this.ProcessDefineQuantizationTablesMarker(stream, remaining); + break; + case JpegConstants.Markers.DRI: + this.ProcessDefineRestartIntervalMarker(stream, remaining); + break; + case JpegConstants.Markers.EOI: + return; + } + } + + // Read next marker. + stream.Read(this.markerBuffer, 0, 2); + fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); + } + } + /// /// Parses the input stream for file markers. /// @@ -225,7 +287,7 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco stream.Read(this.markerBuffer, 0, 2); byte marker = this.markerBuffer[1]; fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2); - this.QuantizationTables = new Block8x8F[4]; + this.QuantizationTables ??= new Block8x8F[4]; // Break only when we discover a valid EOI marker. // https://github.com/SixLabors/ImageSharp/issues/695 @@ -236,7 +298,7 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco if (!fileMarker.Invalid) { - // Get the marker length + // Get the marker length. int remaining = this.ReadUint16(stream) - 2; switch (fileMarker.Marker) @@ -345,7 +407,7 @@ public void Dispose() } /// - /// Returns the correct colorspace based on the image component count + /// Returns the correct colorspace based on the image component count. /// /// The private JpegColorSpace DeduceJpegColorSpace(byte componentCount) @@ -576,7 +638,7 @@ private void ProcessApp2Marker(BufferedReadStream stream, int remaining) /// /// Processes a App13 marker, which contains IPTC data stored with Adobe Photoshop. - /// The content of an APP13 segment is formed by an identifier string followed by a sequence of resource data blocks. + /// The tableBytes of an APP13 segment is formed by an identifier string followed by a sequence of resource data blocks. /// /// The input stream. /// The remaining bytes in the segment block. diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs new file mode 100644 index 0000000000..5a26df95ac --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Tiff.Constants; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors +{ + /// + /// Class to handle cases where TIFF image data is compressed as a jpeg stream. + /// + internal class JpegTiffCompression : TiffBaseDecompressor + { + private readonly Configuration configuration; + + private readonly byte[] jpegTables; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + /// The memoryAllocator to use for buffer allocations. + /// The image width. + /// The bits per pixel. + /// The JPEG tables containing the quantization and/or Huffman tables. + /// The predictor. + public JpegTiffCompression(Configuration configuration, MemoryAllocator memoryAllocator, int width, int bitsPerPixel, byte[] jpegTables, TiffPredictor predictor = TiffPredictor.None) + : base(memoryAllocator, width, bitsPerPixel, predictor) + { + this.configuration = configuration; + this.jpegTables = jpegTables; + } + + /// + protected override void Decompress(BufferedReadStream stream, int byteCount, Span buffer) + { + var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); + + // Should we pass through the CancellationToken from the tiff decoder? + using var spectralConverter = new SpectralConverter(this.configuration, CancellationToken.None); + var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None); + jpegDecoder.LoadTables(this.jpegTables, scanDecoder); + scanDecoder.ResetInterval = 0; + jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None); + + var image = new Image(this.configuration, spectralConverter.PixelBuffer, new ImageMetadata()); + int offset = 0; + for (int y = 0; y < image.Height; y++) + { + Span pixelRowSpan = image.GetPixelRowSpan(y); + Span rgbBytes = MemoryMarshal.AsBytes(pixelRowSpan); + rgbBytes.CopyTo(buffer.Slice(offset)); + offset += rgbBytes.Length; + } + } + + /// + protected override void Dispose(bool disposing) + { + } + } +} diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs index 80bc0af5ab..6dd19c5552 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs @@ -37,5 +37,10 @@ internal enum TiffDecoderCompressionType /// Image data is compressed using modified huffman compression. /// HuffmanRle = 5, + + /// + /// The image data is compressed as a JPEG stream. + /// + Jpeg = 6, } } diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index b1562223aa..ee44a70219 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression internal static class TiffDecompressorsFactory { public static TiffBaseDecompressor Create( + Configuration configuration, TiffDecoderCompressionType method, MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, @@ -19,6 +20,7 @@ public static TiffBaseDecompressor Create( TiffColorType colorType, TiffPredictor predictor, FaxCompressionOptions faxOptions, + byte[] jpegTables, TiffFillOrder fillOrder, ByteOrder byteOrder) { @@ -50,6 +52,10 @@ public static TiffBaseDecompressor Create( DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); return new ModifiedHuffmanTiffCompression(allocator, fillOrder, width, bitsPerPixel, photometricInterpretation); + case TiffDecoderCompressionType.Jpeg: + DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); + return new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables); + default: throw TiffThrowHelper.NotSupportedDecompressor(nameof(method)); } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 28afe4c6f2..5b8c974b46 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -105,6 +105,11 @@ public TiffDecoderCore(Configuration configuration, ITiffDecoderOptions options) /// public TiffFillOrder FillOrder { get; set; } + /// + /// Gets or sets the JPEG tables when jpeg compression is used. + /// + public byte[] JpegTables { get; set; } + /// /// Gets or sets the planar configuration type to use when decoding the image. /// @@ -290,6 +295,7 @@ private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStr } using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( + this.Configuration, this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, @@ -298,6 +304,7 @@ private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStr this.ColorType, this.Predictor, this.FaxCompressionOptions, + this.JpegTables, this.FillOrder, this.byteOrder); @@ -350,6 +357,7 @@ private void DecodeStripsChunky(ImageFrame frame, int rowsPerStr Buffer2D pixels = frame.PixelBuffer; using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( + this.Configuration, this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, @@ -358,6 +366,7 @@ private void DecodeStripsChunky(ImageFrame frame, int rowsPerStr this.ColorType, this.Predictor, this.FaxCompressionOptions, + this.JpegTables, this.FillOrder, this.byteOrder); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index bb435affcc..2a2be6d742 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -87,6 +87,7 @@ public static void VerifyAndParse(this TiffDecoderCore options, ExifProfile exif options.YcbcrCoefficients = exifProfile.GetValue(ExifTag.YCbCrCoefficients)?.Value; options.YcbcrSubSampling = exifProfile.GetValue(ExifTag.YCbCrSubsampling)?.Value; options.FillOrder = fillOrder; + options.JpegTables = exifProfile.GetValue(ExifTag.JPEGTables)?.Value; options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); @@ -424,6 +425,12 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi break; } + case TiffCompression.Jpeg: + { + options.CompressionType = TiffDecoderCompressionType.Jpeg; + break; + } + default: { TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format {compression} is not supported"); From ff8dfde165f937f9f44d2664cdb8f8c1c66496a6 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 11 Aug 2021 12:37:37 +0200 Subject: [PATCH 02/32] Add adobe tech note --- .../Tiff/TIFF-AdobeTechNote-22032002.pdf | Bin 0 -> 317624 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/TIFF-AdobeTechNote-22032002.pdf diff --git a/src/ImageSharp/Formats/Tiff/TIFF-AdobeTechNote-22032002.pdf b/src/ImageSharp/Formats/Tiff/TIFF-AdobeTechNote-22032002.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e4822d4093f701d4e760479616e1ba21e0c13b0c GIT binary patch literal 317624 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ℜPsj_0>zrytHVuciAJmMAF}10E%idGp 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

rh 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

  • Q$ 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

    rV0u6BK9PJ$= z)}sNF;grXbUxE#vWR7_ncyW$-ng)nwjy?d0=4db25z5&%U|j5d077(*{sVh8Im^bd z1;BK2)*HhX01wGok37aRIQ<_$_!!Tia@sVJHpVmPoX-HU9)~Vq{~l)`+H7T<{vKqPV?2X2#xp=R&Y=s1eO(1?U7&KrqBJt+91qGk;zSym z&Jk0CX_fOCAg<%E1qx%oJ!^Zx5)@}W#$HsmdShT5G>roXlrj80Wek50;yR9T11^!H z|0pz0e-Gk14u3!$!{37hox?{^@tnRGxEv1bf<-OPG7_|Fn6+O3bUAeai*p?HfP$Q5 zoVE{wB+lp3Ibt8MV#yKv(7>d}p$m<1>Vs8h;CMOfG4^b;)njnkY-QvzoHW2vDG7R z#6IAu9P>WNtTMR4BBiF*L6F`mJRdyrO)@eHtV%icC{NQ>Pc(7_f?j`0O&tvJS)z?s7W z=7eLt7(@pgeh8QX2d@6FZ8OM?8-}6i3Fa7C$8pAz2?SZS1-j}1iY&$+2go+as;BR> zfC3etwghJ=(Ue4f@*{IxF^j0Rz%;U~D7OgU66@80jdfrnYy)zR{*SS_fy_4O#pL@m zAi(H*z-iIdk5xHvki#i9cs^tUH!CK|;dK8M+637yFhkB&qBLSozhB^Xt(kDvnJKQ-f*j84 ztKKi^pVtyTGo(n;tBuXvuemyp<-{nD4L*nbObTL|G5Dy(??(l&%YLrL;DK&zgM3Zj zXr0u%jpZz`z5U>i7UQvmWCEc^_->w_J@u0YTX>gt%geq(L@#fOQ5b>ExGi z9U9>}G{SXg(EC*Ea^MtK1h2j&$I`OZ_jr&E^!|fJs=E7><@*X*V`u*#&&Y(eAZugN zy&iq5unHL=^jEaa$KFAwp>RcYvix~ z{}$yD=&jyIX~g^fx6BL3FWi4ACSmjnt3sxC3#RYD&$Pu84uW1IKL1 Date: Wed, 11 Aug 2021 13:16:36 +0200 Subject: [PATCH 03/32] Add tiff with jpeg compression tests --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 7 +++++++ tests/ImageSharp.Tests/TestImages.cs | 6 ++++-- tests/Images/Input/Tiff/rgb_jpegcompressed_stripped.tiff | 3 +++ .../Input/Tiff/{rgb_jpeg.tiff => rgb_jpegcompression.tiff} | 0 tests/Images/Input/Tiff/ycbcr_jpegcompressed.tiff | 3 +++ 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tiff/rgb_jpegcompressed_stripped.tiff rename tests/Images/Input/Tiff/{rgb_jpeg.tiff => rgb_jpegcompression.tiff} (100%) create mode 100644 tests/Images/Input/Tiff/ycbcr_jpegcompressed.tiff diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 5a0495e0a2..157a48d6d8 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -368,6 +368,13 @@ public void TiffDecoder_CanDecode_Compressed_LowerOrderBitsFirst(TestIma public void TiffDecoder_CanDecode_PackBitsCompressed(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(RgbJpegCompressed, PixelTypes.Rgba32)] + [WithFile(RgbWithStripsJpegCompressed, PixelTypes.Rgba32)] + [WithFile(YCbCrJpegCompressed, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_JpegCompressed(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)] public void DecodeMultiframe(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 0e892baec6..6cdf498949 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -552,7 +552,8 @@ public static class Tiff public const string RgbDeflate = "Tiff/rgb_deflate.tiff"; public const string RgbDeflatePredictor = "Tiff/rgb_deflate_predictor.tiff"; public const string RgbDeflateMultistrip = "Tiff/rgb_deflate_multistrip.tiff"; - public const string RgbJpeg = "Tiff/rgb_jpeg.tiff"; + public const string RgbJpegCompressed = "Tiff/rgb_jpegcompression.tiff"; + public const string RgbWithStripsJpegCompressed = "Tiff/rgb_jpegcompressed_stripped.tiff"; public const string RgbLzwPredictor = "Tiff/rgb_lzw_predictor.tiff"; public const string RgbLzwNoPredictor = "Tiff/rgb_lzw_no_predictor.tiff"; public const string RgbLzwNoPredictorMultistrip = "Tiff/rgb_lzw_noPredictor_multistrip.tiff"; @@ -600,6 +601,7 @@ public static class Tiff public const string RgbYCbCr888Contiguoush2v1 = "Tiff/rgb-ycbcr-contig-08_h2v1.tiff"; public const string RgbYCbCr888Contiguoush2v2 = "Tiff/rgb-ycbcr-contig-08_h2v2.tiff"; public const string RgbYCbCr888Contiguoush4v4 = "Tiff/rgb-ycbcr-contig-08_h4v4.tiff"; + public const string YCbCrJpegCompressed = "Tiff/ycbcr_jpegcompressed.tiff"; public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff"; public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff"; @@ -659,7 +661,7 @@ public static class Tiff public static readonly string[] Metadata = { SampleMetadata }; - public static readonly string[] NotSupported = { Calliphora_RgbJpeg, RgbJpeg, RgbUncompressedTiled, MultiframeDifferentSize, MultiframeDifferentVariants, Calliphora_Fax4Compressed, Fax4_Motorola }; + public static readonly string[] NotSupported = { RgbUncompressedTiled, MultiframeDifferentSize, MultiframeDifferentVariants, Calliphora_Fax4Compressed, Fax4_Motorola }; } } } diff --git a/tests/Images/Input/Tiff/rgb_jpegcompressed_stripped.tiff b/tests/Images/Input/Tiff/rgb_jpegcompressed_stripped.tiff new file mode 100644 index 0000000000..2d43f97789 --- /dev/null +++ b/tests/Images/Input/Tiff/rgb_jpegcompressed_stripped.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f027d8c2ab0b244f04e51b9bf724eac0123e104a2446324496a08bdf5881922 +size 10550 diff --git a/tests/Images/Input/Tiff/rgb_jpeg.tiff b/tests/Images/Input/Tiff/rgb_jpegcompression.tiff similarity index 100% rename from tests/Images/Input/Tiff/rgb_jpeg.tiff rename to tests/Images/Input/Tiff/rgb_jpegcompression.tiff diff --git a/tests/Images/Input/Tiff/ycbcr_jpegcompressed.tiff b/tests/Images/Input/Tiff/ycbcr_jpegcompressed.tiff new file mode 100644 index 0000000000..18334be2af --- /dev/null +++ b/tests/Images/Input/Tiff/ycbcr_jpegcompressed.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27fa1d37cd62a9cf105a5e3e015e6a16a13ca7fa82f927a73d32847046c66073 +size 6136 From 48374293f9347b276354ca2c6e1eae16eddc23b1 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 11 Aug 2021 15:34:46 +0200 Subject: [PATCH 04/32] Read complete jpeg stream, if JPEGTables is not present --- .../Decompressors/JpegTiffCompression.cs | 25 +++++++++++++------ .../Formats/Tiff/TiffDecoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 1 + .../Tiff/rgb_jpegcompressed_nojpegtable.tiff | 3 +++ 4 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs index 5a26df95ac..2722c7db48 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs @@ -42,16 +42,25 @@ public JpegTiffCompression(Configuration configuration, MemoryAllocator memoryAl /// protected override void Decompress(BufferedReadStream stream, int byteCount, Span buffer) { - var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); + Image image; + if (this.jpegTables != null) + { + var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); + + // Should we pass through the CancellationToken from the tiff decoder? + using var spectralConverter = new SpectralConverter(this.configuration, CancellationToken.None); + var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None); + jpegDecoder.LoadTables(this.jpegTables, scanDecoder); + scanDecoder.ResetInterval = 0; + jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None); - // Should we pass through the CancellationToken from the tiff decoder? - using var spectralConverter = new SpectralConverter(this.configuration, CancellationToken.None); - var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None); - jpegDecoder.LoadTables(this.jpegTables, scanDecoder); - scanDecoder.ResetInterval = 0; - jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None); + image = new Image(this.configuration, spectralConverter.PixelBuffer, new ImageMetadata()); + } + else + { + image = Image.Load(stream); + } - var image = new Image(this.configuration, spectralConverter.PixelBuffer, new ImageMetadata()); int offset = 0; for (int y = 0; y < image.Height; y++) { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 157a48d6d8..a1d3865a29 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -372,6 +372,7 @@ public void TiffDecoder_CanDecode_PackBitsCompressed(TestImageProvider(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6cdf498949..b0b962624b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -554,6 +554,7 @@ public static class Tiff public const string RgbDeflateMultistrip = "Tiff/rgb_deflate_multistrip.tiff"; public const string RgbJpegCompressed = "Tiff/rgb_jpegcompression.tiff"; public const string RgbWithStripsJpegCompressed = "Tiff/rgb_jpegcompressed_stripped.tiff"; + public const string RgbJpegCompressedNoJpegTable = "Tiff/rgb_jpegcompressed_nojpegtable.tiff"; public const string RgbLzwPredictor = "Tiff/rgb_lzw_predictor.tiff"; public const string RgbLzwNoPredictor = "Tiff/rgb_lzw_no_predictor.tiff"; public const string RgbLzwNoPredictorMultistrip = "Tiff/rgb_lzw_noPredictor_multistrip.tiff"; diff --git a/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff b/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff new file mode 100644 index 0000000000..b97ab8830d --- /dev/null +++ b/tests/Images/Input/Tiff/rgb_jpegcompressed_nojpegtable.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b81013d7b0a29ed1ac9c33e175e0c0e69494b93b2b65b692f16d9ea042b9d5d +size 7759 From 1df665158d1054d07debbc3532fd474e04beb92c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 07:10:39 +0200 Subject: [PATCH 05/32] Add option to encode jpeg in rgb colorspace instead of YCbCr --- .../Components/Encoder/HuffmanScanEncoder.cs | 80 ++++++++++-- .../Encoder/RgbForwardConverter{TPixel}.cs | 114 ++++++++++++++++++ .../YCbCrForwardConverter420{TPixel}.cs | 8 +- .../YCbCrForwardConverter444{TPixel}.cs | 8 +- .../Formats/Jpeg/JpegEncoderCore.cs | 67 +++++----- src/ImageSharp/Formats/Jpeg/JpegSubsample.cs | 7 +- 6 files changed, 236 insertions(+), 48 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 331da275cc..5468d93c48 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs @@ -41,7 +41,7 @@ internal class HuffmanScanEncoder private int emitLen = 0; ///

    - /// Emmited bits 'micro buffer' before being transfered to the . + /// Emitted bits 'micro buffer' before being transferred to the . /// private int accumulatedBits; @@ -58,18 +58,15 @@ internal class HuffmanScanEncoder /// private readonly Stream target; - public HuffmanScanEncoder(Stream outputStream) - { - this.target = outputStream; - } + public HuffmanScanEncoder(Stream outputStream) => this.target = outputStream; /// /// Encodes the image with no subsampling. /// /// The pixel format. /// The pixel accessor providing access to the image pixels. - /// Luminance quantization table provided by the callee - /// Chrominance quantization table provided by the callee + /// Luminance quantization table provided by the callee. + /// Chrominance quantization table provided by the callee. /// The token to monitor for cancellation. public void Encode444(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel @@ -128,8 +125,8 @@ public void Encode444(Image pixels, ref Block8x8F luminanceQuant /// /// The pixel format. /// The pixel accessor providing access to the image pixels. - /// Luminance quantization table provided by the callee - /// Chrominance quantization table provided by the callee + /// Luminance quantization table provided by the callee. + /// Chrominance quantization table provided by the callee. /// The token to monitor for cancellation. public void Encode420(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel @@ -196,7 +193,7 @@ public void Encode420(Image pixels, ref Block8x8F luminanceQuant /// /// The pixel format. /// The pixel accessor providing access to the image pixels. - /// Luminance quantization table provided by the callee + /// Luminance quantization table provided by the callee. /// The token to monitor for cancellation. public void EncodeGrayscale(Image pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel @@ -234,6 +231,65 @@ public void EncodeGrayscale(Image pixels, ref Block8x8F luminanc this.FlushInternalBuffer(); } + /// + /// Encodes the image with no subsampling and keeps the pixel data as Rgb24. + /// + /// The pixel format. + /// The pixel accessor providing access to the image pixels. + /// Luminance quantization table provided by the callee. + /// Chrominance quantization table provided by the callee. + /// The token to monitor for cancellation. + public void EncodeRgb(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) + where TPixel : unmanaged, IPixel + { + this.huffmanTables = HuffmanLut.TheHuffmanLut; + + var unzig = ZigZag.CreateUnzigTable(); + + // ReSharper disable once InconsistentNaming + int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; + + ImageFrame frame = pixels.Frames.RootFrame; + Buffer2D pixelBuffer = frame.PixelBuffer; + RowOctet currentRows = default; + + var pixelConverter = new RgbForwardConverter(frame); + + for (int y = 0; y < pixels.Height; y += 8) + { + cancellationToken.ThrowIfCancellationRequested(); + currentRows.Update(pixelBuffer, y); + + for (int x = 0; x < pixels.Width; x += 8) + { + pixelConverter.Convert(x, y, ref currentRows); + + prevDCY = this.WriteBlock( + QuantIndex.Luminance, + prevDCY, + ref pixelConverter.R, + ref luminanceQuantTable, + ref unzig); + + prevDCCb = this.WriteBlock( + QuantIndex.Chrominance, + prevDCCb, + ref pixelConverter.G, + ref chrominanceQuantTable, + ref unzig); + + prevDCCr = this.WriteBlock( + QuantIndex.Chrominance, + prevDCCr, + ref pixelConverter.B, + ref chrominanceQuantTable, + ref unzig); + } + } + + this.FlushInternalBuffer(); + } + /// /// Writes a block of pixel data using the given quantization table, /// returning the post-quantized DC value of the DCT-transformed block. @@ -437,7 +493,7 @@ internal static int GetHuffmanEncodingLength(uint value) DebugGuard.IsTrue(value <= (1 << 16), "Huffman encoder is supposed to encode a value of 16bit size max"); #if SUPPORTS_BITOPERATIONS // This should have been implemented as (BitOperations.Log2(value) + 1) as in non-intrinsic implementation - // But internal log2 is implementated like this: (31 - (int)Lzcnt.LeadingZeroCount(value)) + // But internal log2 is implemented like this: (31 - (int)Lzcnt.LeadingZeroCount(value)) // BitOperations.Log2 implementation also checks if input value is zero for the convention 0->0 // Lzcnt would return 32 for input value of 0 - no need to check that with branching @@ -449,7 +505,7 @@ internal static int GetHuffmanEncodingLength(uint value) // if 0 - return 0 in this case // else - return log2(value) + 1 // - // Hack based on input value constaint: + // Hack based on input value constraint: // We know that input values are guaranteed to be maximum 16 bit large for huffman encoding // We can safely shift input value for one bit -> log2(value << 1) // Because of the 16 bit value constraint it won't overflow diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs new file mode 100644 index 0000000000..e23cf348a2 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder +{ + /// + /// On-stack worker struct to convert TPixel -> Rgb24 of 8x8 pixel blocks. + /// + /// The pixel type to work on. + internal ref struct RgbForwardConverter + where TPixel : unmanaged, IPixel + { + /// + /// Number of pixels processed per single call + /// + private const int PixelsPerSample = 8 * 8; + + /// + /// Total byte size of processed pixels converted from TPixel to + /// + private const int RgbSpanByteSize = PixelsPerSample * 3; + + /// + /// of sampling area from given frame pixel buffer. + /// + private static readonly Size SampleSize = new Size(8, 8); + + /// + /// The Red component. + /// + public Block8x8F R; + + /// + /// The Green component. + /// + public Block8x8F G; + + /// + /// The Blue component. + /// + public Block8x8F B; + + /// + /// Temporal 64-byte span to hold unconverted TPixel data. + /// + private readonly Span pixelSpan; + + /// + /// Temporal 64-byte span to hold converted Rgb24 data. + /// + private readonly Span rgbSpan; + + /// + /// Sampled pixel buffer size. + /// + private readonly Size samplingAreaSize; + + /// + /// for internal operations. + /// + private readonly Configuration config; + + public RgbForwardConverter(ImageFrame frame) + { + this.R = default; + this.G = default; + this.B = default; + + // temporal pixel buffers + this.pixelSpan = new TPixel[PixelsPerSample].AsSpan(); + this.rgbSpan = MemoryMarshal.Cast(new byte[RgbSpanByteSize + RgbToYCbCrConverterVectorized.AvxCompatibilityPadding].AsSpan()); + + // frame data + this.samplingAreaSize = new Size(frame.Width, frame.Height); + this.config = frame.GetConfiguration(); + } + + /// + /// Converts a 8x8 image area inside 'pixels' at position (x, y) to Rgb24. + /// + public void Convert(int x, int y, ref RowOctet currentRows) + { + YCbCrForwardConverter.LoadAndStretchEdges(currentRows, this.pixelSpan, new Point(x, y), SampleSize, this.samplingAreaSize); + + PixelOperations.Instance.ToRgb24(this.config, this.pixelSpan, this.rgbSpan); + + ref Block8x8F redBlock = ref this.R; + ref Block8x8F greenBlock = ref this.G; + ref Block8x8F blueBlock = ref this.B; + + CopyToBlock(this.rgbSpan, ref redBlock, ref greenBlock, ref blueBlock); + } + + private static void CopyToBlock(Span rgbSpan, ref Block8x8F redBlock, ref Block8x8F greenBlock, ref Block8x8F blueBlock) + { + ref Rgb24 rgbStart = ref rgbSpan[0]; + + for (int i = 0; i < Block8x8F.Size; i++) + { + Rgb24 c = Unsafe.Add(ref rgbStart, i); + + redBlock[i] = c.R; + greenBlock[i] = c.G; + blueBlock[i] = c.B; + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs index a4abd532b3..bfeafcbb3d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs @@ -58,22 +58,22 @@ internal ref struct YCbCrForwardConverter420 /// /// Temporal 16x8 block to hold TPixel data /// - private Span pixelSpan; + private readonly Span pixelSpan; /// /// Temporal RGB block /// - private Span rgbSpan; + private readonly Span rgbSpan; /// /// Sampled pixel buffer size /// - private Size samplingAreaSize; + private readonly Size samplingAreaSize; /// /// for internal operations /// - private Configuration config; + private readonly Configuration config; public YCbCrForwardConverter420(ImageFrame frame) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter444{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter444{TPixel}.cs index ef589272bd..2dbd1a2dc5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter444{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter444{TPixel}.cs @@ -53,22 +53,22 @@ internal ref struct YCbCrForwardConverter444 /// /// Temporal 64-byte span to hold unconverted TPixel data /// - private Span pixelSpan; + private readonly Span pixelSpan; /// /// Temporal 64-byte span to hold converted Rgb24 data /// - private Span rgbSpan; + private readonly Span rgbSpan; /// /// Sampled pixel buffer size /// - private Size samplingAreaSize; + private readonly Size samplingAreaSize; /// /// for internal operations /// - private Configuration config; + private readonly Configuration config; public YCbCrForwardConverter444(ImageFrame frame) { diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 88d96f554d..d49e40d2fe 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -90,6 +90,7 @@ public void Encode(Image image, Stream stream, CancellationToken // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; + byte[] componentIds = this.GetComponentIds(); // TODO: Right now encoder writes both quantization tables for grayscale images - we shouldn't do that // Initialize the quantization tables. @@ -105,13 +106,13 @@ public void Encode(Image image, Stream stream, CancellationToken this.WriteDefineQuantizationTables(ref luminanceQuantTable, ref chrominanceQuantTable); // Write the image dimensions. - this.WriteStartOfFrame(image.Width, image.Height, componentCount); + this.WriteStartOfFrame(image.Width, image.Height, componentCount, componentIds); // Write the Huffman tables. this.WriteDefineHuffmanTables(componentCount); // Write the scan header. - this.WriteStartOfScan(image, componentCount, cancellationToken); + this.WriteStartOfScan(componentCount, componentIds); // Write the scan compressed data. var scanEncoder = new HuffmanScanEncoder(stream); @@ -131,6 +132,9 @@ public void Encode(Image image, Stream stream, CancellationToken case JpegSubsample.Ratio420: scanEncoder.Encode420(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; + case JpegSubsample.Rgb: + scanEncoder.EncodeRgb(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); + break; } } @@ -141,12 +145,27 @@ public void Encode(Image image, Stream stream, CancellationToken } /// - /// Writes data to "Define Quantization Tables" block for QuantIndex + /// Gets the component ids. + /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3. /// - /// The "Define Quantization Tables" block - /// Offset in "Define Quantization Tables" block - /// The quantization index - /// The quantization table to copy data from + /// The component Ids. + private byte[] GetComponentIds() + { + if (this.subsample == JpegSubsample.Rgb) + { + return new byte[] { 82, 71, 66 }; + } + + return new byte[] { 1, 2, 3 }; + } + + /// + /// Writes data to "Define Quantization Tables" block for QuantIndex. + /// + /// The "Define Quantization Tables" block. + /// Offset in "Define Quantization Tables" block. + /// The quantization index. + /// The quantization table to copy data from. private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F quant) { dqt[offset++] = (byte)i; @@ -343,7 +362,7 @@ private void WriteIptcProfile(IptcProfile iptcProfile) throw new ImageFormatException($"Iptc profile size exceeds limit of {Max} bytes"); } - var app13Length = 2 + ProfileResolver.AdobePhotoshopApp13Marker.Length + + int app13Length = 2 + ProfileResolver.AdobePhotoshopApp13Marker.Length + ProfileResolver.AdobeImageResourceBlockMarker.Length + ProfileResolver.AdobeIptcMarker.Length + 2 + 4 + data.Length; @@ -478,12 +497,13 @@ private void WriteProfiles(ImageMetadata metadata) } /// - /// Writes the Start Of Frame (Baseline) marker + /// Writes the Start Of Frame (Baseline) marker. /// - /// The width of the image - /// The height of the image - /// The number of components in a pixel - private void WriteStartOfFrame(int width, int height, int componentCount) + /// The width of the image. + /// The height of the image. + /// The number of components in a pixel. + /// The component Id's. + private void WriteStartOfFrame(int width, int height, int componentCount, byte[] componentIds) { // "default" to 4:2:0 Span subsamples = stackalloc byte[] @@ -513,6 +533,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount) { switch (this.subsample) { + case JpegSubsample.Rgb: case JpegSubsample.Ratio444: subsamples = stackalloc byte[] { @@ -545,8 +566,9 @@ private void WriteStartOfFrame(int width, int height, int componentCount) for (int i = 0; i < componentCount; i++) { int i3 = 3 * i; - this.buffer[i3 + 6] = (byte)(i + 1); + // Component ID. + this.buffer[i3 + 6] = componentIds[i]; this.buffer[i3 + 7] = subsamples[i]; this.buffer[i3 + 8] = chroma[i]; } @@ -557,19 +579,10 @@ private void WriteStartOfFrame(int width, int height, int componentCount) /// /// Writes the StartOfScan marker. /// - /// The pixel format. - /// The pixel accessor providing access to the image pixels. /// The number of components in a pixel. - /// The token to monitor for cancellation. - private void WriteStartOfScan(Image image, int componentCount, CancellationToken cancellationToken) - where TPixel : unmanaged, IPixel + /// The componentId's. + private void WriteStartOfScan(int componentCount, byte[] componentIds) { - Span componentId = stackalloc byte[] - { - 0x01, - 0x02, - 0x03 - }; Span huffmanId = stackalloc byte[] { 0x00, @@ -597,7 +610,7 @@ private void WriteStartOfScan(Image image, int componentCount, C for (int i = 0; i < componentCount; i++) { int i2 = 2 * i; - this.buffer[i2 + 5] = componentId[i]; // Component Id + this.buffer[i2 + 5] = componentIds[i]; // Component Id this.buffer[i2 + 6] = huffmanId[i]; // DC/AC Huffman table } @@ -633,7 +646,7 @@ private void WriteMarkerHeader(byte marker, int length) } /// - /// Initializes quntization tables. + /// Initializes quantization tables. /// /// /// We take quality values in a hierarchical order: diff --git a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs index 16488f6d21..760ba3a962 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs @@ -18,6 +18,11 @@ public enum JpegSubsample /// Medium Quality - The horizontal sampling is halved and the Cb and Cr channels are only /// sampled on each alternate line. /// - Ratio420 + Ratio420, + + /// + /// The pixel data will be preserved as RGB without any sub sampling. + /// + Rgb, } } From fd957fae842ed9de6b79f626deb9cfcca6ed97df Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 07:12:00 +0200 Subject: [PATCH 06/32] Add option to encode Tiff's with jpeg compression --- .../Compression/Compressors/PackBitsWriter.cs | 2 +- .../Compressors/TiffJpegCompressor.cs | 49 +++++++++++++++++++ .../Tiff/Compression/TiffCompressorFactory.cs | 6 ++- .../Compression/TiffDecompressorsFactory.cs | 2 +- .../Formats/Tiff/TiffDecoderCore.cs | 2 +- .../Tiff/TiffEncoderEntriesCollector.cs | 3 ++ .../Formats/Tiff/TiffEncoderTests.cs | 7 ++- 7 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs index 30d21e54ce..f456324e53 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs @@ -80,7 +80,7 @@ private static void WriteRun(ReadOnlySpan rowSpan, int start, int runLengt private static bool IsReplicateRun(ReadOnlySpan rowSpan, int startPos) { // We consider run which has at least 3 same consecutive bytes a candidate for a run. - var startByte = rowSpan[startPos]; + byte startByte = rowSpan[startPos]; int count = 0; for (int i = startPos + 1; i < rowSpan.Length; i++) { diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs new file mode 100644 index 0000000000..1098c3b292 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs @@ -0,0 +1,49 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Tiff.Constants; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors +{ + internal class TiffJpegCompressor : TiffBaseCompressor + { + public TiffJpegCompressor(Stream output, MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffPredictor predictor = TiffPredictor.None) + : base(output, memoryAllocator, width, bitsPerPixel, predictor) + { + } + + /// + public override TiffCompression Method => TiffCompression.Jpeg; + + /// + public override void Initialize(int rowsPerStrip) + { + } + + /// + public override void CompressStrip(Span rows, int height) + { + int pixelCount = rows.Length / 3; + int width = pixelCount / height; + + using var memoryStream = new MemoryStream(); + var image = Image.LoadPixelData(rows, width, height); + image.Save(memoryStream, new JpegEncoder() + { + Subsample = JpegSubsample.Rgb + }); + memoryStream.Position = 0; + memoryStream.WriteTo(this.Output); + } + + /// + protected override void Dispose(bool disposing) + { + } + } +} diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffCompressorFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffCompressorFactory.cs index 14a0c6e9d7..db2b935b74 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffCompressorFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffCompressorFactory.cs @@ -25,7 +25,6 @@ public static TiffBaseCompressor Create( // The following compression types are not implemented in the encoder and will default to no compression instead. case TiffCompression.ItuTRecT43: case TiffCompression.ItuTRecT82: - case TiffCompression.Jpeg: case TiffCompression.OldJpeg: case TiffCompression.OldDeflate: case TiffCompression.None: @@ -34,6 +33,11 @@ public static TiffBaseCompressor Create( return new NoCompressor(output, allocator, width, bitsPerPixel); + case TiffCompression.Jpeg: + DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set"); + DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); + return new TiffJpegCompressor(output, allocator, width, bitsPerPixel); + case TiffCompression.PackBits: DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set"); DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index ee44a70219..04f38c6be2 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -20,7 +20,7 @@ public static TiffBaseDecompressor Create( TiffColorType colorType, TiffPredictor predictor, FaxCompressionOptions faxOptions, - byte[] jpegTables, + byte[] jpegTables, TiffFillOrder fillOrder, ByteOrder byteOrder) { diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 5b8c974b46..b0acbf39d4 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -366,7 +366,7 @@ private void DecodeStripsChunky(ImageFrame frame, int rowsPerStr this.ColorType, this.Predictor, this.FaxCompressionOptions, - this.JpegTables, + this.JpegTables, this.FillOrder, this.byteOrder); diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index 15694978fc..55dd7d3973 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -396,6 +396,9 @@ private static ushort GetCompressionType(TiffEncoderCore encoder) case TiffCompression.Ccitt1D: return (ushort)TiffCompression.Ccitt1D; + + case TiffCompression.Jpeg: + return (ushort)TiffCompression.Jpeg; } return (ushort)TiffCompression.None; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 712c8502ab..1a201dd096 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -114,7 +114,7 @@ public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPix [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Ccitt1D, TiffBitsPerPixel.Bit1, TiffCompression.Ccitt1D)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.ItuTRecT43, TiffBitsPerPixel.Bit24, TiffCompression.None)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.ItuTRecT82, TiffBitsPerPixel.Bit24, TiffCompression.None)] - [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, TiffBitsPerPixel.Bit24, TiffCompression.None)] + [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, TiffBitsPerPixel.Bit24, TiffCompression.Jpeg)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.OldDeflate, TiffBitsPerPixel.Bit24, TiffCompression.None)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.OldJpeg, TiffBitsPerPixel.Bit24, TiffCompression.None)] public void EncoderOptions_SetPhotometricInterpretationAndCompression_Works( @@ -288,6 +288,11 @@ public void TiffEncoder_EncodeRgb_WithLzwCompressionAndPredictor_Works(T public void TiffEncoder_EncodeRgb_WithPackBitsCompression_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.PackBits); + [Theory] + [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeRgb_WithjpegCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg); + [Theory] [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray_Works(TestImageProvider provider) From e3e42a5652464be6fd23852d5210ac193a56d3a3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 07:14:07 +0200 Subject: [PATCH 07/32] Update readme --- src/ImageSharp/Formats/Tiff/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md index ab3394c565..d137b6fc1f 100644 --- a/src/ImageSharp/Formats/Tiff/README.md +++ b/src/ImageSharp/Formats/Tiff/README.md @@ -48,7 +48,7 @@ |CcittGroup4Fax | | | | |Lzw | Y | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case | |Old Jpeg | | | We should not even try to support this | -|Jpeg (Technote 2) | | | | +|Jpeg (Technote 2) | Y | Y | | |Deflate (Technote 2) | Y | Y | Based on PNG Deflate. | |Old Deflate (Technote 2) | | Y | | From 15ef2d9e7f52c865f499b61de65e17f61246bc21 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 07:38:57 +0200 Subject: [PATCH 08/32] Change rows per strip calculation: Jpeg = one strip, compression = use larger strip size --- src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index d7c9848a44..16b3158a4d 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -223,7 +223,7 @@ private long WriteFrame( entriesCollector, (int)this.BitsPerPixel); - int rowsPerStrip = this.CalcRowsPerStrip(frame.Height, colorWriter.BytesPerRow); + int rowsPerStrip = this.CalcRowsPerStrip(frame.Height, colorWriter.BytesPerRow, this.CompressionType); colorWriter.Write(compressor, rowsPerStrip); @@ -245,13 +245,22 @@ private long WriteFrame( /// /// The height of the image. /// The number of bytes per row. + /// The compression used. /// Number of rows per strip. - private int CalcRowsPerStrip(int height, int bytesPerRow) + private int CalcRowsPerStrip(int height, int bytesPerRow, TiffCompression? compression) { DebugGuard.MustBeGreaterThan(height, 0, nameof(height)); DebugGuard.MustBeGreaterThan(bytesPerRow, 0, nameof(bytesPerRow)); - int rowsPerStrip = TiffConstants.DefaultStripSize / bytesPerRow; + // Jpeg compressed images should be written in one strip. + if (compression is TiffCompression.Jpeg) + { + return height; + } + + // If compression is used, change stripSizeInBytes heuristically to a larger value to not write to many strips. + int stripSizeInBytes = compression is TiffCompression.Deflate || compression is TiffCompression.Lzw ? TiffConstants.DefaultStripSize * 2 : TiffConstants.DefaultStripSize; + int rowsPerStrip = stripSizeInBytes / bytesPerRow; if (rowsPerStrip > 0) { From f59de37ca42d090a6ef514c0fb3d4699db226ba0 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 09:33:00 +0200 Subject: [PATCH 09/32] Use smaller test images --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 2 +- tests/Images/Input/Tiff/Calliphora_bicolor_uncompressed.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_ccitt_fax3.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_ccitt_fax4.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_gray_deflate.tiff | 4 ++-- .../Images/Input/Tiff/Calliphora_gray_deflate_predictor.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff | 4 ++-- .../Images/Input/Tiff/Calliphora_grayscale_uncompressed.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_huffman_rle.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_palette_uncompressed.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_rgb_deflate_predictor.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_rgb_jpeg.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif | 3 --- tests/Images/Input/Tiff/Calliphora_rgb_lzw.tiff | 3 +++ tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_rgb_packbits.tiff | 4 ++-- tests/Images/Input/Tiff/Calliphora_rgb_uncompressed.tiff | 4 ++-- 17 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif create mode 100644 tests/Images/Input/Tiff/Calliphora_rgb_lzw.tiff diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index a1d3865a29..482c1b811c 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -37,7 +37,7 @@ public void ThrowsNotSupported(TestImageProvider provider) [Theory] [InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)] [InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(Calliphora_GrayscaleUncompressed, 8, 804, 1198, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(Calliphora_GrayscaleUncompressed, 8, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { diff --git a/tests/Images/Input/Tiff/Calliphora_bicolor_uncompressed.tiff b/tests/Images/Input/Tiff/Calliphora_bicolor_uncompressed.tiff index b0dbdde549..5b668ac513 100644 --- a/tests/Images/Input/Tiff/Calliphora_bicolor_uncompressed.tiff +++ b/tests/Images/Input/Tiff/Calliphora_bicolor_uncompressed.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed3b08730e5c34eb8d268f58d1e09efe2605398899bfd726cc3b35de21baa6ff -size 121196 +oid sha256:c35902ca485fba441230efa88f794ee5aafa9f75ad5e4a14cb3d592a0a98c538 +size 7760 diff --git a/tests/Images/Input/Tiff/Calliphora_ccitt_fax3.tiff b/tests/Images/Input/Tiff/Calliphora_ccitt_fax3.tiff index d2761d2919..3592206bc5 100644 --- a/tests/Images/Input/Tiff/Calliphora_ccitt_fax3.tiff +++ b/tests/Images/Input/Tiff/Calliphora_ccitt_fax3.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bba35f1e43c8425f3bcfab682efae4d2c00c62f0d8a4b411e646d32047469526 -size 125802 +oid sha256:da7d98823c284d92982a88c4a51434bbc140dceac245a8a054c6e41a489d0cc7 +size 5986 diff --git a/tests/Images/Input/Tiff/Calliphora_ccitt_fax4.tiff b/tests/Images/Input/Tiff/Calliphora_ccitt_fax4.tiff index 384d00eaa9..94b6a7ee66 100644 --- a/tests/Images/Input/Tiff/Calliphora_ccitt_fax4.tiff +++ b/tests/Images/Input/Tiff/Calliphora_ccitt_fax4.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2c95aec08b96bca30af344f7d9952a603a951802ce534a5f2c5f563795cbd2 -size 117704 +oid sha256:3e968748833a239d06879ecf100681f5f93c8c3830558c438b684d78dd5faefa +size 4258 diff --git a/tests/Images/Input/Tiff/Calliphora_gray_deflate.tiff b/tests/Images/Input/Tiff/Calliphora_gray_deflate.tiff index 621ef158aa..3909521203 100644 --- a/tests/Images/Input/Tiff/Calliphora_gray_deflate.tiff +++ b/tests/Images/Input/Tiff/Calliphora_gray_deflate.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2314b31ca9938fa8b11cbabda0b118a90025a45d2931fca9afa131c0d6919aca -size 557717 +oid sha256:d4d3541db6b7751d3225599aa822c3376fb27bb9dc2dd28674ef4f78bf426191 +size 83356 diff --git a/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor.tiff b/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor.tiff index f44a6e9343..e7fdef14bb 100644 --- a/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor.tiff +++ b/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9576b3a49b84e26938a7e9ded5f43a1a3c3390bf4824803f5aaab8e00c1afb4 -size 630947 +oid sha256:d007429701cc20154e84909af6988414001e6e60fba5c995f67b2a04cad6e57b +size 41135 diff --git a/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff b/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff index b14eeba8d5..de85622968 100644 --- a/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff +++ b/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f24fd8f36a4847fcb84a317de4fd2eacd5eb0c58ef4436d33919f0a6658d0d9 -size 698309 +oid sha256:649f0b8ad50a9465fdb447c411e33f20a8b367600e7c3af83c8f686f3ab3e6dc +size 47143 diff --git a/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed.tiff b/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed.tiff index 5db7ef564e..e6ff007d4a 100644 --- a/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed.tiff +++ b/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0283f2be39a151ca3ed19be97ebe4a6b17978ed251dd4d0d568895865fec24c7 -size 964588 +oid sha256:5925388b374b75161ef49273e8c85c4f99713e5e3be380ea13a03895f47809ba +size 60001 diff --git a/tests/Images/Input/Tiff/Calliphora_huffman_rle.tiff b/tests/Images/Input/Tiff/Calliphora_huffman_rle.tiff index e0a39d2483..1998b371cb 100644 --- a/tests/Images/Input/Tiff/Calliphora_huffman_rle.tiff +++ b/tests/Images/Input/Tiff/Calliphora_huffman_rle.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a4f687de9925863b1c9f32f53b6c05fb121f9d7b02ff5869113c4745433f10d -size 124644 +oid sha256:f27e758bb72d5e03fdcf0b1c58c417e4a7928cbdf8d432dc5b9a7d8d7ee4d06b +size 5668 diff --git a/tests/Images/Input/Tiff/Calliphora_palette_uncompressed.tiff b/tests/Images/Input/Tiff/Calliphora_palette_uncompressed.tiff index 1592645c8e..1d3c9a7899 100644 --- a/tests/Images/Input/Tiff/Calliphora_palette_uncompressed.tiff +++ b/tests/Images/Input/Tiff/Calliphora_palette_uncompressed.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b70500348b1af7828c15e7782eaca105ff749136d7c45eb4cab8c5cd5269c3f6 -size 966134 +oid sha256:29d4b30265158a7cc651d75130843a7f5a7ebf8b2f0f4bb0cf86c82cbec7f6ec +size 61549 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_deflate_predictor.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_deflate_predictor.tiff index c2ebed3649..0ded461400 100644 --- a/tests/Images/Input/Tiff/Calliphora_rgb_deflate_predictor.tiff +++ b/tests/Images/Input/Tiff/Calliphora_rgb_deflate_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da6e6a35a0bb0f5f2d49e3c5f0eb2deb7118718dd08844f66a6cb72f48b5c489 -size 1476294 +oid sha256:392e1269220e7e3feb9e2b256e82cce6a2394a5cabef042fdb10def6b24ff165 +size 111819 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_jpeg.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_jpeg.tiff index c9f5fadee8..f45aacce44 100644 --- a/tests/Images/Input/Tiff/Calliphora_rgb_jpeg.tiff +++ b/tests/Images/Input/Tiff/Calliphora_rgb_jpeg.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba79ffac35e16208406e073492d770d3a77e51a47112aa02ab8fd98b5a8487b2 -size 198564 +oid sha256:4baf0f4c462e5bef71ab36f505dfff87a31bd1d25deabccd822a359c1075e08e +size 65748 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif b/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif deleted file mode 100644 index 7450522679..0000000000 --- a/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:53006876fcdc655a794462de57eb6b56f4d0cdd3cb8b752c63328db0eb4aa3c1 -size 725085 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tiff new file mode 100644 index 0000000000..5e4cf8be9b --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_rgb_lzw.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d83d8a81ebb7337f00b319a8c37cfdef07423d6a61006411130e386238dd00dd +size 121907 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff index 99642af524..2fa884f36b 100644 --- a/tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff +++ b/tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ecb529e5e3e0eca6f5e407b034fa8ba67bb4b9068af9e9b30425b08d30a249c0 -size 1756355 +oid sha256:993207c34358165af5fac0d0b955b56cd79e9707c1c46344863e01cbc9c7707d +size 126695 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_packbits.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_packbits.tiff index 862db0b39f..6fc2c9b213 100644 --- a/tests/Images/Input/Tiff/Calliphora_rgb_packbits.tiff +++ b/tests/Images/Input/Tiff/Calliphora_rgb_packbits.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59dbb48f10c40cbbd4f5617a9f57536790ce0b9a4cc241dc8d6257095598cb76 -size 2891292 +oid sha256:81e7456578510c85e5bebe8bc7c5796da6e2cd61f5bbe0a1f6bb46b8aee3d695 +size 179949 diff --git a/tests/Images/Input/Tiff/Calliphora_rgb_uncompressed.tiff b/tests/Images/Input/Tiff/Calliphora_rgb_uncompressed.tiff index 7ebd74d9d4..7fc5923153 100644 --- a/tests/Images/Input/Tiff/Calliphora_rgb_uncompressed.tiff +++ b/tests/Images/Input/Tiff/Calliphora_rgb_uncompressed.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acb46c990af78fcb0e63849f0f26acffe26833d5cfd2fc77a728baf92166eea3 -size 2893218 +oid sha256:bb25349a7f803aeafc47d8a05deca1a8afdc4bdc5a53e2916f68d5c3e7d8cad3 +size 179207 From fd96562c8ad2764888c4d6d82ffff3ce2b1c1099 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 12 Aug 2021 09:40:44 +0200 Subject: [PATCH 10/32] Use CancellationToken --- .../Formats/Tiff/TiffDecoderCore.cs | 34 +++++++++++++------ .../Formats/Tiff/TiffEncoderCore.cs | 2 ++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index b0acbf39d4..104d0dcd08 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -149,7 +149,8 @@ public Image Decode(BufferedReadStream stream, CancellationToken var frames = new List>(); foreach (ExifProfile ifd in directories) { - ImageFrame frame = this.DecodeFrame(ifd); + cancellationToken.ThrowIfCancellationRequested(); + ImageFrame frame = this.DecodeFrame(ifd, cancellationToken); frames.Add(frame); } @@ -191,10 +192,9 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella /// /// The pixel format. /// The IFD tags. - /// - /// The tiff frame. - /// - private ImageFrame DecodeFrame(ExifProfile tags) + /// The token to monitor cancellation. + /// The tiff frame. + private ImageFrame DecodeFrame(ExifProfile tags, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { ImageFrameMetadata imageFrameMetaData = this.ignoreMetadata ? @@ -216,11 +216,11 @@ private ImageFrame DecodeFrame(ExifProfile tags) if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { - this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts); + this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } else { - this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts); + this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } return frame; @@ -268,14 +268,15 @@ private int CalculateStripBufferSize(int width, int height, int plane = -1) } /// - /// Decodes the image data for strip encoded data. + /// Decodes the image data for planar encoded pixel data. /// /// The pixel format. /// The image frame to decode data into. /// The number of rows per strip of data. /// An array of byte offsets to each strip in the image. /// An array of the size of each strip (in bytes). - private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts) + /// The token to monitor cancellation. + private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int stripsPerPixel = this.BitsPerSample.Channels; @@ -319,6 +320,8 @@ private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStr for (int i = 0; i < stripsPerPlane; i++) { + cancellationToken.ThrowIfCancellationRequested(); + int stripHeight = i < stripsPerPlane - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip; int stripIndex = i; @@ -340,7 +343,16 @@ private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStr } } - private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts) + /// + /// Decodes the image data for chunky encoded pixel data. + /// + /// The pixel format. + /// The image frame to decode data into. + /// The rows per strip. + /// The strip offsets. + /// The strip byte counts. + /// The token to monitor cancellation. + private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. @@ -383,6 +395,8 @@ private void DecodeStripsChunky(ImageFrame frame, int rowsPerStr for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++) { + cancellationToken.ThrowIfCancellationRequested(); + int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip; diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 16b3158a4d..1e4254a4ef 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -155,6 +155,8 @@ public void Encode(Image image, Stream stream, CancellationToken Image metadataImage = image; foreach (ImageFrame frame in image.Frames) { + cancellationToken.ThrowIfCancellationRequested(); + var subfileType = (TiffNewSubfileType)(frame.Metadata.ExifProfile?.GetValue(ExifTag.SubfileType)?.Value ?? (int)TiffNewSubfileType.FullImage); ifdMarker = this.WriteFrame(writer, frame, image.Metadata, metadataImage, ifdMarker); From a531a2db24a024a25d14c49b3915f26a2b20c439 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 13 Aug 2021 19:55:55 +0200 Subject: [PATCH 11/32] Remove JpegSubsample and use JpegColorType instead --- .../Formats/Jpeg/IJpegEncoderOptions.cs | 8 +-- src/ImageSharp/Formats/Jpeg/JpegColorType.cs | 18 ++++- .../Formats/Jpeg/JpegDecoderCore.cs | 17 ++++- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 15 ++--- .../Formats/Jpeg/JpegEncoderCore.cs | 45 ++++++------- src/ImageSharp/Formats/Jpeg/JpegSubsample.cs | 28 -------- .../Compressors/TiffJpegCompressor.cs | 2 +- .../Codecs/Jpeg/EncodeJpeg.cs | 4 +- .../Formats/Jpg/JpegEncoderTests.cs | 65 ++++++++++--------- .../Formats/Jpg/JpegMetadataTests.cs | 2 +- .../Formats/Jpg/SpectralJpegTests.cs | 6 +- .../JpegProfilingBenchmarks.cs | 14 ++-- 12 files changed, 100 insertions(+), 124 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/JpegSubsample.cs diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs index a9f564b450..70cfd18e94 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -16,13 +16,7 @@ internal interface IJpegEncoderOptions public int? Quality { get; set; } /// - /// Gets the subsample ration, that will be used to encode the image. - /// - /// The subsample ratio of the jpg image. - JpegSubsample? Subsample { get; } - - /// - /// Gets the color type. + /// Gets the color type, that will be used to encode the image. /// JpegColorType? ColorType { get; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs index 73b3215d62..a0b9c7fe68 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs @@ -10,12 +10,26 @@ public enum JpegColorType : byte { /// /// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification. + /// Medium Quality - The horizontal sampling is halved and the Cb and Cr channels are only + /// sampled on each alternate line. /// - YCbCr = 0, + YCbCrRatio420 = 0, + + /// + /// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification. + /// High Quality - Each of the three Y'CbCr components have the same sample rate, + /// thus there is no chroma subsampling. + /// + YCbCrRatio444 = 1, /// /// Single channel, luminance. /// - Luminance = 1 + Luminance = 2, + + /// + /// The pixel data will be preserved as RGB without any sub sampling. + /// + Rgb, } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 5c80599390..13049dda12 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -312,7 +312,7 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco case JpegConstants.Markers.SOS: if (!metadataOnly) { - this.ProcessStartOfScanMarker(stream, remaining, cancellationToken); + this.ProcessStartOfScanMarker(stream, remaining); break; } else @@ -953,7 +953,18 @@ private void ProcessStartOfFrameMarker(BufferedReadStream stream, int remaining, this.ColorSpace = this.DeduceJpegColorSpace(componentCount, this.Frame.Components); - this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr; + switch (this.ColorSpace) + { + case JpegColorSpace.Grayscale: + this.Metadata.GetJpegMetadata().ColorType = JpegColorType.Luminance; + break; + case JpegColorSpace.RGB: + this.Metadata.GetJpegMetadata().ColorType = JpegColorType.Rgb; + break; + default: + this.Metadata.GetJpegMetadata().ColorType = JpegColorType.YCbCrRatio420; + break; + } if (!metadataOnly) { @@ -1051,7 +1062,7 @@ private void ProcessDefineRestartIntervalMarker(BufferedReadStream stream, int r /// /// Processes the SOS (Start of scan marker). /// - private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining, CancellationToken cancellationToken) + private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining) { if (this.Frame is null) { diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 5e199b4204..6f116f4fb3 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -16,14 +16,7 @@ public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions /// public int? Quality { get; set; } - /// - /// Gets or sets the subsample ration, that will be used to encode the image. - /// - public JpegSubsample? Subsample { get; set; } - - /// - /// Gets or sets the color type, that will be used to encode the image. - /// + /// public JpegColorType? ColorType { get; set; } /// @@ -36,7 +29,7 @@ public void Encode(Image image, Stream stream) where TPixel : unmanaged, IPixel { var encoder = new JpegEncoderCore(this); - this.InitializeColorType(image); + this.InitializeColorType(image); encoder.Encode(image, stream); } @@ -52,7 +45,7 @@ public Task EncodeAsync(Image image, Stream stream, Cancellation where TPixel : unmanaged, IPixel { var encoder = new JpegEncoderCore(this); - this.InitializeColorType(image); + this.InitializeColorType(image); return encoder.EncodeAsync(image, stream, cancellationToken); } @@ -75,7 +68,7 @@ private void InitializeColorType(Image image) bool isGrayscale = typeof(TPixel) == typeof(L8) || typeof(TPixel) == typeof(L16) || typeof(TPixel) == typeof(La16) || typeof(TPixel) == typeof(La32); - this.ColorType = isGrayscale ? JpegColorType.Luminance : JpegColorType.YCbCr; + this.ColorType = isGrayscale ? JpegColorType.Luminance : JpegColorType.YCbCrRatio420; } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index d49e40d2fe..8d2b436438 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -33,20 +33,15 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals /// private readonly byte[] buffer = new byte[20]; - /// - /// Gets or sets the subsampling method to use. - /// - private JpegSubsample? subsample; - /// /// The quality, that will be used to encode the image. /// private readonly int? quality; /// - /// Gets or sets the subsampling method to use. + /// Gets or sets the colorspace to use. /// - private readonly JpegColorType? colorType; + private JpegColorType? colorType; /// /// The output stream. All attempted writes after the first error become no-ops. @@ -56,11 +51,10 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals /// /// Initializes a new instance of the class. /// - /// The options + /// The options. public JpegEncoderCore(IJpegEncoderOptions options) { this.quality = options.Quality; - this.subsample = options.Subsample; this.colorType = options.ColorType; } @@ -118,21 +112,22 @@ public void Encode(Image image, Stream stream, CancellationToken var scanEncoder = new HuffmanScanEncoder(stream); if (this.colorType == JpegColorType.Luminance) { - // luminance quantization table only + // luminance quantization table only. scanEncoder.EncodeGrayscale(image, ref luminanceQuantTable, cancellationToken); } else { - // luminance and chrominance quantization tables - switch (this.subsample) + // luminance and chrominance quantization tables. + switch (this.colorType) { - case JpegSubsample.Ratio444: + case JpegColorType.YCbCrRatio444: + case JpegColorType.Luminance: scanEncoder.Encode444(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; - case JpegSubsample.Ratio420: + case JpegColorType.YCbCrRatio420: scanEncoder.Encode420(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; - case JpegSubsample.Rgb: + case JpegColorType.Rgb: scanEncoder.EncodeRgb(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; } @@ -151,7 +146,7 @@ public void Encode(Image image, Stream stream, CancellationToken /// The component Ids. private byte[] GetComponentIds() { - if (this.subsample == JpegSubsample.Rgb) + if (this.colorType == JpegColorType.Rgb) { return new byte[] { 82, 71, 66 }; } @@ -268,7 +263,7 @@ private void WriteDefineHuffmanTables(int componentCount) /// private void WriteDefineQuantizationTables(ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable) { - // Marker + quantization table lengths + // Marker + quantization table lengths. int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size)); this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen); @@ -404,7 +399,7 @@ private void WriteAppHeader(int length, byte appMarker) /// /// The ICC profile to write. /// - /// Thrown if any of the ICC profiles size exceeds the limit + /// Thrown if any of the ICC profiles size exceeds the limit. /// private void WriteIccProfile(IccProfile iccProfile) { @@ -424,7 +419,7 @@ private void WriteIccProfile(IccProfile iccProfile) return; } - // Calculate the number of markers we'll need, rounding up of course + // Calculate the number of markers we'll need, rounding up of course. int dataLength = data.Length; int count = dataLength / MaxData; @@ -531,10 +526,10 @@ private void WriteStartOfFrame(int width, int height, int componentCount, byte[] } else { - switch (this.subsample) + switch (this.colorType) { - case JpegSubsample.Rgb: - case JpegSubsample.Ratio444: + case JpegColorType.YCbCrRatio444: + case JpegColorType.Rgb: subsamples = stackalloc byte[] { 0x11, @@ -542,7 +537,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, byte[] 0x11 }; break; - case JpegSubsample.Ratio420: + case JpegColorType.YCbCrRatio420: subsamples = stackalloc byte[] { 0x22, @@ -685,9 +680,9 @@ private void InitQuantizationTables(int componentCount, JpegMetadata metadata, o chromaQuality = Numerics.Clamp(chromaQuality, 1, 100); chrominanceQuantTable = Quantization.ScaleChrominanceTable(chromaQuality); - if (!this.subsample.HasValue) + if (!this.colorType.HasValue) { - this.subsample = chromaQuality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420; + this.colorType = chromaQuality >= 91 ? JpegColorType.YCbCrRatio444 : JpegColorType.YCbCrRatio420; } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs deleted file mode 100644 index 760ba3a962..0000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg -{ - /// - /// Enumerates the chroma subsampling method applied to the image. - /// - public enum JpegSubsample - { - /// - /// High Quality - Each of the three Y'CbCr components have the same sample rate, - /// thus there is no chroma subsampling. - /// - Ratio444, - - /// - /// Medium Quality - The horizontal sampling is halved and the Cb and Cr channels are only - /// sampled on each alternate line. - /// - Ratio420, - - /// - /// The pixel data will be preserved as RGB without any sub sampling. - /// - Rgb, - } -} diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs index 1098c3b292..0ae8fd37bd 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffJpegCompressor.cs @@ -35,7 +35,7 @@ public override void CompressStrip(Span rows, int height) var image = Image.LoadPixelData(rows, width, height); image.Save(memoryStream, new JpegEncoder() { - Subsample = JpegSubsample.Rgb + ColorType = JpegColorType.Rgb }); memoryStream.Position = 0; memoryStream.WriteTo(this.Output); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs index 87170e8d24..508b4b3b09 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs @@ -40,8 +40,8 @@ public void ReadImages() this.bmpCore = Image.Load(this.bmpStream); this.bmpCore.Metadata.ExifProfile = null; - this.encoder420 = new JpegEncoder { Quality = this.Quality, Subsample = JpegSubsample.Ratio420 }; - this.encoder444 = new JpegEncoder { Quality = this.Quality, Subsample = JpegSubsample.Ratio444 }; + this.encoder420 = new JpegEncoder { Quality = this.Quality, ColorType = JpegColorType.YCbCrRatio420 }; + this.encoder444 = new JpegEncoder { Quality = this.Quality, ColorType = JpegColorType.YCbCrRatio444 }; this.bmpStream.Position = 0; this.bmpDrawing = SDImage.FromStream(this.bmpStream); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 8e12b04be9..574f859c50 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -31,15 +31,18 @@ public class JpegEncoderTests { TestImages.Jpeg.Progressive.Fb, 75 } }; - public static readonly TheoryData BitsPerPixel_Quality = - new TheoryData + public static readonly TheoryData BitsPerPixel_Quality = + new TheoryData { - { JpegSubsample.Ratio420, 40 }, - { JpegSubsample.Ratio420, 60 }, - { JpegSubsample.Ratio420, 100 }, - { JpegSubsample.Ratio444, 40 }, - { JpegSubsample.Ratio444, 60 }, - { JpegSubsample.Ratio444, 100 }, + { JpegColorType.Rgb, 40 }, + { JpegColorType.Rgb, 60 }, + { JpegColorType.Rgb, 100 }, + { JpegColorType.YCbCrRatio420, 40 }, + { JpegColorType.YCbCrRatio420, 60 }, + { JpegColorType.YCbCrRatio420, 100 }, + { JpegColorType.YCbCrRatio444, 40 }, + { JpegColorType.YCbCrRatio444, 60 }, + { JpegColorType.YCbCrRatio444, 100 }, }; public static readonly TheoryData Grayscale_Quality = @@ -91,8 +94,8 @@ public void Encode_PreserveQuality(string imagePath, int quality) [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 600, 400, PixelTypes.Rgba32)] [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)] - public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegSubsample subsample, int quality) - where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, subsample, quality); + public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality) + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] [WithFile(TestImages.Png.BikeGrayscale, nameof(Grayscale_Quality), PixelTypes.L8)] @@ -102,33 +105,33 @@ public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider(TestImageProvider provider, int quality) - where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, null, quality, JpegColorType.Luminance); + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegColorType.Luminance, quality); [Theory] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)] - public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegSubsample subsample, int quality) - where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, subsample, quality); + public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType colorType, int quality) + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegSubsample.Ratio444)] - [WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegSubsample.Ratio444)] - [WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegSubsample.Ratio420)] - [WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegSubsample.Ratio420)] - public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegSubsample subsample) + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] + [WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] + [WithTestPatternImages(677, 683, PixelTypes.Bgra32, JpegColorType.YCbCrRatio420)] + [WithSolidFilledImages(400, 400, "Red", PixelTypes.Bgr24, JpegColorType.YCbCrRatio420)] + public void EncodeBaseline_WorksWithDiscontiguousBuffers(TestImageProvider provider, JpegColorType colorType) where TPixel : unmanaged, IPixel { - ImageComparer comparer = subsample == JpegSubsample.Ratio444 + ImageComparer comparer = colorType == JpegColorType.YCbCrRatio444 ? ImageComparer.TolerantPercentage(0.1f) : ImageComparer.TolerantPercentage(5f); provider.LimitAllocatorBufferCapacity().InBytesSqrt(200); - TestJpegEncoderCore(provider, subsample, 100, JpegColorType.YCbCr, comparer); + TestJpegEncoderCore(provider, colorType, 100, comparer); } /// /// Anton's SUPER-SCIENTIFIC tolerance threshold calculation /// - private static ImageComparer GetComparer(int quality, JpegSubsample? subsample) + private static ImageComparer GetComparer(int quality, JpegColorType? colorType) { float tolerance = 0.015f; // ~1.5% @@ -136,10 +139,10 @@ private static ImageComparer GetComparer(int quality, JpegSubsample? subsample) { tolerance *= 10f; } - else if (quality < 75 || subsample == JpegSubsample.Ratio420) + else if (quality < 75 || colorType == JpegColorType.YCbCrRatio420) { tolerance *= 5f; - if (subsample == JpegSubsample.Ratio420) + if (colorType == JpegColorType.YCbCrRatio420) { tolerance *= 2f; } @@ -150,9 +153,8 @@ private static ImageComparer GetComparer(int quality, JpegSubsample? subsample) private static void TestJpegEncoderCore( TestImageProvider provider, - JpegSubsample? subsample, + JpegColorType colorType = JpegColorType.YCbCrRatio420, int quality = 100, - JpegColorType colorType = JpegColorType.YCbCr, ImageComparer comparer = null) where TPixel : unmanaged, IPixel { @@ -163,13 +165,12 @@ private static void TestJpegEncoderCore( var encoder = new JpegEncoder { - Subsample = subsample, Quality = quality, ColorType = colorType }; - string info = $"{subsample}-Q{quality}"; + string info = $"{colorType}-Q{quality}"; - comparer ??= GetComparer(quality, subsample); + comparer ??= GetComparer(quality, colorType); // Does DebugSave & load reference CompareToReferenceInput(): image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "png"); @@ -312,9 +313,9 @@ public void Encode_PreservesIccProfile() } [Theory] - [InlineData(JpegSubsample.Ratio420)] - [InlineData(JpegSubsample.Ratio444)] - public async Task Encode_IsCancellable(JpegSubsample subsample) + [InlineData(JpegColorType.YCbCrRatio420)] + [InlineData(JpegColorType.YCbCrRatio444)] + public async Task Encode_IsCancellable(JpegColorType colorType) { var cts = new CancellationTokenSource(); using var pausedStream = new PausedStream(new MemoryStream()); @@ -336,7 +337,7 @@ public async Task Encode_IsCancellable(JpegSubsample subsample) using var image = new Image(5000, 5000); await Assert.ThrowsAsync(async () => { - var encoder = new JpegEncoder() { Subsample = subsample }; + var encoder = new JpegEncoder() { ColorType = colorType }; await image.SaveAsync(pausedStream, encoder, cts.Token); }); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 56bf207b97..3f045dd1a0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -16,7 +16,7 @@ public void CloneIsDeep() var clone = (JpegMetadata)meta.DeepClone(); clone.Quality = 99; - clone.ColorType = JpegColorType.YCbCr; + clone.ColorType = JpegColorType.YCbCrRatio420; Assert.False(meta.Quality.Equals(clone.Quality)); Assert.False(meta.ColorType.Equals(clone.ColorType)); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 40b9e68677..1785f3dec4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class SpectralJpegTests { - public SpectralJpegTests(ITestOutputHelper output) - { - this.Output = output; - } + public SpectralJpegTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } @@ -46,7 +43,6 @@ public SpectralJpegTests(ITestOutputHelper output) public static readonly string[] AllTestJpegs = BaselineTestJpegs.Concat(ProgressiveTestJpegs).ToArray(); [Theory(Skip = "Debug only, enable manually!")] - //[Theory] [WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)] public void Decoder_ParseStream_SaveSpectralResult(TestImageProvider provider) where TPixel : unmanaged, IPixel diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 9de3fc8dfe..4a47ac2365 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -70,7 +70,7 @@ private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder, int img.Dispose(); }, #pragma warning disable SA1515 // Single-line comment should be preceded by blank line - // ReSharper disable once ExplicitCallerInfoArgument + // ReSharper disable once ExplicitCallerInfoArgument $"Decode {fileName}"); #pragma warning restore SA1515 // Single-line comment should be preceded by blank line } @@ -92,11 +92,11 @@ public void EncodeJpeg_SingleMidSize() // Benchmark, enable manually! [Theory(Skip = ProfilingSetup.SkipProfilingTests)] - [InlineData(1, 75, JpegSubsample.Ratio420)] - [InlineData(30, 75, JpegSubsample.Ratio420)] - [InlineData(30, 75, JpegSubsample.Ratio444)] - [InlineData(30, 100, JpegSubsample.Ratio444)] - public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) + [InlineData(1, 75, JpegColorType.YCbCrRatio420)] + [InlineData(30, 75, JpegColorType.YCbCrRatio420)] + [InlineData(30, 75, JpegColorType.YCbCrRatio444)] + [InlineData(30, 100, JpegColorType.YCbCrRatio444)] + public void EncodeJpeg(int executionCount, int quality, JpegColorType colorType) { // do not run this on CI even by accident if (TestEnvironment.RunsOnCI) @@ -118,7 +118,7 @@ public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { foreach (Image img in testImages) { - var options = new JpegEncoder { Quality = quality, Subsample = subsample }; + var options = new JpegEncoder { Quality = quality, ColorType = colorType }; img.Save(ms, options); ms.Seek(0, SeekOrigin.Begin); } From 96edc48fbf9b0d8ed8e84b1b4c05c69554f395bd Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 13 Aug 2021 21:18:26 +0200 Subject: [PATCH 12/32] Define componentId's as static readonly array's --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 8d2b436438..18d31d978c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -33,6 +33,16 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals /// private readonly byte[] buffer = new byte[20]; + /// + /// The default component id's. + /// + private static readonly byte[] DefaultComponentIds = { 1, 2, 3 }; + + /// + /// Component id's for RGB colorspace. + /// + private static readonly byte[] RgbComponentIds = { 82, 71, 66 }; + /// /// The quality, that will be used to encode the image. /// @@ -148,10 +158,10 @@ private byte[] GetComponentIds() { if (this.colorType == JpegColorType.Rgb) { - return new byte[] { 82, 71, 66 }; + return RgbComponentIds; } - return new byte[] { 1, 2, 3 }; + return DefaultComponentIds; } /// From b23707adee1d8f548633bf983f22371abcc6bc25 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 13 Aug 2021 21:18:43 +0200 Subject: [PATCH 13/32] Use MemoryMarshal.GetReference for rgbStart --- .../Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs index e23cf348a2..7fad63e117 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbForwardConverter{TPixel}.cs @@ -99,7 +99,7 @@ public void Convert(int x, int y, ref RowOctet currentRows) private static void CopyToBlock(Span rgbSpan, ref Block8x8F redBlock, ref Block8x8F greenBlock, ref Block8x8F blueBlock) { - ref Rgb24 rgbStart = ref rgbSpan[0]; + ref Rgb24 rgbStart = ref MemoryMarshal.GetReference(rgbSpan); for (int i = 0; i < Block8x8F.Size; i++) { From 77cdbbb8da94e0c620f04c695c522eaf1826a450 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 13 Aug 2021 21:25:30 +0200 Subject: [PATCH 14/32] Use ReadOnlySpan for componentId's --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 18d31d978c..dc84a161fb 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -94,7 +94,7 @@ public void Encode(Image image, Stream stream, CancellationToken // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; - byte[] componentIds = this.GetComponentIds(); + ReadOnlySpan componentIds = this.GetComponentIds(); // TODO: Right now encoder writes both quantization tables for grayscale images - we shouldn't do that // Initialize the quantization tables. @@ -154,7 +154,7 @@ public void Encode(Image image, Stream stream, CancellationToken /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3. /// /// The component Ids. - private byte[] GetComponentIds() + private ReadOnlySpan GetComponentIds() { if (this.colorType == JpegColorType.Rgb) { @@ -508,7 +508,7 @@ private void WriteProfiles(ImageMetadata metadata) /// The height of the image. /// The number of components in a pixel. /// The component Id's. - private void WriteStartOfFrame(int width, int height, int componentCount, byte[] componentIds) + private void WriteStartOfFrame(int width, int height, int componentCount, ReadOnlySpan componentIds) { // "default" to 4:2:0 Span subsamples = stackalloc byte[] @@ -586,7 +586,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, byte[] /// /// The number of components in a pixel. /// The componentId's. - private void WriteStartOfScan(int componentCount, byte[] componentIds) + private void WriteStartOfScan(int componentCount, ReadOnlySpan componentIds) { Span huffmanId = stackalloc byte[] { From e092d86b8fda863f8719188e4b963df2a0c0fa1f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 13 Aug 2021 21:25:52 +0200 Subject: [PATCH 15/32] Use TolerantComparer for Tiff Jpeg test's --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 482c1b811c..5ed05478ca 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -374,7 +374,7 @@ public void TiffDecoder_CanDecode_PackBitsCompressed(TestImageProvider(TestImageProvider provider) - where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, useExactComparer: false); [Theory] [WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)] From 1b019841386c327bf12edb6ceefbfb6e8f82fd49 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 14 Aug 2021 19:10:28 +0200 Subject: [PATCH 16/32] For YCbCr Tiff's with Jpeg compression explicitly assume RGB color space --- .../Components/Decoder/HuffmanScanDecoder.cs | 2 +- .../Components/Decoder/SpectralConverter.cs | 10 ++++++ .../Decoder/SpectralConverter{TPixel}.cs | 11 +++++-- .../Decompressors/JpegTiffCompression.cs | 22 ++++++++++--- .../Decompressors/RgbJpegSpectralConverter.cs | 33 +++++++++++++++++++ .../Compression/TiffDecompressorsFactory.cs | 2 +- .../Formats/Jpg/SpectralJpegTests.cs | 3 ++ .../Formats/Tiff/TiffEncoderTests.cs | 4 +-- 8 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 28ef6a96f7..b5a51c5a4a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -67,7 +67,7 @@ internal class HuffmanScanDecoder private readonly SpectralConverter spectralConverter; - private CancellationToken cancellationToken; + private readonly CancellationToken cancellationToken; /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index e84d13ff16..46821d45d4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; + namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { /// @@ -30,5 +32,13 @@ internal abstract class SpectralConverter /// Actual stride height depends on the subsampling factor of the given component. /// public abstract void ConvertStrideBaseline(); + + /// + /// Gets the color converter. + /// + /// The jpeg frame with the color space to convert to. + /// The raw JPEG data. + /// The color converter. + public abstract JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 50cfa0188a..50fc46c1e8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -11,12 +11,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { - internal sealed class SpectralConverter : SpectralConverter, IDisposable + internal class SpectralConverter : SpectralConverter, IDisposable where TPixel : unmanaged, IPixel { private readonly Configuration configuration; - private CancellationToken cancellationToken; + private readonly CancellationToken cancellationToken; private JpegComponentPostProcessor[] componentProcessors; @@ -59,6 +59,7 @@ public Buffer2D PixelBuffer } } + /// public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) { MemoryAllocator allocator = this.configuration.MemoryAllocator; @@ -85,9 +86,10 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); // color converter from Rgba32 to TPixel - this.colorConverter = JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); + this.colorConverter = this.GetConverter(frame, jpegData); } + /// public override void ConvertStrideBaseline() { // Convert next pixel stride using single spectral `stride' @@ -103,6 +105,9 @@ public override void ConvertStrideBaseline() } } + /// + public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); + public void Dispose() { if (this.componentProcessors != null) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs index 2722c7db48..8abaf20088 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs @@ -23,6 +23,8 @@ internal class JpegTiffCompression : TiffBaseDecompressor private readonly byte[] jpegTables; + private readonly TiffPhotometricInterpretation photometricInterpretation; + /// /// Initializes a new instance of the class. /// @@ -31,12 +33,19 @@ internal class JpegTiffCompression : TiffBaseDecompressor /// The image width. /// The bits per pixel. /// The JPEG tables containing the quantization and/or Huffman tables. - /// The predictor. - public JpegTiffCompression(Configuration configuration, MemoryAllocator memoryAllocator, int width, int bitsPerPixel, byte[] jpegTables, TiffPredictor predictor = TiffPredictor.None) - : base(memoryAllocator, width, bitsPerPixel, predictor) + /// The photometric interpretation. + public JpegTiffCompression( + Configuration configuration, + MemoryAllocator memoryAllocator, + int width, + int bitsPerPixel, + byte[] jpegTables, + TiffPhotometricInterpretation photometricInterpretation) + : base(memoryAllocator, width, bitsPerPixel) { this.configuration = configuration; this.jpegTables = jpegTables; + this.photometricInterpretation = photometricInterpretation; } /// @@ -47,8 +56,11 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, Spa { var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); - // Should we pass through the CancellationToken from the tiff decoder? - using var spectralConverter = new SpectralConverter(this.configuration, CancellationToken.None); + // TODO: Should we pass through the CancellationToken from the tiff decoder? + // If the PhotometricInterpretation is YCbCr we explicitly assume the JPEG data is in RGB color space. + // There seems no other way to determine that the JPEG data is RGB colorspace (no APP14 marker, componentId's are not RGB). + using SpectralConverter spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ? + new RgbJpegSpectralConverter(this.configuration, CancellationToken.None) : new SpectralConverter(this.configuration, CancellationToken.None); var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None); jpegDecoder.LoadTables(this.jpegTables, scanDecoder); scanDecoder.ResetInterval = 0; diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs new file mode 100644 index 0000000000..46ec537165 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Threading; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors +{ + /// + /// Spectral converter for YCbCr TIFF's which use the JPEG compression. + /// The jpeg data should be always treated as RGB color space. + /// + /// The type of the pixel. + internal sealed class RgbJpegSpectralConverter : SpectralConverter + where TPixel : unmanaged, IPixel + { + /// + /// Initializes a new instance of the class. + /// This Spectral converter will always convert the pixel data to RGB color. + /// + /// The configuration. + /// The cancellation token. + public RgbJpegSpectralConverter(Configuration configuration, CancellationToken cancellationToken) + : base(configuration, cancellationToken) + { + } + + /// + public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(JpegColorSpace.RGB, frame.Precision); + } +} diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index 04f38c6be2..2ac00b4129 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -54,7 +54,7 @@ public static TiffBaseDecompressor Create( case TiffDecoderCompressionType.Jpeg: DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); - return new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables); + return new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation); default: throw TiffThrowHelper.NotSupportedDecompressor(nameof(method)); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 1785f3dec4..57d02f6432 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -200,6 +201,8 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) this.spectralData = new LibJpegTools.SpectralData(spectralComponents); } + + public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 1a201dd096..d7333c0b5a 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -290,8 +290,8 @@ public void TiffEncoder_EncodeRgb_WithPackBitsCompression_Works(TestImag [Theory] [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] - public void TiffEncoder_EncodeRgb_WithjpegCompression_Works(TestImageProvider provider) - where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg); + public void TiffEncoder_EncodeRgb_WithJpegCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, TiffCompression.Jpeg, useExactComparer: false, compareTolerance: 0.012f); [Theory] [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] From bb539aa6fa44010300eee4a422fedd4e01e8ca63 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 14 Aug 2021 19:19:15 +0200 Subject: [PATCH 17/32] Fix build error in Benchmark project --- .../Codecs/Jpeg/DecodeJpegParseStreamOnly.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index 9db666c374..64994ff564 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -5,6 +5,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Tests; using SDSize = System.Drawing.Size; @@ -58,6 +59,8 @@ public override void ConvertStrideBaseline() public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) { } + + public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); } } } From 310fefd5eaa3d65ec08eeff26802725cbcc8f45b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 05:34:12 +0200 Subject: [PATCH 18/32] Make GetColorConverter() virtual --- .../Formats/Jpeg/Components/Decoder/SpectralConverter.cs | 2 +- .../Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs | 5 +---- .../Compression/Decompressors/RgbJpegSpectralConverter.cs | 2 +- .../Codecs/Jpeg/DecodeJpegParseStreamOnly.cs | 3 --- tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs | 3 --- 5 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index 46821d45d4..23bb01409c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -39,6 +39,6 @@ internal abstract class SpectralConverter /// The jpeg frame with the color space to convert to. /// The raw JPEG data. /// The color converter. - public abstract JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData); + public virtual JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 50fc46c1e8..313a132b81 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -86,7 +86,7 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); // color converter from Rgba32 to TPixel - this.colorConverter = this.GetConverter(frame, jpegData); + this.colorConverter = this.GetColorConverter(frame, jpegData); } /// @@ -105,9 +105,6 @@ public override void ConvertStrideBaseline() } } - /// - public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); - public void Dispose() { if (this.componentProcessors != null) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs index 46ec537165..45be3dd038 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs @@ -28,6 +28,6 @@ public RgbJpegSpectralConverter(Configuration configuration, CancellationToken c } /// - public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(JpegColorSpace.RGB, frame.Precision); + public override JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(JpegColorSpace.RGB, frame.Precision); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index 64994ff564..9db666c374 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -5,7 +5,6 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Tests; using SDSize = System.Drawing.Size; @@ -59,8 +58,6 @@ public override void ConvertStrideBaseline() public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) { } - - public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 57d02f6432..1785f3dec4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -7,7 +7,6 @@ using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -201,8 +200,6 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) this.spectralData = new LibJpegTools.SpectralData(spectralComponents); } - - public override JpegColorConverter GetConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); } } } From 57335b8ed4c91f0a985f14e632bfdb041cad3057 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 08:14:25 +0200 Subject: [PATCH 19/32] Add detect color type tests --- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 54 ++++++++++++------- .../Formats/Jpg/JpegDecoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/baseline/jpeg-rgb.jpg | 3 ++ 4 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 tests/Images/Input/Jpg/baseline/jpeg-rgb.jpg diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 403eeaf908..b56748d138 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -67,16 +67,13 @@ public void MetadataIsParsedCorrectly( string imagePath, int expectedPixelSize, bool exifProfilePresent, - bool iccProfilePresent) - { - TestMetadataImpl( + bool iccProfilePresent) => TestMetadataImpl( useIdentify, JpegDecoder, imagePath, expectedPixelSize, exifProfilePresent, iccProfilePresent); - } [Theory] [MemberData(nameof(RatioFiles))] @@ -133,8 +130,7 @@ public void Decode_VerifyQuality(string imagePath, int quality) var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - var decoder = new JpegDecoder(); - using (Image image = decoder.Decode(Configuration.Default, stream)) + using (Image image = JpegDecoder.Decode(Configuration.Default, stream)) { JpegMetadata meta = image.Metadata.GetJpegMetadata(); Assert.Equal(quality, meta.Quality); @@ -142,6 +138,37 @@ public void Decode_VerifyQuality(string imagePath, int quality) } } + [Theory] + [InlineData(TestImages.Jpeg.Baseline.Floorplan, JpegColorType.Luminance)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegColorType.YCbCrRatio420)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegColorType.YCbCrRatio444)] + [InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegColorType.Rgb)] + public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType expectedColorType) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo image = JpegDecoder.Identify(Configuration.Default, stream); + JpegMetadata meta = image.Metadata.GetJpegMetadata(); + Assert.Equal(expectedColorType, meta.ColorType); + } + } + + [Theory] + [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegColorType.Luminance)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegColorType.YCbCrRatio420)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] + [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegColorType.Rgb)] + public void Decode_DetectsCorrectColorType(TestImageProvider provider, JpegColorType expectedColorType) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(JpegDecoder)) + { + JpegMetadata meta = image.Metadata.GetJpegMetadata(); + Assert.Equal(expectedColorType, meta.ColorType); + } + } + private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action test) { var testFile = TestFile.Create(imagePath); @@ -161,9 +188,7 @@ private static void TestMetadataImpl( string imagePath, int expectedPixelSize, bool exifProfilePresent, - bool iccProfilePresent) - { - TestImageInfo( + bool iccProfilePresent) => TestImageInfo( imagePath, decoder, useIdentify, @@ -207,7 +232,6 @@ private static void TestMetadataImpl( Assert.Null(iccProfile); } }); - } [Theory] [InlineData(false)] @@ -237,9 +261,7 @@ public void IgnoreMetadata_ControlsWhetherMetadataIsParsed(bool ignoreMetadata) [Theory] [InlineData(false)] [InlineData(true)] - public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify) - { - TestImageInfo( + public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify) => TestImageInfo( TestImages.Jpeg.Baseline.Floorplan, JpegDecoder, useIdentify, @@ -248,14 +270,11 @@ public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify) Assert.Equal(300, imageInfo.Metadata.HorizontalResolution); Assert.Equal(300, imageInfo.Metadata.VerticalResolution); }); - } [Theory] [InlineData(false)] [InlineData(true)] - public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify) - { - TestImageInfo( + public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify) => TestImageInfo( TestImages.Jpeg.Baseline.Jpeg420Exif, JpegDecoder, useIdentify, @@ -264,6 +283,5 @@ public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify) Assert.Equal(72, imageInfo.Metadata.HorizontalResolution); Assert.Equal(72, imageInfo.Metadata.VerticalResolution); }); - } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index e8d307f909..2d265e22c9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -180,7 +180,7 @@ public async Task Identify_IsCancellable() public void Issue1732_DecodesWithRgbColorSpace(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(new JpegDecoder())) + using (Image image = provider.GetImage(JpegDecoder)) { image.DebugSave(provider); image.CompareToOriginal(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8a7ea9d92d..572c5abce1 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -190,6 +190,7 @@ public static class Bad public const string Jpeg420Exif = "Jpg/baseline/jpeg420exif.jpg"; public const string Jpeg444 = "Jpg/baseline/jpeg444.jpg"; public const string Jpeg420Small = "Jpg/baseline/jpeg420small.jpg"; + public const string JpegRgb = "Jpg/baseline/jpeg-rgb.jpg"; public const string Testorig420 = "Jpg/baseline/testorig.jpg"; public const string MultiScanBaselineCMYK = "Jpg/baseline/MultiScanBaselineCMYK.jpg"; public const string Ratio1x1 = "Jpg/baseline/ratio-1x1.jpg"; diff --git a/tests/Images/Input/Jpg/baseline/jpeg-rgb.jpg b/tests/Images/Input/Jpg/baseline/jpeg-rgb.jpg new file mode 100644 index 0000000000..2f2be0fa1a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/jpeg-rgb.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4630c33d722a89de5cb1834bffa43c729f204c0f8c95d4ec2127ddfcd433f60 +size 10100 From 2e89d3c932b05c4bb81737e1e8d8e6ae9168a31a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 08:55:18 +0200 Subject: [PATCH 20/32] Fix deduce jpeg color type --- src/ImageSharp/Formats/Jpeg/JpegColorType.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 52 +++++++++++++------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs index a0b9c7fe68..11d5f65a4c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs @@ -30,6 +30,6 @@ public enum JpegColorType : byte /// /// The pixel data will be preserved as RGB without any sub sampling. /// - Rgb, + Rgb = 3, } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 13049dda12..343362f6c8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -409,8 +409,9 @@ public void Dispose() /// /// Returns the correct colorspace based on the image component count and the jpeg frame component id's. /// + /// The number of components. /// The - private JpegColorSpace DeduceJpegColorSpace(byte componentCount, JpegComponent[] components) + private JpegColorSpace DeduceJpegColorSpace(byte componentCount) { if (componentCount == 1) { @@ -425,7 +426,7 @@ private JpegColorSpace DeduceJpegColorSpace(byte componentCount, JpegComponent[] } // If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr. - if (components[2].Id == 66 && components[1].Id == 71 && components[0].Id == 82) + if (this.Components[2].Id == 66 && this.Components[1].Id == 71 && this.Components[0].Id == 82) { return JpegColorSpace.RGB; } @@ -446,6 +447,35 @@ private JpegColorSpace DeduceJpegColorSpace(byte componentCount, JpegComponent[] return default; } + /// + /// Returns the jpeg color type based on the colorspace and subsampling used. + /// + /// Jpeg color type. + private JpegColorType DeduceJpegColorType() + { + switch (this.ColorSpace) + { + case JpegColorSpace.Grayscale: + return JpegColorType.Luminance; + case JpegColorSpace.RGB: + return JpegColorType.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 JpegColorType.YCbCrRatio444; + } + else + { + return JpegColorType.YCbCrRatio420; + } + + default: + return JpegColorType.YCbCrRatio420; + } + } + /// /// Initializes the EXIF profile. /// @@ -859,7 +889,7 @@ private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, in } /// - /// Processes the Start of Frame marker. Specified in section B.2.2. + /// Processes the Start of Frame marker. Specified in section B.2.2. /// /// The input stream. /// The remaining bytes in the segment block. @@ -951,20 +981,8 @@ private void ProcessStartOfFrameMarker(BufferedReadStream stream, int remaining, index += componentBytes; } - this.ColorSpace = this.DeduceJpegColorSpace(componentCount, this.Frame.Components); - - switch (this.ColorSpace) - { - case JpegColorSpace.Grayscale: - this.Metadata.GetJpegMetadata().ColorType = JpegColorType.Luminance; - break; - case JpegColorSpace.RGB: - this.Metadata.GetJpegMetadata().ColorType = JpegColorType.Rgb; - break; - default: - this.Metadata.GetJpegMetadata().ColorType = JpegColorType.YCbCrRatio420; - break; - } + this.ColorSpace = this.DeduceJpegColorSpace(componentCount); + this.Metadata.GetJpegMetadata().ColorType = this.DeduceJpegColorType(); if (!metadataOnly) { From 89289f1a39a5a21e962e497a790ed4804f9e1b35 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 09:44:07 +0200 Subject: [PATCH 21/32] Use color type of the input image, if it was not specified in the encoder options --- .../Formats/Jpeg/JpegEncoderCore.cs | 3 ++ .../Formats/Jpg/JpegEncoderTests.cs | 45 +++++++++++++------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index dc84a161fb..7174b6d50d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -92,6 +92,9 @@ public void Encode(Image image, Stream stream, CancellationToken ImageMetadata metadata = image.Metadata; JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); + // If the color type was not specified by the user, preserve the color type of the input image. + this.colorType ??= jpegMetadata.ColorType; + // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; ReadOnlySpan componentIds = this.GetComponentIds(); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 574f859c50..dcd5e42c8a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -24,6 +24,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class JpegEncoderTests { + private static JpegEncoder JpegEncoder => new JpegEncoder(); + + private static JpegDecoder JpegDecoder => new JpegDecoder(); + public static readonly TheoryData QualityFiles = new TheoryData { @@ -62,17 +66,37 @@ public class JpegEncoderTests }; [Theory] - [MemberData(nameof(QualityFiles))] - public void Encode_PreserveQuality(string imagePath, int quality) + [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegColorType.Luminance)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegColorType.YCbCrRatio420)] + [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegColorType.Rgb)] + public void Encode_PreservesColorType(TestImageProvider provider, JpegColorType expectedColorType) + where TPixel : unmanaged, IPixel { - var options = new JpegEncoder(); + // arrange + using Image input = provider.GetImage(JpegDecoder); + using var memoryStream = new MemoryStream(); + + // act + input.Save(memoryStream, JpegEncoder); + // assert + memoryStream.Position = 0; + using var output = Image.Load(memoryStream); + JpegMetadata meta = output.Metadata.GetJpegMetadata(); + Assert.Equal(expectedColorType, meta.ColorType); + } + + [Theory] + [MemberData(nameof(QualityFiles))] + public void Encode_PreservesQuality(string imagePath, int quality) + { var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) { - input.Save(memStream, options); + input.Save(memStream, JpegEncoder); memStream.Position = 0; using (var output = Image.Load(memStream)) @@ -226,14 +250,12 @@ public void Quality_0_And_100_Are_Not_Identical() [MemberData(nameof(RatioFiles))] public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var options = new JpegEncoder(); - var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) { - input.Save(memStream, options); + input.Save(memStream, JpegEncoder); memStream.Position = 0; using (var output = Image.Load(memStream)) @@ -254,11 +276,10 @@ public void Encode_PreservesIptcProfile() using var input = new Image(1, 1); input.Metadata.IptcProfile = new IptcProfile(); input.Metadata.IptcProfile.SetValue(IptcTag.Byline, "unit_test"); - var encoder = new JpegEncoder(); // act using var memStream = new MemoryStream(); - input.Save(memStream, encoder); + input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; @@ -276,11 +297,10 @@ public void Encode_PreservesExifProfile() using var input = new Image(1, 1); input.Metadata.ExifProfile = new ExifProfile(); input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test"); - var encoder = new JpegEncoder(); // act using var memStream = new MemoryStream(); - input.Save(memStream, encoder); + input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; @@ -297,11 +317,10 @@ public void Encode_PreservesIccProfile() // arrange using var input = new Image(1, 1); input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array); - var encoder = new JpegEncoder(); // act using var memStream = new MemoryStream(); - input.Save(memStream, encoder); + input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; From 83d0788cf5c44241724dc2b5ee4f4a6d73dcb802 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 14:22:54 +0200 Subject: [PATCH 22/32] Use much smaller tolerance for jpeg encoder tests --- .../Formats/Jpg/JpegEncoderTests.cs | 82 ++++++++++++++++--- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index dcd5e42c8a..3cdfb5fad3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -38,15 +38,15 @@ public class JpegEncoderTests public static readonly TheoryData BitsPerPixel_Quality = new TheoryData { - { JpegColorType.Rgb, 40 }, - { JpegColorType.Rgb, 60 }, - { JpegColorType.Rgb, 100 }, { JpegColorType.YCbCrRatio420, 40 }, { JpegColorType.YCbCrRatio420, 60 }, { JpegColorType.YCbCrRatio420, 100 }, { JpegColorType.YCbCrRatio444, 40 }, { JpegColorType.YCbCrRatio444, 60 }, { JpegColorType.YCbCrRatio444, 100 }, + { JpegColorType.Rgb, 40 }, + { JpegColorType.Rgb, 60 }, + { JpegColorType.Rgb, 100 } }; public static readonly TheoryData Grayscale_Quality = @@ -87,6 +87,51 @@ public void Encode_PreservesColorType(TestImageProvider provider Assert.Equal(expectedColorType, meta.ColorType); } + [Theory] + [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg410, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg411, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg422, PixelTypes.Rgba32)] + public void Encode_WithUnsupportedColorType_FromInput_DefaultsToYCbCr420(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + // arrange + using Image input = provider.GetImage(JpegDecoder); + using var memoryStream = new MemoryStream(); + + // act + input.Save(memoryStream, JpegEncoder); + + // assert + memoryStream.Position = 0; + using var output = Image.Load(memoryStream); + JpegMetadata meta = output.Metadata.GetJpegMetadata(); + Assert.Equal(JpegColorType.YCbCrRatio420, meta.ColorType); + } + + [Theory] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.Cmyk)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio410)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio411)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio422)] + public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(TestImageProvider provider, JpegColorType colorType) + where TPixel : unmanaged, IPixel + { + // arrange + var jpegEncoder = new JpegEncoder() { ColorType = colorType }; + using var input = new Image(10, 10); + using var memoryStream = new MemoryStream(); + + // act + input.Save(memoryStream, jpegEncoder); + + // assert + memoryStream.Position = 0; + using var output = Image.Load(memoryStream); + JpegMetadata meta = output.Metadata.GetJpegMetadata(); + Assert.Equal(JpegColorType.YCbCrRatio420, meta.ColorType); + } + [Theory] [MemberData(nameof(QualityFiles))] public void Encode_PreservesQuality(string imagePath, int quality) @@ -111,16 +156,24 @@ public void Encode_PreservesQuality(string imagePath, int quality) [Theory] [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 24, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 46, 8, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 51, 7, PixelTypes.Rgba32)] - [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 48, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 138, 24, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 153, 21, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 600, 400, PixelTypes.Rgba32)] - [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)] public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegColorType colorType, int quality) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); + [Theory] + [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] + [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)] + [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, JpegColorType colorType, int quality) + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.12f)); + [Theory] [WithFile(TestImages.Png.BikeGrayscale, nameof(Grayscale_Quality), PixelTypes.L8)] [WithSolidFilledImages(1, 1, 100, 100, 100, 255, PixelTypes.Rgba32, 100)] @@ -132,10 +185,15 @@ public void EncodeBaseline_Grayscale(TestImageProvider provider, where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, JpegColorType.Luminance, quality); [Theory] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 96, PixelTypes.Rgba32 | PixelTypes.Bgra32)] public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegColorType 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, JpegColorType colorType, int quality) + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.06f)); + [Theory] [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] [WithTestPatternImages(587, 821, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] @@ -161,11 +219,11 @@ private static ImageComparer GetComparer(int quality, JpegColorType? colorType) if (quality < 50) { - tolerance *= 10f; + tolerance *= 2.5f; } else if (quality < 75 || colorType == JpegColorType.YCbCrRatio420) { - tolerance *= 5f; + tolerance *= 1.5f; if (colorType == JpegColorType.YCbCrRatio420) { tolerance *= 2f; From 5834e4fb539dbbc3c0a26180cb798f7ad72e026c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 16:56:40 +0200 Subject: [PATCH 23/32] Write APP14 marker if RGB color space --- .../Formats/Jpeg/JpegEncoderCore.cs | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 7174b6d50d..546de74dac 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -65,7 +65,11 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals public JpegEncoderCore(IJpegEncoderOptions options) { this.quality = options.Quality; - this.colorType = options.ColorType; + + if (IsSupportedColorType(options.ColorType)) + { + this.colorType = options.ColorType; + } } /// @@ -92,8 +96,11 @@ public void Encode(Image image, Stream stream, CancellationToken ImageMetadata metadata = image.Metadata; JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); - // If the color type was not specified by the user, preserve the color type of the input image. - this.colorType ??= jpegMetadata.ColorType; + // If the color type was not specified by the user, preserve the color type of the input image, if it's a supported color type. + if (!this.colorType.HasValue && IsSupportedColorType(jpegMetadata.ColorType)) + { + this.colorType = jpegMetadata.ColorType; + } // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; @@ -109,6 +116,12 @@ public void Encode(Image image, Stream stream, CancellationToken // Write Exif, ICC and IPTC profiles this.WriteProfiles(metadata); + if (this.colorType == JpegColorType.Rgb) + { + // Write App14 marker to indicate RGB color space. + this.WriteApp14Marker(); + } + // Write the quantization tables. this.WriteDefineQuantizationTables(ref luminanceQuantTable, ref chrominanceQuantTable); @@ -152,6 +165,21 @@ public void Encode(Image image, Stream stream, CancellationToken stream.Flush(); } + /// + /// Returns true, if the color type is supported by the encoder. + /// + /// The color type. + /// true, if color type is supported. + private static bool IsSupportedColorType(JpegColorType? colorType) + { + if (colorType == JpegColorType.YCbCrRatio444 || colorType == JpegColorType.YCbCrRatio420 || colorType == JpegColorType.Luminance || colorType == JpegColorType.Rgb) + { + return true; + } + + return false; + } + /// /// Gets the component ids. /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3. @@ -292,6 +320,35 @@ private void WriteDefineQuantizationTables(ref Block8x8F luminanceQuantTable, re 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); + + // Identifier: ASCII "Adobe". + this.buffer[0] = 0x41; + this.buffer[1] = 0x64; + this.buffer[2] = 0x6F; + this.buffer[3] = 0x62; + this.buffer[4] = 0x65; + + // Version, currently 100. + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(5, 2), 100); + + // Flags0 + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(7, 2), 0); + + // Flags1 + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(9, 2), 0); + + // Transform byte, 0 in combination with three components means the image is in RGB colorspace. + this.buffer[11] = 0; + + this.outputStream.Write(this.buffer.AsSpan(0, 12)); + } + /// /// Writes the EXIF profile. /// From b506e924793a8d14cc7a9694c6bb33c151fd2157 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 15 Aug 2021 17:21:54 +0200 Subject: [PATCH 24/32] Add additional YCbCr subsample rates --- src/ImageSharp/Formats/Jpeg/JpegColorType.cs | 35 +++++++++++++++++-- .../Formats/Jpeg/JpegDecoderCore.cs | 29 +++++++++++++++ .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 5 +++ .../Formats/Jpg/JpegEncoderTests.cs | 23 +++++++----- tests/ImageSharp.Tests/TestImages.cs | 3 ++ tests/Images/Input/Jpg/baseline/jpeg410.jpg | 3 ++ tests/Images/Input/Jpg/baseline/jpeg411.jpg | 3 ++ tests/Images/Input/Jpg/baseline/jpeg422.jpg | 3 ++ 8 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 tests/Images/Input/Jpg/baseline/jpeg410.jpg create mode 100644 tests/Images/Input/Jpg/baseline/jpeg411.jpg create mode 100644 tests/Images/Input/Jpg/baseline/jpeg422.jpg diff --git a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs index 11d5f65a4c..d6a9542c35 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs @@ -22,14 +22,45 @@ public enum JpegColorType : byte /// YCbCrRatio444 = 1, + /// + /// 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, + + /// + /// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification. + /// This ratio uses half of the vertical and one-fourth the horizontal color resolutions. + /// + /// Note: Not supported by the encoder. + /// + YCbCrRatio410 = 4, + /// /// Single channel, luminance. /// - Luminance = 2, + Luminance = 5, /// /// The pixel data will be preserved as RGB without any sub sampling. /// - Rgb = 3, + Rgb = 6, + + /// + /// CMYK colorspace (cyan, magenta, yellow, and key black) intended for printing. + /// + /// Note: Not supported by the encoder. + /// + Cmyk = 7, } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 343362f6c8..83aacb48fb 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -457,8 +457,10 @@ private JpegColorType DeduceJpegColorType() { case JpegColorSpace.Grayscale: return JpegColorType.Luminance; + case JpegColorSpace.RGB: return JpegColorType.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 && @@ -466,11 +468,38 @@ private JpegColorType DeduceJpegColorType() { return JpegColorType.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 JpegColorType.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 JpegColorType.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 JpegColorType.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 JpegColorType.YCbCrRatio410; + } else { return JpegColorType.YCbCrRatio420; } + case JpegColorSpace.Cmyk: + return JpegColorType.Cmyk; + default: return JpegColorType.YCbCrRatio420; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index b56748d138..e5f8989c5c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -143,6 +143,10 @@ public void Decode_VerifyQuality(string imagePath, int quality) [InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, JpegColorType.YCbCrRatio420)] [InlineData(TestImages.Jpeg.Baseline.Jpeg444, JpegColorType.YCbCrRatio444)] [InlineData(TestImages.Jpeg.Baseline.JpegRgb, JpegColorType.Rgb)] + [InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorType.Cmyk)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg410, JpegColorType.YCbCrRatio410)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg422, JpegColorType.YCbCrRatio422)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegColorType.YCbCrRatio411)] public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType expectedColorType) { var testFile = TestFile.Create(imagePath); @@ -159,6 +163,7 @@ public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType exp [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegColorType.YCbCrRatio420)] [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegColorType.Rgb)] + [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgba32, JpegColorType.Cmyk)] public void Decode_DetectsCorrectColorType(TestImageProvider provider, JpegColorType expectedColorType) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 3cdfb5fad3..a30a5611f9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -92,7 +92,7 @@ public void Encode_PreservesColorType(TestImageProvider provider [WithFile(TestImages.Jpeg.Baseline.Jpeg410, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Baseline.Jpeg411, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Baseline.Jpeg422, PixelTypes.Rgba32)] - public void Encode_WithUnsupportedColorType_FromInput_DefaultsToYCbCr420(TestImageProvider provider) + public void Encode_WithUnsupportedColorType_FromInputImage_DefaultsToYCbCr420(TestImageProvider provider) where TPixel : unmanaged, IPixel { // arrange @@ -100,7 +100,10 @@ public void Encode_WithUnsupportedColorType_FromInput_DefaultsToYCbCr420 using var memoryStream = new MemoryStream(); // act - input.Save(memoryStream, JpegEncoder); + input.Save(memoryStream, new JpegEncoder() + { + Quality = 75 + }); // assert memoryStream.Position = 0; @@ -110,12 +113,11 @@ public void Encode_WithUnsupportedColorType_FromInput_DefaultsToYCbCr420 } [Theory] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.Cmyk)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio410)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio411)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio422)] - public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(TestImageProvider provider, JpegColorType colorType) - where TPixel : unmanaged, IPixel + [InlineData(JpegColorType.Cmyk)] + [InlineData(JpegColorType.YCbCrRatio410)] + [InlineData(JpegColorType.YCbCrRatio411)] + [InlineData(JpegColorType.YCbCrRatio422)] + public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420(JpegColorType colorType) { // arrange var jpegEncoder = new JpegEncoder() { ColorType = colorType }; @@ -153,6 +155,11 @@ public void Encode_PreservesQuality(string imagePath, int quality) } } + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] + public void EncodeBaseline_CalliphoraPartial(TestImageProvider provider, JpegColorType colorType, int quality) + where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); + [Theory] [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 572c5abce1..feff08b94f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -191,6 +191,9 @@ public static class Bad public const string Jpeg444 = "Jpg/baseline/jpeg444.jpg"; public const string Jpeg420Small = "Jpg/baseline/jpeg420small.jpg"; public const string JpegRgb = "Jpg/baseline/jpeg-rgb.jpg"; + public const string Jpeg410 = "Jpg/baseline/jpeg410.jpg"; + public const string Jpeg411 = "Jpg/baseline/jpeg411.jpg"; + public const string Jpeg422 = "Jpg/baseline/jpeg422.jpg"; public const string Testorig420 = "Jpg/baseline/testorig.jpg"; public const string MultiScanBaselineCMYK = "Jpg/baseline/MultiScanBaselineCMYK.jpg"; public const string Ratio1x1 = "Jpg/baseline/ratio-1x1.jpg"; diff --git a/tests/Images/Input/Jpg/baseline/jpeg410.jpg b/tests/Images/Input/Jpg/baseline/jpeg410.jpg new file mode 100644 index 0000000000..3bc41af8d8 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/jpeg410.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:318338c1a541227632a99cc47b04fc9f6d19c3e8300a76e71136edec2d17a5f5 +size 9073 diff --git a/tests/Images/Input/Jpg/baseline/jpeg411.jpg b/tests/Images/Input/Jpg/baseline/jpeg411.jpg new file mode 100644 index 0000000000..43a2ba49d8 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/jpeg411.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70315936e36bb1edf38fc950b7b321f20be5a2592db59bfd28d79dbc391a5aaf +size 4465 diff --git a/tests/Images/Input/Jpg/baseline/jpeg422.jpg b/tests/Images/Input/Jpg/baseline/jpeg422.jpg new file mode 100644 index 0000000000..4782b53b33 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/jpeg422.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be21207ecb96bcb0925706649678c522c68bf08ee26e6e8878456f4f7772dd31 +size 3951 From ed9bd16cd35d3c8da38cb80ac18d3cb413dcd341 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 16 Aug 2021 17:05:56 +0200 Subject: [PATCH 25/32] Split WriteApplicationHeader into WriteStartOfImage and WriteJfifApplicationHeader. Do not write WriteJfifApplicationHeader with RGB. --- .../Jpeg/Components/Encoder/QuantIndex.cs | 10 ++-- src/ImageSharp/Formats/Jpeg/JpegColorType.cs | 2 +- .../Formats/Jpeg/JpegEncoderCore.cs | 58 ++++++++++++------- .../Formats/Jpg/JpegEncoderTests.cs | 17 +++--- 4 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs index 5eee5dfde4..f9d0fba57f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs @@ -1,21 +1,21 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { /// - /// Enumerates the quantization tables + /// Enumerates the quantization tables. /// internal enum QuantIndex { /// - /// The luminance quantization table index + /// The luminance quantization table index. /// Luminance = 0, /// - /// The chrominance quantization table index + /// The chrominance quantization table index. /// Chrominance = 1, } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs index d6a9542c35..c15038c23b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegColorType.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegColorType.cs @@ -41,7 +41,7 @@ public enum JpegColorType : byte /// /// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification. /// This ratio uses half of the vertical and one-fourth the horizontal color resolutions. - /// + /// /// Note: Not supported by the encoder. /// YCbCrRatio410 = 4, diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 546de74dac..7f411ee53f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -111,7 +111,13 @@ public void Encode(Image image, Stream stream, CancellationToken this.InitQuantizationTables(componentCount, jpegMetadata, out Block8x8F luminanceQuantTable, out Block8x8F chrominanceQuantTable); // Write the Start Of Image marker. - this.WriteApplicationHeader(metadata); + this.WriteStartOfImage(); + + // Do not write APP0 marker for RGB colorspace. + if (this.colorType != JpegColorType.Rgb) + { + this.WriteJfifApplicationHeader(metadata); + } // Write Exif, ICC and IPTC profiles this.WriteProfiles(metadata); @@ -212,52 +218,60 @@ private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref } /// - /// Writes the application header containing the JFIF identifier plus extra data. + /// Write the start of image marker. /// - /// The image metadata. - private void WriteApplicationHeader(ImageMetadata meta) + private void WriteStartOfImage() { - // Write the start of image marker. Markers are always prefixed with 0xff. + // Markers are always prefixed with 0xff. this.buffer[0] = JpegConstants.Markers.XFF; this.buffer[1] = JpegConstants.Markers.SOI; + this.outputStream.Write(this.buffer, 0, 2); + } + + /// + /// Writes the application header containing the JFIF identifier plus extra data. + /// + /// The image metadata. + private void WriteJfifApplicationHeader(ImageMetadata meta) + { // Write the JFIF headers - this.buffer[2] = JpegConstants.Markers.XFF; - this.buffer[3] = JpegConstants.Markers.APP0; // Application Marker - this.buffer[4] = 0x00; - this.buffer[5] = 0x10; - this.buffer[6] = 0x4a; // J + this.buffer[0] = JpegConstants.Markers.XFF; + this.buffer[1] = JpegConstants.Markers.APP0; // Application Marker + this.buffer[2] = 0x00; + this.buffer[3] = 0x10; + this.buffer[4] = 0x4a; // J + this.buffer[5] = 0x46; // F + this.buffer[6] = 0x49; // I this.buffer[7] = 0x46; // F - this.buffer[8] = 0x49; // I - this.buffer[9] = 0x46; // F - this.buffer[10] = 0x00; // = "JFIF",'\0' - this.buffer[11] = 0x01; // versionhi - this.buffer[12] = 0x01; // versionlo + this.buffer[8] = 0x00; // = "JFIF",'\0' + this.buffer[9] = 0x01; // versionhi + this.buffer[10] = 0x01; // versionlo // Resolution. Big Endian - Span hResolution = this.buffer.AsSpan(14, 2); - Span vResolution = this.buffer.AsSpan(16, 2); + Span hResolution = this.buffer.AsSpan(12, 2); + Span vResolution = this.buffer.AsSpan(14, 2); if (meta.ResolutionUnits == PixelResolutionUnit.PixelsPerMeter) { // Scale down to PPI - this.buffer[13] = (byte)PixelResolutionUnit.PixelsPerInch; // xyunits + this.buffer[11] = (byte)PixelResolutionUnit.PixelsPerInch; // xyunits BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.HorizontalResolution))); BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.VerticalResolution))); } else { // We can simply pass the value. - this.buffer[13] = (byte)meta.ResolutionUnits; // xyunits + this.buffer[11] = (byte)meta.ResolutionUnits; // xyunits BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(meta.HorizontalResolution)); BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(meta.VerticalResolution)); } // No thumbnail - this.buffer[18] = 0x00; // Thumbnail width - this.buffer[19] = 0x00; // Thumbnail height + this.buffer[16] = 0x00; // Thumbnail width + this.buffer[17] = 0x00; // Thumbnail height - this.outputStream.Write(this.buffer, 0, 20); + this.outputStream.Write(this.buffer, 0, 18); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index a30a5611f9..2bd2961de3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -162,22 +162,23 @@ public void EncodeBaseline_CalliphoraPartial(TestImageProvider p [Theory] [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 48, PixelTypes.Rgba32)] - [WithTestPatternImages(nameof(BitsPerPixel_Quality), 138, 24, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 158, 24, PixelTypes.Rgba32)] [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, JpegColorType colorType, int quality) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality); [Theory] + [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)] [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 143, 81, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] - [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 100, 100, 100, 255, PixelTypes.L8)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 96, 48, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] [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, JpegColorType colorType, int quality) where TPixel : unmanaged, IPixel => TestJpegEncoderCore(provider, colorType, quality, comparer: ImageComparer.Tolerant(0.12f)); @@ -226,14 +227,14 @@ private static ImageComparer GetComparer(int quality, JpegColorType? colorType) if (quality < 50) { - tolerance *= 2.5f; + tolerance *= 4.5f; } else if (quality < 75 || colorType == JpegColorType.YCbCrRatio420) { - tolerance *= 1.5f; + tolerance *= 2.0f; if (colorType == JpegColorType.YCbCrRatio420) { - tolerance *= 2f; + tolerance *= 2.0f; } } From 612f7914e4a4ce671d984c796b565a39f78e2fc2 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 16 Aug 2021 17:23:15 +0200 Subject: [PATCH 26/32] Use luminance quant table for all channel with RGB --- .../Components/Encoder/HuffmanScanEncoder.cs | 25 +++++++++---------- .../Formats/Jpeg/JpegEncoderCore.cs | 24 +++++++++++++++++- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 5468d93c48..4b74400cac 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs @@ -237,9 +237,8 @@ public void EncodeGrayscale(Image pixels, ref Block8x8F luminanc /// The pixel format. /// The pixel accessor providing access to the image pixels. /// Luminance quantization table provided by the callee. - /// Chrominance quantization table provided by the callee. /// The token to monitor for cancellation. - public void EncodeRgb(Image pixels, ref Block8x8F luminanceQuantTable, ref Block8x8F chrominanceQuantTable, CancellationToken cancellationToken) + public void EncodeRgb(Image pixels, ref Block8x8F luminanceQuantTable, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { this.huffmanTables = HuffmanLut.TheHuffmanLut; @@ -247,7 +246,7 @@ public void EncodeRgb(Image pixels, ref Block8x8F luminanceQuant var unzig = ZigZag.CreateUnzigTable(); // ReSharper disable once InconsistentNaming - int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; + int prevDCR = 0, prevDCG = 0, prevDCB = 0; ImageFrame frame = pixels.Frames.RootFrame; Buffer2D pixelBuffer = frame.PixelBuffer; @@ -264,25 +263,25 @@ public void EncodeRgb(Image pixels, ref Block8x8F luminanceQuant { pixelConverter.Convert(x, y, ref currentRows); - prevDCY = this.WriteBlock( + prevDCR = this.WriteBlock( QuantIndex.Luminance, - prevDCY, + prevDCR, ref pixelConverter.R, ref luminanceQuantTable, ref unzig); - prevDCCb = this.WriteBlock( - QuantIndex.Chrominance, - prevDCCb, + prevDCG = this.WriteBlock( + QuantIndex.Luminance, + prevDCG, ref pixelConverter.G, - ref chrominanceQuantTable, + ref luminanceQuantTable, ref unzig); - prevDCCr = this.WriteBlock( - QuantIndex.Chrominance, - prevDCCr, + prevDCB = this.WriteBlock( + QuantIndex.Luminance, + prevDCB, ref pixelConverter.B, - ref chrominanceQuantTable, + ref luminanceQuantTable, ref unzig); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 7f411ee53f..48b7d267a9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -160,7 +160,7 @@ public void Encode(Image image, Stream stream, CancellationToken scanEncoder.Encode420(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; case JpegColorType.Rgb: - scanEncoder.EncodeRgb(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); + scanEncoder.EncodeRgb(image, ref luminanceQuantTable, cancellationToken); break; } } @@ -620,6 +620,17 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn 0x11, 0x11 }; + + if (this.colorType == JpegColorType.Rgb) + { + chroma = stackalloc byte[] + { + 0x00, + 0x00, + 0x00 + }; + } + break; case JpegColorType.YCbCrRatio420: subsamples = stackalloc byte[] @@ -669,6 +680,17 @@ private void WriteStartOfScan(int componentCount, ReadOnlySpan componentId 0x11 }; + // Use the same DC/AC tables for all channels for RGB. + if (this.colorType == JpegColorType.Rgb) + { + huffmanId = stackalloc byte[] + { + 0x00, + 0x00, + 0x00 + }; + } + // Write the SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes: // - the marker length "\x00\x0c", // - the number of components "\x03", From f39702f676d8ca5f5a9f466969c47f6ee992f655 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 16 Aug 2021 17:33:38 +0200 Subject: [PATCH 27/32] Change GetComponentIds as suggested by review --- .../Formats/Jpeg/JpegEncoderCore.cs | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 48b7d267a9..b7a3680064 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -33,16 +33,6 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals /// private readonly byte[] buffer = new byte[20]; - /// - /// The default component id's. - /// - private static readonly byte[] DefaultComponentIds = { 1, 2, 3 }; - - /// - /// Component id's for RGB colorspace. - /// - private static readonly byte[] RgbComponentIds = { 82, 71, 66 }; - /// /// The quality, that will be used to encode the image. /// @@ -191,15 +181,9 @@ private static bool IsSupportedColorType(JpegColorType? colorType) /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3. /// /// The component Ids. - private ReadOnlySpan GetComponentIds() - { - if (this.colorType == JpegColorType.Rgb) - { - return RgbComponentIds; - } - - return DefaultComponentIds; - } + private ReadOnlySpan GetComponentIds() => this.colorType == JpegColorType.Rgb + ? new ReadOnlySpan(new byte[] { 82, 71, 66 }) + : new ReadOnlySpan(new byte[] { 1, 2, 3 }); /// /// Writes data to "Define Quantization Tables" block for QuantIndex. From 49d86e1b31f51664f8f0425879a82d8fd11aa07c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 16 Aug 2021 17:40:39 +0200 Subject: [PATCH 28/32] Use buffer as span to reduce some bound checks when writing components --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index b7a3680064..ad05b298be 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -642,9 +642,10 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn int i3 = 3 * i; // Component ID. - this.buffer[i3 + 6] = componentIds[i]; - this.buffer[i3 + 7] = subsamples[i]; - this.buffer[i3 + 8] = chroma[i]; + Span bufferSpan = this.buffer.AsSpan(i3 + 6, 3); + bufferSpan[2] = chroma[i]; + bufferSpan[1] = subsamples[i]; + bufferSpan[0] = componentIds[i]; } this.outputStream.Write(this.buffer, 0, (3 * (componentCount - 1)) + 9); From 66a9d1ae4ff130e2d00d1f46d3b82b6cf3386e5a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 16 Aug 2021 18:39:28 +0200 Subject: [PATCH 29/32] Use ReadOnlySpan instead of stackalloc --- .../Formats/Jpeg/JpegEncoderCore.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index ad05b298be..71f9827e27 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -265,7 +265,7 @@ private void WriteJfifApplicationHeader(ImageMetadata meta) private void WriteDefineHuffmanTables(int componentCount) { // Table identifiers. - Span headers = stackalloc byte[] + ReadOnlySpan headers = new byte[] { 0x00, 0x10, @@ -568,15 +568,17 @@ private void WriteProfiles(ImageMetadata metadata) /// The component Id's. private void WriteStartOfFrame(int width, int height, int componentCount, ReadOnlySpan componentIds) { + // This uses a C#'s compiler optimization that refers to the static data segment of the assembly, + // and doesn't incur any allocation at all. // "default" to 4:2:0 - Span subsamples = stackalloc byte[] + ReadOnlySpan subsamples = new byte[] { 0x22, 0x11, 0x11 }; - Span chroma = stackalloc byte[] + ReadOnlySpan chroma = new byte[] { 0x00, 0x01, @@ -585,7 +587,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn if (this.colorType == JpegColorType.Luminance) { - subsamples = stackalloc byte[] + subsamples = new byte[] { 0x11, 0x00, @@ -598,7 +600,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn { case JpegColorType.YCbCrRatio444: case JpegColorType.Rgb: - subsamples = stackalloc byte[] + subsamples = new byte[] { 0x11, 0x11, @@ -607,7 +609,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn if (this.colorType == JpegColorType.Rgb) { - chroma = stackalloc byte[] + chroma = new byte[] { 0x00, 0x00, @@ -617,7 +619,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn break; case JpegColorType.YCbCrRatio420: - subsamples = stackalloc byte[] + subsamples = new byte[] { 0x22, 0x11, @@ -658,7 +660,9 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn /// The componentId's. private void WriteStartOfScan(int componentCount, ReadOnlySpan componentIds) { - Span huffmanId = stackalloc byte[] + // This uses a C#'s compiler optimization that refers to the static data segment of the assembly, + // and doesn't incur any allocation at all. + ReadOnlySpan huffmanId = new byte[] { 0x00, 0x11, @@ -668,7 +672,7 @@ private void WriteStartOfScan(int componentCount, ReadOnlySpan componentId // Use the same DC/AC tables for all channels for RGB. if (this.colorType == JpegColorType.Rgb) { - huffmanId = stackalloc byte[] + huffmanId = new byte[] { 0x00, 0x00, From 9e6fbdb96b5a72a6173c708b4b3876e3c3d9d311 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 24 Aug 2021 13:44:15 +0200 Subject: [PATCH 30/32] Fix build issue, dispose decoded jpeg image --- .../Decompressors/JpegTiffCompression.cs | 16 ++++++++++------ .../Compression/TiffDecoderCompressionType.cs | 6 +++--- .../Formats/Tiff/TiffDecoderTests.cs | 2 -- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs index 8abaf20088..bd1c496b49 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors /// /// Class to handle cases where TIFF image data is compressed as a jpeg stream. /// - internal class JpegTiffCompression : TiffBaseDecompressor + internal sealed class JpegTiffCompression : TiffBaseDecompressor { private readonly Configuration configuration; @@ -49,12 +49,11 @@ public JpegTiffCompression( } /// - protected override void Decompress(BufferedReadStream stream, int byteCount, Span buffer) + protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span buffer) { - Image image; if (this.jpegTables != null) { - var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); + using var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder()); // TODO: Should we pass through the CancellationToken from the tiff decoder? // If the PhotometricInterpretation is YCbCr we explicitly assume the JPEG data is in RGB color space. @@ -66,13 +65,18 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, Spa scanDecoder.ResetInterval = 0; jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None); - image = new Image(this.configuration, spectralConverter.PixelBuffer, new ImageMetadata()); + using var image = new Image(this.configuration, spectralConverter.PixelBuffer, new ImageMetadata()); + CopyImageBytesToBuffer(buffer, image); } else { - image = Image.Load(stream); + using var image = Image.Load(stream); + CopyImageBytesToBuffer(buffer, image); } + } + private static void CopyImageBytesToBuffer(Span buffer, Image image) + { int offset = 0; for (int y = 0; y < image.Height; y++) { diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs index 4353cb1231..d8843c1078 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecoderCompressionType.cs @@ -36,16 +36,16 @@ internal enum TiffDecoderCompressionType /// /// Image data is compressed using CCITT T.6 fax compression. /// - T6 = 6, + T6 = 5, /// /// Image data is compressed using modified huffman compression. /// - HuffmanRle = 5, + HuffmanRle = 6, /// /// The image data is compressed as a JPEG stream. /// - Jpeg = 6, + Jpeg = 7, } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index c01237b6a9..b64d22991f 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -28,8 +28,6 @@ public class TiffDecoderTests private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder(); [Theory] - [WithFile(Calliphora_RgbJpeg, PixelTypes.Rgba32)] - [WithFile(RgbJpeg, PixelTypes.Rgba32)] [WithFile(RgbUncompressedTiled, PixelTypes.Rgba32)] [WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)] [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)] From 39eba0d82ca31722cababe7277730f913b497248 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 26 Aug 2021 11:32:17 +1000 Subject: [PATCH 31/32] Use stackalloc --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 71f9827e27..3fd1a3c489 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -265,7 +265,7 @@ private void WriteJfifApplicationHeader(ImageMetadata meta) private void WriteDefineHuffmanTables(int componentCount) { // Table identifiers. - ReadOnlySpan headers = new byte[] + ReadOnlySpan headers = stackalloc byte[] { 0x00, 0x10, From f25ce22ed85b4c7a7d481af5d92e6101632eac5d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 26 Aug 2021 11:51:11 +1000 Subject: [PATCH 32/32] Update JpegEncoderCore.cs --- .../Formats/Jpeg/JpegEncoderCore.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 3fd1a3c489..14e7cc6778 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -167,14 +167,10 @@ public void Encode(Image image, Stream stream, CancellationToken /// The color type. /// true, if color type is supported. private static bool IsSupportedColorType(JpegColorType? colorType) - { - if (colorType == JpegColorType.YCbCrRatio444 || colorType == JpegColorType.YCbCrRatio420 || colorType == JpegColorType.Luminance || colorType == JpegColorType.Rgb) - { - return true; - } - - return false; - } + => colorType == JpegColorType.YCbCrRatio444 + || colorType == JpegColorType.YCbCrRatio420 + || colorType == JpegColorType.Luminance + || colorType == JpegColorType.Rgb; /// /// Gets the component ids. @@ -571,14 +567,14 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn // This uses a C#'s compiler optimization that refers to the static data segment of the assembly, // and doesn't incur any allocation at all. // "default" to 4:2:0 - ReadOnlySpan subsamples = new byte[] + ReadOnlySpan subsamples = stackalloc byte[] { 0x22, 0x11, 0x11 }; - ReadOnlySpan chroma = new byte[] + ReadOnlySpan chroma = stackalloc byte[] { 0x00, 0x01, @@ -587,7 +583,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn if (this.colorType == JpegColorType.Luminance) { - subsamples = new byte[] + subsamples = stackalloc byte[] { 0x11, 0x00, @@ -600,7 +596,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn { case JpegColorType.YCbCrRatio444: case JpegColorType.Rgb: - subsamples = new byte[] + subsamples = stackalloc byte[] { 0x11, 0x11, @@ -609,7 +605,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn if (this.colorType == JpegColorType.Rgb) { - chroma = new byte[] + chroma = stackalloc byte[] { 0x00, 0x00, @@ -619,7 +615,7 @@ private void WriteStartOfFrame(int width, int height, int componentCount, ReadOn break; case JpegColorType.YCbCrRatio420: - subsamples = new byte[] + subsamples = stackalloc byte[] { 0x22, 0x11, @@ -662,7 +658,7 @@ private void WriteStartOfScan(int componentCount, ReadOnlySpan componentId { // This uses a C#'s compiler optimization that refers to the static data segment of the assembly, // and doesn't incur any allocation at all. - ReadOnlySpan huffmanId = new byte[] + ReadOnlySpan huffmanId = stackalloc byte[] { 0x00, 0x11, @@ -672,7 +668,7 @@ private void WriteStartOfScan(int componentCount, ReadOnlySpan componentId // Use the same DC/AC tables for all channels for RGB. if (this.colorType == JpegColorType.Rgb) { - huffmanId = new byte[] + huffmanId = stackalloc byte[] { 0x00, 0x00,