Browse Source

initial version for reading and writing ICC profiles

af/merge-core
Johannes Bildstein 9 years ago
parent
commit
4152134a97
  1. 40
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccCurveSegment.cs
  2. 84
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccFormulaCurveElement.cs
  3. 55
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccOneDimensionalCurve.cs
  4. 147
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs
  5. 82
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs
  6. 39
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccSampledCurveElement.cs
  7. 28
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccClutDataType.cs
  8. 138
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs
  9. 38
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorantEncoding.cs
  10. 62
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs
  11. 23
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccCurveSegmentSignature.cs
  12. 2
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDataType.cs
  13. 56
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs
  14. 28
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccMeasurementGeometry.cs
  15. 38
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs
  16. 38
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs
  17. 21
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs
  18. 24
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileConversionMethod.cs
  19. 26
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs
  20. 39
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs
  21. 18
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs
  22. 82
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccSignatureName.cs
  23. 58
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccStandardIlluminant.cs
  24. 28
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccStandardObserver.cs
  25. 112
      src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
  26. 42
      src/ImageSharp/MetaData/Profiles/ICC/Exceptions/InvalidIccProfileException.cs
  27. 1727
      src/ImageSharp/MetaData/Profiles/ICC/IccDataReader.cs
  28. 2003
      src/ImageSharp/MetaData/Profiles/ICC/IccDataWriter.cs
  29. 107
      src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
  30. 103
      src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs
  31. 113
      src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
  32. 68
      src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs
  33. 106
      src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
  34. 23
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs
  35. 40
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs
  36. 42
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs
  37. 23
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs
  38. 71
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs
  39. 64
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs
  40. 136
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs
  41. 55
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs
  42. 56
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs
  43. 122
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs
  44. 92
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
  45. 51
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs
  46. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs
  47. 153
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs
  48. 156
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs
  49. 274
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs
  50. 274
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs
  51. 89
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs
  52. 53
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs
  53. 72
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs
  54. 137
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs
  55. 50
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs
  56. 54
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs
  57. 53
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs
  58. 66
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs
  59. 51
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs
  60. 85
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs
  61. 50
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs
  62. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs
  63. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs
  64. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs
  65. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs
  66. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs
  67. 52
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs
  68. 69
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs
  69. 53
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs
  70. 175
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccClut.cs
  71. 125
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccColorantTableEntry.cs
  72. 69
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccLocalizedString.cs
  73. 81
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccLut.cs
  74. 110
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccNamedColor.cs
  75. 91
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccPositionNumber.cs
  76. 90
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileDescription.cs
  77. 138
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs
  78. 51
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs
  79. 96
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccResponseNumber.cs
  80. 105
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccTagTableEntry.cs

40
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccCurveSegment.cs

@ -0,0 +1,40 @@
namespace ImageSharp
{
using System;
/// <summary>
/// A segment of a curve
/// </summary>
internal abstract class IccCurveSegment : IEquatable<IccCurveSegment>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveSegment"/> class.
/// </summary>
/// <param name="signature">The signature of this segment</param>
protected IccCurveSegment(IccCurveSegmentSignature signature)
{
this.Signature = signature;
}
/// <summary>
/// Gets the signature of this segment
/// </summary>
public IccCurveSegmentSignature Signature { get; }
/// <inheritdoc/>
public virtual bool Equals(IccCurveSegment other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.Signature == other.Signature;
}
}
}

84
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccFormulaCurveElement.cs

@ -0,0 +1,84 @@
namespace ImageSharp
{
/// <summary>
/// A formula based curve segment
/// </summary>
internal sealed class IccFormulaCurveElement : IccCurveSegment
{
/// <summary>
/// Initializes a new instance of the <see cref="IccFormulaCurveElement"/> class.
/// </summary>
/// <param name="type">The type of this segment (0-2)</param>
/// <param name="gamma">Gamma segment parameter</param>
/// <param name="a">A segment parameter</param>
/// <param name="b">B segment parameter</param>
/// <param name="c">C segment parameter</param>
/// <param name="d">D segment parameter</param>
/// <param name="e">E segment parameter</param>
public IccFormulaCurveElement(ushort type, double gamma, double a, double b, double c, double d, double e)
: base(IccCurveSegmentSignature.FormulaCurve)
{
Guard.MustBeBetweenOrEqualTo(type, 0, 2, nameof(type));
this.Type = type;
this.Gamma = gamma;
this.A = a;
this.B = b;
this.C = c;
this.D = d;
this.E = e;
}
/// <summary>
/// Gets the type of this curve
/// </summary>
public ushort Type { get; }
/// <summary>
/// Gets the gamma curve parameter
/// </summary>
public double Gamma { get; }
/// <summary>
/// Gets the A curve parameter
/// </summary>
public double A { get; }
/// <summary>
/// Gets the B curve parameter
/// </summary>
public double B { get; }
/// <summary>
/// Gets the C curve parameter
/// </summary>
public double C { get; }
/// <summary>
/// Gets the D curve parameter
/// </summary>
public double D { get; }
/// <summary>
/// Gets the E curve parameter
/// </summary>
public double E { get; }
/// <inheritdoc />
public override bool Equals(IccCurveSegment other)
{
if (base.Equals(other) && other is IccFormulaCurveElement segment)
{
return this.Type == segment.Type
&& this.Gamma == segment.Gamma
&& this.A == segment.A
&& this.B == segment.B
&& this.C == segment.C
&& this.D == segment.D
&& this.E == segment.E;
}
return false;
}
}
}

55
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccOneDimensionalCurve.cs

@ -0,0 +1,55 @@
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// A one dimensional curve
/// </summary>
internal sealed class IccOneDimensionalCurve : IEquatable<IccOneDimensionalCurve>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccOneDimensionalCurve"/> class.
/// </summary>
/// <param name="breakPoints">The break points of this curve</param>
/// <param name="segments">The segments of this curve</param>
public IccOneDimensionalCurve(float[] breakPoints, IccCurveSegment[] segments)
{
Guard.NotNull(breakPoints, nameof(breakPoints));
Guard.NotNull(segments, nameof(segments));
bool isWrongSize = breakPoints.Length != segments.Length - 1;
Guard.IsTrue(isWrongSize, $"{nameof(breakPoints)},{nameof(segments)}", "Number of BreakPoints must be one less than number of Segments");
this.BreakPoints = breakPoints;
this.Segments = segments;
}
/// <summary>
/// Gets the breakpoints that separate two curve segments
/// </summary>
public float[] BreakPoints { get; }
/// <summary>
/// Gets an array of curve segments
/// </summary>
public IccCurveSegment[] Segments { get; }
/// <inheritdoc />
public bool Equals(IccOneDimensionalCurve other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.BreakPoints.SequenceEqual(other.BreakPoints)
&& this.Segments.SequenceEqual(other.Segments);
}
}
}

147
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs

@ -0,0 +1,147 @@
namespace ImageSharp
{
using System;
/// <summary>
/// A parametric curve
/// </summary>
internal sealed class IccParametricCurve : IEquatable<IccParametricCurve>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurve"/> class.
/// </summary>
/// <param name="g">G curve parameter</param>
public IccParametricCurve(double g)
: this(0, g, 0, 0, 0, 0, 0, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurve"/> class.
/// </summary>
/// <param name="g">G curve parameter</param>
/// <param name="a">A curve parameter</param>
/// <param name="b">B curve parameter</param>
public IccParametricCurve(double g, double a, double b)
: this(1, g, a, b, 0, 0, 0, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurve"/> class.
/// </summary>
/// <param name="g">G curve parameter</param>
/// <param name="a">A curve parameter</param>
/// <param name="b">B curve parameter</param>
/// <param name="c">C curve parameter</param>
public IccParametricCurve(double g, double a, double b, double c)
: this(2, g, a, b, c, 0, 0, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurve"/> class.
/// </summary>
/// <param name="g">G curve parameter</param>
/// <param name="a">A curve parameter</param>
/// <param name="b">B curve parameter</param>
/// <param name="c">C curve parameter</param>
/// <param name="d">D curve parameter</param>
public IccParametricCurve(double g, double a, double b, double c, double d)
: this(3, g, a, b, c, d, 0, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurve"/> class.
/// </summary>
/// <param name="g">G curve parameter</param>
/// <param name="a">A curve parameter</param>
/// <param name="b">B curve parameter</param>
/// <param name="c">C curve parameter</param>
/// <param name="d">D curve parameter</param>
/// <param name="e">E curve parameter</param>
/// <param name="f">F curve parameter</param>
public IccParametricCurve(double g, double a, double b, double c, double d, double e, double f)
: this(4, g, a, b, c, d, e, f)
{
}
private IccParametricCurve(ushort type, double g, double a, double b, double c, double d, double e, double f)
{
Guard.MustBeBetweenOrEqualTo(type, 0, 4, nameof(type));
this.Type = type;
this.G = g;
this.A = a;
this.B = b;
this.C = c;
this.D = d;
this.E = e;
this.F = f;
}
/// <summary>
/// Gets the type of this curve
/// </summary>
public ushort Type { get; }
/// <summary>
/// Gets the G curve parameter
/// </summary>
public double G { get; }
/// <summary>
/// Gets the A curve parameter
/// </summary>
public double A { get; }
/// <summary>
/// Gets the B curve parameter
/// </summary>
public double B { get; }
/// <summary>
/// Gets the C curve parameter
/// </summary>
public double C { get; }
/// <summary>
/// Gets the D curve parameter
/// </summary>
public double D { get; }
/// <summary>
/// Gets the E curve parameter
/// </summary>
public double E { get; }
/// <summary>
/// Gets the F curve parameter
/// </summary>
public double F { get; }
/// <inheritdoc/>
public bool Equals(IccParametricCurve other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.Type == other.Type
&& this.G == other.G
&& this.A == other.A
&& this.B == other.B
&& this.C == other.C
&& this.D == other.D
&& this.E == other.E
&& this.F == other.F;
}
}
}

82
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs

@ -0,0 +1,82 @@
namespace ImageSharp
{
using System;
using System.Linq;
using System.Numerics;
/// <summary>
/// A response curve
/// </summary>
internal sealed class IccResponseCurve : IEquatable<IccResponseCurve>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccResponseCurve"/> class.
/// </summary>
/// <param name="curveType">The type of this curve</param>
/// <param name="xyzValues">The XYZ values</param>
/// <param name="responseArrays">The response arrays</param>
public IccResponseCurve(IccCurveMeasurementEncodings curveType, Vector3[] xyzValues, IccResponseNumber[][] responseArrays)
{
Guard.NotNull(xyzValues, nameof(xyzValues));
Guard.NotNull(responseArrays, nameof(responseArrays));
Guard.IsTrue(xyzValues.Length != responseArrays.Length, $"{nameof(xyzValues)},{nameof(responseArrays)}", "Arrays must have same length");
Guard.MustBeBetweenOrEqualTo(xyzValues.Length, 1, 15, nameof(xyzValues));
this.CurveType = curveType;
this.XyzValues = xyzValues;
this.ResponseArrays = responseArrays;
}
/// <summary>
/// Gets the type of this curve
/// </summary>
public IccCurveMeasurementEncodings CurveType { get; }
/// <summary>
/// Gets the XYZ values
/// </summary>
public Vector3[] XyzValues { get; }
/// <summary>
/// Gets the response arrays
/// </summary>
public IccResponseNumber[][] ResponseArrays { get; }
/// <inheritdoc/>
public bool Equals(IccResponseCurve other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.CurveType == other.CurveType
&& this.XyzValues.SequenceEqual(other.XyzValues)
&& this.EqualsResponseArray(other);
}
private bool EqualsResponseArray(IccResponseCurve other)
{
if (this.ResponseArrays.Length != other.ResponseArrays.Length)
{
return false;
}
for (int i = 0; i < this.ResponseArrays.Length; i++)
{
if (!this.ResponseArrays[i].SequenceEqual(other.ResponseArrays[i]))
{
return false;
}
}
return true;
}
}
}

39
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccSampledCurveElement.cs

@ -0,0 +1,39 @@
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// A sampled curve segment
/// </summary>
internal sealed class IccSampledCurveElement : IccCurveSegment
{
/// <summary>
/// Initializes a new instance of the <see cref="IccSampledCurveElement"/> class.
/// </summary>
/// <param name="curveEntries">The curve values of this segment</param>
public IccSampledCurveElement(float[] curveEntries)
: base(IccCurveSegmentSignature.SampledCurve)
{
Guard.NotNull(curveEntries, nameof(curveEntries));
Guard.IsTrue(curveEntries.Length < 1, nameof(curveEntries), "There must be at least one value");
this.CurveEntries = curveEntries;
}
/// <summary>
/// Gets the curve values of this segment
/// </summary>
public float[] CurveEntries { get; }
/// <inheritdoc />
public override bool Equals(IccCurveSegment other)
{
if (base.Equals(other) && other is IccSampledCurveElement segment)
{
return this.CurveEntries.SequenceEqual(segment.CurveEntries);
}
return false;
}
}
}

28
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccClutDataType.cs

@ -0,0 +1,28 @@
// <copyright file="IccClutDataType.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Color lookup table data type
/// </summary>
internal enum IccClutDataType
{
/// <summary>
/// 32bit floating point
/// </summary>
Float,
/// <summary>
/// 8bit unsigned integer (byte)
/// </summary>
UInt8,
/// <summary>
/// 16bit unsigned integer (ushort)
/// </summary>
UInt16,
}
}

138
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorSpaceType.cs

@ -0,0 +1,138 @@
// <copyright file="IccColorSpaceType.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Color Space Type
/// </summary>
internal enum IccColorSpaceType : uint
{
/// <summary>
/// CIE XYZ
/// </summary>
CieXyz = 0x58595A20, // XYZ
/// <summary>
/// CIE Lab
/// </summary>
CieLab = 0x4C616220, // Lab
/// <summary>
/// CIE Luv
/// </summary>
CieLuv = 0x4C757620, // Luv
/// <summary>
/// YCbCr
/// </summary>
YCbCr = 0x59436272, // YCbr
/// <summary>
/// CIE Yxy
/// </summary>
CieYxy = 0x59787920, // Yxy
/// <summary>
/// RGB
/// </summary>
Rgb = 0x52474220, // RGB
/// <summary>
/// Gray
/// </summary>
Gray = 0x47524159, // GRAY
/// <summary>
/// HSV
/// </summary>
Hsv = 0x48535620, // HSV
/// <summary>
/// HLS
/// </summary>
Hls = 0x484C5320, // HLS
/// <summary>
/// CMYK
/// </summary>
Cmyk = 0x434D594B, // CMYK
/// <summary>
/// CMY
/// </summary>
Cmy = 0x434D5920, // CMY
/// <summary>
/// Generic 2 channel color
/// </summary>
Color2 = 0x32434C52, // 2CLR
/// <summary>
/// Generic 3 channel color
/// </summary>
Color3 = 0x33434C52, // 3CLR
/// <summary>
/// Generic 4 channel color
/// </summary>
Color4 = 0x34434C52, // 4CLR
/// <summary>
/// Generic 5 channel color
/// </summary>
Color5 = 0x35434C52, // 5CLR
/// <summary>
/// Generic 6 channel color
/// </summary>
Color6 = 0x36434C52, // 6CLR
/// <summary>
/// Generic 7 channel color
/// </summary>
Color7 = 0x37434C52, // 7CLR
/// <summary>
/// Generic 8 channel color
/// </summary>
Color8 = 0x38434C52, // 8CLR
/// <summary>
/// Generic 9 channel color
/// </summary>
Color9 = 0x39434C52, // 9CLR
/// <summary>
/// Generic 10 channel color
/// </summary>
Color10 = 0x41434C52, // ACLR
/// <summary>
/// Generic 11 channel color
/// </summary>
Color11 = 0x42434C52, // BCLR
/// <summary>
/// Generic 12 channel color
/// </summary>
Color12 = 0x43434C52, // CCLR
/// <summary>
/// Generic 13 channel color
/// </summary>
Color13 = 0x44434C52, // DCLR
/// <summary>
/// Generic 14 channel color
/// </summary>
Color14 = 0x45434C52, // ECLR
/// <summary>
/// Generic 15 channel color
/// </summary>
Color15 = 0x46434C52, // FCLR
}
}

38
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccColorantEncoding.cs

@ -0,0 +1,38 @@
// <copyright file="IccColorantEncoding.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Colorant Encoding
/// </summary>
internal enum IccColorantEncoding : ushort
{
/// <summary>
/// Unknown colorant encoding
/// </summary>
Unknown = 0x0000,
/// <summary>
/// ITU-R BT.709-2 colorant encoding
/// </summary>
ITU_R_BT_709_2 = 0x0001,
/// <summary>
/// SMPTE RP145 colorant encoding
/// </summary>
SMPTE_RP145 = 0x0002,
/// <summary>
/// EBU Tech.3213-E colorant encoding
/// </summary>
EBU_Tech_3213_E = 0x0003,
/// <summary>
/// P22 colorant encoding
/// </summary>
P22 = 0x0004,
}
}

62
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs

@ -0,0 +1,62 @@
// <copyright file="IccCurveMeasurementEncodings.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Curve Measurement Encodings
/// </summary>
internal enum IccCurveMeasurementEncodings : uint
{
/// <summary>
/// ISO 5-3 densitometer response. This is the accepted standard for
/// reflection densitometers for measuring photographic color prints
/// </summary>
StatusA = 0x53746141, // StaA
/// <summary>
/// ISO 5-3 densitometer response which is the accepted standard in
/// Europe for color reflection densitometers
/// </summary>
StatusE = 0x53746145, // StaE
/// <summary>
/// ISO 5-3 densitometer response commonly referred to as narrow band
/// or interference-type response.
/// </summary>
StatusI = 0x53746149, // StaI
/// <summary>
/// ISO 5-3 wide band color reflection densitometer response which is
/// the accepted standard in the United States for color reflection densitometers
/// </summary>
StatusT = 0x53746154, // StaT
/// <summary>
/// ISO 5-3 densitometer response for measuring color negatives
/// </summary>
StatusM = 0x5374614D, // StaM
/// <summary>
/// DIN 16536-2 densitometer response, with no polarizing filter
/// </summary>
DinE = 0x434E2020, // DN
/// <summary>
/// DIN 16536-2 densitometer response, with polarizing filter
/// </summary>
DinE_pol = 0x434E2050, // DNP
/// <summary>
/// DIN 16536-2 narrow band densitometer response, with no polarizing filter
/// </summary>
DinI = 0x434E4E20, // DNN
/// <summary>
/// DIN 16536-2 narrow band densitometer response, with polarizing filter
/// </summary>
DinI_pol = 0x434E4E50, // DNNP
}
}

23
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccCurveSegmentSignature.cs

@ -0,0 +1,23 @@
// <copyright file="IccCurveSegmentSignature.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Curve Segment Signature
/// </summary>
internal enum IccCurveSegmentSignature : uint
{
/// <summary>
/// Curve defined by a formula
/// </summary>
FormulaCurve = 0x70617266, // parf
/// <summary>
/// Curve defined by multiple segments
/// </summary>
SampledCurve = 0x73616D66, // samf
}
}

2
src/ImageSharp/MetaData/Profiles/ICC/IccDataType.cs → src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDataType.cs

@ -9,7 +9,7 @@ namespace ImageSharp
/// Enumerates the basic data types as defined in ICC.1:2010 version 4.3.0.0
/// <see href="http://www.color.org/specification/ICC1v43_2010-12.pdf"/> Section 4.2 to 4.15
/// </summary>
public enum IccDataType
internal enum IccDataType
{
/// <summary>
/// A 12-byte value representation of the time and date

56
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccDeviceAttribute.cs

@ -0,0 +1,56 @@
// <copyright file="IccDeviceAttribute.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Device attributes. Can be combined with a logical OR
/// </summary>
[Flags]
internal enum IccDeviceAttribute : long
{
/// <summary>
/// Opacity transparent
/// </summary>
OpacityTransparent = 1 << 31,
/// <summary>
/// Opacity reflective
/// </summary>
OpacityReflective = 0,
/// <summary>
/// Reflectivity matte
/// </summary>
ReflectivityMatte = 1 << 30,
/// <summary>
/// Reflectivity glossy
/// </summary>
ReflectivityGlossy = 0,
/// <summary>
/// Polarity negative
/// </summary>
PolarityNegative = 1 << 29,
/// <summary>
/// Polarity positive
/// </summary>
PolarityPositive = 0,
/// <summary>
/// Chroma black and white
/// </summary>
ChromaBlackWhite = 1 << 28,
/// <summary>
/// Chroma color
/// </summary>
ChromaColor = 0,
}
}

28
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccMeasurementGeometry.cs

@ -0,0 +1,28 @@
// <copyright file="IccMeasurementGeometry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Measurement Geometry
/// </summary>
internal enum IccMeasurementGeometry : uint
{
/// <summary>
/// Unknown geometry
/// </summary>
Unknown = 0,
/// <summary>
/// Geometry of 0°:45° or 45°:0°
/// </summary>
MG_0_45_45_0 = 1,
/// <summary>
/// Geometry of 0°:d or d:0°
/// </summary>
MG_0d_d0 = 2,
}
}

38
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs

@ -0,0 +1,38 @@
// <copyright file="IccMultiProcessElementSignature.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Multi process element signature
/// </summary>
internal enum IccMultiProcessElementSignature : uint
{
/// <summary>
/// Set of curves
/// </summary>
CurveSet = 0x6D666C74, // cvst
/// <summary>
/// Matrix transformation
/// </summary>
Matrix = 0x6D617466, // matf
/// <summary>
/// Color lookup table
/// </summary>
Clut = 0x636C7574, // clut
/// <summary>
/// Reserved for future expansion. Do not use!
/// </summary>
BAcs = 0x62414353, // bACS
/// <summary>
/// Reserved for future expansion. Do not use!
/// </summary>
EAcs = 0x65414353, // eACS
}
}

38
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccPrimaryPlatformType.cs

@ -0,0 +1,38 @@
// <copyright file="IccPrimaryPlatformType.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Enumerates the primary platform/operating system framework for which the profile was created
/// </summary>
internal enum IccPrimaryPlatformType : uint
{
/// <summary>
/// No platform identified
/// </summary>
NotIdentified = 0x00000000,
/// <summary>
/// Apple Computer, Inc.
/// </summary>
AppleComputerInc = 0x4150504C, // APPL
/// <summary>
/// Microsoft Corporation
/// </summary>
MicrosoftCorporation = 0x4D534654, // MSFT
/// <summary>
/// Silicon Graphics, Inc.
/// </summary>
SiliconGraphicsInc = 0x53474920, // SGI
/// <summary>
/// Sun Microsystems, Inc.
/// </summary>
SunMicrosystemsInc = 0x53554E57, // SUNW
}
}

21
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs

@ -0,0 +1,21 @@
// <copyright file="IccProfileClass.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Profile Class Name
/// </summary>
internal enum IccProfileClass : uint
{
InputDevice = 0x73636E72, // scnr
DisplayDevice = 0x6D6E7472, // mntr
OutputDevice = 0x70727472, // prtr
DeviceLink = 0x6C696E6B, // link
ColorSpace = 0x73706163, // spac
Abstract = 0x61627374, // abst
NamedColor = 0x6E6D636C, // nmcl
}
}

24
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileConversionMethod.cs

@ -0,0 +1,24 @@
// <copyright file="IccProfileConversionMethod.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Profile Conversion Method
/// </summary>
internal enum IccProfileConversionMethod
{
Invalid,
D0,
D1,
D2,
D3,
A0,
A1,
A2,
ColorTRC,
GrayTRC,
}
}

26
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs

@ -0,0 +1,26 @@
// <copyright file="IccProfileFlag.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Profile flags. Can be combined with a logical OR
/// </summary>
[Flags]
internal enum IccProfileFlag : int
{
/// <summary>
/// Profile is embedded within another file
/// </summary>
Embedded = 1 << 31,
/// <summary>
/// Profile cannot be used independently of the embedded colour data
/// </summary>
Independent = 1 << 30,
}
}

39
src/ImageSharp/MetaData/Profiles/ICC/IccProfileTag.cs → src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs

@ -12,8 +12,13 @@ namespace ImageSharp
/// Each tag value represent the size of the tag in the profile.
/// </remarks>
/// </summary>
public enum IccProfileTag
internal enum IccProfileTag : uint
{
/// <summary>
/// Unknown tag
/// </summary>
Unknown,
/// <summary>
/// A2B0 - This tag defines a colour transform from Device, Colour Encoding or PCS, to PCS, or a colour transform
/// from Device 1 to Device 2, using lookup table tag element structures
@ -162,32 +167,32 @@ namespace ImageSharp
DeviceSettings = 0x64657673,
/// <summary>
/// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB0 tag
/// </summary>
DToB0 = 0x44324230,
/// <summary>
/// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
/// </summary>
DToB1 = 0x44324230,
/// <summary>
/// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
/// </summary>
DToB2 = 0x44324230,
/// <summary>
/// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
/// </summary>
DToB3 = 0x44324230,
/// <summary>
/// gamt - This tag provides a table in which PCS values are the input and a single
/// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut.
/// gamt - This tag provides a table in which PCS values are the input and a single
/// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut.
/// If the output is non-zero, the PCS colour is out-of-gamut
/// </summary>
Gamut = 0x67616D74,
@ -204,18 +209,18 @@ namespace ImageSharp
GreenMatrixColumn = 0x6758595A,
/// <summary>
/// gTRC - This tag contains the green channel tone reproduction curve. The first element represents no
/// colorant (white) or phosphor (black) and the last element represents 100 % colorant (green) or 100 % phosphor (green).
/// gTRC - This tag contains the green channel tone reproduction curve. The first element represents no
/// colorant (white) or phosphor (black) and the last element represents 100 % colorant (green) or 100 % phosphor (green).
/// </summary>
GreenTRC = 0x67545243,
/// <summary>
/// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel.
/// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel.
/// </summary>
Luminance = 0x6C756d69,
/// <summary>
/// meas - This tag describes the alternative measurement specification, such as a D65 illuminant instead of the default D50.
/// meas - This tag describes the alternative measurement specification, such as a D65 illuminant instead of the default D50.
/// </summary>
Measurement = 0x6D656173,
@ -237,19 +242,19 @@ namespace ImageSharp
/// <summary>
/// ncl2 - This tag contains the named colour information providing a PCS and optional device representation
/// for a list of named colours.
/// for a list of named colours.
/// </summary>
NamedColor2 = 0x6E636C32,
/// <summary>
/// resp - This tag describes the structure containing a description of the device response for which the profile is intended.
/// resp - This tag describes the structure containing a description of the device response for which the profile is intended.
/// </summary>
OutputResponse = 0x72657370,
/// <summary>
/// rig0 - There is only one standard reference medium gamut, as defined in ISO 12640-3
/// </summary>
PerceptualRenderingIntentGamut = 0x72696730, /* 'rig0' */
PerceptualRenderingIntentGamut = 0x72696730,
/// <summary>
/// pre0 - This tag contains the preview transformation from PCS to device space and back to the PCS.
@ -309,7 +314,7 @@ namespace ImageSharp
Ps2RenderingIntent = 0x70733269,
/// <summary>
/// rXYZ - This tag contains the first column in the matrix, which is used in matrix/TRC transforms.
/// rXYZ - This tag contains the first column in the matrix, which is used in matrix/TRC transforms.
/// </summary>
RedMatrixColumn = 0x7258595A,
@ -345,8 +350,8 @@ namespace ImageSharp
UcrBg = 0x62666420,
/// <summary>
/// vued - This tag describes the structure containing invariant and localizable
/// versions of the viewing conditions.
/// vued - This tag describes the structure containing invariant and localizable
/// versions of the viewing conditions.
/// </summary>
ViewingCondDesc = 0x76756564,

18
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs

@ -0,0 +1,18 @@
// <copyright file="IccRenderingIntent.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Rendering intent
/// </summary>
internal enum IccRenderingIntent : uint
{
Perceptual = 0,
MediaRelativeColorimetric = 1,
Saturation = 2,
AbsoluteColorimetric = 3,
}
}

82
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccSignatureName.cs

@ -0,0 +1,82 @@
// <copyright file="IccSignatureName.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Signature Name
/// </summary>
internal enum IccSignatureName : uint
{
/// <summary>
/// Unknown signature
/// </summary>
Unknown = 0,
SceneColorimetryEstimates = 0x73636F65, // scoe
SceneAppearanceEstimates = 0x73617065, // sape
FocalPlaneColorimetryEstimates = 0x66706365, // fpce
ReflectionHardcopyOriginalColorimetry = 0x72686F63, // rhoc
ReflectionPrintOutputColorimetry = 0x72706F63, // rpoc
PerceptualReferenceMediumGamut = 0x70726D67, // prmg
FilmScanner = 0x6673636E, // fscn
DigitalCamera = 0x6463616D, // dcam
ReflectiveScanner = 0x7273636E, // rscn
InkJetPrinter = 0x696A6574, // ijet
ThermalWaxPrinter = 0x74776178, // twax
ElectrophotographicPrinter = 0x6570686F, // epho
ElectrostaticPrinter = 0x65737461, // esta
DyeSublimationPrinter = 0x64737562, // dsub
PhotographicPaperPrinter = 0x7270686F, // rpho
FilmWriter = 0x6670726E, // fprn
VideoMonitor = 0x7669646D, // vidm
VideoCamera = 0x76696463, // vidc
ProjectionTelevision = 0x706A7476, // pjtv
CathodeRayTubeDisplay = 0x43525420, // CRT
PassiveMatrixDisplay = 0x504D4420, // PMD
ActiveMatrixDisplay = 0x414D4420, // AMD
PhotoCD = 0x4B504344, // KPCD
PhotographicImageSetter = 0x696D6773, // imgs
Gravure = 0x67726176, // grav
OffsetLithography = 0x6F666673, // offs
Silkscreen = 0x73696C6B, // silk
Flexography = 0x666C6578, // flex
MotionPictureFilmScanner = 0x6D706673, // mpfs
MotionPictureFilmRecorder = 0x6D706672, // mpfr
DigitalMotionPictureCamera = 0x646D7063, // dmpc
DigitalCinemaProjector = 0x64636A70, // dcpj
}
}

58
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccStandardIlluminant.cs

@ -0,0 +1,58 @@
// <copyright file="IccStandardIlluminant.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Standard Illuminant
/// </summary>
internal enum IccStandardIlluminant : uint
{
/// <summary>
/// Unknown illuminant
/// </summary>
Unknown = 0,
/// <summary>
/// D50 illuminant
/// </summary>
D50 = 1,
/// <summary>
/// D65 illuminant
/// </summary>
D65 = 2,
/// <summary>
/// D93 illuminant
/// </summary>
D93 = 3,
/// <summary>
/// F2 illuminant
/// </summary>
F2 = 4,
/// <summary>
/// D55 illuminant
/// </summary>
D55 = 5,
/// <summary>
/// A illuminant
/// </summary>
A = 6,
/// <summary>
/// D50 illuminant
/// </summary>
EquiPowerE = 7,
/// <summary>
/// F8 illuminant
/// </summary>
F8 = 8,
}
}

28
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccStandardObserver.cs

@ -0,0 +1,28 @@
// <copyright file="IccStandardObserver.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Standard Observer
/// </summary>
internal enum IccStandardObserver : uint
{
/// <summary>
/// Unknown observer
/// </summary>
Unkown = 0,
/// <summary>
/// CIE 1931 observer
/// </summary>
CIE1931Observer = 1,
/// <summary>
/// CIE 1964 observer
/// </summary>
CIE1964Observer = 2,
}
}

112
src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs

@ -0,0 +1,112 @@
// <copyright file="IccTypeSignature.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Type Signature
/// </summary>
internal enum IccTypeSignature : uint
{
/// <summary>
/// Unknown type signature
/// </summary>
Unknown,
Chromaticity = 0x6368726D,
ColorantOrder = 0x636c726f,
ColorantTable = 0x636c7274,
Curve = 0x63757276,
Data = 0x64617461,
/// <summary>
/// Date and time defined by 6 unsigned 16bit integers (year, month, day, hour, minute, second)
/// </summary>
DateTime = 0x6474696D,
/// <summary>
/// Lookup table with 16bit unsigned integers (ushort)
/// </summary>
Lut16 = 0x6D667432,
/// <summary>
/// Lookup table with 8bit unsigned integers (byte)
/// </summary>
Lut8 = 0x6D667431,
LutAToB = 0x6D414220,
LutBToA = 0x6D424120,
Measurement = 0x6D656173,
/// <summary>
/// Unicode text in one or more languages
/// </summary>
MultiLocalizedUnicode = 0x6D6C7563,
MultiProcessElements = 0x6D706574,
NamedColor2 = 0x6E636C32,
ParametricCurve = 0x70617261,
ProfileSequenceDesc = 0x70736571,
ProfileSequenceIdentifier = 0x70736964,
ResponseCurveSet16 = 0x72637332,
/// <summary>
/// Array of signed floating point numbers with 1 sign bit, 15 value bits and 16 fractional bits
/// </summary>
S15Fixed16Array = 0x73663332,
Signature = 0x73696720,
/// <summary>
/// Simple ASCII text
/// </summary>
Text = 0x74657874,
/// <summary>
/// Array of unsigned floating point numbers with 16 value bits and 16 fractional bits
/// </summary>
U16Fixed16Array = 0x75663332,
/// <summary>
/// Array of unsigned 16bit integers (ushort)
/// </summary>
UInt16Array = 0x75693136,
/// <summary>
/// Array of unsigned 32bit integers (uint)
/// </summary>
UInt32Array = 0x75693332,
/// <summary>
/// Array of unsigned 64bit integers (ulong)
/// </summary>
UInt64Array = 0x75693634,
/// <summary>
/// Array of unsigned 8bit integers (byte)
/// </summary>
UInt8Array = 0x75693038,
ViewingConditions = 0x76696577,
/// <summary>
/// 3 floating point values describing a XYZ color value
/// </summary>
Xyz = 0x58595A20,
TextDescription = 0x64657363,
}
}

42
src/ImageSharp/MetaData/Profiles/ICC/Exceptions/InvalidIccProfileException.cs

@ -0,0 +1,42 @@
// <copyright file="InvalidIccProfileException.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Represents an error that happened while reading or writing a corrupt/invalid ICC profile
/// </summary>
public class InvalidIccProfileException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="InvalidIccProfileException"/> class.
/// </summary>
public InvalidIccProfileException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="InvalidIccProfileException"/> class.
/// </summary>
/// <param name="message">The message that describes the error</param>
public InvalidIccProfileException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="InvalidIccProfileException"/> class.
/// </summary>
/// <param name="message">The message that describes the error</param>
/// <param name="inner">The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified</param>
public InvalidIccProfileException(string message, Exception inner)
: base(message, inner)
{
}
}
}

1727
src/ImageSharp/MetaData/Profiles/ICC/IccDataReader.cs

File diff suppressed because it is too large

2003
src/ImageSharp/MetaData/Profiles/ICC/IccDataWriter.cs

File diff suppressed because it is too large

107
src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs

@ -0,0 +1,107 @@
// <copyright file="IccProfile.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Collections.Generic;
#if !NETSTANDARD1_1
using System;
using System.Security.Cryptography;
#endif
/// <summary>
/// Represents an ICC profile
/// </summary>
internal class IccProfile
{
/// <summary>
/// The byte array to read the ICC profile from
/// </summary>
private readonly byte[] data;
/// <summary>
/// The backing file for the <see cref="Entries"/> property
/// </summary>
private readonly List<IccTagDataEntry> entries;
/// <summary>
/// ICC profile header
/// </summary>
private readonly IccProfileHeader header;
/// <summary>
/// Initializes a new instance of the <see cref="IccProfile"/> class.
/// </summary>
public IccProfile()
{
this.data = null;
this.entries = new List<IccTagDataEntry>();
this.header = new IccProfileHeader();
}
/// <summary>
/// Initializes a new instance of the <see cref="IccProfile"/> class.
/// </summary>
/// <param name="data">The raw ICC profile data</param>
public IccProfile(byte[] data)
{
Guard.NotNull(data, nameof(data));
this.data = data;
IccReader reader = new IccReader();
this.header = reader.ReadHeader(data);
this.entries = new List<IccTagDataEntry>(reader.ReadTagData(data));
}
/// <summary>
/// Gets the profile header
/// </summary>
public IccProfileHeader Header
{
get { return this.header; }
}
/// <summary>
/// Gets the actual profile data
/// </summary>
public List<IccTagDataEntry> Entries
{
get { return this.entries; }
}
#if !NETSTANDARD1_1
/// <summary>
/// Calculates the MD5 hash value of an ICC profile header
/// </summary>
/// <param name="data">The data of which to calculate the hash value</param>
/// <returns>The calculated hash</returns>
public static IccProfileId CalculateHash(byte[] data)
{
Guard.NotNull(data, nameof(data));
Guard.IsTrue(data.Length < 128, nameof(data), "Data length must be at least 128 to be a valid profile header");
byte[] header = new byte[128];
Buffer.BlockCopy(data, 0, header, 0, 128);
using (MD5 md5 = MD5.Create())
{
// Zero out some values
Array.Clear(header, 44, 4); // Profile flags
Array.Clear(header, 64, 4); // Rendering Intent
Array.Clear(header, 84, 16); // Profile ID
// Calculate hash
byte[] hash = md5.ComputeHash(data);
// Read values from hash
IccDataReader reader = new IccDataReader(hash);
return reader.ReadProfileId();
}
}
#endif
}
}

103
src/ImageSharp/MetaData/Profiles/ICC/IccProfileHeader.cs

@ -0,0 +1,103 @@
// <copyright file="IccProfileHeader.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
/// <summary>
/// Contains all values of an ICC profile header
/// </summary>
internal sealed class IccProfileHeader
{
/// <summary>
/// Gets or sets the profile size in bytes (will be ignored when writing a profile)
/// </summary>
public uint Size { get; set; }
/// <summary>
/// Gets or sets the preferred CMM (Color Management Module) type
/// </summary>
public string CmmType { get; set; }
/// <summary>
/// Gets or sets the profiles version number
/// </summary>
public Version Version { get; set; }
/// <summary>
/// Gets or sets the type of the profile
/// </summary>
public IccProfileClass Class { get; set; }
/// <summary>
/// Gets or sets the data colorspace
/// </summary>
public IccColorSpaceType DataColorSpace { get; set; }
/// <summary>
/// Gets or sets the profile connection space
/// </summary>
public IccColorSpaceType ProfileConnectionSpace { get; set; }
/// <summary>
/// Gets or sets the date and time this profile was created
/// </summary>
public DateTime CreationDate { get; set; }
/// <summary>
/// Gets or sets the file signature. Should always be "acsp".
/// Value will be ignored when writing a profile.
/// </summary>
public string FileSignature { get; set; }
/// <summary>
/// Gets or sets the primary platform this profile as created for
/// </summary>
public IccPrimaryPlatformType PrimaryPlatformSignature { get; set; }
/// <summary>
/// Gets or sets the profile flags to indicate various options for the CMM
/// such as distributed processing and caching options
/// </summary>
public IccProfileFlag Flags { get; set; }
/// <summary>
/// Gets or sets the device manufacturer of the device for which this profile is created
/// </summary>
public uint DeviceManufacturer { get; set; }
/// <summary>
/// Gets or sets the model of the device for which this profile is created
/// </summary>
public uint DeviceModel { get; set; }
/// <summary>
/// Gets or sets the device attributes unique to the particular device setup such as media type
/// </summary>
public IccDeviceAttribute DeviceAttributes { get; set; }
/// <summary>
/// Gets or sets the rendering Intent
/// </summary>
public IccRenderingIntent RenderingIntent { get; set; }
/// <summary>
/// Gets or sets The normalized XYZ values of the illuminant of the PCS
/// </summary>
public Vector3 PcsIlluminant { get; set; }
/// <summary>
/// Gets or sets Profile creator signature
/// </summary>
public string CreatorSignature { get; set; }
/// <summary>
/// Gets or sets the profile ID (hash)
/// </summary>
public IccProfileId Id { get; set; }
}
}

113
src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs

@ -0,0 +1,113 @@
// <copyright file="IccReader.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Reads and parses ICC data from a byte array
/// </summary>
internal sealed class IccReader
{
/// <summary>
/// Reads an ICC profile
/// </summary>
/// <param name="data">The raw ICC data</param>
/// <returns>The read ICC profile</returns>
public IccProfile Read(byte[] data)
{
Guard.IsTrue(data.Length < 128, nameof(data), "Data length must be at least 128 to be a valid ICC profile");
IccDataReader reader = new IccDataReader(data);
IccProfileHeader header = this.ReadHeader(reader);
IccTagDataEntry[] tagDate = this.ReadTagData(reader);
return new IccProfile();
}
/// <summary>
/// Reads an ICC profile header
/// </summary>
/// <param name="data">The raw ICC data</param>
/// <returns>The read ICC profile header</returns>
public IccProfileHeader ReadHeader(byte[] data)
{
Guard.IsTrue(data.Length < 128, nameof(data), "Data length must be at least 128 to be a valid profile header");
IccDataReader reader = new IccDataReader(data);
return this.ReadHeader(reader);
}
/// <summary>
/// Reads the ICC profile tag data
/// </summary>
/// <param name="data">The raw ICC data</param>
/// <returns>The read ICC profile tag data</returns>
public IccTagDataEntry[] ReadTagData(byte[] data)
{
Guard.IsTrue(data.Length < 128, nameof(data), "Data length must be at least 128 to be a valid ICC profile");
IccDataReader reader = new IccDataReader(data);
return this.ReadTagData(reader);
}
private IccProfileHeader ReadHeader(IccDataReader reader)
{
reader.SetIndex(0);
return new IccProfileHeader
{
Size = reader.ReadUInt32(),
CmmType = reader.ReadASCIIString(4),
Version = reader.ReadVersionNumber(),
Class = (IccProfileClass)reader.ReadUInt32(),
DataColorSpace = (IccColorSpaceType)reader.ReadUInt32(),
ProfileConnectionSpace = (IccColorSpaceType)reader.ReadUInt32(),
CreationDate = reader.ReadDateTime(),
FileSignature = reader.ReadASCIIString(4),
PrimaryPlatformSignature = (IccPrimaryPlatformType)reader.ReadUInt32(),
Flags = (IccProfileFlag)reader.ReadDirect32(),
DeviceManufacturer = reader.ReadUInt32(),
DeviceModel = reader.ReadUInt32(),
DeviceAttributes = (IccDeviceAttribute)reader.ReadDirect64(),
RenderingIntent = (IccRenderingIntent)reader.ReadUInt32(),
PcsIlluminant = reader.ReadXyzNumber(),
CreatorSignature = reader.ReadASCIIString(4),
Id = reader.ReadProfileId(),
};
}
private IccTagDataEntry[] ReadTagData(IccDataReader reader)
{
IccTagTableEntry[] tagTable = this.ReadTagTable(reader);
IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length];
for (int i = 0; i < tagTable.Length; i++)
{
IccTagDataEntry entry = reader.ReadTagDataEntry(tagTable[i]);
entry.TagSignature = tagTable[i].Signature;
entries[i] = entry;
}
return entries;
}
private IccTagTableEntry[] ReadTagTable(IccDataReader reader)
{
reader.SetIndex(128); // An ICC header is 128 bytes long
uint tagCount = reader.ReadUInt32();
IccTagTableEntry[] table = new IccTagTableEntry[tagCount];
for (int i = 0; i < tagCount; i++)
{
uint tagSignature = reader.ReadUInt32();
uint tagOffset = reader.ReadUInt32();
uint tagSize = reader.ReadUInt32();
table[i] = new IccTagTableEntry((IccProfileTag)tagSignature, tagOffset, tagSize);
}
return table;
}
}
}

68
src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs

@ -0,0 +1,68 @@
// <copyright file="IccTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// The data of an ICC tag entry
/// </summary>
internal abstract class IccTagDataEntry : IEquatable<IccTagDataEntry>
{
private IccProfileTag tagSignature = IccProfileTag.Unknown;
/// <summary>
/// Initializes a new instance of the <see cref="IccTagDataEntry"/> class.
/// TagSignature will be <see cref="IccProfileTag.Unknown"/>
/// </summary>
/// <param name="signature">Type Signature</param>
protected IccTagDataEntry(IccTypeSignature signature)
: this(signature, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccTagDataEntry"/> class.
/// </summary>
/// <param name="signature">Type Signature</param>
/// <param name="tagSignature">Tag Signature</param>
protected IccTagDataEntry(IccTypeSignature signature, IccProfileTag tagSignature)
{
this.Signature = signature;
this.tagSignature = tagSignature;
}
/// <summary>
/// Gets the type Signature
/// </summary>
public IccTypeSignature Signature { get; }
/// <summary>
/// Gets or sets the tag Signature
/// </summary>
public IccProfileTag TagSignature
{
get { return this.tagSignature; }
set { this.tagSignature = value; }
}
/// <inheritdoc/>
public virtual bool Equals(IccTagDataEntry other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.Signature == other.Signature;
}
}
}

106
src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs

@ -0,0 +1,106 @@
// <copyright file="IccWriter.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Contains methods for writing ICC profiles.
/// </summary>
internal sealed class IccWriter
{
/// <summary>
/// Writes the ICC profile into a byte array
/// </summary>
/// <param name="profile">The ICC profile to write</param>
/// <returns>The ICC profile as a byte array</returns>
public byte[] Write(IccProfile profile)
{
IccDataWriter writer = new IccDataWriter();
IccTagTableEntry[] tagTable = this.WriteTagData(writer, profile.Entries);
this.WriteTagTable(writer, tagTable);
this.WriteHeader(writer, profile.Header);
return writer.GetData();
}
private void WriteHeader(IccDataWriter writer, IccProfileHeader header)
{
writer.SetIndex(0);
writer.WriteUInt32(writer.Length + 128);
writer.WriteASCIIString(header.CmmType, 4, ' ');
writer.WriteVersionNumber(header.Version);
writer.WriteUInt32((uint)header.Class);
writer.WriteUInt32((uint)header.DataColorSpace);
writer.WriteUInt32((uint)header.ProfileConnectionSpace);
writer.WriteDateTime(header.CreationDate);
writer.WriteASCIIString("acsp");
writer.WriteUInt32((uint)header.PrimaryPlatformSignature);
writer.WriteDirect32((int)header.Flags);
writer.WriteUInt32(header.DeviceManufacturer);
writer.WriteUInt32(header.DeviceModel);
writer.WriteDirect64((long)header.DeviceAttributes);
writer.WriteUInt32((uint)header.RenderingIntent);
writer.WriteXYZNumber(header.PcsIlluminant);
writer.WriteASCIIString(header.CreatorSignature, 4, ' ');
#if !NETSTANDARD1_1
IccProfileId id = IccProfile.CalculateHash(writer.GetData());
writer.WriteProfileId(id);
#else
writer.WriteProfileId(IccProfileId.Zero);
#endif
}
private void WriteTagTable(IccDataWriter writer, IccTagTableEntry[] table)
{
// 128 = size of ICC header
writer.SetIndex(128);
writer.WriteUInt32((uint)table.Length);
foreach (IccTagTableEntry entry in table)
{
writer.WriteUInt32((uint)entry.Signature);
writer.WriteUInt32(entry.Offset);
writer.WriteUInt32(entry.DataSize);
}
}
private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List<IccTagDataEntry> entries)
{
List<IccTagDataEntry> inData = new List<IccTagDataEntry>(entries);
List<IccTagDataEntry[]> dupData = new List<IccTagDataEntry[]>();
// Filter out duplicate entries. They only need to be defined once but can be used multiple times
while (inData.Count > 0)
{
IccTagDataEntry[] items = inData.Where(t => inData[0].Equals(t)).ToArray();
dupData.Add(items);
foreach (IccTagDataEntry item in items)
{
inData.Remove(item);
}
}
List<IccTagTableEntry> table = new List<IccTagTableEntry>();
// (Header size) + (entry count) + (nr of entries) * (size of table entry)
writer.SetIndex(128 + 4 + (entries.Count * 12));
foreach (IccTagDataEntry[] entry in dupData)
{
writer.WriteTagDataEntry(entry[0], out IccTagTableEntry tentry);
foreach (IccTagDataEntry item in entry)
{
table.Add(new IccTagTableEntry(item.TagSignature, tentry.Offset, tentry.DataSize));
}
}
return table.ToArray();
}
}
}

23
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs

@ -0,0 +1,23 @@
// <copyright file="IccBAcsProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// A placeholder <see cref="IccMultiProcessElement"/> (might be used for future ICC versions)
/// </summary>
internal sealed class IccBAcsProcessElement : IccMultiProcessElement
{
/// <summary>
/// Initializes a new instance of the <see cref="IccBAcsProcessElement"/> class.
/// </summary>
/// <param name="inChannelCount">Number of input channels</param>
/// <param name="outChannelCount">Number of output channels</param>
public IccBAcsProcessElement(int inChannelCount, int outChannelCount)
: base(IccMultiProcessElementSignature.BAcs, inChannelCount, outChannelCount)
{
}
}
}

40
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs

@ -0,0 +1,40 @@
// <copyright file="IccClutProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// A CLUT (color lookup table) element to process data
/// </summary>
internal sealed class IccClutProcessElement : IccMultiProcessElement
{
/// <summary>
/// Initializes a new instance of the <see cref="IccClutProcessElement"/> class.
/// </summary>
/// <param name="clutValue">The color lookup table of this element</param>
public IccClutProcessElement(IccClut clutValue)
: base(IccMultiProcessElementSignature.Clut, clutValue?.InputChannelCount ?? 1, clutValue?.OutputChannelCount ?? 1)
{
Guard.NotNull(clutValue, nameof(clutValue));
this.ClutValue = clutValue;
}
/// <summary>
/// Gets the color lookup table of this element
/// </summary>
public IccClut ClutValue { get; }
/// <inheritdoc />
public override bool Equals(IccMultiProcessElement other)
{
if (base.Equals(other) && other is IccClutProcessElement element)
{
return this.ClutValue.Equals(element.ClutValue);
}
return false;
}
}
}

42
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs

@ -0,0 +1,42 @@
// <copyright file="IccCurveSetProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// A set of curves to process data
/// </summary>
internal sealed class IccCurveSetProcessElement : IccMultiProcessElement
{
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveSetProcessElement"/> class.
/// </summary>
/// <param name="curves">An array with one dimensional curves</param>
public IccCurveSetProcessElement(IccOneDimensionalCurve[] curves)
: base(IccMultiProcessElementSignature.CurveSet, curves?.Length ?? 1, curves?.Length ?? 1)
{
Guard.NotNull(curves, nameof(curves));
this.Curves = curves;
}
/// <summary>
/// Gets an array of one dimensional curves
/// </summary>
public IccOneDimensionalCurve[] Curves { get; }
/// <inheritdoc />
public override bool Equals(IccMultiProcessElement other)
{
if (base.Equals(other) && other is IccCurveSetProcessElement element)
{
return this.Curves.SequenceEqual(element.Curves);
}
return false;
}
}
}

23
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs

@ -0,0 +1,23 @@
// <copyright file="IccEAcsProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// A placeholder <see cref="IccMultiProcessElement"/> (might be used for future ICC versions)
/// </summary>
internal sealed class IccEAcsProcessElement : IccMultiProcessElement
{
/// <summary>
/// Initializes a new instance of the <see cref="IccEAcsProcessElement"/> class.
/// </summary>
/// <param name="inChannelCount">Number of input channels</param>
/// <param name="outChannelCount">Number of output channels</param>
public IccEAcsProcessElement(int inChannelCount, int outChannelCount)
: base(IccMultiProcessElementSignature.EAcs, inChannelCount, outChannelCount)
{
}
}
}

71
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs

@ -0,0 +1,71 @@
// <copyright file="IccMatrixProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// A matrix element to process data
/// </summary>
internal sealed class IccMatrixProcessElement : IccMultiProcessElement
{
/// <summary>
/// Initializes a new instance of the <see cref="IccMatrixProcessElement"/> class.
/// </summary>
/// <param name="matrixIxO">Two dimensional matrix with size of Input-Channels x Output-Channels</param>
/// <param name="matrixOx1">One dimensional matrix with size of Output-Channels x 1</param>
public IccMatrixProcessElement(float[,] matrixIxO, float[] matrixOx1)
: base(IccMultiProcessElementSignature.Matrix, matrixIxO?.GetLength(0) ?? 1, matrixIxO?.GetLength(1) ?? 1)
{
Guard.NotNull(matrixIxO, nameof(matrixIxO));
Guard.NotNull(matrixOx1, nameof(matrixOx1));
bool wrongMatrixSize = matrixIxO.GetLength(1) != matrixOx1.Length;
Guard.IsTrue(wrongMatrixSize, $"{nameof(matrixIxO)},{nameof(matrixIxO)}", "Output channel length must match");
this.MatrixIxO = matrixIxO;
this.MatrixOx1 = matrixOx1;
}
/// <summary>
/// Gets the two dimensional matrix with size of Input-Channels x Output-Channels
/// </summary>
public Fast2DArray<float> MatrixIxO { get; }
/// <summary>
/// Gets the one dimensional matrix with size of Output-Channels x 1
/// </summary>
public float[] MatrixOx1 { get; }
/// <inheritdoc />
public override bool Equals(IccMultiProcessElement other)
{
if (base.Equals(other) && other is IccMatrixProcessElement element)
{
return this.EqualsMatrix(element)
&& this.MatrixOx1.SequenceEqual(element.MatrixOx1);
}
return false;
}
private bool EqualsMatrix(IccMatrixProcessElement element)
{
for (int x = 0; x < this.MatrixIxO.Width; x++)
{
for (int y = 0; y < this.MatrixIxO.Height; y++)
{
if (this.MatrixIxO[x, y] != element.MatrixIxO[x, y])
{
return false;
}
}
}
return true;
}
}
}

64
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs

@ -0,0 +1,64 @@
// <copyright file="IccMultiProcessElement.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// An element to process data
/// </summary>
internal abstract class IccMultiProcessElement : IEquatable<IccMultiProcessElement>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccMultiProcessElement"/> class.
/// </summary>
/// <param name="signature">The signature of this element</param>
/// <param name="inChannelCount">Number of input channels</param>
/// <param name="outChannelCount">Number of output channels</param>
protected IccMultiProcessElement(IccMultiProcessElementSignature signature, int inChannelCount, int outChannelCount)
{
Guard.MustBeBetweenOrEqualTo(inChannelCount, 1, 15, nameof(inChannelCount));
Guard.MustBeBetweenOrEqualTo(outChannelCount, 1, 15, nameof(outChannelCount));
this.Signature = signature;
this.InputChannelCount = inChannelCount;
this.OutputChannelCount = outChannelCount;
}
/// <summary>
/// Gets the signature of this element
/// </summary>
public IccMultiProcessElementSignature Signature { get; }
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount { get; }
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount { get; }
/// <inheritdoc/>
public virtual bool Equals(IccMultiProcessElement other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.Signature == other.Signature
&& this.InputChannelCount == other.InputChannelCount
&& this.OutputChannelCount == other.OutputChannelCount;
}
}
}

136
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs

@ -0,0 +1,136 @@
// <copyright file="IccChromaticityTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// The chromaticity tag type provides basic chromaticity data
/// and type of phosphors or colorants of a monitor to applications and utilities.
/// </summary>
internal sealed class IccChromaticityTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccChromaticityTagDataEntry"/> class.
/// </summary>
/// <param name="colorantType">Colorant Type</param>
public IccChromaticityTagDataEntry(IccColorantEncoding colorantType)
: this(colorantType, GetColorantArray(colorantType), IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccChromaticityTagDataEntry"/> class.
/// </summary>
/// <param name="channelValues">Values per channel</param>
public IccChromaticityTagDataEntry(double[][] channelValues)
: this(IccColorantEncoding.Unknown, channelValues, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccChromaticityTagDataEntry"/> class.
/// </summary>
/// <param name="colorantType">Colorant Type</param>
/// <param name="tagSignature">Tag Signature</param>
public IccChromaticityTagDataEntry(IccColorantEncoding colorantType, IccProfileTag tagSignature)
: this(colorantType, GetColorantArray(colorantType), tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccChromaticityTagDataEntry"/> class.
/// </summary>
/// <param name="channelValues">Values per channel</param>
/// <param name="tagSignature">Tag Signature</param>
public IccChromaticityTagDataEntry(double[][] channelValues, IccProfileTag tagSignature)
: this(IccColorantEncoding.Unknown, channelValues, tagSignature)
{
}
private IccChromaticityTagDataEntry(IccColorantEncoding colorantType, double[][] channelValues, IccProfileTag tagSignature)
: base(IccTypeSignature.Chromaticity, tagSignature)
{
Guard.NotNull(channelValues, nameof(channelValues));
Guard.MustBeBetweenOrEqualTo(channelValues.Length, 1, 15, nameof(channelValues));
this.ColorantType = colorantType;
this.ChannelValues = channelValues;
int channelLength = channelValues[0].Length;
bool channelsNotSame = channelValues.Any(t => t == null || t.Length != channelLength);
Guard.IsTrue(channelsNotSame, nameof(channelValues), "The number of values per channel is not the same for all channels");
}
/// <summary>
/// Gets the number of channels
/// </summary>
public int ChannelCount
{
get { return this.ChannelValues.Length; }
}
/// <summary>
/// Gets the colorant type
/// </summary>
public IccColorantEncoding ColorantType { get; }
/// <summary>
/// Gets the values per channel
/// </summary>
public double[][] ChannelValues { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccChromaticityTagDataEntry entry)
{
return this.ColorantType == entry.ColorantType
&& this.ChannelValues.SequenceEqual(entry.ChannelValues);
}
return false;
}
private static double[][] GetColorantArray(IccColorantEncoding colorantType)
{
switch (colorantType)
{
case IccColorantEncoding.EBU_Tech_3213_E:
return new double[][]
{
new double[] { 0.640, 0.330 },
new double[] { 0.290, 0.600 },
new double[] { 0.150, 0.060 },
};
case IccColorantEncoding.ITU_R_BT_709_2:
return new double[][]
{
new double[] { 0.640, 0.330 },
new double[] { 0.300, 0.600 },
new double[] { 0.150, 0.060 },
};
case IccColorantEncoding.P22:
return new double[][]
{
new double[] { 0.625, 0.340 },
new double[] { 0.280, 0.605 },
new double[] { 0.155, 0.070 },
};
case IccColorantEncoding.SMPTE_RP145:
return new double[][]
{
new double[] { 0.630, 0.340 },
new double[] { 0.310, 0.595 },
new double[] { 0.155, 0.070 },
};
default:
throw new ArgumentException("Unrecognized colorant encoding");
}
}
}
}

55
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs

@ -0,0 +1,55 @@
// <copyright file="IccColorantOrderTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This tag specifies the laydown order in which colorants
/// will be printed on an n-colorant device.
/// </summary>
internal sealed class IccColorantOrderTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantOrderTagDataEntry"/> class.
/// </summary>
/// <param name="colorantNumber">Colorant order numbers</param>
public IccColorantOrderTagDataEntry(byte[] colorantNumber)
: this(colorantNumber, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantOrderTagDataEntry"/> class.
/// </summary>
/// <param name="colorantNumber">Colorant order numbers</param>
/// <param name="tagSignature">Tag Signature</param>
public IccColorantOrderTagDataEntry(byte[] colorantNumber, IccProfileTag tagSignature)
: base(IccTypeSignature.ColorantOrder, tagSignature)
{
Guard.NotNull(colorantNumber, nameof(colorantNumber));
Guard.MustBeBetweenOrEqualTo(colorantNumber.Length, 1, 15, nameof(colorantNumber));
this.ColorantNumber = colorantNumber;
}
/// <summary>
/// Gets the colorant order numbers
/// </summary>
public byte[] ColorantNumber { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccColorantOrderTagDataEntry entry)
{
return this.ColorantNumber.SequenceEqual(entry.ColorantNumber);
}
return false;
}
}
}

56
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs

@ -0,0 +1,56 @@
// <copyright file="IccColorantTableTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// The purpose of this tag is to identify the colorants used in
/// the profile by a unique name and set of PCSXYZ or PCSLAB values
/// to give the colorant an unambiguous value.
/// </summary>
internal sealed class IccColorantTableTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantTableTagDataEntry"/> class.
/// </summary>
/// <param name="colorantData">Colorant Data</param>
public IccColorantTableTagDataEntry(IccColorantTableEntry[] colorantData)
: this(colorantData, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantTableTagDataEntry"/> class.
/// </summary>
/// <param name="colorantData">Colorant Data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccColorantTableTagDataEntry(IccColorantTableEntry[] colorantData, IccProfileTag tagSignature)
: base(IccTypeSignature.ColorantTable, tagSignature)
{
Guard.NotNull(colorantData, nameof(colorantData));
Guard.MustBeBetweenOrEqualTo(colorantData.Length, 1, 15, nameof(colorantData));
this.ColorantData = colorantData;
}
/// <summary>
/// Gets the colorant data
/// </summary>
public IccColorantTableEntry[] ColorantData { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccColorantTableTagDataEntry entry)
{
return this.ColorantData.SequenceEqual(entry.ColorantData);
}
return false;
}
}
}

122
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs

@ -0,0 +1,122 @@
// <copyright file="IccCurveTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// The type contains a one-dimensional table of double values.
/// </summary>
internal sealed class IccCurveTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
public IccCurveTagDataEntry()
: this(new float[0], IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
/// <param name="gamma">Gamma value</param>
public IccCurveTagDataEntry(float gamma)
: this(new float[] { gamma }, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
/// <param name="curveData">Curve Data</param>
public IccCurveTagDataEntry(float[] curveData)
: this(curveData, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
/// <param name="tagSignature">Tag Signature</param>
public IccCurveTagDataEntry(IccProfileTag tagSignature)
: this(new float[0], tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
/// <param name="gamma">Gamma value</param>
/// <param name="tagSignature">Tag Signature</param>
public IccCurveTagDataEntry(float gamma, IccProfileTag tagSignature)
: this(new float[] { gamma }, tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccCurveTagDataEntry"/> class.
/// </summary>
/// <param name="curveData">Curve Data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccCurveTagDataEntry(float[] curveData, IccProfileTag tagSignature)
: base(IccTypeSignature.Curve, tagSignature)
{
this.CurveData = curveData ?? new float[0];
}
/// <summary>
/// Gets the curve data
/// </summary>
public float[] CurveData { get; }
/// <summary>
/// Gets the gamma value.
/// Only valid if <see cref="IsGamma"/> is true
/// </summary>
public float Gamma
{
get
{
if (this.IsGamma)
{
return this.CurveData[0];
}
else
{
return 0;
}
}
}
/// <summary>
/// Gets a value indicating whether the curve maps input directly to output
/// </summary>
public bool IsIdentityResponse
{
get { return this.CurveData.Length == 0; }
}
/// <summary>
/// Gets a value indicating whether the curve is a gamma curve
/// </summary>
public bool IsGamma
{
get { return this.CurveData.Length == 1; }
}
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccCurveTagDataEntry entry)
{
return this.CurveData.SequenceEqual(entry.CurveData);
}
return false;
}
}
}

92
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs

@ -0,0 +1,92 @@
// <copyright file="IccDataTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
using System.Text;
/// <summary>
/// The dataType is a simple data structure that contains
/// either 7-bit ASCII or binary data, i.e. textType data or transparent bytes.
/// </summary>
internal sealed class IccDataTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccDataTagDataEntry"/> class.
/// </summary>
/// <param name="data">The raw data</param>
public IccDataTagDataEntry(byte[] data)
: this(data, false, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccDataTagDataEntry"/> class.
/// </summary>
/// <param name="data">The raw data</param>
/// <param name="isAscii">True if the given data is 7bit ASCII encoded text</param>
public IccDataTagDataEntry(byte[] data, bool isAscii)
: this(data, isAscii, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccDataTagDataEntry"/> class.
/// </summary>
/// <param name="data">The raw data</param>
/// <param name="isAscii">True if the given data is 7bit ASCII encoded text</param>
/// <param name="tagSignature">Tag Signature</param>
public IccDataTagDataEntry(byte[] data, bool isAscii, IccProfileTag tagSignature)
: base(IccTypeSignature.Data, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
this.IsAscii = isAscii;
}
/// <summary>
/// Gets the raw Data
/// </summary>
public byte[] Data { get; }
/// <summary>
/// Gets a value indicating whether the <see cref="Data"/> represents 7bit ASCII encoded text
/// </summary>
public bool IsAscii { get; }
/// <summary>
/// Gets the <see cref="Data"/> decoded as 7bit ASCII.
/// If <see cref="IsAscii"/> is false, returns null
/// </summary>
public string AsciiString
{
get
{
if (this.IsAscii)
{
// Encoding.ASCII is missing in netstandard1.1, use UTF8 instead because it's compatible with ASCII
return Encoding.UTF8.GetString(this.Data, 0, this.Data.Length);
}
else
{
return null;
}
}
}
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccDataTagDataEntry entry)
{
return this.IsAscii == entry.IsAscii
&& this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

51
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs

@ -0,0 +1,51 @@
// <copyright file="IccDateTimeTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// This type is a representation of the time and date.
/// </summary>
internal sealed class IccDateTimeTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccDateTimeTagDataEntry"/> class.
/// </summary>
/// <param name="value">The DateTime value</param>
public IccDateTimeTagDataEntry(DateTime value)
: this(value, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccDateTimeTagDataEntry"/> class.
/// </summary>
/// <param name="value">The DateTime value</param>
/// <param name="tagSignature">Tag Signature</param>
public IccDateTimeTagDataEntry(DateTime value, IccProfileTag tagSignature)
: base(IccTypeSignature.DateTime, tagSignature)
{
this.Value = value;
}
/// <summary>
/// Gets the date and time value
/// </summary>
public DateTime Value { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccDateTimeTagDataEntry entry)
{
return this.Value == entry.Value;
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccFix16ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of doubles (from 32bit fixed point values).
/// </summary>
internal sealed class IccFix16ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccFix16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccFix16ArrayTagDataEntry(float[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccFix16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.S15Fixed16Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public float[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccFix16ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

153
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs

@ -0,0 +1,153 @@
// <copyright file="IccLut16TagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
using System.Numerics;
/// <summary>
/// This structure represents a color transform using tables
/// with 16-bit precision.
/// </summary>
internal sealed class IccLut16TagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLut16TagDataEntry"/> class.
/// </summary>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
public IccLut16TagDataEntry(IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues)
: this(null, inputValues, clutValues, outputValues, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut16TagDataEntry"/> class.
/// </summary>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLut16TagDataEntry(IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues, IccProfileTag tagSignature)
: this(null, inputValues, clutValues, outputValues, tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut16TagDataEntry"/> class.
/// </summary>
/// <param name="matrix">Conversion matrix (must be 3x3)</param>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
public IccLut16TagDataEntry(float[,] matrix, IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues)
: this(matrix, inputValues, clutValues, outputValues, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut16TagDataEntry"/> class.
/// </summary>
/// <param name="matrix">Conversion matrix (must be 3x3)</param>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLut16TagDataEntry(float[,] matrix, IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues, IccProfileTag tagSignature)
: base(IccTypeSignature.Lut16, tagSignature)
{
Guard.NotNull(inputValues, nameof(inputValues));
Guard.NotNull(clutValues, nameof(clutValues));
Guard.NotNull(outputValues, nameof(outputValues));
if (matrix != null)
{
bool isNot3By3 = matrix.GetLength(0) != 3 || matrix.GetLength(1) != 3;
Guard.IsTrue(isNot3By3, nameof(matrix), "Matrix must have a size of three by three");
}
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
this.Matrix = this.CreateMatrix(matrix);
this.InputValues = inputValues;
this.ClutValues = clutValues;
this.OutputValues = outputValues;
}
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount
{
get { return this.InputValues.Length; }
}
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount
{
get { return this.OutputValues.Length; }
}
/// <summary>
/// Gets the conversion matrix
/// </summary>
public Matrix4x4 Matrix { get; }
/// <summary>
/// Gets the input lookup table
/// </summary>
public IccLut[] InputValues { get; }
/// <summary>
/// Gets the color lookup table
/// </summary>
public IccClut ClutValues { get; }
/// <summary>
/// Gets the output lookup table
/// </summary>
public IccLut[] OutputValues { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccLut16TagDataEntry entry)
{
return this.ClutValues == entry.ClutValues
&& this.Matrix == entry.Matrix
&& this.InputValues.SequenceEqual(entry.InputValues)
&& this.OutputValues.SequenceEqual(entry.OutputValues);
}
return false;
}
private Matrix4x4 CreateMatrix(float[,] matrix)
{
return new Matrix4x4(
matrix[0, 0],
matrix[0, 1],
matrix[0, 2],
0,
matrix[1, 0],
matrix[1, 1],
matrix[1, 2],
0,
matrix[2, 0],
matrix[2, 1],
matrix[2, 2],
0,
0,
0,
0,
1);
}
}
}

156
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs

@ -0,0 +1,156 @@
// <copyright file="IccLut8TagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
using System.Numerics;
/// <summary>
/// This structure represents a color transform using tables
/// with 8-bit precision.
/// </summary>
internal sealed class IccLut8TagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLut8TagDataEntry"/> class.
/// </summary>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
public IccLut8TagDataEntry(IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues)
: this(null, inputValues, clutValues, outputValues, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut8TagDataEntry"/> class.
/// </summary>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLut8TagDataEntry(IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues, IccProfileTag tagSignature)
: this(null, inputValues, clutValues, outputValues, tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut8TagDataEntry"/> class.
/// </summary>
/// <param name="matrix">Conversion matrix (must be 3x3)</param>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
public IccLut8TagDataEntry(float[,] matrix, IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues)
: this(matrix, inputValues, clutValues, outputValues, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut8TagDataEntry"/> class.
/// </summary>
/// <param name="matrix">Conversion matrix (must be 3x3)</param>
/// <param name="inputValues">Input LUT</param>
/// <param name="clutValues">CLUT</param>
/// <param name="outputValues">Output LUT</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLut8TagDataEntry(float[,] matrix, IccLut[] inputValues, IccClut clutValues, IccLut[] outputValues, IccProfileTag tagSignature)
: base(IccTypeSignature.Lut8, tagSignature)
{
Guard.NotNull(inputValues, nameof(inputValues));
Guard.NotNull(clutValues, nameof(clutValues));
Guard.NotNull(outputValues, nameof(outputValues));
if (matrix != null)
{
bool isNot3By3 = matrix.GetLength(0) != 3 || matrix.GetLength(1) != 3;
Guard.IsTrue(isNot3By3, nameof(matrix), "Matrix must have a size of three by three");
}
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
Guard.IsTrue(inputValues.Any(t => t.Values.Length != 256), nameof(inputValues), "Input lookup table has to have a length of 256");
Guard.IsTrue(outputValues.Any(t => t.Values.Length != 256), nameof(outputValues), "Output lookup table has to have a length of 256");
this.Matrix = this.CreateMatrix(matrix);
this.InputValues = inputValues;
this.ClutValues = clutValues;
this.OutputValues = outputValues;
}
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount
{
get { return this.InputValues.Length; }
}
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount
{
get { return this.OutputValues.Length; }
}
/// <summary>
/// Gets the conversion matrix
/// </summary>
public Matrix4x4 Matrix { get; }
/// <summary>
/// Gets the input lookup table
/// </summary>
public IccLut[] InputValues { get; }
/// <summary>
/// Gets the color lookup table
/// </summary>
public IccClut ClutValues { get; }
/// <summary>
/// Gets the output lookup table
/// </summary>
public IccLut[] OutputValues { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccLut16TagDataEntry entry)
{
return this.ClutValues == entry.ClutValues
&& this.Matrix == entry.Matrix
&& this.InputValues.SequenceEqual(entry.InputValues)
&& this.OutputValues.SequenceEqual(entry.OutputValues);
}
return false;
}
private Matrix4x4 CreateMatrix(float[,] matrix)
{
return new Matrix4x4(
matrix[0, 0],
matrix[0, 1],
matrix[0, 2],
0,
matrix[1, 0],
matrix[1, 1],
matrix[1, 2],
0,
matrix[2, 0],
matrix[2, 1],
matrix[2, 2],
0,
0,
0,
0,
1);
}
}
}

274
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs

@ -0,0 +1,274 @@
// <copyright file="IccLutAToBTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
using System.Numerics;
/// <summary>
/// This structure represents a color transform.
/// </summary>
internal sealed class IccLutAToBTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLutAToBTagDataEntry"/> class.
/// </summary>
/// <param name="curveA">A Curve</param>
/// <param name="clutValues">CLUT</param>
/// <param name="curveM">M Curve</param>
/// <param name="matrix3x3">Two dimensional conversion matrix (3x3)</param>
/// <param name="matrix3x1">One dimensional conversion matrix (3x1)</param>
/// <param name="curveB">B Curve</param>
public IccLutAToBTagDataEntry(
IccTagDataEntry[] curveB,
float[,] matrix3x3,
float[] matrix3x1,
IccTagDataEntry[] curveM,
IccClut clutValues,
IccTagDataEntry[] curveA)
: this(curveB, matrix3x3, matrix3x1, curveM, clutValues, curveA, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLutAToBTagDataEntry"/> class.
/// </summary>
/// <param name="curveA">A Curve</param>
/// <param name="clutValues">CLUT</param>
/// <param name="curveM">M Curve</param>
/// <param name="matrix3x3">Two dimensional conversion matrix (3x3)</param>
/// <param name="matrix3x1">One dimensional conversion matrix (3x1)</param>
/// <param name="curveB">B Curve</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLutAToBTagDataEntry(
IccTagDataEntry[] curveB,
float[,] matrix3x3,
float[] matrix3x1,
IccTagDataEntry[] curveM,
IccClut clutValues,
IccTagDataEntry[] curveA,
IccProfileTag tagSignature)
: base(IccTypeSignature.LutAToB, tagSignature)
{
this.VerifyMatrix(matrix3x3, matrix3x1);
this.VerifyCurve(curveA, nameof(curveA));
this.VerifyCurve(curveB, nameof(curveB));
this.VerifyCurve(curveM, nameof(curveM));
this.Matrix3x3 = this.CreateMatrix3x3(matrix3x3);
this.Matrix3x1 = this.CreateMatrix3x1(matrix3x1);
this.CurveA = curveA;
this.CurveB = curveB;
this.CurveM = curveM;
this.ClutValues = clutValues;
if (this.IsAClutMMatrixB())
{
Guard.IsTrue(this.CurveB.Length != 3, nameof(this.CurveB), $"{nameof(this.CurveB)} must have a length of three");
Guard.IsTrue(this.CurveM.Length != 3, nameof(this.CurveM), $"{nameof(this.CurveM)} must have a length of three");
Guard.MustBeBetweenOrEqualTo(this.CurveA.Length, 1, 15, nameof(this.CurveA));
this.InputChannelCount = curveA.Length;
this.OutputChannelCount = 3;
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
}
else if (this.IsMMatrixB())
{
Guard.IsTrue(this.CurveB.Length != 3, nameof(this.CurveB), $"{nameof(this.CurveB)} must have a length of three");
Guard.IsTrue(this.CurveM.Length != 3, nameof(this.CurveM), $"{nameof(this.CurveM)} must have a length of three");
this.InputChannelCount = this.OutputChannelCount = 3;
}
else if (this.IsAClutB())
{
Guard.MustBeBetweenOrEqualTo(this.CurveA.Length, 1, 15, nameof(this.CurveA));
Guard.MustBeBetweenOrEqualTo(this.CurveB.Length, 1, 15, nameof(this.CurveB));
this.InputChannelCount = curveA.Length;
this.OutputChannelCount = curveB.Length;
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
}
else if (this.IsB())
{
this.InputChannelCount = this.OutputChannelCount = this.CurveB.Length;
}
else
{
throw new ArgumentException("Invalid combination of values given");
}
}
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount { get; }
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount { get; }
/// <summary>
/// Gets the two dimensional conversion matrix (3x3)
/// </summary>
public Matrix4x4? Matrix3x3 { get; }
/// <summary>
/// Gets the one dimensional conversion matrix (3x1)
/// </summary>
public Vector3? Matrix3x1 { get; }
/// <summary>
/// Gets the color lookup table
/// </summary>
public IccClut ClutValues { get; }
/// <summary>
/// Gets the B Curve
/// </summary>
public IccTagDataEntry[] CurveB { get; }
/// <summary>
/// Gets the M Curve
/// </summary>
public IccTagDataEntry[] CurveM { get; }
/// <summary>
/// Gets the A Curve
/// </summary>
public IccTagDataEntry[] CurveA { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccLutAToBTagDataEntry entry)
{
return this.InputChannelCount == entry.InputChannelCount
&& this.OutputChannelCount == entry.OutputChannelCount
&& this.Matrix3x1 == entry.Matrix3x1
&& this.Matrix3x3 == entry.Matrix3x3
&& this.ClutValues == entry.ClutValues
&& this.EqualsCurve(this.CurveA, entry.CurveA)
&& this.EqualsCurve(this.CurveB, entry.CurveB)
&& this.EqualsCurve(this.CurveM, entry.CurveM);
}
return false;
}
private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves)
{
bool thisNull = thisCurves == null;
bool entryNull = entryCurves == null;
if (thisNull && entryNull)
{
return true;
}
if (entryNull)
{
return false;
}
return thisCurves.SequenceEqual(entryCurves);
}
private bool IsAClutMMatrixB()
{
return this.CurveB != null
&& this.Matrix3x3 != null
&& this.Matrix3x1 != null
&& this.CurveM != null
&& this.ClutValues != null
&& this.CurveA != null;
}
private bool IsMMatrixB()
{
return this.CurveB != null
&& this.Matrix3x3 != null
&& this.Matrix3x1 != null
&& this.CurveM != null;
}
private bool IsAClutB()
{
return this.CurveB != null
&& this.ClutValues != null
&& this.CurveA != null;
}
private bool IsB()
{
return this.CurveB != null;
}
private void VerifyCurve(IccTagDataEntry[] curves, string name)
{
if (curves != null)
{
bool isNotCurve = curves.Any(t => !(t is IccParametricCurveTagDataEntry) && !(t is IccCurveTagDataEntry));
Guard.IsTrue(isNotCurve, nameof(name), $"{nameof(name)} must be of type {nameof(IccParametricCurveTagDataEntry)} or {nameof(IccCurveTagDataEntry)}");
}
}
private void VerifyMatrix(float[,] matrix3x3, float[] matrix3x1)
{
if (matrix3x1 != null)
{
Guard.IsTrue(matrix3x1.Length != 3, nameof(matrix3x1), "Matrix must have a size of three");
}
if (matrix3x3 != null)
{
bool isNot3By3 = matrix3x3.GetLength(0) != 3 || matrix3x3.GetLength(1) != 3;
Guard.IsTrue(isNot3By3, nameof(matrix3x3), "Matrix must have a size of three by three");
}
}
private Vector3? CreateMatrix3x1(float[] matrix)
{
if (matrix == null)
{
return null;
}
return new Vector3(matrix[0], matrix[1], matrix[2]);
}
private Matrix4x4? CreateMatrix3x3(float[,] matrix)
{
if (matrix == null)
{
return null;
}
return new Matrix4x4(
matrix[0, 0],
matrix[0, 1],
matrix[0, 2],
0,
matrix[1, 0],
matrix[1, 1],
matrix[1, 2],
0,
matrix[2, 0],
matrix[2, 1],
matrix[2, 2],
0,
0,
0,
0,
1);
}
}
}

274
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs

@ -0,0 +1,274 @@
// <copyright file="IccLutBToATagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
using System.Numerics;
/// <summary>
/// This structure represents a color transform.
/// </summary>
internal sealed class IccLutBToATagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLutBToATagDataEntry"/> class.
/// </summary>
/// <param name="curveA">A Curve</param>
/// <param name="clutValues">CLUT</param>
/// <param name="curveM">M Curve</param>
/// <param name="matrix3x3">Two dimensional conversion matrix (3x3)</param>
/// <param name="matrix3x1">One dimensional conversion matrix (3x1)</param>
/// <param name="curveB">B Curve</param>
public IccLutBToATagDataEntry(
IccTagDataEntry[] curveB,
float[,] matrix3x3,
float[] matrix3x1,
IccTagDataEntry[] curveM,
IccClut clutValues,
IccTagDataEntry[] curveA)
: this(curveB, matrix3x3, matrix3x1, curveM, clutValues, curveA, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLutBToATagDataEntry"/> class.
/// </summary>
/// <param name="curveA">A Curve</param>
/// <param name="clutValues">CLUT</param>
/// <param name="curveM">M Curve</param>
/// <param name="matrix3x3">Two dimensional conversion matrix (3x3)</param>
/// <param name="matrix3x1">One dimensional conversion matrix (3x1)</param>
/// <param name="curveB">B Curve</param>
/// <param name="tagSignature">Tag Signature</param>
public IccLutBToATagDataEntry(
IccTagDataEntry[] curveB,
float[,] matrix3x3,
float[] matrix3x1,
IccTagDataEntry[] curveM,
IccClut clutValues,
IccTagDataEntry[] curveA,
IccProfileTag tagSignature)
: base(IccTypeSignature.LutBToA, tagSignature)
{
this.VerifyMatrix(matrix3x3, matrix3x1);
this.VerifyCurve(curveA, nameof(curveA));
this.VerifyCurve(curveB, nameof(curveB));
this.VerifyCurve(curveM, nameof(curveM));
this.Matrix3x3 = this.CreateMatrix3x3(matrix3x3);
this.Matrix3x1 = this.CreateMatrix3x1(matrix3x1);
this.CurveA = curveA;
this.CurveB = curveB;
this.CurveM = curveM;
this.ClutValues = clutValues;
if (this.IsBMatrixMClutA())
{
Guard.IsTrue(this.CurveB.Length != 3, nameof(this.CurveB), $"{nameof(this.CurveB)} must have a length of three");
Guard.IsTrue(this.CurveM.Length != 3, nameof(this.CurveM), $"{nameof(this.CurveM)} must have a length of three");
Guard.MustBeBetweenOrEqualTo(this.CurveA.Length, 1, 15, nameof(this.CurveA));
this.InputChannelCount = 3;
this.OutputChannelCount = curveA.Length;
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
}
else if (this.IsBMatrixM())
{
Guard.IsTrue(this.CurveB.Length != 3, nameof(this.CurveB), $"{nameof(this.CurveB)} must have a length of three");
Guard.IsTrue(this.CurveM.Length != 3, nameof(this.CurveM), $"{nameof(this.CurveM)} must have a length of three");
this.InputChannelCount = this.OutputChannelCount = 3;
}
else if (this.IsBClutA())
{
Guard.MustBeBetweenOrEqualTo(this.CurveA.Length, 1, 15, nameof(this.CurveA));
Guard.MustBeBetweenOrEqualTo(this.CurveB.Length, 1, 15, nameof(this.CurveB));
this.InputChannelCount = curveB.Length;
this.OutputChannelCount = curveA.Length;
Guard.IsTrue(this.InputChannelCount != clutValues.InputChannelCount, nameof(clutValues), "Input channel count does not match the CLUT size");
Guard.IsTrue(this.OutputChannelCount != clutValues.OutputChannelCount, nameof(clutValues), "Output channel count does not match the CLUT size");
}
else if (this.IsB())
{
this.InputChannelCount = this.OutputChannelCount = this.CurveB.Length;
}
else
{
throw new ArgumentException("Invalid combination of values given");
}
}
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount { get; }
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount { get; }
/// <summary>
/// Gets the two dimensional conversion matrix (3x3)
/// </summary>
public Matrix4x4? Matrix3x3 { get; }
/// <summary>
/// Gets the one dimensional conversion matrix (3x1)
/// </summary>
public Vector3? Matrix3x1 { get; }
/// <summary>
/// Gets the color lookup table
/// </summary>
public IccClut ClutValues { get; }
/// <summary>
/// Gets the B Curve
/// </summary>
public IccTagDataEntry[] CurveB { get; }
/// <summary>
/// Gets the M Curve
/// </summary>
public IccTagDataEntry[] CurveM { get; }
/// <summary>
/// Gets the A Curve
/// </summary>
public IccTagDataEntry[] CurveA { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccLutBToATagDataEntry entry)
{
return this.InputChannelCount == entry.InputChannelCount
&& this.OutputChannelCount == entry.OutputChannelCount
&& this.Matrix3x1 == entry.Matrix3x1
&& this.Matrix3x3 == entry.Matrix3x3
&& this.ClutValues == entry.ClutValues
&& this.EqualsCurve(this.CurveA, entry.CurveA)
&& this.EqualsCurve(this.CurveB, entry.CurveB)
&& this.EqualsCurve(this.CurveM, entry.CurveM);
}
return false;
}
private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves)
{
bool thisNull = thisCurves == null;
bool entryNull = entryCurves == null;
if (thisNull && entryNull)
{
return true;
}
if (entryNull)
{
return false;
}
return thisCurves.SequenceEqual(entryCurves);
}
private bool IsBMatrixMClutA()
{
return this.CurveB != null
&& this.Matrix3x3 != null
&& this.Matrix3x1 != null
&& this.CurveM != null
&& this.ClutValues != null
&& this.CurveA != null;
}
private bool IsBMatrixM()
{
return this.CurveB != null
&& this.Matrix3x3 != null
&& this.Matrix3x1 != null
&& this.CurveM != null;
}
private bool IsBClutA()
{
return this.CurveB != null
&& this.ClutValues != null
&& this.CurveA != null;
}
private bool IsB()
{
return this.CurveB != null;
}
private void VerifyCurve(IccTagDataEntry[] curves, string name)
{
if (curves != null)
{
bool isNotCurve = curves.Any(t => !(t is IccParametricCurveTagDataEntry) && !(t is IccCurveTagDataEntry));
Guard.IsTrue(isNotCurve, nameof(name), $"{nameof(name)} must be of type {nameof(IccParametricCurveTagDataEntry)} or {nameof(IccCurveTagDataEntry)}");
}
}
private void VerifyMatrix(float[,] matrix3x3, float[] matrix3x1)
{
if (matrix3x1 != null)
{
Guard.IsTrue(matrix3x1.Length != 3, nameof(matrix3x1), "Matrix must have a size of three");
}
if (matrix3x3 != null)
{
bool isNot3By3 = matrix3x3.GetLength(0) != 3 || matrix3x3.GetLength(1) != 3;
Guard.IsTrue(isNot3By3, nameof(matrix3x3), "Matrix must have a size of three by three");
}
}
private Vector3? CreateMatrix3x1(float[] matrix)
{
if (matrix == null)
{
return null;
}
return new Vector3(matrix[0], matrix[1], matrix[2]);
}
private Matrix4x4? CreateMatrix3x3(float[,] matrix)
{
if (matrix == null)
{
return null;
}
return new Matrix4x4(
matrix[0, 0],
matrix[0, 1],
matrix[0, 2],
0,
matrix[1, 0],
matrix[1, 1],
matrix[1, 2],
0,
matrix[2, 0],
matrix[2, 1],
matrix[2, 2],
0,
0,
0,
0,
1);
}
}
}

89
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs

@ -0,0 +1,89 @@
// <copyright file="IccMeasurementTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
/// <summary>
/// The measurementType information refers only to the internal
/// profile data and is meant to provide profile makers an alternative
/// to the default measurement specifications.
/// </summary>
internal sealed class IccMeasurementTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccMeasurementTagDataEntry"/> class.
/// </summary>
/// <param name="observer">Observer</param>
/// <param name="xyzBacking">XYZ Backing values</param>
/// <param name="geometry">Geometry</param>
/// <param name="flare">Flare</param>
/// <param name="illuminant">Illuminant</param>
public IccMeasurementTagDataEntry(IccStandardObserver observer, Vector3 xyzBacking, IccMeasurementGeometry geometry, float flare, IccStandardIlluminant illuminant)
: this(observer, xyzBacking, geometry, flare, illuminant, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccMeasurementTagDataEntry"/> class.
/// </summary>
/// <param name="observer">Observer</param>
/// <param name="xyzBacking">XYZ Backing values</param>
/// <param name="geometry">Geometry</param>
/// <param name="flare">Flare</param>
/// <param name="illuminant">Illuminant</param>
/// <param name="tagSignature">Tag Signature</param>
public IccMeasurementTagDataEntry(IccStandardObserver observer, Vector3 xyzBacking, IccMeasurementGeometry geometry, float flare, IccStandardIlluminant illuminant, IccProfileTag tagSignature)
: base(IccTypeSignature.Measurement, tagSignature)
{
this.Observer = observer;
this.XyzBacking = xyzBacking;
this.Geometry = geometry;
this.Flare = flare;
this.Illuminant = illuminant;
}
/// <summary>
/// Gets the observer
/// </summary>
public IccStandardObserver Observer { get; }
/// <summary>
/// Gets the XYZ Backing values
/// </summary>
public Vector3 XyzBacking { get; }
/// <summary>
/// Gets the geometry
/// </summary>
public IccMeasurementGeometry Geometry { get; }
/// <summary>
/// Gets the flare
/// </summary>
public float Flare { get; }
/// <summary>
/// Gets the illuminant
/// </summary>
public IccStandardIlluminant Illuminant { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccMeasurementTagDataEntry entry)
{
return this.Observer == entry.Observer
&& this.XyzBacking == entry.XyzBacking
&& this.Geometry == entry.Geometry
&& this.Flare == entry.Flare
&& this.Illuminant == entry.Illuminant;
}
return false;
}
}
}

53
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs

@ -0,0 +1,53 @@
// <copyright file="IccMultiLocalizedUnicodeTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This tag structure contains a set of records each referencing
/// a multilingual string associated with a profile.
/// </summary>
internal sealed class IccMultiLocalizedUnicodeTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccMultiLocalizedUnicodeTagDataEntry"/> class.
/// </summary>
/// <param name="texts">Localized Text</param>
public IccMultiLocalizedUnicodeTagDataEntry(IccLocalizedString[] texts)
: this(texts, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccMultiLocalizedUnicodeTagDataEntry"/> class.
/// </summary>
/// <param name="texts">Localized Text</param>
/// <param name="tagSignature">Tag Signature</param>
public IccMultiLocalizedUnicodeTagDataEntry(IccLocalizedString[] texts, IccProfileTag tagSignature)
: base(IccTypeSignature.MultiLocalizedUnicode, tagSignature)
{
Guard.NotNull(texts, nameof(texts));
this.Texts = texts;
}
/// <summary>
/// Gets the localized texts
/// </summary>
public IccLocalizedString[] Texts { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccMultiLocalizedUnicodeTagDataEntry entry)
{
return this.Texts.SequenceEqual(entry.Texts);
}
return false;
}
}
}

72
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs

@ -0,0 +1,72 @@
// <copyright file="IccMultiProcessElementsTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This structure represents a color transform, containing
/// a sequence of processing elements.
/// </summary>
internal sealed class IccMultiProcessElementsTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccMultiProcessElementsTagDataEntry"/> class.
/// </summary>
/// <param name="data">Processing elements</param>
public IccMultiProcessElementsTagDataEntry(IccMultiProcessElement[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccMultiProcessElementsTagDataEntry"/> class.
/// </summary>
/// <param name="data">Processing elements</param>
/// <param name="tagSignature">Tag Signature</param>
public IccMultiProcessElementsTagDataEntry(IccMultiProcessElement[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.MultiProcessElements, tagSignature)
{
Guard.NotNull(data, nameof(data));
Guard.IsTrue(data.Length < 1, nameof(data), $"{nameof(data)} must have at least one element");
this.InputChannelCount = data[0].InputChannelCount;
this.OutputChannelCount = data[0].OutputChannelCount;
this.Data = data;
bool channelsNotSame = data.Any(t => t.InputChannelCount != this.InputChannelCount || t.OutputChannelCount != this.OutputChannelCount);
Guard.IsTrue(channelsNotSame, nameof(data), "The number of input and output channels are not the same for all elements");
}
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount { get; }
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount { get; }
/// <summary>
/// Gets the processing elements
/// </summary>
public IccMultiProcessElement[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccMultiProcessElementsTagDataEntry entry)
{
return this.InputChannelCount == entry.InputChannelCount
&& this.OutputChannelCount == entry.OutputChannelCount
&& this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

137
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs

@ -0,0 +1,137 @@
// <copyright file="IccNamedColor2TagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// The namedColor2Type is a count value and array of structures
/// that provide color coordinates for color names.
/// </summary>
internal sealed class IccNamedColor2TagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="colors">The named colors</param>
public IccNamedColor2TagDataEntry(IccNamedColor[] colors)
: this(0, null, null, colors, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="prefix">Prefix</param>
/// <param name="suffix">Suffix</param>
/// /// <param name="colors">The named colors</param>
public IccNamedColor2TagDataEntry(string prefix, string suffix, IccNamedColor[] colors)
: this(0, prefix, suffix, colors, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="vendorFlags">Vendor specific flags</param>
/// <param name="prefix">Prefix</param>
/// <param name="suffix">Suffix</param>
/// <param name="colors">The named colors</param>
public IccNamedColor2TagDataEntry(int vendorFlags, string prefix, string suffix, IccNamedColor[] colors)
: this(vendorFlags, prefix, suffix, colors, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="colors">The named colors</param>
/// <param name="tagSignature">Tag Signature</param>
public IccNamedColor2TagDataEntry(IccNamedColor[] colors, IccProfileTag tagSignature)
: this(0, null, null, colors, tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="prefix">Prefix</param>
/// <param name="suffix">Suffix</param>
/// <param name="colors">The named colors</param>
/// <param name="tagSignature">Tag Signature</param>
public IccNamedColor2TagDataEntry(string prefix, string suffix, IccNamedColor[] colors, IccProfileTag tagSignature)
: this(0, prefix, suffix, colors, tagSignature)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor2TagDataEntry"/> class.
/// </summary>
/// <param name="vendorFlags">Vendor specific flags</param>
/// <param name="prefix">Prefix</param>
/// <param name="suffix">Suffix</param>
/// <param name="colors">The named colors</param>
/// <param name="tagSignature">Tag Signature</param>
public IccNamedColor2TagDataEntry(int vendorFlags, string prefix, string suffix, IccNamedColor[] colors, IccProfileTag tagSignature)
: base(IccTypeSignature.NamedColor2, tagSignature)
{
Guard.NotNull(colors, nameof(colors));
int coordinateCount = 0;
if (colors.Length > 0)
{
coordinateCount = colors[0].DeviceCoordinates?.Length ?? 0;
Guard.IsTrue(colors.Any(t => (t.DeviceCoordinates?.Length ?? 0) != coordinateCount), nameof(colors), "Device coordinate count must be the same for all colors");
}
this.VendorFlags = vendorFlags;
this.CoordinateCount = coordinateCount;
this.Prefix = prefix;
this.Suffix = suffix;
this.Colors = colors;
}
/// <summary>
/// Gets the number of coordinates
/// </summary>
public int CoordinateCount { get; }
/// <summary>
/// Gets the prefix
/// </summary>
public string Prefix { get; }
/// <summary>
/// Gets the suffix
/// </summary>
public string Suffix { get; }
/// <summary>
/// Gets the vendor specific flags
/// </summary>
public int VendorFlags { get; }
/// <summary>
/// Gets the named colors
/// </summary>
public IccNamedColor[] Colors { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccNamedColor2TagDataEntry entry)
{
return this.CoordinateCount == entry.CoordinateCount
&& this.Prefix == entry.Prefix
&& this.Suffix == entry.Suffix
&& this.VendorFlags == entry.VendorFlags
&& this.Colors.SequenceEqual(entry.Colors);
}
return false;
}
}
}

50
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs

@ -0,0 +1,50 @@
// <copyright file="IccParametricCurveTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// The parametricCurveType describes a one-dimensional curve by
/// specifying one of a predefined set of functions using the parameters.
/// </summary>
internal sealed class IccParametricCurveTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurveTagDataEntry"/> class.
/// </summary>
/// <param name="curve">The Curve</param>
public IccParametricCurveTagDataEntry(IccParametricCurve curve)
: this(curve, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccParametricCurveTagDataEntry"/> class.
/// </summary>
/// <param name="curve">The Curve</param>
/// <param name="tagSignature">Tag Signature</param>
public IccParametricCurveTagDataEntry(IccParametricCurve curve, IccProfileTag tagSignature)
: base(IccTypeSignature.ParametricCurve, tagSignature)
{
this.Curve = curve;
}
/// <summary>
/// Gets the Curve
/// </summary>
public IccParametricCurve Curve { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccParametricCurveTagDataEntry entry)
{
return this.Curve == entry.Curve;
}
return false;
}
}
}

54
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs

@ -0,0 +1,54 @@
// <copyright file="IccProfileSequenceDescTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type is an array of structures, each of which contains information
/// from the header fields and tags from the original profiles which were
/// combined to create the final profile.
/// </summary>
internal sealed class IccProfileSequenceDescTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileSequenceDescTagDataEntry"/> class.
/// </summary>
/// <param name="descriptions">Profile Descriptions</param>
public IccProfileSequenceDescTagDataEntry(IccProfileDescription[] descriptions)
: this(descriptions, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileSequenceDescTagDataEntry"/> class.
/// </summary>
/// <param name="descriptions">Profile Descriptions</param>
/// <param name="tagSignature">Tag Signature</param>
public IccProfileSequenceDescTagDataEntry(IccProfileDescription[] descriptions, IccProfileTag tagSignature)
: base(IccTypeSignature.ProfileSequenceDesc, tagSignature)
{
Guard.NotNull(descriptions, nameof(descriptions));
this.Descriptions = descriptions;
}
/// <summary>
/// Gets the profile descriptions
/// </summary>
public IccProfileDescription[] Descriptions { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccProfileSequenceDescTagDataEntry entry)
{
return this.Descriptions.SequenceEqual(entry.Descriptions);
}
return false;
}
}
}

53
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs

@ -0,0 +1,53 @@
// <copyright file="IccProfileSequenceIdentifierTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type is an array of structures, each of which contains information
/// for identification of a profile used in a sequence.
/// </summary>
internal sealed class IccProfileSequenceIdentifierTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileSequenceIdentifierTagDataEntry"/> class.
/// </summary>
/// <param name="data">Profile Identifiers</param>
public IccProfileSequenceIdentifierTagDataEntry(IccProfileSequenceIdentifier[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileSequenceIdentifierTagDataEntry"/> class.
/// </summary>
/// <param name="data">Profile Identifiers</param>
/// <param name="tagSignature">Tag Signature</param>
public IccProfileSequenceIdentifierTagDataEntry(IccProfileSequenceIdentifier[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.ProfileSequenceIdentifier, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the profile identifiers
/// </summary>
public IccProfileSequenceIdentifier[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccProfileSequenceIdentifierTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

66
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs

@ -0,0 +1,66 @@
// <copyright file="IccResponseCurveSet16TagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// The purpose of this tag type is to provide a mechanism to relate physical
/// colorant amounts with the normalized device codes produced by lut8Type, lut16Type,
/// lutAToBType, lutBToAType or multiProcessElementsType tags so that corrections can
/// be made for variation in the device without having to produce a new profile.
/// </summary>
internal sealed class IccResponseCurveSet16TagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccResponseCurveSet16TagDataEntry"/> class.
/// </summary>
/// <param name="curves">The Curves</param>
public IccResponseCurveSet16TagDataEntry(IccResponseCurve[] curves)
: this(curves, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccResponseCurveSet16TagDataEntry"/> class.
/// </summary>
/// <param name="curves">The Curves</param>
/// <param name="tagSignature">Tag Signature</param>
public IccResponseCurveSet16TagDataEntry(IccResponseCurve[] curves, IccProfileTag tagSignature)
: base(IccTypeSignature.ResponseCurveSet16, tagSignature)
{
Guard.NotNull(curves, nameof(curves));
Guard.IsTrue(curves.Length < 1, nameof(curves), $"{nameof(curves)} needs at least one element");
this.Curves = curves;
this.ChannelCount = (ushort)curves[0].ResponseArrays.Length;
Guard.IsTrue(curves.Any(t => t.ResponseArrays.Length != this.ChannelCount), nameof(curves), "All curves need to have the same number of channels");
}
/// <summary>
/// Gets the number of channels
/// </summary>
public ushort ChannelCount { get; }
/// <summary>
/// Gets the curves
/// </summary>
public IccResponseCurve[] Curves { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccResponseCurveSet16TagDataEntry entry)
{
return this.ChannelCount == entry.ChannelCount
&& this.Curves.SequenceEqual(entry.Curves);
}
return false;
}
}
}

51
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs

@ -0,0 +1,51 @@
// <copyright file="IccSignatureTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Typically this type is used for registered tags that can
/// be displayed on many development systems as a sequence of four characters.
/// </summary>
internal sealed class IccSignatureTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccSignatureTagDataEntry"/> class.
/// </summary>
/// <param name="signatureData">The Signature</param>
public IccSignatureTagDataEntry(string signatureData)
: this(signatureData, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccSignatureTagDataEntry"/> class.
/// </summary>
/// <param name="signatureData">The Signature</param>
/// <param name="tagSignature">Tag Signature</param>
public IccSignatureTagDataEntry(string signatureData, IccProfileTag tagSignature)
: base(IccTypeSignature.Signature, tagSignature)
{
Guard.NotNull(signatureData, nameof(signatureData));
this.SignatureData = signatureData;
}
/// <summary>
/// Gets the Signature
/// </summary>
public string SignatureData { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccSignatureTagDataEntry entry)
{
return this.SignatureData == entry.SignatureData;
}
return false;
}
}
}

85
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs

@ -0,0 +1,85 @@
// <copyright file="IccTextDescriptionTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// The TextDescriptionType contains three types of text description.
/// </summary>
internal sealed class IccTextDescriptionTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccTextDescriptionTagDataEntry"/> class.
/// </summary>
/// <param name="ascii">ASCII text</param>
/// <param name="unicode">Unicode text</param>
/// <param name="scriptCode">ScriptCode text</param>
/// <param name="unicodeLanguageCode">Unicode Language-Code</param>
/// <param name="scriptCodeCode">ScriptCode Code</param>
public IccTextDescriptionTagDataEntry(string ascii, string unicode, string scriptCode, uint unicodeLanguageCode, ushort scriptCodeCode)
: this(ascii, unicode, scriptCode, unicodeLanguageCode, scriptCodeCode, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccTextDescriptionTagDataEntry"/> class.
/// </summary>
/// <param name="ascii">ASCII text</param>
/// <param name="unicode">Unicode text</param>
/// <param name="scriptCode">ScriptCode text</param>
/// <param name="unicodeLanguageCode">Unicode Language-Code</param>
/// <param name="scriptCodeCode">ScriptCode Code</param>
/// <param name="tagSignature">Tag Signature</param>
public IccTextDescriptionTagDataEntry(string ascii, string unicode, string scriptCode, uint unicodeLanguageCode, ushort scriptCodeCode, IccProfileTag tagSignature)
: base(IccTypeSignature.TextDescription, tagSignature)
{
this.Ascii = ascii;
this.Unicode = unicode;
this.ScriptCode = scriptCode;
this.UnicodeLanguageCode = unicodeLanguageCode;
this.ScriptCodeCode = scriptCodeCode;
}
/// <summary>
/// Gets the ASCII text
/// </summary>
public string Ascii { get; }
/// <summary>
/// Gets the Unicode text
/// </summary>
public string Unicode { get; }
/// <summary>
/// Gets the ScriptCode text
/// </summary>
public string ScriptCode { get; }
/// <summary>
/// Gets the Unicode Language-Code
/// </summary>
public uint UnicodeLanguageCode { get; }
/// <summary>
/// Gets the ScriptCode Code
/// </summary>
public ushort ScriptCodeCode { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccTextDescriptionTagDataEntry entry)
{
return this.Ascii == entry.Ascii
&& this.Unicode == entry.Unicode
&& this.ScriptCode == entry.ScriptCode
&& this.UnicodeLanguageCode == entry.UnicodeLanguageCode
&& this.ScriptCodeCode == entry.ScriptCodeCode;
}
return false;
}
}
}

50
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs

@ -0,0 +1,50 @@
// <copyright file="IccTextTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// This is a simple text structure that contains a text string.
/// </summary>
internal sealed class IccTextTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccTextTagDataEntry"/> class.
/// </summary>
/// <param name="text">The Text</param>
public IccTextTagDataEntry(string text)
: this(text, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccTextTagDataEntry"/> class.
/// </summary>
/// <param name="text">The Text</param>
/// <param name="tagSignature">Tag Signature</param>
public IccTextTagDataEntry(string text, IccProfileTag tagSignature)
: base(IccTypeSignature.Text, tagSignature)
{
Guard.NotNull(text, nameof(text));
this.Text = text;
}
/// <summary>
/// Gets the Text
/// </summary>
public string Text { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccTextTagDataEntry entry)
{
return this.Text == entry.Text;
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUFix16ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of doubles (from 32bit values).
/// </summary>
internal sealed class IccUFix16ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUFix16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccUFix16ArrayTagDataEntry(float[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUFix16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.U16Fixed16Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public float[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUFix16ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUInt16ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of unsigned shorts.
/// </summary>
internal sealed class IccUInt16ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccUInt16ArrayTagDataEntry(ushort[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt16ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUInt16ArrayTagDataEntry(ushort[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt16Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public ushort[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUInt16ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUInt32ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of unsigned 32bit integers.
/// </summary>
internal sealed class IccUInt32ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt32ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccUInt32ArrayTagDataEntry(uint[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt32ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUInt32ArrayTagDataEntry(uint[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt32Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public uint[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUInt32ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUInt64ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of unsigned 64bit integers.
/// </summary>
internal sealed class IccUInt64ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt64ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccUInt64ArrayTagDataEntry(ulong[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt64ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUInt64ArrayTagDataEntry(ulong[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt64Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public ulong[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUInt64ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUInt8ArrayTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This type represents an array of bytes.
/// </summary>
internal sealed class IccUInt8ArrayTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt8ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
public IccUInt8ArrayTagDataEntry(byte[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUInt8ArrayTagDataEntry"/> class.
/// </summary>
/// <param name="data">The array data</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUInt8ArrayTagDataEntry(byte[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt8Array, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the array data
/// </summary>
public byte[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUInt8ArrayTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

52
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs

@ -0,0 +1,52 @@
// <copyright file="IccUnknownTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
/// <summary>
/// This tag stores data of an unknown tag data entry
/// </summary>
internal sealed class IccUnknownTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccUnknownTagDataEntry"/> class.
/// </summary>
/// <param name="data">The raw data of the entry</param>
public IccUnknownTagDataEntry(byte[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccUnknownTagDataEntry"/> class.
/// </summary>
/// <param name="data">The raw data of the entry</param>
/// <param name="tagSignature">Tag Signature</param>
public IccUnknownTagDataEntry(byte[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.Unknown, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the raw data of the entry
/// </summary>
public byte[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccUnknownTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

69
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs

@ -0,0 +1,69 @@
// <copyright file="IccViewingConditionsTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
/// <summary>
/// This type represents a set of viewing condition parameters.
/// </summary>
internal sealed class IccViewingConditionsTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccViewingConditionsTagDataEntry"/> class.
/// </summary>
/// <param name="illuminantXyz">XYZ values of Illuminant</param>
/// <param name="surroundXyz">XYZ values of Surrounding</param>
/// <param name="illuminant">Illuminant</param>
public IccViewingConditionsTagDataEntry(Vector3 illuminantXyz, Vector3 surroundXyz, IccStandardIlluminant illuminant)
: this(illuminantXyz, surroundXyz, illuminant, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccViewingConditionsTagDataEntry"/> class.
/// </summary>
/// <param name="illuminantXyz">XYZ values of Illuminant</param>
/// <param name="surroundXyz">XYZ values of Surrounding</param>
/// <param name="illuminant">Illuminant</param>
/// <param name="tagSignature">Tag Signature</param>
public IccViewingConditionsTagDataEntry(Vector3 illuminantXyz, Vector3 surroundXyz, IccStandardIlluminant illuminant, IccProfileTag tagSignature)
: base(IccTypeSignature.ViewingConditions, tagSignature)
{
this.IlluminantXyz = illuminantXyz;
this.SurroundXyz = surroundXyz;
this.Illuminant = illuminant;
}
/// <summary>
/// Gets the XYZ values of Illuminant
/// </summary>
public Vector3 IlluminantXyz { get; }
/// <summary>
/// Gets the XYZ values of Surrounding
/// </summary>
public Vector3 SurroundXyz { get; }
/// <summary>
/// Gets the illuminant
/// </summary>
public IccStandardIlluminant Illuminant { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccViewingConditionsTagDataEntry entry)
{
return this.IlluminantXyz == entry.IlluminantXyz
&& this.SurroundXyz == entry.SurroundXyz
&& this.Illuminant == entry.Illuminant;
}
return false;
}
}
}

53
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs

@ -0,0 +1,53 @@
// <copyright file="IccXyzTagDataEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Linq;
using System.Numerics;
/// <summary>
/// The XYZType contains an array of XYZ values.
/// </summary>
internal sealed class IccXyzTagDataEntry : IccTagDataEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="IccXyzTagDataEntry"/> class.
/// </summary>
/// <param name="data">The XYZ numbers</param>
public IccXyzTagDataEntry(Vector3[] data)
: this(data, IccProfileTag.Unknown)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccXyzTagDataEntry"/> class.
/// </summary>
/// <param name="data">The XYZ numbers</param>
/// <param name="tagSignature">Tag Signature</param>
public IccXyzTagDataEntry(Vector3[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.Xyz, tagSignature)
{
Guard.NotNull(data, nameof(data));
this.Data = data;
}
/// <summary>
/// Gets the XYZ numbers
/// </summary>
public Vector3[] Data { get; }
/// <inheritdoc />
public override bool Equals(IccTagDataEntry other)
{
if (base.Equals(other) && other is IccXyzTagDataEntry entry)
{
return this.Data.SequenceEqual(entry.Data);
}
return false;
}
}
}

175
src/ImageSharp/MetaData/Profiles/ICC/Various/IccClut.cs

@ -0,0 +1,175 @@
// <copyright file="IccClut.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// Color Lookup Table
/// </summary>
internal sealed class IccClut : IEquatable<IccClut>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccClut"/> class.
/// </summary>
/// <param name="values">The CLUT values</param>
/// <param name="gridPointCount">The gridpoint count</param>
/// <param name="type">The data type of this CLUT</param>
public IccClut(float[][] values, byte[] gridPointCount, IccClutDataType type)
{
Guard.NotNull(values, nameof(values));
Guard.NotNull(gridPointCount, nameof(gridPointCount));
this.Values = values;
this.DataType = IccClutDataType.Float;
this.InputChannelCount = gridPointCount.Length;
this.OutputChannelCount = values[0].Length;
this.GridPointCount = gridPointCount;
this.CheckValues();
}
/// <summary>
/// Initializes a new instance of the <see cref="IccClut"/> class.
/// </summary>
/// <param name="values">The CLUT values</param>
/// <param name="gridPointCount">The gridpoint count</param>
public IccClut(ushort[][] values, byte[] gridPointCount)
{
Guard.NotNull(values, nameof(values));
Guard.NotNull(gridPointCount, nameof(gridPointCount));
const float max = ushort.MaxValue;
this.Values = new float[values.Length][];
for (int i = 0; i < values.Length; i++)
{
this.Values[i] = new float[values[i].Length];
for (int j = 0; j < values[i].Length; j++)
{
this.Values[i][j] = values[i][j] / max;
}
}
this.DataType = IccClutDataType.UInt16;
this.InputChannelCount = gridPointCount.Length;
this.OutputChannelCount = values[0].Length;
this.GridPointCount = gridPointCount;
this.CheckValues();
}
/// <summary>
/// Initializes a new instance of the <see cref="IccClut"/> class.
/// </summary>
/// <param name="values">The CLUT values</param>
/// <param name="gridPointCount">The gridpoint count</param>
public IccClut(byte[][] values, byte[] gridPointCount)
{
Guard.NotNull(values, nameof(values));
Guard.NotNull(gridPointCount, nameof(gridPointCount));
const float max = byte.MaxValue;
this.Values = new float[values.Length][];
for (int i = 0; i < values.Length; i++)
{
this.Values[i] = new float[values[i].Length];
for (int j = 0; j < values[i].Length; j++)
{
this.Values[i][j] = values[i][j] / max;
}
}
this.DataType = IccClutDataType.UInt8;
this.InputChannelCount = gridPointCount.Length;
this.OutputChannelCount = values[0].Length;
this.GridPointCount = gridPointCount;
this.CheckValues();
}
/// <summary>
/// Gets the values that make up this table
/// </summary>
public float[][] Values { get; }
/// <summary>
/// Gets or sets the CLUT data type (important when writing a profile)
/// </summary>
public IccClutDataType DataType { get; set; }
/// <summary>
/// Gets the number of input channels
/// </summary>
public int InputChannelCount { get; }
/// <summary>
/// Gets the number of output channels
/// </summary>
public int OutputChannelCount { get; }
/// <summary>
/// Gets the number of grid points per input channel
/// </summary>
public byte[] GridPointCount { get; }
/// <inheritdoc/>
public bool Equals(IccClut other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.DataType == other.DataType
&& this.InputChannelCount == other.InputChannelCount
&& this.OutputChannelCount == other.OutputChannelCount
&& this.GridPointCount.SequenceEqual(other.GridPointCount)
&& this.EqualsValuesArray(other);
}
private bool EqualsValuesArray(IccClut other)
{
if (this.Values.Length != other.Values.Length)
{
return false;
}
for (int i = 0; i < this.Values.Length; i++)
{
if (!this.Values[i].SequenceEqual(other.Values[i]))
{
return false;
}
}
return true;
}
private void CheckValues()
{
Guard.MustBeBetweenOrEqualTo(this.InputChannelCount, 1, 15, nameof(this.InputChannelCount));
Guard.MustBeBetweenOrEqualTo(this.OutputChannelCount, 1, 15, nameof(this.OutputChannelCount));
bool isLengthDifferent = this.Values.Any(t => t.Length != this.OutputChannelCount);
Guard.IsTrue(isLengthDifferent, nameof(this.Values), "The number of output values varies");
int length = 0;
for (int i = 0; i < this.InputChannelCount; i++)
{
length += (int)Math.Pow(this.GridPointCount[i], this.InputChannelCount);
}
length /= this.InputChannelCount;
Guard.IsTrue(this.Values.Length != length, nameof(this.Values), "Length of values array does not match the grid points");
}
}
}

125
src/ImageSharp/MetaData/Profiles/ICC/Various/IccColorantTableEntry.cs

@ -0,0 +1,125 @@
// <copyright file="IccColorantTableEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Entry of ICC colorant table
/// </summary>
internal struct IccColorantTableEntry : IEquatable<IccColorantTableEntry>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantTableEntry"/> struct.
/// </summary>
/// <param name="name">Name of the colorant</param>
public IccColorantTableEntry(string name)
: this(name, 0, 0, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccColorantTableEntry"/> struct.
/// </summary>
/// <param name="name">Name of the colorant</param>
/// <param name="pcs1">First PCS value</param>
/// <param name="pcs2">Second PCS value</param>
/// <param name="pcs3">Third PCS value</param>
public IccColorantTableEntry(string name, ushort pcs1, ushort pcs2, ushort pcs3)
{
Guard.NotNull(name, nameof(name));
this.Name = name;
this.Pcs1 = pcs1;
this.Pcs2 = pcs2;
this.Pcs3 = pcs3;
}
/// <summary>
/// Gets the colorant name
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the first PCS value
/// </summary>
public ushort Pcs1 { get; }
/// <summary>
/// Gets the second PCS value
/// </summary>
public ushort Pcs2 { get; }
/// <summary>
/// Gets the third PCS value
/// </summary>
public ushort Pcs3 { get; }
/// <summary>
/// Compares two <see cref="IccColorantTableEntry"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccColorantTableEntry"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccColorantTableEntry"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccColorantTableEntry left, IccColorantTableEntry right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccColorantTableEntry"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccColorantTableEntry"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccColorantTableEntry"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccColorantTableEntry left, IccColorantTableEntry right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccColorantTableEntry) && this.Equals((IccColorantTableEntry)other);
}
/// <inheritdoc/>
public bool Equals(IccColorantTableEntry other)
{
return this.Name == other.Name
&& this.Pcs1 == other.Pcs1
&& this.Pcs2 == other.Pcs2
&& this.Pcs3 == other.Pcs3;
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.Name.GetHashCode();
hashCode = (hashCode * 397) ^ this.Pcs1.GetHashCode();
hashCode = (hashCode * 397) ^ this.Pcs2.GetHashCode();
hashCode = (hashCode * 397) ^ this.Pcs3.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"{this.Name}: {this.Pcs1}; {this.Pcs2}; {this.Pcs3}";
}
}
}

69
src/ImageSharp/MetaData/Profiles/ICC/Various/IccLocalizedString.cs

@ -0,0 +1,69 @@
// <copyright file="IccLocalizedString.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Globalization;
/// <summary>
/// A string with a specific locale
/// </summary>
internal sealed class IccLocalizedString : IEquatable<IccLocalizedString>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLocalizedString"/> class.
/// The culture will be <see cref="CultureInfo.CurrentCulture"/>
/// </summary>
/// <param name="text">The text value of this string</param>
public IccLocalizedString(string text)
: this(CultureInfo.CurrentCulture, text)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLocalizedString"/> class.
/// The culture will be <see cref="CultureInfo.CurrentCulture"/>
/// </summary>
/// <param name="culture">The culture of this string</param>
/// <param name="text">The text value of this string</param>
public IccLocalizedString(CultureInfo culture, string text)
{
Guard.NotNull(culture, nameof(culture));
Guard.NotNull(text, nameof(text));
this.Culture = culture;
this.Text = text;
}
/// <summary>
/// Gets the actual text value
/// </summary>
public string Text { get; }
/// <summary>
/// Gets the culture of the text
/// </summary>
public CultureInfo Culture { get; }
/// <inheritdoc />
public bool Equals(IccLocalizedString other)
{
if (ReferenceEquals(this, other))
{
return true;
}
return this.Culture.Equals(other.Culture)
&& this.Text == other.Text;
}
/// <inheritdoc />
public override string ToString()
{
return $"{this.Culture.Name}: {this.Text}";
}
}
}

81
src/ImageSharp/MetaData/Profiles/ICC/Various/IccLut.cs

@ -0,0 +1,81 @@
// <copyright file="IccLut.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// Lookup Table
/// </summary>
internal sealed class IccLut : IEquatable<IccLut>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccLut"/> class.
/// </summary>
/// <param name="values">The LUT values</param>
public IccLut(float[] values)
{
Guard.NotNull(values, nameof(values));
this.Values = values;
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut"/> class.
/// </summary>
/// <param name="values">The LUT values</param>
public IccLut(ushort[] values)
{
Guard.NotNull(values, nameof(values));
const float max = ushort.MaxValue;
this.Values = new float[values.Length];
for (int i = 0; i < values.Length; i++)
{
this.Values[i] = values[i] / max;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="IccLut"/> class.
/// </summary>
/// <param name="values">The LUT values</param>
public IccLut(byte[] values)
{
Guard.NotNull(values, nameof(values));
const float max = byte.MaxValue;
this.Values = new float[values.Length];
for (int i = 0; i < values.Length; i++)
{
this.Values[i] = values[i] / max;
}
}
/// <summary>
/// Gets the values that make up this table
/// </summary>
public float[] Values { get; }
/// <inheritdoc/>
public bool Equals(IccLut other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.Values.SequenceEqual(other.Values);
}
}
}

110
src/ImageSharp/MetaData/Profiles/ICC/Various/IccNamedColor.cs

@ -0,0 +1,110 @@
// <copyright file="IccNamedColor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// A specific color with a name
/// </summary>
internal struct IccNamedColor : IEquatable<IccNamedColor>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccNamedColor"/> struct.
/// </summary>
/// <param name="name">Name of the color</param>
/// <param name="pcsCoordinates">Coordinates of the color in the profiles PCS</param>
/// <param name="deviceCoordinates">Coordinates of the color in the profiles Device-Space</param>
public IccNamedColor(string name, ushort[] pcsCoordinates, ushort[] deviceCoordinates)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(pcsCoordinates, nameof(pcsCoordinates));
Guard.IsTrue(pcsCoordinates.Length != 3, nameof(pcsCoordinates), "Must have a length of 3");
this.Name = name;
this.PcsCoordinates = pcsCoordinates;
this.DeviceCoordinates = deviceCoordinates;
}
/// <summary>
/// Gets the name of the color
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the coordinates of the color in the profiles PCS
/// </summary>
public ushort[] PcsCoordinates { get; }
/// <summary>
/// Gets the coordinates of the color in the profiles Device-Space
/// </summary>
public ushort[] DeviceCoordinates { get; }
/// <summary>
/// Compares two <see cref="IccNamedColor"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccNamedColor"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccNamedColor"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccNamedColor left, IccNamedColor right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccNamedColor"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccNamedColor"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccNamedColor"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccNamedColor left, IccNamedColor right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccNamedColor) && this.Equals((IccNamedColor)other);
}
/// <inheritdoc/>
public bool Equals(IccNamedColor other)
{
return this.Name == other.Name
&& this.PcsCoordinates.SequenceEqual(other.PcsCoordinates)
&& this.DeviceCoordinates.SequenceEqual(other.DeviceCoordinates);
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.Name.GetHashCode();
hashCode = (hashCode * 397) ^ this.PcsCoordinates.GetHashCode();
hashCode = (hashCode * 397) ^ this.DeviceCoordinates.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
return this.Name;
}
}
}

91
src/ImageSharp/MetaData/Profiles/ICC/Various/IccPositionNumber.cs

@ -0,0 +1,91 @@
// <copyright file="IccPositionNumber.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Position of an object within an ICC profile
/// </summary>
internal struct IccPositionNumber : IEquatable<IccPositionNumber>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccPositionNumber"/> struct.
/// </summary>
/// <param name="offset">Offset in bytes</param>
/// <param name="size">Size in bytes</param>
public IccPositionNumber(uint offset, uint size)
{
this.Offset = offset;
this.Size = size;
}
/// <summary>
/// Gets the offset in bytes
/// </summary>
public uint Offset { get; }
/// <summary>
/// Gets the size in bytes
/// </summary>
public uint Size { get; }
/// <summary>
/// Compares two <see cref="IccPositionNumber"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccPositionNumber"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccPositionNumber"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccPositionNumber left, IccPositionNumber right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccPositionNumber"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccPositionNumber"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccPositionNumber"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccPositionNumber left, IccPositionNumber right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccPositionNumber) && this.Equals((IccPositionNumber)other);
}
/// <inheritdoc/>
public bool Equals(IccPositionNumber other)
{
return this.Offset == other.Offset
&& this.Size == other.Size;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return unchecked((int)(this.Offset ^ this.Size));
}
/// <inheritdoc/>
public override string ToString()
{
return $"{this.Offset}; {this.Size}";
}
}
}

90
src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileDescription.cs

@ -0,0 +1,90 @@
// <copyright file="IccProfileDescription.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// ICC Profile description
/// </summary>
internal sealed class IccProfileDescription : IEquatable<IccProfileDescription>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileDescription"/> class.
/// </summary>
/// <param name="deviceManufacturer">Device Manufacturer</param>
/// <param name="deviceModel">Device Model</param>
/// <param name="deviceAttributes">Device Attributes</param>
/// <param name="technologyInformation">Technology Information</param>
/// <param name="deviceManufacturerInfo">Device Manufacturer Info</param>
/// <param name="deviceModelInfo">Device Model Info</param>
public IccProfileDescription(
uint deviceManufacturer,
uint deviceModel,
IccDeviceAttribute deviceAttributes,
IccProfileTag technologyInformation,
IccLocalizedString[] deviceManufacturerInfo,
IccLocalizedString[] deviceModelInfo)
{
Guard.NotNull(deviceManufacturerInfo, nameof(deviceManufacturerInfo));
Guard.NotNull(deviceModelInfo, nameof(deviceModelInfo));
this.DeviceManufacturer = deviceManufacturer;
this.DeviceModel = deviceModel;
this.DeviceAttributes = deviceAttributes;
this.TechnologyInformation = technologyInformation;
this.DeviceManufacturerInfo = deviceManufacturerInfo;
this.DeviceModelInfo = deviceModelInfo;
}
/// <summary>
/// Gets the device manufacturer
/// </summary>
public uint DeviceManufacturer { get; }
/// <summary>
/// Gets the device model
/// </summary>
public uint DeviceModel { get; }
/// <summary>
/// Gets the device attributes
/// </summary>
public IccDeviceAttribute DeviceAttributes { get; }
/// <summary>
/// Gets the technology information
/// </summary>
public IccProfileTag TechnologyInformation { get; }
/// <summary>
/// Gets the device manufacturer info
/// </summary>
public IccLocalizedString[] DeviceManufacturerInfo { get; }
/// <summary>
/// Gets the device model info
/// </summary>
public IccLocalizedString[] DeviceModelInfo { get; }
/// <inheritdoc />
public bool Equals(IccProfileDescription other)
{
if (ReferenceEquals(this, other))
{
return true;
}
return this.DeviceManufacturer == other.DeviceManufacturer
&& this.DeviceModel == other.DeviceModel
&& this.DeviceAttributes == other.DeviceAttributes
&& this.TechnologyInformation == other.TechnologyInformation
&& this.DeviceManufacturerInfo.SequenceEqual(other.DeviceManufacturerInfo)
&& this.DeviceModelInfo.SequenceEqual(other.DeviceModelInfo);
}
}
}

138
src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileId.cs

@ -0,0 +1,138 @@
// <copyright file="IccProfileId.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// ICC Profile ID
/// </summary>
internal struct IccProfileId : IEquatable<IccProfileId>
{
/// <summary>
/// A profile ID with all values set to zero
/// </summary>
public static readonly IccProfileId Zero = new IccProfileId(0, 0, 0, 0);
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileId"/> struct.
/// </summary>
/// <param name="p1">Part 1 of the ID</param>
/// <param name="p2">Part 2 of the ID</param>
/// <param name="p3">Part 3 of the ID</param>
/// <param name="p4">Part 4 of the ID</param>
public IccProfileId(uint p1, uint p2, uint p3, uint p4)
{
this.Part1 = p1;
this.Part2 = p2;
this.Part3 = p3;
this.Part4 = p4;
}
/// <summary>
/// Gets the first part of the ID
/// </summary>
public uint Part1 { get; }
/// <summary>
/// Gets the second part of the ID
/// </summary>
public uint Part2 { get; }
/// <summary>
/// Gets the third part of the ID
/// </summary>
public uint Part3 { get; }
/// <summary>
/// Gets the fourth part of the ID
/// </summary>
public uint Part4 { get; }
/// <summary>
/// Gets a value indicating whether the ID is set or just consists of zeros
/// </summary>
public bool IsSet
{
get
{
return this.Part1 != 0
&& this.Part2 != 0
&& this.Part3 != 0
&& this.Part4 != 0;
}
}
/// <summary>
/// Compares two <see cref="IccProfileId"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccProfileId"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccProfileId"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccProfileId left, IccProfileId right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccProfileId"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccProfileId"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccProfileId"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccProfileId left, IccProfileId right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccProfileId) && this.Equals((IccProfileId)other);
}
/// <inheritdoc/>
public bool Equals(IccProfileId other)
{
return this.Part1 == other.Part1
&& this.Part2 == other.Part2
&& this.Part3 == other.Part3
&& this.Part4 == other.Part4;
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.Part1.GetHashCode();
hashCode = (hashCode * 397) ^ this.Part2.GetHashCode();
hashCode = (hashCode * 397) ^ this.Part3.GetHashCode();
hashCode = (hashCode * 397) ^ this.Part4.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"{ToHex(this.Part1)}-{ToHex(this.Part2)}-{ToHex(this.Part3)}-{ToHex(this.Part4)}";
}
private static string ToHex(uint value)
{
return value.ToString("X").PadLeft(8, '0');
}
}
}

51
src/ImageSharp/MetaData/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs

@ -0,0 +1,51 @@
// <copyright file="IccProfileSequenceIdentifier.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Linq;
/// <summary>
/// Description of a profile within a sequence
/// </summary>
internal sealed class IccProfileSequenceIdentifier : IEquatable<IccProfileSequenceIdentifier>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccProfileSequenceIdentifier"/> class.
/// </summary>
/// <param name="id">ID of the profile</param>
/// <param name="description">Description of the profile</param>
public IccProfileSequenceIdentifier(IccProfileId id, IccLocalizedString[] description)
{
Guard.NotNull(description, nameof(description));
this.Id = id;
this.Description = description;
}
/// <summary>
/// Gets the ID of the profile
/// </summary>
public IccProfileId Id { get; }
/// <summary>
/// Gets the description of the profile
/// </summary>
public IccLocalizedString[] Description { get; }
/// <inheritdoc />
public bool Equals(IccProfileSequenceIdentifier other)
{
if (ReferenceEquals(this, other))
{
return true;
}
return this.Id.Equals(other.Id)
&& this.Description.SequenceEqual(other.Description);
}
}
}

96
src/ImageSharp/MetaData/Profiles/ICC/Various/IccResponseNumber.cs

@ -0,0 +1,96 @@
// <copyright file="IccResponseNumber.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Associates a normalized device code with a measurement value
/// </summary>
internal struct IccResponseNumber : IEquatable<IccResponseNumber>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccResponseNumber"/> struct.
/// </summary>
/// <param name="deviceCode">Device Code</param>
/// <param name="measurementValue">Measurement Value</param>
public IccResponseNumber(ushort deviceCode, float measurementValue)
{
this.DeviceCode = deviceCode;
this.MeasurementValue = measurementValue;
}
/// <summary>
/// Gets the device code
/// </summary>
public ushort DeviceCode { get; }
/// <summary>
/// Gets the measurement value
/// </summary>
public float MeasurementValue { get; }
/// <summary>
/// Compares two <see cref="IccResponseNumber"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccResponseNumber"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccResponseNumber"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccResponseNumber left, IccResponseNumber right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccResponseNumber"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccResponseNumber"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccResponseNumber"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccResponseNumber left, IccResponseNumber right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccResponseNumber) && this.Equals((IccResponseNumber)other);
}
/// <inheritdoc/>
public bool Equals(IccResponseNumber other)
{
return this.DeviceCode == other.DeviceCode
&& this.MeasurementValue == other.MeasurementValue;
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.DeviceCode.GetHashCode();
hashCode = (hashCode * 397) ^ this.MeasurementValue.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"Code: {this.DeviceCode}; Value: {this.MeasurementValue}";
}
}
}

105
src/ImageSharp/MetaData/Profiles/ICC/Various/IccTagTableEntry.cs

@ -0,0 +1,105 @@
// <copyright file="IccTagTableEntry.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
/// <summary>
/// Entry of ICC tag table
/// </summary>
internal struct IccTagTableEntry : IEquatable<IccTagTableEntry>
{
/// <summary>
/// Initializes a new instance of the <see cref="IccTagTableEntry"/> struct.
/// </summary>
/// <param name="signature">Signature of the tag</param>
/// <param name="offset">Offset of entry in bytes</param>
/// <param name="dataSize">Size of entry in bytes</param>
public IccTagTableEntry(IccProfileTag signature, uint offset, uint dataSize)
{
this.Signature = signature;
this.Offset = offset;
this.DataSize = dataSize;
}
/// <summary>
/// Gets the signature of the tag
/// </summary>
public IccProfileTag Signature { get; }
/// <summary>
/// Gets the offset of entry in bytes
/// </summary>
public uint Offset { get; }
/// <summary>
/// Gets the size of entry in bytes
/// </summary>
public uint DataSize { get; }
/// <summary>
/// Compares two <see cref="IccTagTableEntry"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="IccTagTableEntry"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="IccTagTableEntry"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(IccTagTableEntry left, IccTagTableEntry right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="IccTagTableEntry"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="IccTagTableEntry"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="IccTagTableEntry"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(IccTagTableEntry left, IccTagTableEntry right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object other)
{
return (other is IccProfileId) && this.Equals((IccProfileId)other);
}
/// <inheritdoc/>
public bool Equals(IccTagTableEntry other)
{
return this.Signature == other.Signature
&& this.Offset == other.Offset
&& this.DataSize == other.DataSize;
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.Signature.GetHashCode();
hashCode = (hashCode * 397) ^ this.Offset.GetHashCode();
hashCode = (hashCode * 397) ^ this.DataSize.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"{this.Signature} (Offset: {this.Offset}; Size: {this.DataSize})";
}
}
}
Loading…
Cancel
Save