diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs
index a008bf8ea2..cc41cf5a29 100644
--- a/src/ImageSharp/Formats/Png/PngChunkType.cs
+++ b/src/ImageSharp/Formats/Png/PngChunkType.cs
@@ -140,6 +140,12 @@ internal enum PngChunkType : uint
/// cHRM (Single)
Chroma = 0x6348524d,
+ ///
+ /// If this chunk is present, it specifies the color space, transfer function, matrix coefficients of the image
+ /// using the code points specified in [ITU-T-H.273]
+ ///
+ Cicp = 0x63494350,
+
///
/// This chunk is an ancillary chunk as defined in the PNG Specification.
/// It must appear before the first IDAT chunk within a valid PNG stream.
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 84eea9a5a5..95154d68d3 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -17,6 +17,7 @@
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Memory.Internals;
using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.Metadata.Profiles.Cicp;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
@@ -191,6 +192,9 @@ public Image Decode(BufferedReadStream stream, CancellationToken
case PngChunkType.Gamma:
ReadGammaChunk(pngMetadata, chunk.Data.GetSpan());
break;
+ case PngChunkType.Cicp:
+ ReadCicpChunk(metadata, chunk.Data.GetSpan());
+ break;
case PngChunkType.FrameControl:
frameCount++;
if (frameCount == this.maxFrames)
@@ -360,6 +364,15 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
ReadGammaChunk(pngMetadata, chunk.Data.GetSpan());
break;
+ case PngChunkType.Cicp:
+ if (this.colorMetadataOnly)
+ {
+ this.SkipChunkDataAndCrc(chunk);
+ break;
+ }
+
+ ReadCicpChunk(metadata, chunk.Data.GetSpan());
+ break;
case PngChunkType.FrameControl:
++frameCount;
if (frameCount == this.maxFrames)
@@ -1426,6 +1439,26 @@ private static bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string
return false;
}
+ ///
+ /// Reads the CICP color profile chunk.
+ ///
+ /// The metadata.
+ /// The bytes containing the profile.
+ private static void ReadCicpChunk(ImageMetadata metadata, ReadOnlySpan data)
+ {
+ if (data.Length < 4)
+ {
+ // Ignore invalid cICP chunks.
+ return;
+ }
+
+ byte colorPrimaries = data[0];
+ byte transferFunction = data[1];
+ byte matrixCoefficients = data[2];
+ bool? fullRange = data[3] == 1 ? true : data[3] == 0 ? false : null;
+ metadata.CicpProfile = new CicpProfile(colorPrimaries, transferFunction, matrixCoefficients, fullRange);
+ }
+
///
/// Reads exif data encoded into a text chunk with the name "raw profile type exif".
/// This method was used by ImageMagick, exiftool, exiv2, digiKam, etc, before the
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 932916dec2..ddef1c9cd9 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -177,6 +177,7 @@ public void Encode(Image image, Stream stream, CancellationToken
this.WriteHeaderChunk(stream);
this.WriteGammaChunk(stream);
+ this.WriteCicpChunk(stream, metadata);
this.WriteColorProfileChunk(stream, metadata);
this.WritePaletteChunk(stream, quantized);
this.WriteTransparencyChunk(stream, pngMetadata);
@@ -852,6 +853,32 @@ private void WriteXmpChunk(Stream stream, ImageMetadata meta)
this.WriteChunk(stream, PngChunkType.InternationalText, payload);
}
+ ///
+ /// Writes the CICP profile chunk
+ ///
+ /// The containing image data.
+ /// The image meta data.
+ private void WriteCicpChunk(Stream stream, ImageMetadata metaData)
+ {
+ if (metaData.CicpProfile is null)
+ {
+ return;
+ }
+
+ // by spec, the matrix coefficients must be set to Identity
+ if (metaData.CicpProfile.MatrixCoefficients != Metadata.Profiles.Cicp.CicpMatrixCoefficients.Identity)
+ {
+ throw new NotSupportedException("CICP matrix coefficients other than Identity are not supported in PNG");
+ }
+
+ Span outputBytes = this.chunkDataBuffer.Span[..4];
+ outputBytes[0] = (byte)metaData.CicpProfile.ColorPrimaries;
+ outputBytes[1] = (byte)metaData.CicpProfile.TransferCharacteristics;
+ outputBytes[2] = (byte)metaData.CicpProfile.MatrixCoefficients;
+ outputBytes[3] = (byte)(metaData.CicpProfile.FullRange ? 1 : 0);
+ this.WriteChunk(stream, PngChunkType.Cicp, outputBytes);
+ }
+
///
/// Writes the color profile chunk.
///
diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs
index 03f628afa3..1c0330d5d0 100644
--- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs
+++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Metadata.Profiles.Cicp;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
@@ -43,6 +44,7 @@ internal ImageFrameMetadata(ImageFrameMetadata other)
this.IccProfile = other.IccProfile?.DeepClone();
this.IptcProfile = other.IptcProfile?.DeepClone();
this.XmpProfile = other.XmpProfile?.DeepClone();
+ this.CicpProfile = other.CicpProfile?.DeepClone();
}
///
@@ -65,6 +67,11 @@ internal ImageFrameMetadata(ImageFrameMetadata other)
///
public IptcProfile? IptcProfile { get; set; }
+ ///
+ /// Gets or sets the CICP profile
+ ///
+ public CicpProfile? CicpProfile { get; set; }
+
///
public ImageFrameMetadata DeepClone() => new(this);
diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs
index e1284b50e8..6b62be08ff 100644
--- a/src/ImageSharp/Metadata/ImageMetadata.cs
+++ b/src/ImageSharp/Metadata/ImageMetadata.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Metadata.Profiles.Cicp;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
@@ -68,6 +69,7 @@ private ImageMetadata(ImageMetadata other)
this.IccProfile = other.IccProfile?.DeepClone();
this.IptcProfile = other.IptcProfile?.DeepClone();
this.XmpProfile = other.XmpProfile?.DeepClone();
+ this.CicpProfile = other.CicpProfile?.DeepClone();
// NOTE: This clone is actually shallow but we share the same format
// instances for all images in the configuration.
@@ -157,6 +159,11 @@ public double VerticalResolution
///
public IptcProfile? IptcProfile { get; set; }
+ ///
+ /// Gets or sets the CICP profile.
+ ///
+ public CicpProfile? CicpProfile { get; set; }
+
///
/// Gets the original format, if any, the image was decode from.
///
diff --git a/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs
new file mode 100644
index 0000000000..2657903dfa
--- /dev/null
+++ b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp;
+
+///
+/// Represents a Cicp profile as per ITU-T H.273 / ISO/IEC 23091-2_2019 providing access to color space information
+///
+public sealed class CicpProfile : IDeepCloneable
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CicpProfile()
+ : this(2, 2, 2, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color primaries as number according to ITU-T H.273 / ISO/IEC 23091-2_2019.
+ /// The transfer characteristics as number according to ITU-T H.273 / ISO/IEC 23091-2_2019.
+ /// The matrix coefficients as number according to ITU-T H.273 / ISO/IEC 23091-2_2019.
+ /// The full range flag, or null if unknown.
+ public CicpProfile(byte colorPrimaries, byte transferCharacteristics, byte matrixCoefficients, bool? fullRange)
+ {
+ this.ColorPrimaries = Enum.IsDefined(typeof(CicpColorPrimaries), colorPrimaries) ? (CicpColorPrimaries)colorPrimaries : CicpColorPrimaries.Unspecified;
+ this.TransferCharacteristics = Enum.IsDefined(typeof(CicpTransferCharacteristics), transferCharacteristics) ? (CicpTransferCharacteristics)transferCharacteristics : CicpTransferCharacteristics.Unspecified;
+ this.MatrixCoefficients = Enum.IsDefined(typeof(CicpMatrixCoefficients), matrixCoefficients) ? (CicpMatrixCoefficients)matrixCoefficients : CicpMatrixCoefficients.Unspecified;
+ this.FullRange = fullRange ?? (this.MatrixCoefficients == CicpMatrixCoefficients.Identity);
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// by making a copy from another CICP profile.
+ ///
+ /// The other CICP profile, where the clone should be made from.
+ /// is null.>
+ private CicpProfile(CicpProfile other)
+ {
+ Guard.NotNull(other, nameof(other));
+
+ this.ColorPrimaries = other.ColorPrimaries;
+ this.TransferCharacteristics = other.TransferCharacteristics;
+ this.MatrixCoefficients = other.MatrixCoefficients;
+ this.FullRange = other.FullRange;
+ }
+
+ ///
+ /// Gets or sets the color primaries
+ ///
+ public CicpColorPrimaries ColorPrimaries { get; set; }
+
+ ///
+ /// Gets or sets the transfer characteristics
+ ///
+ public CicpTransferCharacteristics TransferCharacteristics { get; set; }
+
+ ///
+ /// Gets or sets the matrix coefficients
+ ///
+ public CicpMatrixCoefficients MatrixCoefficients { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the colors use the full numeric range
+ ///
+ public bool FullRange { get; set; }
+
+ ///
+ public CicpProfile DeepClone() => new(this);
+}
diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs
new file mode 100644
index 0000000000..bab888dd71
--- /dev/null
+++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp;
+
+#pragma warning disable CA1707 // Underscores in enum members
+
+///
+/// Color primaries according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.1
+///
+public enum CicpColorPrimaries : byte
+{
+ ///
+ /// Rec. ITU-R BT.709-6
+ /// IEC 61966-2-1 sRGB or sYCC
+ /// IEC 61966-2-4
+ /// SMPTE RP 177 (1993) Annex B
+ ///
+ ItuRBt709_6 = 1,
+
+ ///
+ /// Image characteristics are unknown or are determined by the application.
+ ///
+ Unspecified = 2,
+
+ ///
+ /// Rec. ITU-R BT.470-6 System M (historical)
+ ///
+ ItuRBt470_6M = 4,
+
+ ///
+ /// Rec. ITU-R BT.601-7 625
+ /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM
+ ///
+ ItuRBt601_7_625 = 5,
+
+ ///
+ /// Rec. ITU-R BT.601-7 525
+ /// Rec. ITU-R BT.1700-0 NTSC
+ /// SMPTE ST 170 (2004)
+ /// (functionally the same as the value 7)
+ ///
+ ItuRBt601_7_525 = 6,
+
+ ///
+ /// SMPTE ST 240 (1999)
+ /// (functionally the same as the value 6)
+ ///
+ SmpteSt240 = 7,
+
+ ///
+ /// Generic film (colour filters using Illuminant C)
+ ///
+ GenericFilm = 8,
+
+ ///
+ /// Rec. ITU-R BT.2020-2
+ /// Rec. ITU-R BT.2100-2
+ ///
+ ItuRBt2020_2 = 9,
+
+ ///
+ /// SMPTE ST 428-1 (2019)
+ /// (CIE 1931 XYZ as in ISO 11664-1)
+ ///
+ SmpteSt428_1 = 10,
+
+ ///
+ /// SMPTE RP 431-2 (2011)
+ /// DCI P3
+ ///
+ SmpteRp431_2 = 11,
+
+ ///
+ /// SMPTE ST 432-1 (2010)
+ /// P3 D65 / Display P3
+ ///
+ SmpteEg432_1 = 12,
+
+ ///
+ /// EBU Tech.3213-E
+ ///
+ EbuTech3213E = 22,
+}
+
+#pragma warning restore CA1707 // Underscores in enum members
diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs
new file mode 100644
index 0000000000..931beac846
--- /dev/null
+++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp;
+
+#pragma warning disable CA1707 // Underscores in enum members
+
+///
+/// Matrix coefficients according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.3
+///
+public enum CicpMatrixCoefficients : byte
+{
+ ///
+ /// The identity matrix.
+ /// IEC 61966-2-1 sRGB
+ /// SMPTE ST 428-1 (2019)
+ ///
+ Identity = 0,
+
+ ///
+ /// Rec. ITU-R BT.709-6
+ /// IEC 61966-2-4 xvYCC709
+ /// SMPTE RP 177 (1993) Annex B
+ ///
+ ItuRBt709_6 = 1,
+
+ ///
+ /// Image characteristics are unknown or are determined by the application.
+ ///
+ Unspecified = 2,
+
+ ///
+ /// FCC Title 47 Code of Federal Regulations 73.682 (a) (20)
+ ///
+ Fcc47 = 4,
+
+ ///
+ /// Rec. ITU-R BT.601-7 625
+ /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM
+ /// IEC 61966-2-1 sYCC
+ /// IEC 61966-2-4 xvYCC601
+ /// (functionally the same as the value 6)
+ ///
+ ItuRBt601_7_625 = 5,
+
+ ///
+ /// Rec. ITU-R BT.601-7 525
+ /// Rec. ITU-R BT.1700-0 NTSC
+ /// SMPTE ST 170 (2004)
+ /// (functionally the same as the value 5)
+ ///
+ ItuRBt601_7_525 = 6,
+
+ ///
+ /// SMPTE ST 240 (1999)
+ ///
+ SmpteSt240 = 7,
+
+ ///
+ /// YCgCo
+ ///
+ YCgCo = 8,
+
+ ///
+ /// Rec. ITU-R BT.2020-2 (non-constant luminance)
+ /// Rec. ITU-R BT.2100-2 Y′CbCr
+ ///
+ ItuRBt2020_2_Ncl = 9,
+
+ ///
+ /// Rec. ITU-R BT.2020-2 (constant luminance)
+ ///
+ ItuRBt2020_2_Cl = 10,
+
+ ///
+ /// SMPTE ST 2085 (2015)
+ ///
+ SmpteSt2085 = 11,
+
+ ///
+ /// Chromaticity-derived non-constant luminance system
+ ///
+ ChromaDerivedNcl = 12,
+
+ ///
+ /// Chromaticity-derived constant luminance system
+ ///
+ ChromaDerivedCl = 13,
+
+ ///
+ /// Rec. ITU-R BT.2100-2 ICtCp
+ ///
+ ICtCp = 14,
+}
+
+#pragma warning restore CA1707 // Underscores in enum members
diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs
new file mode 100644
index 0000000000..86eea0b70d
--- /dev/null
+++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs
@@ -0,0 +1,109 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp;
+
+#pragma warning disable CA1707 // Underscores in enum values
+
+///
+/// Transfer characteristics according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.2
+/// ///
+public enum CicpTransferCharacteristics : byte
+{
+ ///
+ /// Rec. ITU-R BT.709-6
+ /// (functionally the same as the values 6, 14 and 15)
+ ///
+ ItuRBt709_6 = 1,
+
+ ///
+ /// Image characteristics are unknown or are determined by the application.
+ ///
+ Unspecified = 2,
+
+ ///
+ /// Assumed display gamma 2.2
+ /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM
+ ///
+ Gamma2_2 = 4,
+
+ ///
+ /// Assumed display gamma 2.8
+ /// Rec. ITU-R BT.470-6 System B, G (historical)
+ ///
+ Gamma2_8 = 5,
+
+ ///
+ /// Rec. ITU-R BT.601-7 525 or 625
+ /// Rec. ITU-R BT.1700-0 NTSC
+ /// SMPTE ST 170 (2004)
+ /// (functionally the same as the values 1, 14 and 15)
+ ///
+ ItuRBt601_7 = 6,
+
+ ///
+ /// SMPTE ST 240 (1999)
+ ///
+ SmpteSt240 = 7,
+
+ ///
+ /// Linear transfer characteristics
+ ///
+ Linear = 8,
+
+ ///
+ /// Logarithmic transfer characteristic (100:1 range)
+ ///
+ Log100 = 9,
+
+ ///
+ /// Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)
+ ///
+ Log100Sqrt = 10,
+
+ ///
+ /// IEC 61966-2-4
+ ///
+ Iec61966_2_4 = 11,
+
+ ///
+ /// Rec. ITU-R BT.1361-0 extended colour gamut system (historical)
+ ///
+ ItuRBt1361_0 = 12,
+
+ ///
+ /// IEC 61966-2-1 sRGB or sYCC / Display P3
+ ///
+ Iec61966_2_1 = 13,
+
+ ///
+ /// Rec. ITU-R BT.2020-2 (10-bit system)
+ /// (functionally the same as the values 1, 6 and 15)
+ ///
+ ItuRBt2020_2_10bit = 14,
+
+ ///
+ /// Rec. ITU-R BT.2020-2 (12-bit system)
+ /// (functionally the same as the values 1, 6 and 14)
+ /// ///
+ ItuRBt2020_2_12bit = 15,
+
+ ///
+ /// SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems
+ /// Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system
+ ///
+ SmpteSt2084 = 16,
+
+ ///
+ /// SMPTE ST 428-1 (2019)
+ ///
+ SmpteSt428_1 = 17,
+
+ ///
+ /// ARIB STD-B67 (2015)
+ /// Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system
+ ///
+ AribStdB67 = 18,
+}
+
+#pragma warning restore CA1707 // Underscores in enum members
diff --git a/src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf b/src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf
new file mode 100644
index 0000000000..12086dd779
Binary files /dev/null and b/src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf differ
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
index 06cb079e5b..02e8dc7dfb 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
@@ -29,6 +29,7 @@ public void ChunkTypeIdsAreCorrect()
Assert.Equal(PngChunkType.Background, GetType("bKGD"));
Assert.Equal(PngChunkType.EmbeddedColorProfile, GetType("iCCP"));
Assert.Equal(PngChunkType.StandardRgbColourSpace, GetType("sRGB"));
+ Assert.Equal(PngChunkType.Cicp, GetType("cICP"));
Assert.Equal(PngChunkType.SignificantBits, GetType("sBIT"));
Assert.Equal(PngChunkType.Histogram, GetType("hIST"));
Assert.Equal(PngChunkType.SuggestedPalette, GetType("sPLT"));
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs
new file mode 100644
index 0000000000..76e2d35c45
--- /dev/null
+++ b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Metadata.Profiles.Cicp;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Cicp;
+
+public class CicpProfileTests
+{
+ [Theory]
+ [WithFile(TestImages.Png.AdamHeadsHlg, PixelTypes.Rgba64)]
+ public async Task ReadCicpMetadata_FromPng_Works(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = await provider.GetImageAsync(PngDecoder.Instance);
+
+ CicpProfile actual = image.Metadata.CicpProfile ?? image.Frames.RootFrame.Metadata.CicpProfile;
+ CicpProfileContainsExpectedValues(actual);
+ }
+
+ [Fact]
+ public void WritingPng_PreservesCicpProfile()
+ {
+ // arrange
+ using var image = new Image(1, 1);
+ var original = CreateCicpProfile();
+ image.Metadata.CicpProfile = original;
+ var encoder = new PngEncoder();
+
+ // act
+ using Image reloadedImage = WriteAndRead(image, encoder);
+
+ // assert
+ CicpProfile actual = reloadedImage.Metadata.CicpProfile ?? reloadedImage.Frames.RootFrame.Metadata.CicpProfile;
+ CicpProfileIsValidAndEqual(actual, original);
+ }
+
+ private static void CicpProfileContainsExpectedValues(CicpProfile cicp)
+ {
+ Assert.NotNull(cicp);
+ Assert.Equal(CicpColorPrimaries.ItuRBt2020_2, cicp.ColorPrimaries);
+ Assert.Equal(CicpTransferCharacteristics.AribStdB67, cicp.TransferCharacteristics);
+ Assert.Equal(CicpMatrixCoefficients.Identity, cicp.MatrixCoefficients);
+ Assert.True(cicp.FullRange);
+ }
+
+ private static CicpProfile CreateCicpProfile()
+ {
+ var profile = new CicpProfile()
+ {
+ ColorPrimaries = CicpColorPrimaries.ItuRBt2020_2,
+ TransferCharacteristics = CicpTransferCharacteristics.SmpteSt2084,
+ MatrixCoefficients = CicpMatrixCoefficients.Identity,
+ FullRange = true,
+ };
+ return profile;
+ }
+
+ private static void CicpProfileIsValidAndEqual(CicpProfile actual, CicpProfile original)
+ {
+ Assert.NotNull(actual);
+ Assert.Equal(actual.ColorPrimaries, original.ColorPrimaries);
+ Assert.Equal(actual.TransferCharacteristics, original.TransferCharacteristics);
+ Assert.Equal(actual.MatrixCoefficients, original.MatrixCoefficients);
+ Assert.Equal(actual.FullRange, original.FullRange);
+ }
+
+ private static Image WriteAndRead(Image image, IImageEncoder encoder)
+ {
+ using (var memStream = new MemoryStream())
+ {
+ image.Save(memStream, encoder);
+ image.Dispose();
+
+ memStream.Position = 0;
+ return Image.Load(memStream);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 7a7da22119..7e862f7d4f 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -61,6 +61,7 @@ public static class Png
public const string TestPattern31x31 = "Png/testpattern31x31.png";
public const string TestPattern31x31HalfTransparent = "Png/testpattern31x31-halftransparent.png";
public const string XmpColorPalette = "Png/xmp-colorpalette.png";
+ public const string AdamHeadsHlg = "Png/adamHeadsHLG.png";
// Animated
// https://philip.html5.org/tests/apng/tests.html
diff --git a/tests/Images/Input/Png/adamHeadsHLG.png b/tests/Images/Input/Png/adamHeadsHLG.png
new file mode 100644
index 0000000000..f5d26ac50c
--- /dev/null
+++ b/tests/Images/Input/Png/adamHeadsHLG.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8c50691da3b3af21ff4f8fc30f1313bc412b84fb0a07a5bf3b8b14eae7581ade
+size 201440