From db9afff904ef1b3f9bc7d9e90f55ef8bb9c53d07 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 24 Apr 2017 15:42:04 +1000 Subject: [PATCH] Can now read and store ICC profile --- .../Conversion/ColorSpaceConverter.Rgb.cs | 6 +- src/ImageSharp/Formats/Jpeg/JpegConstants.cs | 5 ++ .../Formats/Jpeg/JpegDecoderCore.cs | 55 ++++++++++++++++++- src/ImageSharp/MetaData/ImageMetaData.cs | 5 ++ .../Profiles/ICC/Enums/IccColorSpaceType.cs | 2 +- .../Profiles/ICC/Enums/IccDeviceAttribute.cs | 2 +- .../ICC/Enums/IccPrimaryPlatformType.cs | 2 +- .../Profiles/ICC/Enums/IccProfileClass.cs | 2 +- .../Profiles/ICC/Enums/IccProfileFlag.cs | 2 +- .../Profiles/ICC/Enums/IccProfileTag.cs | 2 +- .../Profiles/ICC/Enums/IccRenderingIntent.cs | 2 +- .../Profiles/ICC/Enums/IccTypeSignature.cs | 2 +- .../MetaData/Profiles/ICC/IccProfile.cs | 2 +- .../MetaData/Profiles/ICC/IccProfileHeader.cs | 2 +- .../MetaData/Profiles/ICC/IccTagDataEntry.cs | 6 +- .../Profiles/ICC/Various/IccProfileId.cs | 2 +- 16 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index 1469888a1a..e22f230aca 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -144,7 +144,11 @@ namespace ImageSharp.ColorSpaces.Conversion Guard.NotNull(color, nameof(color)); // Conversion - return YCbCrAndRgbConverter.Convert(color); + Rgb rgb = YCbCrAndRgbConverter.Convert(color); + + // Adaptation + // TODO: Check this! + return rgb.WorkingSpace.Equals(this.TargetRgbWorkingSpace) ? rgb : this.Adapt(rgb); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index 74f9a3c07d..dcda39842e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -200,6 +200,11 @@ namespace ImageSharp.Formats /// public const byte APP1 = 0xe1; + /// + /// Application specific marker for marking where to store ICC profile information. + /// + public const byte APP2 = 0xe2; + /// /// Application specific marker used by Adobe for storing encoding information for DCT filters. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 186c1e5282..1af3e1c88a 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -83,6 +83,11 @@ namespace ImageSharp.Formats /// private bool isExif; + /// + /// Whether the image has an ICC header + /// + private bool isIcc; + /// /// The vertical resolution. Calculated if the image has a JFIF header. /// @@ -436,6 +441,9 @@ namespace ImageSharp.Formats case JpegConstants.Markers.APP1: this.ProcessApp1Marker(remaining, metadata); break; + case JpegConstants.Markers.APP2: + this.ProcessApp2Marker(remaining, metadata); + break; case JpegConstants.Markers.APP14: this.ProcessApp14Marker(remaining); break; @@ -962,14 +970,57 @@ namespace ImageSharp.Formats byte[] profile = new byte[remaining]; this.InputProcessor.ReadFull(profile, 0, remaining); - if (profile[0] == 'E' && profile[1] == 'x' && profile[2] == 'i' && profile[3] == 'f' && profile[4] == '\0' - && profile[5] == '\0') + if (profile[0] == 'E' && + profile[1] == 'x' && + profile[2] == 'i' && + profile[3] == 'f' && + profile[4] == '\0' && + profile[5] == '\0') { this.isExif = true; metadata.ExifProfile = new ExifProfile(profile); } } + /// + /// Processes the App2 marker retrieving any stored ICC profile information + /// + /// The remaining bytes in the segment block. + /// The image. + private void ProcessApp2Marker(int remaining, ImageMetaData metadata) + { + // Length is 14 though we only need to check 12. + const int Icclength = 14; + if (remaining < Icclength || this.options.IgnoreMetadata) + { + this.InputProcessor.Skip(remaining); + return; + } + + byte[] identifier = new byte[Icclength]; + this.InputProcessor.ReadFull(identifier, 0, Icclength); + + if (identifier[0] == 'I' && + identifier[1] == 'C' && + identifier[2] == 'C' && + identifier[3] == '_' && + identifier[4] == 'P' && + identifier[5] == 'R' && + identifier[6] == 'O' && + identifier[7] == 'F' && + identifier[8] == 'I' && + identifier[9] == 'L' && + identifier[10] == 'E' && + identifier[11] == '\0') + { + this.isIcc = true; + remaining -= Icclength; + byte[] profile = new byte[remaining]; + this.InputProcessor.ReadFull(profile, 0, remaining); + metadata.IccProfile = new IccProfile(profile); + } + } + /// /// Processes the application header containing the JFIF identifier plus extra data. /// diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index aed6efa2cb..c8f3ccc6c7 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -116,6 +116,11 @@ namespace ImageSharp /// public ExifProfile ExifProfile { get; set; } + /// + /// Gets or sets the ICC profile. + /// + public IccProfile IccProfile { get; set; } + /// /// Gets or sets the frame delay for animated images. /// If not 0, this field specifies the number of hundredths (1/100) of a second to diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs index 43af657c5d..3f57ded742 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs @@ -8,7 +8,7 @@ namespace ImageSharp /// /// Color Space Type /// - internal enum IccColorSpaceType : uint + public enum IccColorSpaceType : uint { /// /// CIE XYZ diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs index cde55be763..c57cf4f977 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs @@ -13,7 +13,7 @@ namespace ImageSharp /// the rest can be used for vendor specific values /// [Flags] - internal enum IccDeviceAttribute : long + public enum IccDeviceAttribute : long { /// /// Opacity transparent diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs index cd4e555c15..8fdeb3f418 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs @@ -8,7 +8,7 @@ namespace ImageSharp /// /// Enumerates the primary platform/operating system framework for which the profile was created /// - internal enum IccPrimaryPlatformType : uint + public enum IccPrimaryPlatformType : uint { /// /// No platform identified diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs index 1ce781d082..9fb0b51f32 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs @@ -8,7 +8,7 @@ namespace ImageSharp /// /// Profile Class Name /// - internal enum IccProfileClass : uint + public enum IccProfileClass : uint { /// /// Input profiles are generally used with devices such as scanners and diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs index cb23053f5d..aa8df88bd8 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs @@ -13,7 +13,7 @@ namespace ImageSharp /// the rest can be used for vendor specific values /// [Flags] - internal enum IccProfileFlag : int + public enum IccProfileFlag : int { /// /// No flags (equivalent to NotEmbedded and Independent) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs index 0a082ad8e2..6eab5b3fe8 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs @@ -13,7 +13,7 @@ namespace ImageSharp /// Each tag value represent the size of the tag in the profile. /// /// - internal enum IccProfileTag : uint + public enum IccProfileTag : uint { /// /// Unknown tag diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs index 8f6abf7276..10e0fbac99 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs @@ -8,7 +8,7 @@ namespace ImageSharp /// /// Rendering intent /// - internal enum IccRenderingIntent : uint + public enum IccRenderingIntent : uint { /// /// In perceptual transforms the PCS values represent hypothetical diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs index e4cd23800b..a42cc8cd11 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs @@ -8,7 +8,7 @@ namespace ImageSharp /// /// Type Signature /// - internal enum IccTypeSignature : uint + public enum IccTypeSignature : uint { /// /// Unknown type signature diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 5f131cfa19..b23c8b0689 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -14,7 +14,7 @@ namespace ImageSharp /// /// Represents an ICC profile /// - internal class IccProfile + public sealed class IccProfile { /// /// The byte array to read the ICC profile from diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs index af421f7eb7..8237dc7a82 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs @@ -11,7 +11,7 @@ namespace ImageSharp /// /// Contains all values of an ICC profile header /// - internal sealed class IccProfileHeader + public sealed class IccProfileHeader { /// /// Gets or sets the profile size in bytes (will be ignored when writing a profile) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs index 50ad5ded01..440ef14495 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs @@ -10,7 +10,7 @@ namespace ImageSharp /// /// The data of an ICC tag entry /// - internal abstract class IccTagDataEntry : IEquatable + public abstract class IccTagDataEntry : IEquatable { private IccProfileTag tagSignature = IccProfileTag.Unknown; @@ -45,8 +45,8 @@ namespace ImageSharp /// public IccProfileTag TagSignature { - get { return this.tagSignature; } - set { this.tagSignature = value; } + get => this.tagSignature; + set => this.tagSignature = value; } /// diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs b/src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs index 532b65564b..fc4760d3f1 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs @@ -10,7 +10,7 @@ namespace ImageSharp /// /// ICC Profile ID /// - internal struct IccProfileId : IEquatable + public struct IccProfileId : IEquatable { /// /// A profile ID with all values set to zero