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.IColor",
"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.LineDashPattern",
"UglyToad.PdfPig.Graphics.Core.LineJoinStyle",
@@ -187,6 +194,7 @@
"UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidth",
"UglyToad.PdfPig.Graphics.Operations.TextState.Type3SetGlyphWidthAndBoundingBox",
"UglyToad.PdfPig.Graphics.TextMatrices",
"UglyToad.PdfPig.Images.ColorSpaceDetailsByteConverter",
"UglyToad.PdfPig.Logging.ILog",
"UglyToad.PdfPig.Outline.Bookmarks",
"UglyToad.PdfPig.Outline.BookmarkNode",

View File

@@ -2,6 +2,8 @@
{
using System;
using System.Collections.Generic;
using PdfPig.Core;
using Tokens;
/// <summary>
/// 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>
/// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace.
/// </summary>

View File

@@ -3,12 +3,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content;
using Core;
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)
{
if (decoded == null)
{
return EmptyArray<byte>.Instance;
}
if (details == null)
{
return decoded.ToArray();
}
switch (details)
{
case IndexedColorSpaceDetails indexed:
@@ -41,7 +62,7 @@
transformer = x =>
{
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];
}
@@ -52,7 +73,7 @@
multiplier = 4;
break;
case ColorSpace.DeviceGray:
transformer = x => new[] {indexed.ColorTable[x]};
transformer = x => new[] { indexed.ColorTable[x] };
multiplier = 1;
break;
}

View File

@@ -2,6 +2,7 @@
{
using System.Collections.Generic;
using Content;
using Core;
using Filters;
using Graphics.Colors;
using Parser.Parts;
@@ -135,10 +136,11 @@
&& baseColorSpaceArrayToken.Length > 0 && baseColorSpaceArrayToken[0] is NameToken baseColorSpaceArrayNameToken
&& ColorSpaceMapper.TryMap(baseColorSpaceArrayNameToken, resourceStore, out var baseColorSpaceArrayColorSpace))
{
var pseudoImageDictionary = new DictionaryToken(new Dictionary<NameToken, IToken>
{
{NameToken.ColorSpace, baseColorSpaceArrayToken}
});
var pseudoImageDictionary = new DictionaryToken(
new Dictionary<NameToken, IToken>
{
{NameToken.ColorSpace, baseColorSpaceArrayToken}
});
baseDetails = GetColorSpaceDetails(
baseColorSpaceArrayColorSpace,
@@ -189,7 +191,79 @@
case ColorSpace.Pattern:
return UnsupportedColorSpaceDetails.Instance;
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:
return UnsupportedColorSpaceDetails.Instance;
default: