From 0bee54f5ba5349ea84d65cf65ef89f01b1294786 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Aug 2026 03:37:35 +1000 Subject: [PATCH] Add ICC profile span input --- src/ImageSharp/Formats/Heif/HeifPropertyParser.cs | 8 +++----- src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs | 13 +++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Heif/HeifPropertyParser.cs b/src/ImageSharp/Formats/Heif/HeifPropertyParser.cs index 164fb633e..73ee5dbf3 100644 --- a/src/ImageSharp/Formats/Heif/HeifPropertyParser.cs +++ b/src/ImageSharp/Formats/Heif/HeifPropertyParser.cs @@ -43,11 +43,9 @@ internal static class HeifPropertyParser throw new InvalidImageContentException("The HEIF ICC color property contains an empty profile."); } - // IccProfile retains its input array while the HEIF box-reader buffer is pooled and reused. Perform the one - // required ownership transfer here so item and sequence parsing cannot introduce additional materializations. - byte[] ownedData = GC.AllocateUninitializedArray(data.Length); - data.CopyTo(ownedData); - IccProfile profile = new(ownedData); + // The source belongs to a pooled box-reader buffer. The span constructor performs the single ownership transfer + // required for the profile to retain its exact bytes after that buffer is returned and reused. + IccProfile profile = new(data); if (!profile.CheckIsValid()) { throw new InvalidIccProfileException("Invalid HEIF ICC profile."); diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs index eaba0a045..f0325e720 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs @@ -40,6 +40,19 @@ public sealed partial class IccProfile : IDeepCloneable /// The raw ICC profile data public IccProfile(byte[] data) => this.data = data; + /// + /// Initializes a new instance of the class from raw ICC profile data whose source storage does not need to + /// remain valid for the lifetime of the profile. + /// + /// The raw ICC profile data. + public IccProfile(ReadOnlySpan data) + { + // A span cannot transfer ownership, while IccProfile retains the exact bytes for lazy parsing and byte-for-byte serialization. + // The destination has exactly data.Length elements, so CopyTo immediately overwrites every byte of the uninitialized array. + this.data = GC.AllocateUninitializedArray(data.Length); + data.CopyTo(this.data); + } + /// /// Initializes a new instance of the class. ///