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;