mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
7.2 KiB
219 lines
7.2 KiB
// Copyright (c) Six Labors and contributors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
using System.Numerics;
|
|
|
|
namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
|
|
{
|
|
/// <summary>
|
|
/// Provides methods to read ICC data types
|
|
/// </summary>
|
|
internal sealed partial class IccDataReader
|
|
{
|
|
/// <summary>
|
|
/// Reads a <see cref="IccOneDimensionalCurve"/>
|
|
/// </summary>
|
|
/// <returns>The read curve</returns>
|
|
public IccOneDimensionalCurve ReadOneDimensionalCurve()
|
|
{
|
|
ushort segmentCount = this.ReadUInt16();
|
|
this.AddIndex(2); // 2 bytes reserved
|
|
var breakPoints = new float[segmentCount - 1];
|
|
for (int i = 0; i < breakPoints.Length; i++)
|
|
{
|
|
breakPoints[i] = this.ReadSingle();
|
|
}
|
|
|
|
var segments = new IccCurveSegment[segmentCount];
|
|
for (int i = 0; i < segmentCount; i++)
|
|
{
|
|
segments[i] = this.ReadCurveSegment();
|
|
}
|
|
|
|
return new IccOneDimensionalCurve(breakPoints, segments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a <see cref="IccResponseCurve"/>
|
|
/// </summary>
|
|
/// <param name="channelCount">The number of channels</param>
|
|
/// <returns>The read curve</returns>
|
|
public IccResponseCurve ReadResponseCurve(int channelCount)
|
|
{
|
|
var type = (IccCurveMeasurementEncodings)this.ReadUInt32();
|
|
var measurement = new uint[channelCount];
|
|
for (int i = 0; i < channelCount; i++)
|
|
{
|
|
measurement[i] = this.ReadUInt32();
|
|
}
|
|
|
|
var xyzValues = new Vector3[channelCount];
|
|
for (int i = 0; i < channelCount; i++)
|
|
{
|
|
xyzValues[i] = this.ReadXyzNumber();
|
|
}
|
|
|
|
var response = new IccResponseNumber[channelCount][];
|
|
for (int i = 0; i < channelCount; i++)
|
|
{
|
|
response[i] = new IccResponseNumber[measurement[i]];
|
|
for (uint j = 0; j < measurement[i]; j++)
|
|
{
|
|
response[i][j] = this.ReadResponseNumber();
|
|
}
|
|
}
|
|
|
|
return new IccResponseCurve(type, xyzValues, response);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a <see cref="IccParametricCurve"/>
|
|
/// </summary>
|
|
/// <returns>The read curve</returns>
|
|
public IccParametricCurve ReadParametricCurve()
|
|
{
|
|
ushort type = this.ReadUInt16();
|
|
this.AddIndex(2); // 2 bytes reserved
|
|
float gamma, a, b, c, d, e, f;
|
|
gamma = a = b = c = d = e = f = 0;
|
|
|
|
if (type <= 4)
|
|
{
|
|
gamma = this.ReadFix16();
|
|
}
|
|
|
|
if (type > 0 && type <= 4)
|
|
{
|
|
a = this.ReadFix16();
|
|
b = this.ReadFix16();
|
|
}
|
|
|
|
if (type > 1 && type <= 4)
|
|
{
|
|
c = this.ReadFix16();
|
|
}
|
|
|
|
if (type > 2 && type <= 4)
|
|
{
|
|
d = this.ReadFix16();
|
|
}
|
|
|
|
if (type == 4)
|
|
{
|
|
e = this.ReadFix16();
|
|
f = this.ReadFix16();
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case 0: return new IccParametricCurve(gamma);
|
|
case 1: return new IccParametricCurve(gamma, a, b);
|
|
case 2: return new IccParametricCurve(gamma, a, b, c);
|
|
case 3: return new IccParametricCurve(gamma, a, b, c, d);
|
|
case 4: return new IccParametricCurve(gamma, a, b, c, d, e, f);
|
|
default: throw new InvalidIccProfileException($"Invalid parametric curve type of {type}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a <see cref="IccCurveSegment"/>
|
|
/// </summary>
|
|
/// <returns>The read segment</returns>
|
|
public IccCurveSegment ReadCurveSegment()
|
|
{
|
|
var signature = (IccCurveSegmentSignature)this.ReadUInt32();
|
|
this.AddIndex(4); // 4 bytes reserved
|
|
|
|
switch (signature)
|
|
{
|
|
case IccCurveSegmentSignature.FormulaCurve:
|
|
return this.ReadFormulaCurveElement();
|
|
case IccCurveSegmentSignature.SampledCurve:
|
|
return this.ReadSampledCurveElement();
|
|
default:
|
|
throw new InvalidIccProfileException($"Invalid curve segment type of {signature}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a <see cref="IccFormulaCurveElement"/>
|
|
/// </summary>
|
|
/// <returns>The read segment</returns>
|
|
public IccFormulaCurveElement ReadFormulaCurveElement()
|
|
{
|
|
var type = (IccFormulaCurveType)this.ReadUInt16();
|
|
this.AddIndex(2); // 2 bytes reserved
|
|
float gamma, a, b, c, d, e;
|
|
gamma = d = e = 0;
|
|
|
|
if (type == IccFormulaCurveType.Type1 || type == IccFormulaCurveType.Type2)
|
|
{
|
|
gamma = this.ReadSingle();
|
|
}
|
|
|
|
a = this.ReadSingle();
|
|
b = this.ReadSingle();
|
|
c = this.ReadSingle();
|
|
|
|
if (type == IccFormulaCurveType.Type2 || type == IccFormulaCurveType.Type3)
|
|
{
|
|
d = this.ReadSingle();
|
|
}
|
|
|
|
if (type == IccFormulaCurveType.Type3)
|
|
{
|
|
e = this.ReadSingle();
|
|
}
|
|
|
|
return new IccFormulaCurveElement(type, gamma, a, b, c, d, e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a <see cref="IccSampledCurveElement"/>
|
|
/// </summary>
|
|
/// <returns>The read segment</returns>
|
|
public IccSampledCurveElement ReadSampledCurveElement()
|
|
{
|
|
uint count = this.ReadUInt32();
|
|
var entries = new float[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
entries[i] = this.ReadSingle();
|
|
}
|
|
|
|
return new IccSampledCurveElement(entries);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads curve data
|
|
/// </summary>
|
|
/// <param name="count">Number of input channels</param>
|
|
/// <returns>The curve data</returns>
|
|
private IccTagDataEntry[] ReadCurves(int count)
|
|
{
|
|
var tdata = new IccTagDataEntry[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
IccTypeSignature type = this.ReadTagDataEntryHeader();
|
|
if (type != IccTypeSignature.Curve && type != IccTypeSignature.ParametricCurve)
|
|
{
|
|
throw new InvalidIccProfileException($"Curve has to be either \"{nameof(IccTypeSignature)}.{nameof(IccTypeSignature.Curve)}\" or" +
|
|
$" \"{nameof(IccTypeSignature)}.{nameof(IccTypeSignature.ParametricCurve)}\" for LutAToB- and LutBToA-TagDataEntries");
|
|
}
|
|
|
|
if (type == IccTypeSignature.Curve)
|
|
{
|
|
tdata[i] = this.ReadCurveTagDataEntry();
|
|
}
|
|
else if (type == IccTypeSignature.ParametricCurve)
|
|
{
|
|
tdata[i] = this.ReadParametricCurveTagDataEntry();
|
|
}
|
|
|
|
this.AddPadding();
|
|
}
|
|
|
|
return tdata;
|
|
}
|
|
}
|
|
}
|
|
|