diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
index b41d52aa4..63a295d43 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 94439f35a..5104f606d 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -85,6 +85,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
private byte[] xmpData;
+ ///
+ /// Whether the image has a APP14 adobe marker. This is needed to determine image encoded colorspace.
+ ///
+ private bool hasAdobeMarker;
+
///
/// Contains information about the JFIF marker.
///
@@ -501,49 +506,48 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Returns the correct colorspace based on the image component count and the jpeg frame component id's.
///
/// The number of components.
+ /// Parsed adobe APP14 marker.
/// The
- private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
+ internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount, ref AdobeMarker adobeMarker)
{
- if (componentCount == 1)
- {
- return JpegColorSpace.Grayscale;
- }
-
if (componentCount == 3)
{
- if (!this.adobe.Equals(default))
+ if (adobeMarker.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
- {
- return JpegColorSpace.YCbCr;
- }
-
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
- {
- return JpegColorSpace.RGB;
- }
+ return JpegColorSpace.RGB;
}
- // Fallback to YCbCr
return JpegColorSpace.YCbCr;
}
if (componentCount == 4)
{
- if (!this.adobe.Equals(default))
+ if (adobeMarker.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
{
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
- {
- return JpegColorSpace.Ycck;
- }
-
- if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
- {
- return JpegColorSpace.Cmyk;
- }
+ return JpegColorSpace.Ycck;
}
- // Fallback to CMYK
+ return JpegColorSpace.Cmyk;
+ }
+
+ JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
+ return default;
+ }
+
+ internal static JpegColorSpace DeduceJpegColorSpace(byte componentCount)
+ {
+ if (componentCount == 1)
+ {
+ return JpegColorSpace.Grayscale;
+ }
+
+ if (componentCount == 3)
+ {
+ return JpegColorSpace.YCbCr;
+ }
+
+ if (componentCount == 4)
+ {
return JpegColorSpace.Cmyk;
}
@@ -1013,7 +1017,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
stream.Read(this.temp, 0, MarkerLength);
remaining -= MarkerLength;
- AdobeMarker.TryParse(this.temp, out this.adobe);
+ if (AdobeMarker.TryParse(this.temp, out this.adobe))
+ {
+ this.hasAdobeMarker = true;
+ }
if (remaining > 0)
{
@@ -1260,7 +1267,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
index += componentBytes;
}
- this.ColorSpace = this.DeduceJpegColorSpace(componentCount);
+ this.ColorSpace = this.hasAdobeMarker
+ ? DeduceJpegColorSpace(componentCount, ref this.adobe)
+ : DeduceJpegColorSpace(componentCount);
this.Metadata.GetJpegMetadata().ColorType = this.DeduceJpegColorType();
if (!metadataOnly)
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
new file mode 100644
index 000000000..71951cfef
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Internal.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
+using SixLabors.ImageSharp.Tests.TestUtilities;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
+using Xunit;
+using Xunit.Abstractions;
+
+// ReSharper disable InconsistentNaming
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ [Trait("Format", "Jpg")]
+ public partial class JpegDecoderTests
+ {
+ [Theory]
+ [InlineData(3, JpegConstants.Adobe.ColorTransformUnknown, JpegColorSpace.RGB)]
+ [InlineData(3, JpegConstants.Adobe.ColorTransformYCbCr, JpegColorSpace.YCbCr)]
+ [InlineData(4, JpegConstants.Adobe.ColorTransformUnknown, JpegColorSpace.Cmyk)]
+ [InlineData(4, JpegConstants.Adobe.ColorTransformYcck, JpegColorSpace.Ycck)]
+ internal void DeduceJpegColorSpaceAdobeMarker_ShouldReturnValidColorSpace(byte componentCount, byte adobeFlag, JpegColorSpace expectedColorSpace)
+ {
+ byte[] adobeMarkerPayload = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, adobeFlag };
+ ProfileResolver.AdobeMarker.CopyTo(adobeMarkerPayload);
+
+ _ = AdobeMarker.TryParse(adobeMarkerPayload, out AdobeMarker adobeMarker);
+ JpegColorSpace actualColorSpace = JpegDecoderCore.DeduceJpegColorSpace(componentCount, ref adobeMarker);
+
+ Assert.Equal(expectedColorSpace, actualColorSpace);
+ }
+
+ [Theory]
+ [InlineData(2)]
+ [InlineData(5)]
+ public void DeduceJpegColorSpaceAdobeMarker_ShouldThrowOnUnsupportedComponentCount(byte componentCount)
+ {
+ AdobeMarker adobeMarker = default;
+ Assert.Throws(() => JpegDecoderCore.DeduceJpegColorSpace(componentCount, ref adobeMarker));
+ }
+
+ [Theory]
+ [InlineData(1, JpegColorSpace.Grayscale)]
+ [InlineData(3, JpegColorSpace.YCbCr)]
+ [InlineData(4, JpegColorSpace.Cmyk)]
+ internal void DeduceJpegColorSpace_ShouldReturnValidColorSpace(byte componentCount, JpegColorSpace expectedColorSpace)
+ {
+ JpegColorSpace actualColorSpace = JpegDecoderCore.DeduceJpegColorSpace(componentCount);
+
+ Assert.Equal(expectedColorSpace, actualColorSpace);
+ }
+
+ [Theory]
+ [InlineData(2)]
+ [InlineData(5)]
+ public void DeduceJpegColorSpace_ShouldThrowOnUnsupportedComponentCount(byte componentCount)
+ => Assert.Throws(() => JpegDecoderCore.DeduceJpegColorSpace(componentCount));
+ }
+}