diff --git a/src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs b/src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs index 03427a58..f372d6ff 100644 --- a/src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs +++ b/src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs @@ -1,5 +1,5 @@ -namespace UglyToad.PdfPig.Graphics.Colors -{ +namespace UglyToad.PdfPig.Graphics.Colors +{ using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -10,39 +10,39 @@ using UglyToad.PdfPig.Util; using UglyToad.PdfPig.Util.JetBrains.Annotations; - /// - /// Contains more document-specific information about the . - /// - public abstract class ColorSpaceDetails - { - /// - /// The type of the ColorSpace. - /// + /// + /// Contains more document-specific information about the . + /// + public abstract class ColorSpaceDetails + { + /// + /// The type of the ColorSpace. + /// public ColorSpace Type { get; } /// /// The number of components for the color space. /// public abstract int NumberOfColorComponents { get; } - - /// - /// The underlying type of , usually equal to - /// unless or . - /// + + /// + /// The underlying type of , usually equal to + /// unless or . + /// public ColorSpace BaseType { get; protected set; } /// /// The number of components for the underlying color space. /// internal abstract int BaseNumberOfColorComponents { get; } - - /// - /// Create a new . - /// - protected internal ColorSpaceDetails(ColorSpace type) - { - Type = type; - BaseType = type; + + /// + /// Create a new . + /// + protected internal ColorSpaceDetails(ColorSpace type) + { + Type = type; + BaseType = type; } /// @@ -73,17 +73,17 @@ var rounded = Math.Round(componentValue * 255, MidpointRounding.AwayFromZero); return (byte)rounded; } - } - - /// - /// 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. - /// - public sealed class DeviceGrayColorSpaceDetails : ColorSpaceDetails - { - /// - /// The single instance of the . - /// + } + + /// + /// 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. + /// + public sealed class DeviceGrayColorSpaceDetails : ColorSpaceDetails + { + /// + /// The single instance of the . + /// public static readonly DeviceGrayColorSpaceDetails Instance = new DeviceGrayColorSpaceDetails(); /// @@ -91,8 +91,8 @@ /// internal override int BaseNumberOfColorComponents => NumberOfColorComponents; - - private DeviceGrayColorSpaceDetails() : base(ColorSpace.DeviceGray) + + private DeviceGrayColorSpaceDetails() : base(ColorSpace.DeviceGray) { } /// @@ -135,17 +135,17 @@ { return decoded; } - } - - /// - /// 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. - /// - public sealed class DeviceRgbColorSpaceDetails : ColorSpaceDetails - { - /// - /// The single instance of the . - /// + } + + /// + /// 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. + /// + public sealed class DeviceRgbColorSpaceDetails : ColorSpaceDetails + { + /// + /// The single instance of the . + /// public static readonly DeviceRgbColorSpaceDetails Instance = new DeviceRgbColorSpaceDetails(); /// @@ -153,8 +153,8 @@ /// internal override int BaseNumberOfColorComponents => NumberOfColorComponents; - - private DeviceRgbColorSpaceDetails() : base(ColorSpace.DeviceRGB) + + private DeviceRgbColorSpaceDetails() : base(ColorSpace.DeviceRGB) { } /// @@ -196,17 +196,17 @@ internal override IReadOnlyList Transform(IReadOnlyList decoded) { return decoded; - } - } - - /// - /// Color values are defined by four components cyan, magenta, yellow and black. - /// - public sealed class DeviceCmykColorSpaceDetails : ColorSpaceDetails - { - /// - /// The single instance of the . - /// + } + } + + /// + /// Color values are defined by four components cyan, magenta, yellow and black. + /// + public sealed class DeviceCmykColorSpaceDetails : ColorSpaceDetails + { + /// + /// The single instance of the . + /// public static readonly DeviceCmykColorSpaceDetails Instance = new DeviceCmykColorSpaceDetails(); /// @@ -214,9 +214,9 @@ /// internal override int BaseNumberOfColorComponents => NumberOfColorComponents; - - private DeviceCmykColorSpaceDetails() : base(ColorSpace.DeviceCMYK) - { + + private DeviceCmykColorSpaceDetails() : base(ColorSpace.DeviceCMYK) + { } /// @@ -259,17 +259,17 @@ internal override IReadOnlyList Transform(IReadOnlyList decoded) { return decoded; - } - } - - /// - /// 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. - /// - public sealed class IndexedColorSpaceDetails : ColorSpaceDetails + } + } + + /// + /// 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. + /// + public sealed class IndexedColorSpaceDetails : ColorSpaceDetails { private readonly ConcurrentDictionary cache = new ConcurrentDictionary(); - + /// /// 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 @@ -290,34 +290,34 @@ /// In the case of , gets the ' BaseNumberOfColorComponents. /// internal override int BaseNumberOfColorComponents => BaseColorSpace.BaseNumberOfColorComponents; - - /// - /// 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, - /// but not a Pattern space or another Indexed space. - /// - public ColorSpaceDetails BaseColorSpace { get; } - - /// - /// An integer that specifies the maximum valid index value. Can be no greater than 255. - /// - public byte HiVal { get; } - - /// - /// Provides the mapping between index values and the corresponding colors in the base color space. - /// - public IReadOnlyList ColorTable { get; } - - /// - /// Create a new . - /// - public IndexedColorSpaceDetails(ColorSpaceDetails baseColorSpaceDetails, byte hiVal, IReadOnlyList colorTable) - : base(ColorSpace.Indexed) - { - BaseColorSpace = baseColorSpaceDetails ?? throw new ArgumentNullException(nameof(baseColorSpaceDetails)); - HiVal = hiVal; - ColorTable = colorTable; - BaseType = baseColorSpaceDetails.Type; + + /// + /// 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, + /// but not a Pattern space or another Indexed space. + /// + public ColorSpaceDetails BaseColorSpace { get; } + + /// + /// An integer that specifies the maximum valid index value. Can be no greater than 255. + /// + public byte HiVal { get; } + + /// + /// Provides the mapping between index values and the corresponding colors in the base color space. + /// + public IReadOnlyList ColorTable { get; } + + /// + /// Create a new . + /// + public IndexedColorSpaceDetails(ColorSpaceDetails baseColorSpaceDetails, byte hiVal, IReadOnlyList colorTable) + : base(ColorSpace.Indexed) + { + BaseColorSpace = baseColorSpaceDetails ?? throw new ArgumentNullException(nameof(baseColorSpaceDetails)); + HiVal = hiVal; + ColorTable = colorTable; + BaseType = baseColorSpaceDetails.Type; } /// @@ -342,83 +342,83 @@ }); } - internal byte[] UnwrapIndexedColorSpaceBytes(IReadOnlyList input) + internal byte[] UnwrapIndexedColorSpaceBytes(IReadOnlyList input) { - var multiplier = 1; - Func> transformer = null; - switch (BaseType) + var multiplier = 1; + Func> transformer = null; + switch (BaseType) { - case ColorSpace.DeviceRGB: + case ColorSpace.DeviceRGB: case ColorSpace.CalRGB: - case ColorSpace.Lab: - transformer = x => - { - var r = new byte[3]; - for (var i = 0; i < 3; i++) - { - r[i] = ColorTable[x * 3 + i]; - } - - return r; - }; - multiplier = 3; + case ColorSpace.Lab: + transformer = x => + { + var r = new byte[3]; + for (var i = 0; i < 3; i++) + { + r[i] = ColorTable[x * 3 + i]; + } + + return r; + }; + multiplier = 3; break; - - case ColorSpace.DeviceCMYK: - transformer = x => - { - var r = new byte[4]; - for (var i = 0; i < 4; i++) - { - r[i] = ColorTable[x * 4 + i]; - } - - return r; - }; - - multiplier = 4; + + case ColorSpace.DeviceCMYK: + transformer = x => + { + var r = new byte[4]; + for (var i = 0; i < 4; i++) + { + r[i] = ColorTable[x * 4 + i]; + } + + return r; + }; + + multiplier = 4; break; - - case ColorSpace.DeviceGray: + + case ColorSpace.DeviceGray: case ColorSpace.CalGray: - case ColorSpace.Separation: - transformer = x => new[] { ColorTable[x] }; - multiplier = 1; + case ColorSpace.Separation: + transformer = x => new[] { ColorTable[x] }; + multiplier = 1; break; case ColorSpace.DeviceN: case ColorSpace.ICCBased: - transformer = x => - { - var r = new byte[BaseColorSpace.NumberOfColorComponents]; - for (var i = 0; i < BaseColorSpace.NumberOfColorComponents; i++) - { - r[i] = ColorTable[x * BaseColorSpace.NumberOfColorComponents + i]; - } - - return r; - }; - - multiplier = BaseColorSpace.NumberOfColorComponents; - break; - } - - if (transformer != null) - { - var result = new byte[input.Count * multiplier]; - var i = 0; - foreach (var b in input) - { - foreach (var newByte in transformer(b)) - { - result[i++] = newByte; - } - } - - return result; - } - - return input.ToArray(); + transformer = x => + { + var r = new byte[BaseColorSpace.NumberOfColorComponents]; + for (var i = 0; i < BaseColorSpace.NumberOfColorComponents; i++) + { + r[i] = ColorTable[x * BaseColorSpace.NumberOfColorComponents + i]; + } + + return r; + }; + + multiplier = BaseColorSpace.NumberOfColorComponents; + break; + } + + if (transformer != null) + { + var result = new byte[input.Count * multiplier]; + var i = 0; + foreach (var b in input) + { + foreach (var newByte in transformer(b)) + { + result[i++] = newByte; + } + } + + return result; + } + + return input.ToArray(); } /// @@ -617,14 +617,14 @@ } } } - - /// - /// 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. - /// 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. - /// - public sealed class SeparationColorSpaceDetails : ColorSpaceDetails + + /// + /// 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. + /// 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. + /// + public sealed class SeparationColorSpaceDetails : ColorSpaceDetails { private readonly ConcurrentDictionary cache = new ConcurrentDictionary(); @@ -633,49 +633,49 @@ /// internal override int BaseNumberOfColorComponents => AlternateColorSpace.NumberOfColorComponents; - - /// - /// Specifies the name of the colorant that this Separation color space is intended to represent. - /// - /// - /// - /// The special colorant name All refers collectively to all colorants available on an output device, - /// including those for the standard process colorants. - /// - /// - /// 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. - /// - /// - public NameToken Name { get; } - - /// - /// 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. - /// - public ColorSpaceDetails AlternateColorSpace { get; } - /// - /// 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 . + /// + /// Specifies the name of the colorant that this Separation color space is intended to represent. + /// + /// + /// + /// The special colorant name All refers collectively to all colorants available on an output device, + /// including those for the standard process colorants. + /// + /// + /// 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. + /// + /// + public NameToken Name { get; } + + /// + /// 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. + /// + public ColorSpaceDetails AlternateColorSpace { get; } + + /// + /// 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 . /// public PdfFunction TintFunction { get; } - - /// - /// Create a new . - /// - public SeparationColorSpaceDetails(NameToken name, + + /// + /// Create a new . + /// + public SeparationColorSpaceDetails(NameToken name, ColorSpaceDetails alternateColorSpaceDetails, - PdfFunction tintFunction) - : base(ColorSpace.Separation) - { - Name = name; + PdfFunction tintFunction) + : base(ColorSpace.Separation) + { + Name = name; AlternateColorSpace = alternateColorSpaceDetails; - TintFunction = tintFunction; + TintFunction = tintFunction; } /// @@ -730,14 +730,14 @@ { // The initial value for both the stroking and nonstroking colour in the graphics state shall be 1.0. return GetColor(1.0); - } + } } - /// - /// 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. - /// 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. + /// + /// 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. + /// 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. /// public sealed class CalGrayColorSpaceDetails : ColorSpaceDetails { @@ -767,8 +767,8 @@ /// public double Gamma { get; } - /// - /// Create a new . + /// + /// Create a new . /// public CalGrayColorSpaceDetails([NotNull] IReadOnlyList whitePoint, [CanBeNull] IReadOnlyList blackPoint, double? gamma) : base(ColorSpace.CalGray) @@ -857,12 +857,12 @@ } } - /// - /// 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. - /// 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. - /// + /// + /// 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. + /// 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. + /// public sealed class CalRGBColorSpaceDetails : ColorSpaceDetails { /// @@ -898,8 +898,8 @@ /// public IReadOnlyList Matrix { get; } - /// - /// Create a new . + /// + /// Create a new . /// public CalRGBColorSpaceDetails([NotNull] IReadOnlyList whitePoint, [CanBeNull] IReadOnlyList blackPoint, [CanBeNull] IReadOnlyList gamma, [CanBeNull] IReadOnlyList matrix) : base(ColorSpace.CalRGB) @@ -944,7 +944,8 @@ } /// - /// Transforms the supplied ABC color to RGB (sRGB) using the propeties of this + /// Transforms the supplied ABC color to RGB (sRGB) using the properties of this + /// in the transformation process. /// A, B and C represent red, green and blue calibrated color values in the range 0.0 to 1.0. /// @@ -1139,8 +1140,8 @@ double c = PdfFunction.ClipToRange(0, Matrix[2], Matrix[3]); return TransformToRGB((0, b, c)); } - } - + } + /// /// 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. @@ -1150,8 +1151,8 @@ /// Currently support for this color space is limited in PdfPig. Calculations will only be based on /// the color space of . /// - /// - public sealed class ICCBasedColorSpaceDetails : ColorSpaceDetails + /// + public sealed class ICCBasedColorSpaceDetails : ColorSpaceDetails { /// /// The number of color components in the color space described by the ICC profile data. @@ -1193,32 +1194,32 @@ [CanBeNull] public XmpMetadata Metadata { get; } - /// - /// Create a new . + /// + /// Create a new . /// - internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails, - [CanBeNull] IReadOnlyList range, [CanBeNull] XmpMetadata metadata) - : base(ColorSpace.ICCBased) - { - if (numberOfColorComponents != 1 && numberOfColorComponents != 3 && numberOfColorComponents != 4) - { - throw new ArgumentOutOfRangeException(nameof(numberOfColorComponents), "must be 1, 3 or 4"); - } - - NumberOfColorComponents = numberOfColorComponents; - AlternateColorSpace = alternateColorSpaceDetails ?? - (NumberOfColorComponents == 1 ? (ColorSpaceDetails)DeviceGrayColorSpaceDetails.Instance : - NumberOfColorComponents == 3 ? (ColorSpaceDetails)DeviceRgbColorSpaceDetails.Instance : (ColorSpaceDetails)DeviceCmykColorSpaceDetails.Instance); - - BaseType = AlternateColorSpace.BaseType; - Range = range ?? - Enumerable.Range(0, numberOfColorComponents).Select(x => new[] { 0.0, 1.0 }).SelectMany(x => x).ToArray(); - if (Range.Count != 2 * numberOfColorComponents) - { - throw new ArgumentOutOfRangeException(nameof(range), range, - $"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range.Count}"); - } - Metadata = metadata; + internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails, + [CanBeNull] IReadOnlyList range, [CanBeNull] XmpMetadata metadata) + : base(ColorSpace.ICCBased) + { + if (numberOfColorComponents != 1 && numberOfColorComponents != 3 && numberOfColorComponents != 4) + { + throw new ArgumentOutOfRangeException(nameof(numberOfColorComponents), "must be 1, 3 or 4"); + } + + NumberOfColorComponents = numberOfColorComponents; + AlternateColorSpace = alternateColorSpaceDetails ?? + (NumberOfColorComponents == 1 ? (ColorSpaceDetails)DeviceGrayColorSpaceDetails.Instance : + NumberOfColorComponents == 3 ? (ColorSpaceDetails)DeviceRgbColorSpaceDetails.Instance : (ColorSpaceDetails)DeviceCmykColorSpaceDetails.Instance); + + BaseType = AlternateColorSpace.BaseType; + Range = range ?? + Enumerable.Range(0, numberOfColorComponents).Select(x => new[] { 0.0, 1.0 }).SelectMany(x => x).ToArray(); + if (Range.Count != 2 * numberOfColorComponents) + { + throw new ArgumentOutOfRangeException(nameof(range), range, + $"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range.Count}"); + } + Metadata = metadata; } /// @@ -1266,7 +1267,7 @@ // TODO - use ICC profile return AlternateColorSpace.Transform(decoded); - } + } } /// @@ -1301,8 +1302,8 @@ [CanBeNull] public ColorSpaceDetails UnderlyingColourSpace { get; } - /// - /// Create a new . + /// + /// Create a new . /// /// The patterns. /// The underlying colour space for Uncoloured Tiling Patterns. @@ -1364,16 +1365,16 @@ { throw new InvalidOperationException("PatternColorSpaceDetails"); } - } - - /// - /// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace. - /// - public sealed class UnsupportedColorSpaceDetails : ColorSpaceDetails - { - /// - /// The single instance of the . - /// + } + + /// + /// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace. + /// + public sealed class UnsupportedColorSpaceDetails : ColorSpaceDetails + { + /// + /// The single instance of the . + /// public static readonly UnsupportedColorSpaceDetails Instance = new UnsupportedColorSpaceDetails(); /// @@ -1392,8 +1393,8 @@ /// internal override int BaseNumberOfColorComponents => NumberOfColorComponents; - private UnsupportedColorSpaceDetails() : base(ColorSpace.DeviceGray) - { + private UnsupportedColorSpaceDetails() : base(ColorSpace.DeviceGray) + { } /// @@ -1418,6 +1419,6 @@ internal override IReadOnlyList Transform(IReadOnlyList decoded) { throw new InvalidOperationException("UnsupportedColorSpaceDetails"); - } - } + } + } }