diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs
index 8d25904db..65484e15c 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs
@@ -153,5 +153,17 @@ namespace ImageSharp
pcs2: this.ReadUInt16(),
pcs3: this.ReadUInt16());
}
+
+ ///
+ /// Reads a screening channel
+ ///
+ /// the screening channel
+ public IccScreeningChannel ReadScreeningChannel()
+ {
+ return new IccScreeningChannel(
+ frequency: this.ReadFix16(),
+ angle: this.ReadFix16(),
+ spotShape: (IccScreeningSpotType)this.ReadInt32());
+ }
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
index 3fae2648b..d7842bece 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
@@ -83,10 +83,19 @@ namespace ImageSharp
case IccTypeSignature.Xyz:
return this.ReadXyzTagDataEntry(info.DataSize);
- // V2 Type:
+ // V2 Types:
case IccTypeSignature.TextDescription:
return this.ReadTextDescriptionTagDataEntry();
-
+ case IccTypeSignature.CrdInfo:
+ return this.ReadCrdInfoTagDataEntry();
+ case IccTypeSignature.Screening:
+ return this.ReadScreeningTagDataEntry();
+ case IccTypeSignature.UcrBg:
+ return this.ReadUcrBgTagDataEntry(info.DataSize);
+
+ // Unsupported or unknown
+ case IccTypeSignature.DeviceSettings:
+ case IccTypeSignature.NamedColor:
case IccTypeSignature.Unknown:
default:
return this.ReadUnknownTagDataEntry(info.DataSize);
@@ -790,5 +799,75 @@ namespace ImageSharp
unicodeLangCode,
scriptcodeCode);
}
+
+ ///
+ /// Reads a
+ ///
+ /// The read entry
+ public IccCrdInfoTagDataEntry ReadCrdInfoTagDataEntry()
+ {
+ uint productNameCount = this.ReadUInt32();
+ string productName = this.ReadAsciiString((int)productNameCount);
+
+ uint crd0Count = this.ReadUInt32();
+ string crd0Name = this.ReadAsciiString((int)crd0Count);
+
+ uint crd1Count = this.ReadUInt32();
+ string crd1Name = this.ReadAsciiString((int)crd1Count);
+
+ uint crd2Count = this.ReadUInt32();
+ string crd2Name = this.ReadAsciiString((int)crd2Count);
+
+ uint crd3Count = this.ReadUInt32();
+ string crd3Name = this.ReadAsciiString((int)crd3Count);
+
+ return new IccCrdInfoTagDataEntry(productName, crd0Name, crd1Name, crd2Name, crd3Name);
+ }
+
+ ///
+ /// Reads a
+ ///
+ /// The read entry
+ public IccScreeningTagDataEntry ReadScreeningTagDataEntry()
+ {
+ IccScreeningFlag flags = (IccScreeningFlag)this.ReadInt32();
+ uint channelCount = this.ReadUInt32();
+ IccScreeningChannel[] channels = new IccScreeningChannel[channelCount];
+ for (int i = 0; i < channels.Length; i++)
+ {
+ channels[i] = this.ReadScreeningChannel();
+ }
+
+ return new IccScreeningTagDataEntry(flags, channels);
+ }
+
+ ///
+ /// Reads a
+ ///
+ /// The size of the entry in bytes
+ /// The read entry
+ public IccUcrBgTagDataEntry ReadUcrBgTagDataEntry(uint size)
+ {
+ uint ucrCount = this.ReadUInt32();
+ ushort[] ucrCurve = new ushort[ucrCount];
+ for (int i = 0; i < ucrCurve.Length; i++)
+ {
+ ucrCurve[i] = this.ReadUInt16();
+ }
+
+ uint bgCount = this.ReadUInt32();
+ ushort[] bgCurve = new ushort[bgCount];
+ for (int i = 0; i < bgCurve.Length; i++)
+ {
+ bgCurve[i] = this.ReadUInt16();
+ }
+
+ // ((ucr length + bg length) * UInt16 size) + (ucrCount + bgCount)
+ uint dataSize = ((ucrCount + bgCount) * 2) + 8;
+ int descriptionLength = (int)(size - 8 - dataSize); // 8 is the tag header size
+ string description = this.ReadAsciiString(descriptionLength);
+
+ return new IccUcrBgTagDataEntry(ucrCurve, bgCurve, description);
+ }
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs
index f9c4eceea..544baa950 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs
@@ -119,5 +119,17 @@ namespace ImageSharp
+ this.WriteTagDataEntryHeader(IccTypeSignature.MultiLocalizedUnicode)
+ this.WriteMultiLocalizedUnicodeTagDataEntry(new IccMultiLocalizedUnicodeTagDataEntry(value.DeviceModelInfo));
}
+
+ ///
+ /// Writes a screening channel
+ ///
+ /// The value to write
+ /// the number of bytes written
+ public int WriteScreeningChannel(IccScreeningChannel value)
+ {
+ return this.WriteFix16(value.Frequency)
+ + this.WriteFix16(value.Angle)
+ + this.WriteInt32((int)value.SpotShape);
+ }
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs
index db5e818b0..717a80f6b 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs
@@ -121,11 +121,23 @@ namespace ImageSharp
count += this.WriteXyzTagDataEntry(entry as IccXyzTagDataEntry);
break;
- // V2 Type:
+ // V2 Types:
case IccTypeSignature.TextDescription:
count += this.WriteTextDescriptionTagDataEntry(entry as IccTextDescriptionTagDataEntry);
break;
+ case IccTypeSignature.CrdInfo:
+ count += this.WriteCrdInfoTagDataEntry(entry as IccCrdInfoTagDataEntry);
+ break;
+ case IccTypeSignature.Screening:
+ count += this.WriteScreeningTagDataEntry(entry as IccScreeningTagDataEntry);
+ break;
+ case IccTypeSignature.UcrBg:
+ count += this.WriteUcrBgTagDataEntry(entry as IccUcrBgTagDataEntry);
+ break;
+ // Unsupported or unknown
+ case IccTypeSignature.DeviceSettings:
+ case IccTypeSignature.NamedColor:
case IccTypeSignature.Unknown:
default:
count += this.WriteUnknownTagDataEntry(entry as IccUnknownTagDataEntry);
@@ -909,5 +921,83 @@ namespace ImageSharp
return count;
}
+
+ ///
+ /// Writes a
+ ///
+ /// The entry to write
+ /// The number of bytes written
+ public int WriteCrdInfoTagDataEntry(IccCrdInfoTagDataEntry value)
+ {
+ int count = 0;
+ WriteString(value.PostScriptProductName);
+ WriteString(value.RenderingIntent0Crd);
+ WriteString(value.RenderingIntent1Crd);
+ WriteString(value.RenderingIntent2Crd);
+ WriteString(value.RenderingIntent3Crd);
+
+ return count;
+
+ void WriteString(string text)
+ {
+ int textLength;
+ if (string.IsNullOrEmpty(text))
+ {
+ textLength = 0;
+ }
+ else
+ {
+ textLength = text.Length + 1; // + 1 for null terminator
+ }
+
+ count += this.WriteUInt32((uint)textLength);
+ count += this.WriteAsciiString(text, textLength, true);
+ }
+ }
+
+ ///
+ /// Writes a
+ ///
+ /// The entry to write
+ /// The number of bytes written
+ public int WriteScreeningTagDataEntry(IccScreeningTagDataEntry value)
+ {
+ int count = 0;
+
+ count += this.WriteInt32((int)value.Flags);
+ count += this.WriteUInt32((uint)value.Channels.Length);
+ for (int i = 0; i < value.Channels.Length; i++)
+ {
+ count += this.WriteScreeningChannel(value.Channels[i]);
+ }
+
+ return count;
+ }
+
+ ///
+ /// Writes a
+ ///
+ /// The entry to write
+ /// The number of bytes written
+ public int WriteUcrBgTagDataEntry(IccUcrBgTagDataEntry value)
+ {
+ int count = 0;
+
+ count += this.WriteUInt32((uint)value.UcrCurve.Length);
+ for (int i = 0; i < value.UcrCurve.Length; i++)
+ {
+ count += this.WriteUInt16(value.UcrCurve[i]);
+ }
+
+ count += this.WriteUInt32((uint)value.BgCurve.Length);
+ for (int i = 0; i < value.BgCurve.Length; i++)
+ {
+ count += this.WriteUInt16(value.BgCurve[i]);
+ }
+
+ count += this.WriteAsciiString(value.Description + '\0');
+
+ return count;
+ }
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningFlag.cs
new file mode 100644
index 000000000..2938d4469
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningFlag.cs
@@ -0,0 +1,41 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+
+ ///
+ /// Screening flags. Can be combined with a logical OR.
+ ///
+ [Flags]
+ internal enum IccScreeningFlag : int
+ {
+ ///
+ /// No flags (equivalent to NotDefaultScreens and UnitLinesPerCm)
+ ///
+ None = 0,
+
+ ///
+ /// Use printer default screens
+ ///
+ DefaultScreens = 1 << 0,
+
+ ///
+ /// Don't use printer default screens
+ ///
+ NotDefaultScreens = 0,
+
+ ///
+ /// Frequency units in Lines/Inch
+ ///
+ UnitLinesPerInch = 1 << 1,
+
+ ///
+ /// Frequency units in Lines/cm
+ ///
+ UnitLinesPerCm = 0,
+ }
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningSpotType.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningSpotType.cs
new file mode 100644
index 000000000..0d24c3ae5
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccScreeningSpotType.cs
@@ -0,0 +1,53 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ ///
+ /// Enumerates the screening spot types
+ ///
+ internal enum IccScreeningSpotType : int
+ {
+ ///
+ /// Unknown spot type
+ ///
+ Unknown = 0,
+
+ ///
+ /// Default printer spot type
+ ///
+ PrinterDefault = 1,
+
+ ///
+ /// Round stop type
+ ///
+ Round = 2,
+
+ ///
+ /// Diamond spot type
+ ///
+ Diamond = 3,
+
+ ///
+ /// Ellipse spot type
+ ///
+ Ellipse = 4,
+
+ ///
+ /// Line spot type
+ ///
+ Line = 5,
+
+ ///
+ /// Square spot type
+ ///
+ Square = 6,
+
+ ///
+ /// Cross spot type
+ ///
+ Cross = 7,
+ }
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
index 73c260a7a..e4cd23800 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
@@ -229,8 +229,8 @@ namespace ImageSharp
Xyz = 0x58595A20,
///
- /// The textDescriptionType is a complex structure that contains three types of
- /// text description structures: 7-bit ASCII, Unicode and ScriptCode. Since no
+ /// REMOVED IN V4 - The textDescriptionType is a complex structure that contains three
+ /// types of text description structures: 7-bit ASCII, Unicode and ScriptCode. Since no
/// single standard method for specifying localizable character sets exists across
/// the major platform vendors, including all three provides access for the major
/// operating systems. The 7-bit ASCII description is to be an invariant,
@@ -238,5 +238,36 @@ namespace ImageSharp
/// Unicode and ScriptCode structures be properly localized.
///
TextDescription = 0x64657363,
+
+ ///
+ /// REMOVED IN V4 - This type contains the PostScript product name to which this
+ /// profile corresponds and the names of the companion CRDs
+ ///
+ CrdInfo = 0x63726469,
+
+ ///
+ /// REMOVED IN V4 - The screeningType describes various screening parameters including
+ /// screen frequency, screening angle, and spot shape
+ ///
+ Screening = 0x7363726E,
+
+ ///
+ /// REMOVED IN V4 - This type contains curves representing the under color removal and
+ /// black generation and a text string which is a general description of the method
+ /// used for the UCR and BG
+ ///
+ UcrBg = 0x62666420,
+
+ ///
+ /// REMOVED IN V4 - This type is an array of structures each of which contains
+ /// platform-specific information about the settings of the device for which
+ /// this profile is valid. This type is not supported.
+ ///
+ DeviceSettings = 0x64657673, // not supported
+
+ ///
+ /// REMOVED IN V2 - use instead. This type is not supported.
+ ///
+ NamedColor = 0x6E636F6C, // not supported
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs
new file mode 100644
index 000000000..29edc78d0
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs
@@ -0,0 +1,111 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+
+ ///
+ /// This type contains the PostScript product name to which this profile
+ /// corresponds and the names of the companion CRDs
+ ///
+ internal sealed class IccCrdInfoTagDataEntry : IccTagDataEntry, IEquatable
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// the PostScript product name
+ /// the rendering intent 0 CRD name
+ /// the rendering intent 1 CRD name
+ /// the rendering intent 2 CRD name
+ /// the rendering intent 3 CRD name
+ public IccCrdInfoTagDataEntry(
+ string postScriptProductName,
+ string renderingIntent0Crd,
+ string renderingIntent1Crd,
+ string renderingIntent2Crd,
+ string renderingIntent3Crd)
+ : this(
+ postScriptProductName,
+ renderingIntent0Crd,
+ renderingIntent1Crd,
+ renderingIntent2Crd,
+ renderingIntent3Crd,
+ IccProfileTag.Unknown)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// the PostScript product name
+ /// the rendering intent 0 CRD name
+ /// the rendering intent 1 CRD name
+ /// the rendering intent 2 CRD name
+ /// the rendering intent 3 CRD name
+ /// Tag Signature
+ public IccCrdInfoTagDataEntry(
+ string postScriptProductName,
+ string renderingIntent0Crd,
+ string renderingIntent1Crd,
+ string renderingIntent2Crd,
+ string renderingIntent3Crd,
+ IccProfileTag tagSignature)
+ : base(IccTypeSignature.CrdInfo, tagSignature)
+ {
+ this.PostScriptProductName = postScriptProductName;
+ this.RenderingIntent0Crd = renderingIntent0Crd;
+ this.RenderingIntent1Crd = renderingIntent1Crd;
+ this.RenderingIntent2Crd = renderingIntent2Crd;
+ this.RenderingIntent3Crd = renderingIntent3Crd;
+ }
+
+ ///
+ /// Gets the PostScript product name
+ ///
+ public string PostScriptProductName { get; }
+
+ ///
+ /// Gets the rendering intent 0 CRD name
+ ///
+ public string RenderingIntent0Crd { get; }
+
+ ///
+ /// Gets the rendering intent 1 CRD name
+ ///
+ public string RenderingIntent1Crd { get; }
+
+ ///
+ /// Gets the rendering intent 2 CRD name
+ ///
+ public string RenderingIntent2Crd { get; }
+
+ ///
+ /// Gets the rendering intent 3 CRD name
+ ///
+ public string RenderingIntent3Crd { get; }
+
+ ///
+ public override bool Equals(IccTagDataEntry other)
+ {
+ if (base.Equals(other) && other is IccCrdInfoTagDataEntry entry)
+ {
+ return this.PostScriptProductName == entry.PostScriptProductName
+ && this.RenderingIntent0Crd == entry.RenderingIntent0Crd
+ && this.RenderingIntent1Crd == entry.RenderingIntent1Crd
+ && this.RenderingIntent2Crd == entry.RenderingIntent2Crd
+ && this.RenderingIntent3Crd == entry.RenderingIntent3Crd;
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(IccCrdInfoTagDataEntry other)
+ {
+ return this.Equals((IccTagDataEntry)other);
+ }
+ }
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs
new file mode 100644
index 000000000..166f74b37
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs
@@ -0,0 +1,70 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// This type describes various screening parameters including
+ /// screen frequency, screening angle, and spot shape.
+ ///
+ internal sealed class IccScreeningTagDataEntry : IccTagDataEntry, IEquatable
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Screening flags
+ /// Channel information
+ public IccScreeningTagDataEntry(IccScreeningFlag flags, IccScreeningChannel[] channels)
+ : this(flags, channels, IccProfileTag.Unknown)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Screening flags
+ /// Channel information
+ /// Tag Signature
+ public IccScreeningTagDataEntry(IccScreeningFlag flags, IccScreeningChannel[] channels, IccProfileTag tagSignature)
+ : base(IccTypeSignature.Screening, tagSignature)
+ {
+ Guard.NotNull(channels, nameof(channels));
+
+ this.Flags = flags;
+ this.Channels = channels;
+ }
+
+ ///
+ /// Gets the screening flags
+ ///
+ public IccScreeningFlag Flags { get; }
+
+ ///
+ /// Gets the channel information
+ ///
+ public IccScreeningChannel[] Channels { get; }
+
+ ///
+ public override bool Equals(IccTagDataEntry other)
+ {
+ if (base.Equals(other) && other is IccScreeningTagDataEntry entry)
+ {
+ return this.Flags == entry.Flags
+ && this.Channels.SequenceEqual(entry.Channels);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(IccScreeningTagDataEntry other)
+ {
+ return this.Equals((IccTagDataEntry)other);
+ }
+ }
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
new file mode 100644
index 000000000..b5de0f10a
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
@@ -0,0 +1,81 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// This type contains curves representing the under color removal and black generation
+ /// and a text string which is a general description of the method used for the UCR and BG.
+ ///
+ internal sealed class IccUcrBgTagDataEntry : IccTagDataEntry, IEquatable
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// UCR (under color removal) curve values
+ /// BG (black generation) curve values
+ /// Description of the used UCR and BG method
+ public IccUcrBgTagDataEntry(ushort[] ucrCurve, ushort[] bgCurve, string description)
+ : this(ucrCurve, bgCurve, description, IccProfileTag.Unknown)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// UCR (under color removal) curve values
+ /// BG (black generation) curve values
+ /// Description of the used UCR and BG method
+ /// Tag Signature
+ public IccUcrBgTagDataEntry(ushort[] ucrCurve, ushort[] bgCurve, string description, IccProfileTag tagSignature)
+ : base(IccTypeSignature.UcrBg, tagSignature)
+ {
+ Guard.NotNull(ucrCurve, nameof(ucrCurve));
+ Guard.NotNull(bgCurve, nameof(bgCurve));
+ Guard.NotNull(description, nameof(description));
+
+ this.UcrCurve = ucrCurve;
+ this.BgCurve = bgCurve;
+ this.Description = description;
+ }
+
+ ///
+ /// Gets the UCR (under color removal) curve values
+ ///
+ public ushort[] UcrCurve { get; }
+
+ ///
+ /// Gets the BG (black generation) curve values
+ ///
+ public ushort[] BgCurve { get; }
+
+ ///
+ /// Gets a description of the used UCR and BG method
+ ///
+ public string Description { get; }
+
+ ///
+ public override bool Equals(IccTagDataEntry other)
+ {
+ if (base.Equals(other) && other is IccUcrBgTagDataEntry entry)
+ {
+ return this.Description == entry.Description
+ && this.UcrCurve.SequenceEqual(entry.UcrCurve)
+ && this.BgCurve.SequenceEqual(entry.BgCurve);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(IccUcrBgTagDataEntry other)
+ {
+ return this.Equals((IccTagDataEntry)other);
+ }
+ }
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Various/IccScreeningChannel.cs b/src/ImageSharp/MetaData/Profiles/ICC/Various/IccScreeningChannel.cs
new file mode 100644
index 000000000..40eab6ef4
--- /dev/null
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Various/IccScreeningChannel.cs
@@ -0,0 +1,105 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+
+ ///
+ /// A single channel of a
+ ///
+ internal struct IccScreeningChannel : IEquatable
+ {
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Screen frequency
+ /// Angle in degrees
+ /// Spot shape
+ public IccScreeningChannel(float frequency, float angle, IccScreeningSpotType spotShape)
+ {
+ this.Frequency = frequency;
+ this.Angle = angle;
+ this.SpotShape = spotShape;
+ }
+
+ ///
+ /// Gets the screen frequency
+ ///
+ public float Frequency { get; }
+
+ ///
+ /// Gets the angle in degrees
+ ///
+ public float Angle { get; }
+
+ ///
+ /// Gets the spot shape
+ ///
+ public IccScreeningSpotType SpotShape { get; }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the parameter is equal to the parameter; otherwise, false.
+ ///
+ public static bool operator ==(IccScreeningChannel left, IccScreeningChannel right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
+ ///
+ /// True if the parameter is not equal to the parameter; otherwise, false.
+ ///
+ public static bool operator !=(IccScreeningChannel left, IccScreeningChannel right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ public override bool Equals(object other)
+ {
+ return (other is IccScreeningChannel) && this.Equals((IccScreeningChannel)other);
+ }
+
+ ///
+ public bool Equals(IccScreeningChannel other)
+ {
+ return this.Frequency == other.Frequency
+ && this.Angle == other.Angle
+ && this.SpotShape == other.SpotShape;
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = this.Frequency.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.Angle.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.SpotShape.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ ///
+ public override string ToString()
+ {
+ return $"{this.Frequency}Hz; {this.Angle}°; {this.SpotShape}";
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitivesTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitivesTests.cs
index 2c1113c38..3df131125 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitivesTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.NonPrimitivesTests.cs
@@ -110,6 +110,17 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(expected, output);
}
+ [Theory]
+ [MemberData(nameof(IccTestDataNonPrimitives.ScreeningChannelTestData), MemberType = typeof(IccTestDataNonPrimitives))]
+ internal void ReadScreeningChannel(byte[] data, IccScreeningChannel expected)
+ {
+ IccDataReader reader = CreateReader(data);
+
+ IccScreeningChannel output = reader.ReadScreeningChannel();
+
+ Assert.Equal(expected, output);
+ }
+
private IccDataReader CreateReader(byte[] data)
{
return new IccDataReader(data);
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs
index fe628c1ad..35920139b 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs
@@ -339,6 +339,39 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(expected, output);
}
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.CrdInfoTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void ReadCrdInfoTagDataEntry(byte[] data, IccCrdInfoTagDataEntry expected)
+ {
+ IccDataReader reader = CreateReader(data);
+
+ IccCrdInfoTagDataEntry output = reader.ReadCrdInfoTagDataEntry();
+
+ Assert.Equal(expected, output);
+ }
+
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.ScreeningTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void ReadScreeningTagDataEntry(byte[] data, IccScreeningTagDataEntry expected)
+ {
+ IccDataReader reader = CreateReader(data);
+
+ IccScreeningTagDataEntry output = reader.ReadScreeningTagDataEntry();
+
+ Assert.Equal(expected, output);
+ }
+
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.UcrBgTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void ReadUcrBgTagDataEntry(byte[] data, IccUcrBgTagDataEntry expected, uint size)
+ {
+ IccDataReader reader = CreateReader(data);
+
+ IccUcrBgTagDataEntry output = reader.ReadUcrBgTagDataEntry(size);
+
+ Assert.Equal(expected, output);
+ }
+
private IccDataReader CreateReader(byte[] data)
{
return new IccDataReader(data);
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitivesTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitivesTests.cs
index ae3ab748b..f4e316070 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitivesTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitivesTests.cs
@@ -107,6 +107,18 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(expected, output);
}
+ [Theory]
+ [MemberData(nameof(IccTestDataNonPrimitives.ScreeningChannelTestData), MemberType = typeof(IccTestDataNonPrimitives))]
+ internal void WriteScreeningChannel(byte[] expected, IccScreeningChannel data)
+ {
+ IccDataWriter writer = CreateWriter();
+
+ writer.WriteScreeningChannel(data);
+ byte[] output = writer.GetData();
+
+ Assert.Equal(expected, output);
+ }
+
private IccDataWriter CreateWriter()
{
return new IccDataWriter();
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs
index 8c953a0aa..b00235682 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs
@@ -369,6 +369,42 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(expected, output);
}
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.CrdInfoTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void WriteCrdInfoTagDataEntry(byte[] expected, IccCrdInfoTagDataEntry data)
+ {
+ IccDataWriter writer = CreateWriter();
+
+ writer.WriteCrdInfoTagDataEntry(data);
+ byte[] output = writer.GetData();
+
+ Assert.Equal(expected, output);
+ }
+
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.ScreeningTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void WriteScreeningTagDataEntry(byte[] expected, IccScreeningTagDataEntry data)
+ {
+ IccDataWriter writer = CreateWriter();
+
+ writer.WriteScreeningTagDataEntry(data);
+ byte[] output = writer.GetData();
+
+ Assert.Equal(expected, output);
+ }
+
+ [Theory]
+ [MemberData(nameof(IccTestDataTagDataEntry.UcrBgTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))]
+ internal void WriteUcrBgTagDataEntry(byte[] expected, IccUcrBgTagDataEntry data, uint size)
+ {
+ IccDataWriter writer = CreateWriter();
+
+ writer.WriteUcrBgTagDataEntry(data);
+ byte[] output = writer.GetData();
+
+ Assert.Equal(expected, output);
+ }
+
private IccDataWriter CreateWriter()
{
return new IccDataWriter();
diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs
index da5f6c9d7..e9bdc39be 100644
--- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs
+++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs
@@ -330,5 +330,32 @@
};
#endregion
+
+ #region ScreeningChannel
+
+ public static readonly IccScreeningChannel ScreeningChannel_ValRand1 = new IccScreeningChannel(4, 6, IccScreeningSpotType.Cross);
+ public static readonly IccScreeningChannel ScreeningChannel_ValRand2 = new IccScreeningChannel(8, 5, IccScreeningSpotType.Diamond);
+
+ public static readonly byte[] ScreeningChannel_Rand1 = ArrayHelper.Concat
+ (
+ IccTestDataPrimitives.Fix16_4,
+ IccTestDataPrimitives.Fix16_6,
+ IccTestDataPrimitives.Int32_7
+ );
+
+ public static readonly byte[] ScreeningChannel_Rand2 = ArrayHelper.Concat
+ (
+ IccTestDataPrimitives.Fix16_8,
+ IccTestDataPrimitives.Fix16_5,
+ IccTestDataPrimitives.Int32_3
+ );
+
+ public static readonly object[][] ScreeningChannelTestData =
+ {
+ new object[] { ScreeningChannel_Rand1, ScreeningChannel_ValRand1 },
+ new object[] { ScreeningChannel_Rand2, ScreeningChannel_ValRand2 },
+ };
+
+ #endregion
}
}
diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs
index 8b69646f3..fcfa2d0d7 100644
--- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs
+++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs
@@ -245,10 +245,18 @@ namespace ImageSharp.Tests
#region ASCII String
public const string Ascii_ValRand = "aBcdEf1234";
+ public const string Ascii_ValRand1 = "Ecf3a";
+ public const string Ascii_ValRand2 = "2Bd4c";
+ public const string Ascii_ValRand3 = "cad14";
+ public const string Ascii_ValRand4 = "fd4E1";
public const string Ascii_ValRandLength4 = "aBcd";
public const string Ascii_ValNullRand = "aBcd\0Ef\0123";
public static readonly byte[] Ascii_Rand = { 97, 66, 99, 100, 69, 102, 49, 50, 51, 52 };
+ public static readonly byte[] Ascii_Rand1 = { 69, 99, 102, 51, 97 };
+ public static readonly byte[] Ascii_Rand2 = { 50, 66, 100, 52, 99 };
+ public static readonly byte[] Ascii_Rand3 = { 99, 97, 100, 49, 52 };
+ public static readonly byte[] Ascii_Rand4 = { 102, 100, 52, 69, 49 };
public static readonly byte[] Ascii_RandLength4 = { 97, 66, 99, 100 };
public static readonly byte[] Ascii_PaddedRand = { 97, 66, 99, 100, 69, 102, 49, 50, 51, 52, 0, 0, 0, 0 };
public static readonly byte[] Ascii_NullRand = { 97, 66, 99, 100, 0, 69, 102, 0, 49, 50, 51 };
diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs
index 6863ce719..caff1b31b 100644
--- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs
+++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs
@@ -872,6 +872,97 @@ namespace ImageSharp.Tests
#endregion
+ #region CrdInfoTagDataEntry
+
+ public static readonly IccCrdInfoTagDataEntry CrdInfo_Val = new IccCrdInfoTagDataEntry(
+ IccTestDataPrimitives.Ascii_ValRand4,
+ IccTestDataPrimitives.Ascii_ValRand1,
+ IccTestDataPrimitives.Ascii_ValRand2,
+ IccTestDataPrimitives.Ascii_ValRand3,
+ IccTestDataPrimitives.Ascii_ValRand4
+ );
+ public static readonly byte[] CrdInfo_Arr = ArrayHelper.Concat
+ (
+ IccTestDataPrimitives.UInt32_6,
+ IccTestDataPrimitives.Ascii_Rand4,
+ new byte[] { 0 },
+ IccTestDataPrimitives.UInt32_6,
+ IccTestDataPrimitives.Ascii_Rand1,
+ new byte[] { 0 },
+ IccTestDataPrimitives.UInt32_6,
+ IccTestDataPrimitives.Ascii_Rand2,
+ new byte[] { 0 },
+ IccTestDataPrimitives.UInt32_6,
+ IccTestDataPrimitives.Ascii_Rand3,
+ new byte[] { 0 },
+ IccTestDataPrimitives.UInt32_6,
+ IccTestDataPrimitives.Ascii_Rand4,
+ new byte[] { 0 }
+ );
+
+ public static readonly object[][] CrdInfoTagDataEntryTestData =
+ {
+ new object[] { CrdInfo_Arr, CrdInfo_Val },
+ };
+
+ #endregion
+
+ #region ScreeningTagDataEntry
+
+ public static readonly IccScreeningTagDataEntry Screening_Val = new IccScreeningTagDataEntry(
+ IccScreeningFlag.DefaultScreens | IccScreeningFlag.UnitLinesPerCm,
+ new IccScreeningChannel[]
+ {
+ IccTestDataNonPrimitives.ScreeningChannel_ValRand1,
+ IccTestDataNonPrimitives.ScreeningChannel_ValRand2,
+ }
+ );
+ public static readonly byte[] Screening_Arr = ArrayHelper.Concat
+ (
+ IccTestDataPrimitives.Int32_1,
+ IccTestDataPrimitives.UInt32_2,
+ IccTestDataNonPrimitives.ScreeningChannel_Rand1,
+ IccTestDataNonPrimitives.ScreeningChannel_Rand2
+ );
+
+ public static readonly object[][] ScreeningTagDataEntryTestData =
+ {
+ new object[] { Screening_Arr, Screening_Val },
+ };
+
+ #endregion
+
+ #region UcrBgTagDataEntry
+
+ public static readonly IccUcrBgTagDataEntry UcrBg_Val = new IccUcrBgTagDataEntry(
+ new ushort[] { 3, 4, 6 },
+ new ushort[] { 9, 7, 2, 5 },
+ IccTestDataPrimitives.Ascii_ValRand
+ );
+ public static readonly byte[] UcrBg_Arr = ArrayHelper.Concat
+ (
+ IccTestDataPrimitives.UInt32_3,
+ IccTestDataPrimitives.UInt16_3,
+ IccTestDataPrimitives.UInt16_4,
+ IccTestDataPrimitives.UInt16_6,
+
+ IccTestDataPrimitives.UInt32_4,
+ IccTestDataPrimitives.UInt16_9,
+ IccTestDataPrimitives.UInt16_7,
+ IccTestDataPrimitives.UInt16_2,
+ IccTestDataPrimitives.UInt16_5,
+
+ IccTestDataPrimitives.Ascii_Rand,
+ new byte[] { 0 }
+ );
+
+ public static readonly object[][] UcrBgTagDataEntryTestData =
+ {
+ new object[] { UcrBg_Arr, UcrBg_Val, 41 },
+ };
+
+ #endregion
+
#region TagDataEntry
public static readonly IccTagDataEntry TagDataEntry_CurveVal = Curve_Val_2;