mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-11-18 17:17:54 +08:00
Add (limited) support for the ICCBased color space
This commit is contained in:
@@ -108,6 +108,7 @@
|
||||
"UglyToad.PdfPig.Graphics.Colors.DeviceGrayColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.DeviceRgbColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.DeviceCmykColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.ICCBasedColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.IndexedColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.SeparationColorSpaceDetails",
|
||||
"UglyToad.PdfPig.Graphics.Colors.UnsupportedColorSpaceDetails",
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
namespace UglyToad.PdfPig.Graphics.Colors
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PdfPig.Core;
|
||||
using Tokens;
|
||||
|
||||
using Tokens;
|
||||
using UglyToad.PdfPig.Content;
|
||||
using UglyToad.PdfPig.Util.JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Contains more document-specific information about the <see cref="ColorSpace"/>.
|
||||
/// </summary>
|
||||
@@ -187,6 +190,77 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// The goal is for the same color specification to produce consistent results on different output devices,
|
||||
/// within the limitations of each device.
|
||||
///
|
||||
/// Currently support for this color space is limited in PdfPig, as calculations will only be based on
|
||||
/// the color space of <see cref="AlternateColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public class ICCBasedColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of color components in the color space described by the ICC profile data.
|
||||
/// This numbers shall match the number of components actually in the ICC profile.
|
||||
/// Valid values are 1, 3 and 4.
|
||||
/// </summary>
|
||||
public int NumberOfColorComponents { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An alternate color space that can be used in case the one specified in the stream data is not
|
||||
/// supported. Non-conforming readers may use this color space. The alternate color space may be any
|
||||
/// valid color space (except a Pattern color space). If this property isn't explicitly set during
|
||||
/// construction, it will assume one of the color spaces, DeviceGray, DeviceRGB or DeviceCMYK depending
|
||||
/// on whether the value of <see cref="NumberOfColorComponents"/> is 1, 3 or respectively.
|
||||
///
|
||||
/// Conversion of the source color values should not be performed when using the alternate color space.
|
||||
/// Color values within the range of the ICCBased color space might not be within the range of the
|
||||
/// alternate color space. In this case, the nearest values within the range of the alternate space
|
||||
/// must be substituted.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public ColorSpaceDetails AlternateColorSpaceDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of 2 x <see cref="NumberOfColorComponents"/> numbers [min0 max0 min1 max1 ...] that
|
||||
/// specifies the minimum and maximum valid values of the corresponding color components. These
|
||||
/// values must match the information in the ICC profile. Default value: [0.0 1.0 0.0 1.0 ...].
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public IReadOnlyList<decimal> Range { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional metadata stream that contains metadata for the color space.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public XmpMetadata Metadata { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ICCBasedColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails,
|
||||
[CanBeNull] IReadOnlyList<decimal> 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;
|
||||
AlternateColorSpaceDetails = alternateColorSpaceDetails ??
|
||||
(NumberOfColorComponents == 1 ? DeviceGrayColorSpaceDetails.Instance :
|
||||
NumberOfColorComponents == 3 ? DeviceRgbColorSpaceDetails.Instance : DeviceCmykColorSpaceDetails.Instance);
|
||||
|
||||
BaseType = AlternateColorSpaceDetails.BaseType;
|
||||
Range = range ??
|
||||
Enumerable.Range(0, numberOfColorComponents).Select(x => new[] { 0.0m, 1.0m }).SelectMany(x => x).ToList();
|
||||
Metadata = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace.
|
||||
/// </summary>
|
||||
|
||||
@@ -55,15 +55,24 @@
|
||||
|
||||
private static int GetBytesPerPixel(ColorSpaceDetails details)
|
||||
{
|
||||
var colorSpace = (details is IndexedColorSpaceDetails indexed) ? indexed.BaseColorSpaceDetails.Type : details.Type;
|
||||
switch (colorSpace)
|
||||
switch (details)
|
||||
{
|
||||
case ColorSpace.DeviceRGB:
|
||||
case DeviceGrayColorSpaceDetails:
|
||||
return 1;
|
||||
|
||||
case DeviceRgbColorSpaceDetails:
|
||||
return 3;
|
||||
|
||||
case ColorSpace.DeviceCMYK:
|
||||
case DeviceCmykColorSpaceDetails:
|
||||
return 4;
|
||||
|
||||
case IndexedColorSpaceDetails indexed:
|
||||
return GetBytesPerPixel(indexed.BaseColorSpaceDetails);
|
||||
|
||||
case ICCBasedColorSpaceDetails iccBased:
|
||||
// Currently PdfPig only supports the 'Alternate' color space of ICCBasedColorSpaceDetails
|
||||
return GetBytesPerPixel(iccBased.AlternateColorSpaceDetails);
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@@ -100,7 +109,7 @@
|
||||
{
|
||||
var multiplier = 1;
|
||||
Func<byte, IEnumerable<byte>> transformer = null;
|
||||
switch (indexed.BaseColorSpaceDetails.Type)
|
||||
switch (indexed.BaseType)
|
||||
{
|
||||
case ColorSpace.DeviceRGB:
|
||||
transformer = x =>
|
||||
|
||||
@@ -105,7 +105,51 @@
|
||||
case ColorSpace.Lab:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.ICCBased:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
{
|
||||
if (!TryGetColorSpaceArray(imageDictionary, resourceStore, scanner, out var colorSpaceArray)
|
||||
|| colorSpaceArray.Length != 2)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var first = colorSpaceArray[0] as NameToken;
|
||||
|
||||
if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace)
|
||||
|| innerColorSpace != ColorSpace.ICCBased)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var second = colorSpaceArray[1];
|
||||
|
||||
if (!DirectObjectFinder.TryGet(second, scanner, out StreamToken streamToken) ||
|
||||
!streamToken.StreamDictionary.TryGet(NameToken.N, out NumericToken numeric))
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
ColorSpaceDetails alternateColorSpaceDetails = null;
|
||||
if (streamToken.StreamDictionary.TryGet(NameToken.Alternate, out NameToken alternateColorSpaceNameToken) &&
|
||||
ColorSpaceMapper.TryMap(alternateColorSpaceNameToken, resourceStore, out var alternateColorSpace))
|
||||
{
|
||||
alternateColorSpaceDetails =
|
||||
GetColorSpaceDetails(alternateColorSpace, imageDictionary, scanner, resourceStore, filterProvider, true);
|
||||
}
|
||||
|
||||
IReadOnlyList<decimal> range = null;
|
||||
if (streamToken.StreamDictionary.TryGet(NameToken.Range, out ArrayToken arrayToken))
|
||||
{
|
||||
range = arrayToken.Data.OfType<NumericToken>().Select(x => x.Data).ToList();
|
||||
}
|
||||
|
||||
XmpMetadata metadata = null;
|
||||
if (streamToken.StreamDictionary.TryGet(NameToken.Metadata, out StreamToken metadataStream))
|
||||
{
|
||||
metadata = new XmpMetadata(metadataStream, filterProvider, scanner);
|
||||
}
|
||||
|
||||
return new ICCBasedColorSpaceDetails(numeric.Int, alternateColorSpaceDetails, range, metadata);
|
||||
}
|
||||
case ColorSpace.Indexed:
|
||||
{
|
||||
if (cannotRecurse)
|
||||
|
||||
Reference in New Issue
Block a user