Update src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs

Co-authored-by: Eliot Jones <elioty@hotmail.co.uk>
This commit is contained in:
BobLd 2024-02-14 21:13:02 +00:00
parent 9f3d2745f6
commit 189c0efbba

View File

@ -1,5 +1,5 @@
namespace UglyToad.PdfPig.Graphics.Colors namespace UglyToad.PdfPig.Graphics.Colors
{ {
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -10,39 +10,39 @@
using UglyToad.PdfPig.Util; using UglyToad.PdfPig.Util;
using UglyToad.PdfPig.Util.JetBrains.Annotations; using UglyToad.PdfPig.Util.JetBrains.Annotations;
/// <summary> /// <summary>
/// Contains more document-specific information about the <see cref="ColorSpace"/>. /// Contains more document-specific information about the <see cref="ColorSpace"/>.
/// </summary> /// </summary>
public abstract class ColorSpaceDetails public abstract class ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The type of the ColorSpace. /// The type of the ColorSpace.
/// </summary> /// </summary>
public ColorSpace Type { get; } public ColorSpace Type { get; }
/// <summary> /// <summary>
/// The number of components for the color space. /// The number of components for the color space.
/// </summary> /// </summary>
public abstract int NumberOfColorComponents { get; } public abstract int NumberOfColorComponents { get; }
/// <summary> /// <summary>
/// The underlying type of <see cref="ColorSpace"/>, usually equal to <see cref="Type"/> /// The underlying type of <see cref="ColorSpace"/>, usually equal to <see cref="Type"/>
/// unless <see cref="ColorSpace.Indexed"/> or <see cref="ColorSpace.DeviceN"/>. /// unless <see cref="ColorSpace.Indexed"/> or <see cref="ColorSpace.DeviceN"/>.
/// </summary> /// </summary>
public ColorSpace BaseType { get; protected set; } public ColorSpace BaseType { get; protected set; }
/// <summary> /// <summary>
/// The number of components for the underlying color space. /// The number of components for the underlying color space.
/// </summary> /// </summary>
internal abstract int BaseNumberOfColorComponents { get; } internal abstract int BaseNumberOfColorComponents { get; }
/// <summary> /// <summary>
/// Create a new <see cref="ColorSpaceDetails"/>. /// Create a new <see cref="ColorSpaceDetails"/>.
/// </summary> /// </summary>
protected internal ColorSpaceDetails(ColorSpace type) protected internal ColorSpaceDetails(ColorSpace type)
{ {
Type = type; Type = type;
BaseType = type; BaseType = type;
} }
/// <summary> /// <summary>
@ -73,17 +73,17 @@
var rounded = Math.Round(componentValue * 255, MidpointRounding.AwayFromZero); var rounded = Math.Round(componentValue * 255, MidpointRounding.AwayFromZero);
return (byte)rounded; return (byte)rounded;
} }
} }
/// <summary> /// <summary>
/// A grayscale value is represented by a single number in the range 0.0 to 1.0, /// A grayscale value is represented by a single number in the range 0.0 to 1.0,
/// where 0.0 corresponds to black, 1.0 to white, and intermediate values to different gray levels. /// where 0.0 corresponds to black, 1.0 to white, and intermediate values to different gray levels.
/// </summary> /// </summary>
public sealed class DeviceGrayColorSpaceDetails : ColorSpaceDetails public sealed class DeviceGrayColorSpaceDetails : ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The single instance of the <see cref="DeviceGrayColorSpaceDetails"/>. /// The single instance of the <see cref="DeviceGrayColorSpaceDetails"/>.
/// </summary> /// </summary>
public static readonly DeviceGrayColorSpaceDetails Instance = new DeviceGrayColorSpaceDetails(); public static readonly DeviceGrayColorSpaceDetails Instance = new DeviceGrayColorSpaceDetails();
/// <inheritdoc/> /// <inheritdoc/>
@ -91,8 +91,8 @@
/// <inheritdoc/> /// <inheritdoc/>
internal override int BaseNumberOfColorComponents => NumberOfColorComponents; internal override int BaseNumberOfColorComponents => NumberOfColorComponents;
private DeviceGrayColorSpaceDetails() : base(ColorSpace.DeviceGray) private DeviceGrayColorSpaceDetails() : base(ColorSpace.DeviceGray)
{ } { }
/// <inheritdoc/> /// <inheritdoc/>
@ -135,17 +135,17 @@
{ {
return decoded; return decoded;
} }
} }
/// <summary> /// <summary>
/// Color values are defined by three components representing the intensities of the additive primary colorants red, green and blue. /// Color values are defined by three components representing the intensities of the additive primary colorants red, green and blue.
/// Each component is specified by a number in the range 0.0 to 1.0, where 0.0 denotes the complete absence of a primary component and 1.0 denotes maximum intensity. /// Each component is specified by a number in the range 0.0 to 1.0, where 0.0 denotes the complete absence of a primary component and 1.0 denotes maximum intensity.
/// </summary> /// </summary>
public sealed class DeviceRgbColorSpaceDetails : ColorSpaceDetails public sealed class DeviceRgbColorSpaceDetails : ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The single instance of the <see cref="DeviceRgbColorSpaceDetails"/>. /// The single instance of the <see cref="DeviceRgbColorSpaceDetails"/>.
/// </summary> /// </summary>
public static readonly DeviceRgbColorSpaceDetails Instance = new DeviceRgbColorSpaceDetails(); public static readonly DeviceRgbColorSpaceDetails Instance = new DeviceRgbColorSpaceDetails();
/// <inheritdoc/> /// <inheritdoc/>
@ -153,8 +153,8 @@
/// <inheritdoc/> /// <inheritdoc/>
internal override int BaseNumberOfColorComponents => NumberOfColorComponents; internal override int BaseNumberOfColorComponents => NumberOfColorComponents;
private DeviceRgbColorSpaceDetails() : base(ColorSpace.DeviceRGB) private DeviceRgbColorSpaceDetails() : base(ColorSpace.DeviceRGB)
{ } { }
/// <inheritdoc/> /// <inheritdoc/>
@ -196,17 +196,17 @@
internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded) internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded)
{ {
return decoded; return decoded;
} }
} }
/// <summary> /// <summary>
/// Color values are defined by four components cyan, magenta, yellow and black. /// Color values are defined by four components cyan, magenta, yellow and black.
/// </summary> /// </summary>
public sealed class DeviceCmykColorSpaceDetails : ColorSpaceDetails public sealed class DeviceCmykColorSpaceDetails : ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The single instance of the <see cref="DeviceCmykColorSpaceDetails"/>. /// The single instance of the <see cref="DeviceCmykColorSpaceDetails"/>.
/// </summary> /// </summary>
public static readonly DeviceCmykColorSpaceDetails Instance = new DeviceCmykColorSpaceDetails(); public static readonly DeviceCmykColorSpaceDetails Instance = new DeviceCmykColorSpaceDetails();
/// <inheritdoc/> /// <inheritdoc/>
@ -214,9 +214,9 @@
/// <inheritdoc/> /// <inheritdoc/>
internal override int BaseNumberOfColorComponents => NumberOfColorComponents; internal override int BaseNumberOfColorComponents => NumberOfColorComponents;
private DeviceCmykColorSpaceDetails() : base(ColorSpace.DeviceCMYK) private DeviceCmykColorSpaceDetails() : base(ColorSpace.DeviceCMYK)
{ {
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -259,17 +259,17 @@
internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded) internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded)
{ {
return decoded; return decoded;
} }
} }
/// <summary> /// <summary>
/// An Indexed color space allows a PDF content stream to use small integers as indices into a color map or color table of arbitrary colors in some other space. /// An Indexed color space allows a PDF content stream to use small integers as indices into a color map or color table of arbitrary colors in some other space.
/// A PDF consumer treats each sample value as an index into the color table and uses the color value it finds there. /// A PDF consumer treats each sample value as an index into the color table and uses the color value it finds there.
/// </summary> /// </summary>
public sealed class IndexedColorSpaceDetails : ColorSpaceDetails public sealed class IndexedColorSpaceDetails : ColorSpaceDetails
{ {
private readonly ConcurrentDictionary<double, IColor> cache = new ConcurrentDictionary<double, IColor>(); private readonly ConcurrentDictionary<double, IColor> cache = new ConcurrentDictionary<double, IColor>();
/// <summary> /// <summary>
/// Creates a indexed color space useful for extracting stencil masks as black-and-white images, /// Creates a indexed color space useful for extracting stencil masks as black-and-white images,
/// i.e. with a color palette of two colors (black and white). If the decode parameter array is /// i.e. with a color palette of two colors (black and white). If the decode parameter array is
@ -290,34 +290,34 @@
/// <para>In the case of <see cref="IndexedColorSpaceDetails"/>, gets the <see cref="BaseColorSpace"/>' <c>BaseNumberOfColorComponents</c>.</para> /// <para>In the case of <see cref="IndexedColorSpaceDetails"/>, gets the <see cref="BaseColorSpace"/>' <c>BaseNumberOfColorComponents</c>.</para>
/// </summary> /// </summary>
internal override int BaseNumberOfColorComponents => BaseColorSpace.BaseNumberOfColorComponents; internal override int BaseNumberOfColorComponents => BaseColorSpace.BaseNumberOfColorComponents;
/// <summary> /// <summary>
/// The base color space in which the values in the color table are to be interpreted. /// The base color space in which the values in the color table are to be interpreted.
/// It can be any device or CIE-based color space or (in PDF 1.3) a Separation or DeviceN space, /// It can be any device or CIE-based color space or (in PDF 1.3) a Separation or DeviceN space,
/// but not a Pattern space or another Indexed space. /// but not a Pattern space or another Indexed space.
/// </summary> /// </summary>
public ColorSpaceDetails BaseColorSpace { get; } public ColorSpaceDetails BaseColorSpace { get; }
/// <summary> /// <summary>
/// An integer that specifies the maximum valid index value. Can be no greater than 255. /// An integer that specifies the maximum valid index value. Can be no greater than 255.
/// </summary> /// </summary>
public byte HiVal { get; } public byte HiVal { get; }
/// <summary> /// <summary>
/// Provides the mapping between index values and the corresponding colors in the base color space. /// Provides the mapping between index values and the corresponding colors in the base color space.
/// </summary> /// </summary>
public IReadOnlyList<byte> ColorTable { get; } public IReadOnlyList<byte> ColorTable { get; }
/// <summary> /// <summary>
/// Create a new <see cref="IndexedColorSpaceDetails"/>. /// Create a new <see cref="IndexedColorSpaceDetails"/>.
/// </summary> /// </summary>
public IndexedColorSpaceDetails(ColorSpaceDetails baseColorSpaceDetails, byte hiVal, IReadOnlyList<byte> colorTable) public IndexedColorSpaceDetails(ColorSpaceDetails baseColorSpaceDetails, byte hiVal, IReadOnlyList<byte> colorTable)
: base(ColorSpace.Indexed) : base(ColorSpace.Indexed)
{ {
BaseColorSpace = baseColorSpaceDetails ?? throw new ArgumentNullException(nameof(baseColorSpaceDetails)); BaseColorSpace = baseColorSpaceDetails ?? throw new ArgumentNullException(nameof(baseColorSpaceDetails));
HiVal = hiVal; HiVal = hiVal;
ColorTable = colorTable; ColorTable = colorTable;
BaseType = baseColorSpaceDetails.Type; BaseType = baseColorSpaceDetails.Type;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -342,83 +342,83 @@
}); });
} }
internal byte[] UnwrapIndexedColorSpaceBytes(IReadOnlyList<byte> input) internal byte[] UnwrapIndexedColorSpaceBytes(IReadOnlyList<byte> input)
{ {
var multiplier = 1; var multiplier = 1;
Func<byte, IEnumerable<byte>> transformer = null; Func<byte, IEnumerable<byte>> transformer = null;
switch (BaseType) switch (BaseType)
{ {
case ColorSpace.DeviceRGB: case ColorSpace.DeviceRGB:
case ColorSpace.CalRGB: case ColorSpace.CalRGB:
case ColorSpace.Lab: case ColorSpace.Lab:
transformer = x => transformer = x =>
{ {
var r = new byte[3]; var r = new byte[3];
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
{ {
r[i] = ColorTable[x * 3 + i]; r[i] = ColorTable[x * 3 + i];
} }
return r; return r;
}; };
multiplier = 3; multiplier = 3;
break; break;
case ColorSpace.DeviceCMYK: case ColorSpace.DeviceCMYK:
transformer = x => transformer = x =>
{ {
var r = new byte[4]; var r = new byte[4];
for (var i = 0; i < 4; i++) for (var i = 0; i < 4; i++)
{ {
r[i] = ColorTable[x * 4 + i]; r[i] = ColorTable[x * 4 + i];
} }
return r; return r;
}; };
multiplier = 4; multiplier = 4;
break; break;
case ColorSpace.DeviceGray: case ColorSpace.DeviceGray:
case ColorSpace.CalGray: case ColorSpace.CalGray:
case ColorSpace.Separation: case ColorSpace.Separation:
transformer = x => new[] { ColorTable[x] }; transformer = x => new[] { ColorTable[x] };
multiplier = 1; multiplier = 1;
break; break;
case ColorSpace.DeviceN: case ColorSpace.DeviceN:
case ColorSpace.ICCBased: case ColorSpace.ICCBased:
transformer = x => transformer = x =>
{ {
var r = new byte[BaseColorSpace.NumberOfColorComponents]; var r = new byte[BaseColorSpace.NumberOfColorComponents];
for (var i = 0; i < BaseColorSpace.NumberOfColorComponents; i++) for (var i = 0; i < BaseColorSpace.NumberOfColorComponents; i++)
{ {
r[i] = ColorTable[x * BaseColorSpace.NumberOfColorComponents + i]; r[i] = ColorTable[x * BaseColorSpace.NumberOfColorComponents + i];
} }
return r; return r;
}; };
multiplier = BaseColorSpace.NumberOfColorComponents; multiplier = BaseColorSpace.NumberOfColorComponents;
break; break;
} }
if (transformer != null) if (transformer != null)
{ {
var result = new byte[input.Count * multiplier]; var result = new byte[input.Count * multiplier];
var i = 0; var i = 0;
foreach (var b in input) foreach (var b in input)
{ {
foreach (var newByte in transformer(b)) foreach (var newByte in transformer(b))
{ {
result[i++] = newByte; result[i++] = newByte;
} }
} }
return result; return result;
} }
return input.ToArray(); return input.ToArray();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -617,14 +617,14 @@
} }
} }
} }
/// <summary> /// <summary>
/// A Separation color space provides a means for specifying the use of additional colorants or /// A Separation color space provides a means for specifying the use of additional colorants or
/// for isolating the control of individual color components of a device color space for a subtractive device. /// for isolating the control of individual color components of a device color space for a subtractive device.
/// When such a space is the current color space, the current color is a single-component value, called a tint, /// When such a space is the current color space, the current color is a single-component value, called a tint,
/// that controls the application of the given colorant or color components only. /// that controls the application of the given colorant or color components only.
/// </summary> /// </summary>
public sealed class SeparationColorSpaceDetails : ColorSpaceDetails public sealed class SeparationColorSpaceDetails : ColorSpaceDetails
{ {
private readonly ConcurrentDictionary<double, IColor> cache = new ConcurrentDictionary<double, IColor>(); private readonly ConcurrentDictionary<double, IColor> cache = new ConcurrentDictionary<double, IColor>();
@ -633,49 +633,49 @@
/// <inheritdoc/> /// <inheritdoc/>
internal override int BaseNumberOfColorComponents => AlternateColorSpace.NumberOfColorComponents; internal override int BaseNumberOfColorComponents => AlternateColorSpace.NumberOfColorComponents;
/// <summary>
/// Specifies the name of the colorant that this Separation color space is intended to represent.
/// </summary>
/// <remarks>
/// <para>
/// The special colorant name All refers collectively to all colorants available on an output device,
/// including those for the standard process colorants.
/// </para>
/// <para>
/// The special colorant name None never produces any visible output.
/// Painting operations in a Separation space with this colorant name have no effect on the current page.
/// </para>
/// </remarks>
public NameToken Name { get; }
/// <summary>
/// If the colorant name associated with a Separation color space does not correspond to a colorant available on the device,
/// the application arranges for subsequent painting operations to be performed in an alternate color space.
/// The intended colors can be approximated by colors in a device or CIE-based color space
/// which are then rendered with the usual primary or process colorants.
/// </summary>
public ColorSpaceDetails AlternateColorSpace { get; }
/// <summary> /// <summary>
/// During subsequent painting operations, an application calls this function to transform a tint value into /// Specifies the name of the colorant that this Separation color space is intended to represent.
/// color component values in the alternate color space. /// </summary>
/// The function is called with the tint value and must return the corresponding color component values. /// <remarks>
/// That is, the number of components and the interpretation of their values depend on the <see cref="AlternateColorSpace"/>. /// <para>
/// The special colorant name All refers collectively to all colorants available on an output device,
/// including those for the standard process colorants.
/// </para>
/// <para>
/// The special colorant name None never produces any visible output.
/// Painting operations in a Separation space with this colorant name have no effect on the current page.
/// </para>
/// </remarks>
public NameToken Name { get; }
/// <summary>
/// If the colorant name associated with a Separation color space does not correspond to a colorant available on the device,
/// the application arranges for subsequent painting operations to be performed in an alternate color space.
/// The intended colors can be approximated by colors in a device or CIE-based color space
/// which are then rendered with the usual primary or process colorants.
/// </summary>
public ColorSpaceDetails AlternateColorSpace { get; }
/// <summary>
/// During subsequent painting operations, an application calls this function to transform a tint value into
/// color component values in the alternate color space.
/// The function is called with the tint value and must return the corresponding color component values.
/// That is, the number of components and the interpretation of their values depend on the <see cref="AlternateColorSpace"/>.
/// </summary> /// </summary>
public PdfFunction TintFunction { get; } public PdfFunction TintFunction { get; }
/// <summary> /// <summary>
/// Create a new <see cref="SeparationColorSpaceDetails"/>. /// Create a new <see cref="SeparationColorSpaceDetails"/>.
/// </summary> /// </summary>
public SeparationColorSpaceDetails(NameToken name, public SeparationColorSpaceDetails(NameToken name,
ColorSpaceDetails alternateColorSpaceDetails, ColorSpaceDetails alternateColorSpaceDetails,
PdfFunction tintFunction) PdfFunction tintFunction)
: base(ColorSpace.Separation) : base(ColorSpace.Separation)
{ {
Name = name; Name = name;
AlternateColorSpace = alternateColorSpaceDetails; AlternateColorSpace = alternateColorSpaceDetails;
TintFunction = tintFunction; TintFunction = tintFunction;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -730,14 +730,14 @@
{ {
// The initial value for both the stroking and nonstroking colour in the graphics state shall be 1.0. // The initial value for both the stroking and nonstroking colour in the graphics state shall be 1.0.
return GetColor(1.0); return GetColor(1.0);
} }
} }
/// <summary> /// <summary>
/// CIE (Commission Internationale de l'Éclairage) colorspace. /// CIE (Commission Internationale de l'Éclairage) colorspace.
/// Specifies color related to human visual perception with the aim of producing consistent color on different output devices. /// Specifies color related to human visual perception with the aim of producing consistent color on different output devices.
/// CalGray - A CIE A color space with a single transformation. /// CalGray - A CIE A color space with a single transformation.
/// A represents the gray component of a calibrated gray space. The component must be in the range 0.0 to 1.0. /// A represents the gray component of a calibrated gray space. The component must be in the range 0.0 to 1.0.
/// </summary> /// </summary>
public sealed class CalGrayColorSpaceDetails : ColorSpaceDetails public sealed class CalGrayColorSpaceDetails : ColorSpaceDetails
{ {
@ -767,8 +767,8 @@
/// </summary> /// </summary>
public double Gamma { get; } public double Gamma { get; }
/// <summary> /// <summary>
/// Create a new <see cref="CalGrayColorSpaceDetails"/>. /// Create a new <see cref="CalGrayColorSpaceDetails"/>.
/// </summary> /// </summary>
public CalGrayColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, double? gamma) public CalGrayColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, double? gamma)
: base(ColorSpace.CalGray) : base(ColorSpace.CalGray)
@ -857,12 +857,12 @@
} }
} }
/// <summary> /// <summary>
/// CIE (Commission Internationale de l'Éclairage) colorspace. /// CIE (Commission Internationale de l'Éclairage) colorspace.
/// Specifies color related to human visual perception with the aim of producing consistent color on different output devices. /// Specifies color related to human visual perception with the aim of producing consistent color on different output devices.
/// CalRGB - A CIE ABC color space with a single transformation. /// CalRGB - A CIE ABC color space with a single transformation.
/// A, B and C represent red, green and blue color values in the range 0.0 to 1.0. /// A, B and C represent red, green and blue color values in the range 0.0 to 1.0.
/// </summary> /// </summary>
public sealed class CalRGBColorSpaceDetails : ColorSpaceDetails public sealed class CalRGBColorSpaceDetails : ColorSpaceDetails
{ {
/// <inheritdoc/> /// <inheritdoc/>
@ -898,8 +898,8 @@
/// </summary> /// </summary>
public IReadOnlyList<double> Matrix { get; } public IReadOnlyList<double> Matrix { get; }
/// <summary> /// <summary>
/// Create a new <see cref="CalRGBColorSpaceDetails"/>. /// Create a new <see cref="CalRGBColorSpaceDetails"/>.
/// </summary> /// </summary>
public CalRGBColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, [CanBeNull] IReadOnlyList<double> gamma, [CanBeNull] IReadOnlyList<double> matrix) public CalRGBColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, [CanBeNull] IReadOnlyList<double> gamma, [CanBeNull] IReadOnlyList<double> matrix)
: base(ColorSpace.CalRGB) : base(ColorSpace.CalRGB)
@ -944,7 +944,8 @@
} }
/// <summary> /// <summary>
/// Transforms the supplied ABC color to RGB (sRGB) using the propeties of this <see cref="CalRGBColorSpaceDetails"/> /// Transforms the supplied ABC color to RGB (sRGB) using the properties of this <see cref="CalRGBColorSpaceDetails"/>
/// in the transformation process. /// in the transformation process.
/// A, B and C represent red, green and blue calibrated color values in the range 0.0 to 1.0. /// A, B and C represent red, green and blue calibrated color values in the range 0.0 to 1.0.
/// </summary> /// </summary>
@ -1139,8 +1140,8 @@
double c = PdfFunction.ClipToRange(0, Matrix[2], Matrix[3]); double c = PdfFunction.ClipToRange(0, Matrix[2], Matrix[3]);
return TransformToRGB((0, b, c)); return TransformToRGB((0, b, c));
} }
} }
/// <summary> /// <summary>
/// The ICCBased color space is one of the CIE-based color spaces supported in PDFs. These color spaces /// The ICCBased color space is one of the CIE-based color spaces supported in PDFs. These color spaces
/// enable a page description to specify color values in a way that is related to human visual perception. /// enable a page description to specify color values in a way that is related to human visual perception.
@ -1150,8 +1151,8 @@
/// Currently support for this color space is limited in PdfPig. Calculations will only be based on /// Currently support for this color space is limited in PdfPig. Calculations will only be based on
/// the color space of <see cref="AlternateColorSpace"/>. /// the color space of <see cref="AlternateColorSpace"/>.
/// </para> /// </para>
/// </summary> /// </summary>
public sealed class ICCBasedColorSpaceDetails : ColorSpaceDetails public sealed class ICCBasedColorSpaceDetails : ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The number of color components in the color space described by the ICC profile data. /// The number of color components in the color space described by the ICC profile data.
@ -1193,32 +1194,32 @@
[CanBeNull] [CanBeNull]
public XmpMetadata Metadata { get; } public XmpMetadata Metadata { get; }
/// <summary> /// <summary>
/// Create a new <see cref="ICCBasedColorSpaceDetails"/>. /// Create a new <see cref="ICCBasedColorSpaceDetails"/>.
/// </summary> /// </summary>
internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails, internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails,
[CanBeNull] IReadOnlyList<double> range, [CanBeNull] XmpMetadata metadata) [CanBeNull] IReadOnlyList<double> range, [CanBeNull] XmpMetadata metadata)
: base(ColorSpace.ICCBased) : base(ColorSpace.ICCBased)
{ {
if (numberOfColorComponents != 1 && numberOfColorComponents != 3 && numberOfColorComponents != 4) if (numberOfColorComponents != 1 && numberOfColorComponents != 3 && numberOfColorComponents != 4)
{ {
throw new ArgumentOutOfRangeException(nameof(numberOfColorComponents), "must be 1, 3 or 4"); throw new ArgumentOutOfRangeException(nameof(numberOfColorComponents), "must be 1, 3 or 4");
} }
NumberOfColorComponents = numberOfColorComponents; NumberOfColorComponents = numberOfColorComponents;
AlternateColorSpace = alternateColorSpaceDetails ?? AlternateColorSpace = alternateColorSpaceDetails ??
(NumberOfColorComponents == 1 ? (ColorSpaceDetails)DeviceGrayColorSpaceDetails.Instance : (NumberOfColorComponents == 1 ? (ColorSpaceDetails)DeviceGrayColorSpaceDetails.Instance :
NumberOfColorComponents == 3 ? (ColorSpaceDetails)DeviceRgbColorSpaceDetails.Instance : (ColorSpaceDetails)DeviceCmykColorSpaceDetails.Instance); NumberOfColorComponents == 3 ? (ColorSpaceDetails)DeviceRgbColorSpaceDetails.Instance : (ColorSpaceDetails)DeviceCmykColorSpaceDetails.Instance);
BaseType = AlternateColorSpace.BaseType; BaseType = AlternateColorSpace.BaseType;
Range = range ?? Range = range ??
Enumerable.Range(0, numberOfColorComponents).Select(x => new[] { 0.0, 1.0 }).SelectMany(x => x).ToArray(); Enumerable.Range(0, numberOfColorComponents).Select(x => new[] { 0.0, 1.0 }).SelectMany(x => x).ToArray();
if (Range.Count != 2 * numberOfColorComponents) if (Range.Count != 2 * numberOfColorComponents)
{ {
throw new ArgumentOutOfRangeException(nameof(range), range, throw new ArgumentOutOfRangeException(nameof(range), range,
$"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range.Count}"); $"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range.Count}");
} }
Metadata = metadata; Metadata = metadata;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -1266,7 +1267,7 @@
// TODO - use ICC profile // TODO - use ICC profile
return AlternateColorSpace.Transform(decoded); return AlternateColorSpace.Transform(decoded);
} }
} }
/// <summary> /// <summary>
@ -1301,8 +1302,8 @@
[CanBeNull] [CanBeNull]
public ColorSpaceDetails UnderlyingColourSpace { get; } public ColorSpaceDetails UnderlyingColourSpace { get; }
/// <summary> /// <summary>
/// Create a new <see cref="PatternColorSpaceDetails"/>. /// Create a new <see cref="PatternColorSpaceDetails"/>.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="underlyingColourSpace">The underlying colour space for Uncoloured Tiling Patterns.</param> /// <param name="underlyingColourSpace">The underlying colour space for Uncoloured Tiling Patterns.</param>
@ -1364,16 +1365,16 @@
{ {
throw new InvalidOperationException("PatternColorSpaceDetails"); throw new InvalidOperationException("PatternColorSpaceDetails");
} }
} }
/// <summary> /// <summary>
/// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace. /// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace.
/// </summary> /// </summary>
public sealed class UnsupportedColorSpaceDetails : ColorSpaceDetails public sealed class UnsupportedColorSpaceDetails : ColorSpaceDetails
{ {
/// <summary> /// <summary>
/// The single instance of the <see cref="UnsupportedColorSpaceDetails"/>. /// The single instance of the <see cref="UnsupportedColorSpaceDetails"/>.
/// </summary> /// </summary>
public static readonly UnsupportedColorSpaceDetails Instance = new UnsupportedColorSpaceDetails(); public static readonly UnsupportedColorSpaceDetails Instance = new UnsupportedColorSpaceDetails();
/// <summary> /// <summary>
@ -1392,8 +1393,8 @@
/// </summary> /// </summary>
internal override int BaseNumberOfColorComponents => NumberOfColorComponents; internal override int BaseNumberOfColorComponents => NumberOfColorComponents;
private UnsupportedColorSpaceDetails() : base(ColorSpace.DeviceGray) private UnsupportedColorSpaceDetails() : base(ColorSpace.DeviceGray)
{ {
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -1418,6 +1419,6 @@
internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded) internal override IReadOnlyList<byte> Transform(IReadOnlyList<byte> decoded)
{ {
throw new InvalidOperationException("UnsupportedColorSpaceDetails"); throw new InvalidOperationException("UnsupportedColorSpaceDetails");
} }
} }
} }