make converter public and add separation color space

This commit is contained in:
Eliot Jones
2021-02-08 18:20:41 -04:00
parent 9fc44f50d2
commit c19742a2ae
4 changed files with 166 additions and 8 deletions

View File

@@ -103,6 +103,13 @@
"UglyToad.PdfPig.Graphics.Colors.GrayColor", "UglyToad.PdfPig.Graphics.Colors.GrayColor",
"UglyToad.PdfPig.Graphics.Colors.IColor", "UglyToad.PdfPig.Graphics.Colors.IColor",
"UglyToad.PdfPig.Graphics.Colors.RGBColor", "UglyToad.PdfPig.Graphics.Colors.RGBColor",
"UglyToad.PdfPig.Graphics.Colors.ColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.DeviceGrayColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.DeviceRgbColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.DeviceCmykColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.IndexedColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.SeparationColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Colors.UnsupportedColorSpaceDetails",
"UglyToad.PdfPig.Graphics.Core.LineCapStyle", "UglyToad.PdfPig.Graphics.Core.LineCapStyle",
"UglyToad.PdfPig.Graphics.Core.LineDashPattern", "UglyToad.PdfPig.Graphics.Core.LineDashPattern",
"UglyToad.PdfPig.Graphics.Core.LineJoinStyle", "UglyToad.PdfPig.Graphics.Core.LineJoinStyle",
@@ -187,6 +194,7 @@
"UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidth", "UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidth",
"UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidthAndBoundingBox", "UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidthAndBoundingBox",
"UglyToad.PdfPig.Graphics.TextMatrices", "UglyToad.PdfPig.Graphics.TextMatrices",
"UglyToad.PdfPig.Images.ColorSpaceDetailsByteConverter",
"UglyToad.PdfPig.Logging.ILog", "UglyToad.PdfPig.Logging.ILog",
"UglyToad.PdfPig.Outline.Bookmarks", "UglyToad.PdfPig.Outline.Bookmarks",
"UglyToad.PdfPig.Outline.BookmarkNode", "UglyToad.PdfPig.Outline.BookmarkNode",

View File

@@ -2,6 +2,8 @@
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using PdfPig.Core;
using Tokens;
/// <summary> /// <summary>
/// Contains more document-specific information about the <see cref="ColorSpace"/>. /// Contains more document-specific information about the <see cref="ColorSpace"/>.
@@ -112,6 +114,59 @@
} }
} }
/// <summary>
/// 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.
/// </summary>
public class SeparationColorSpaceDetails : ColorSpaceDetails
{
/// <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 AlternateColorSpaceDetails { 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="AlternateColorSpaceDetails"/>.
/// </summary>
public Union<DictionaryToken, StreamToken> TintFunction { get; }
/// <summary>
/// Create a new <see cref="SeparationColorSpaceDetails"/>.
/// </summary>
public SeparationColorSpaceDetails(NameToken name,
ColorSpaceDetails alternateColorSpaceDetails,
Union<DictionaryToken, StreamToken> tintFunction)
: base(ColorSpace.Separation)
{
Name = name;
AlternateColorSpaceDetails = alternateColorSpaceDetails;
TintFunction = tintFunction;
}
}
/// <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>

View File

@@ -3,12 +3,33 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content;
using Core;
using Graphics.Colors; using Graphics.Colors;
internal static class ColorSpaceDetailsByteConverter /// <summary>
/// Utility for working with the bytes in <see cref="IPdfImage"/>s and converting according to their <see cref="ColorSpaceDetails"/>.s
/// </summary>
public static class ColorSpaceDetailsByteConverter
{ {
/// <summary>
/// Converts the output bytes (if available) of <see cref="IPdfImage.TryGetBytes"/>
/// to actual pixel values using the <see cref="IPdfImage.ColorSpaceDetails"/>. For most images this doesn't
/// change the data but for <see cref="ColorSpace.Indexed"/> it will convert the bytes which are indexes into the
/// real pixel data into the real pixel data.
/// </summary>
public static byte[] Convert(ColorSpaceDetails details, IReadOnlyList<byte> decoded) public static byte[] Convert(ColorSpaceDetails details, IReadOnlyList<byte> decoded)
{ {
if (decoded == null)
{
return EmptyArray<byte>.Instance;
}
if (details == null)
{
return decoded.ToArray();
}
switch (details) switch (details)
{ {
case IndexedColorSpaceDetails indexed: case IndexedColorSpaceDetails indexed:
@@ -41,7 +62,7 @@
transformer = x => transformer = x =>
{ {
var r = new byte[4]; var r = new byte[4];
for (int i = 0; i < 4; i++) for (var i = 0; i < 4; i++)
{ {
r[i] = indexed.ColorTable[x * 4 + i]; r[i] = indexed.ColorTable[x * 4 + i];
} }
@@ -52,7 +73,7 @@
multiplier = 4; multiplier = 4;
break; break;
case ColorSpace.DeviceGray: case ColorSpace.DeviceGray:
transformer = x => new[] {indexed.ColorTable[x]}; transformer = x => new[] { indexed.ColorTable[x] };
multiplier = 1; multiplier = 1;
break; break;
} }

View File

@@ -2,6 +2,7 @@
{ {
using System.Collections.Generic; using System.Collections.Generic;
using Content; using Content;
using Core;
using Filters; using Filters;
using Graphics.Colors; using Graphics.Colors;
using Parser.Parts; using Parser.Parts;
@@ -135,10 +136,11 @@
&& baseColorSpaceArrayToken.Length > 0 && baseColorSpaceArrayToken[0] is NameToken baseColorSpaceArrayNameToken && baseColorSpaceArrayToken.Length > 0 && baseColorSpaceArrayToken[0] is NameToken baseColorSpaceArrayNameToken
&& ColorSpaceMapper.TryMap(baseColorSpaceArrayNameToken, resourceStore, out var baseColorSpaceArrayColorSpace)) && ColorSpaceMapper.TryMap(baseColorSpaceArrayNameToken, resourceStore, out var baseColorSpaceArrayColorSpace))
{ {
var pseudoImageDictionary = new DictionaryToken(new Dictionary<NameToken, IToken> var pseudoImageDictionary = new DictionaryToken(
{ new Dictionary<NameToken, IToken>
{NameToken.ColorSpace, baseColorSpaceArrayToken} {
}); {NameToken.ColorSpace, baseColorSpaceArrayToken}
});
baseDetails = GetColorSpaceDetails( baseDetails = GetColorSpaceDetails(
baseColorSpaceArrayColorSpace, baseColorSpaceArrayColorSpace,
@@ -189,7 +191,79 @@
case ColorSpace.Pattern: case ColorSpace.Pattern:
return UnsupportedColorSpaceDetails.Instance; return UnsupportedColorSpaceDetails.Instance;
case ColorSpace.Separation: case ColorSpace.Separation:
return UnsupportedColorSpaceDetails.Instance; {
if (!imageDictionary.TryGet(NameToken.ColorSpace, scanner, out ArrayToken colorSpaceArray)
|| colorSpaceArray.Length != 4)
{
// Error instead?
return UnsupportedColorSpaceDetails.Instance;
}
if (!DirectObjectFinder.TryGet(colorSpaceArray[0], scanner, out NameToken separationColorSpaceNameToken)
|| !separationColorSpaceNameToken.Equals(NameToken.Separation))
{
return UnsupportedColorSpaceDetails.Instance;
}
if (!DirectObjectFinder.TryGet(colorSpaceArray[1], scanner, out NameToken separationNameToken))
{
return UnsupportedColorSpaceDetails.Instance;
}
ColorSpaceDetails alternateColorSpaceDetails;
if (DirectObjectFinder.TryGet(colorSpaceArray[2], scanner, out NameToken alternateNameToken)
&& ColorSpaceMapper.TryMap(alternateNameToken, resourceStore, out var baseColorSpaceName))
{
alternateColorSpaceDetails = GetColorSpaceDetails(
baseColorSpaceName,
imageDictionary,
scanner,
resourceStore,
filterProvider,
true);
}
else if (DirectObjectFinder.TryGet(colorSpaceArray[2], scanner, out ArrayToken alternateArrayToken)
&& alternateArrayToken.Length > 0
&& alternateArrayToken[0] is NameToken alternateColorSpaceNameToken
&& ColorSpaceMapper.TryMap(alternateColorSpaceNameToken, resourceStore, out var alternateArrayColorSpace))
{
var pseudoImageDictionary = new DictionaryToken(
new Dictionary<NameToken, IToken>
{
{NameToken.ColorSpace, alternateArrayToken}
});
alternateColorSpaceDetails = GetColorSpaceDetails(
alternateArrayColorSpace,
pseudoImageDictionary,
scanner,
resourceStore,
filterProvider,
true);
}
else
{
return UnsupportedColorSpaceDetails.Instance;
}
Union<DictionaryToken, StreamToken> functionTokensUnion;
var func = colorSpaceArray[3];
if (DirectObjectFinder.TryGet(func, scanner, out DictionaryToken functionDictionary))
{
functionTokensUnion = Union<DictionaryToken, StreamToken>.One(functionDictionary);
}
else if (DirectObjectFinder.TryGet(func, scanner, out StreamToken functionStream))
{
functionTokensUnion = Union<DictionaryToken, StreamToken>.Two(functionStream);
}
else
{
return UnsupportedColorSpaceDetails.Instance;
}
return new SeparationColorSpaceDetails(separationNameToken, alternateColorSpaceDetails, functionTokensUnion);
}
case ColorSpace.DeviceN: case ColorSpace.DeviceN:
return UnsupportedColorSpaceDetails.Instance; return UnsupportedColorSpaceDetails.Instance;
default: default: