mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-08 00:14:35 +08:00
add full color space details and transformation into full bytes for indexed
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BE/@EntryIndexedValue">BE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CIE/@EntryIndexedValue">CIE</s:String>
|
||||
|
@@ -84,6 +84,11 @@
|
||||
/// </summary>
|
||||
bool IsInlineImage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Full details for the <see cref="ColorSpace"/> with any associated data.
|
||||
/// </summary>
|
||||
ColorSpaceDetails ColorSpaceDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the decoded bytes of the image if applicable. For JPEG images and some other types the
|
||||
/// <see cref="RawBytes"/> should be used directly.
|
||||
|
@@ -7,6 +7,7 @@
|
||||
using Filters;
|
||||
using Graphics.Colors;
|
||||
using Graphics.Core;
|
||||
using Images;
|
||||
using Tokens;
|
||||
using Images.Png;
|
||||
|
||||
@@ -51,6 +52,9 @@
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<byte> RawBytes { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorSpaceDetails ColorSpaceDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="InlineImage"/>.
|
||||
/// </summary>
|
||||
@@ -61,7 +65,8 @@
|
||||
IReadOnlyList<decimal> decode,
|
||||
IReadOnlyList<byte> bytes,
|
||||
IReadOnlyList<IFilter> filters,
|
||||
DictionaryToken streamDictionary)
|
||||
DictionaryToken streamDictionary,
|
||||
ColorSpaceDetails colorSpaceDetails)
|
||||
{
|
||||
Bounds = bounds;
|
||||
WidthInSamples = widthInSamples;
|
||||
@@ -74,6 +79,7 @@
|
||||
Interpolate = interpolate;
|
||||
|
||||
RawBytes = bytes;
|
||||
ColorSpaceDetails = colorSpaceDetails;
|
||||
|
||||
var supportsFilters = true;
|
||||
foreach (var filter in filters)
|
||||
@@ -107,8 +113,6 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = bytesFactory.Value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
129
src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs
Normal file
129
src/UglyToad.PdfPig/Graphics/Colors/ColorSpaceDetails.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
namespace UglyToad.PdfPig.Graphics.Colors
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Contains more document-specific information about the <see cref="ColorSpace"/>.
|
||||
/// </summary>
|
||||
public abstract class ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the ColorSpace.
|
||||
/// </summary>
|
||||
public ColorSpace Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The underlying type of ColorSpace, usually equal to <see cref="Type"/>
|
||||
/// unless <see cref="ColorSpace.Indexed"/>.
|
||||
/// </summary>
|
||||
public ColorSpace BaseType { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
protected ColorSpaceDetails(ColorSpace type)
|
||||
{
|
||||
Type = type;
|
||||
BaseType = type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public sealed class DeviceGrayColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The single instance of the <see cref="DeviceGrayColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public static readonly DeviceGrayColorSpaceDetails Instance = new DeviceGrayColorSpaceDetails();
|
||||
|
||||
private DeviceGrayColorSpaceDetails() : base(ColorSpace.DeviceGray)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public sealed class DeviceRgbColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The single instance of the <see cref="DeviceRgbColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public static readonly DeviceRgbColorSpaceDetails Instance = new DeviceRgbColorSpaceDetails();
|
||||
|
||||
private DeviceRgbColorSpaceDetails() : base(ColorSpace.DeviceRGB)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color values are defined by four components cyan, magenta, yellow and black
|
||||
/// </summary>
|
||||
public sealed class DeviceCmykColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The single instance of the <see cref="DeviceCmykColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public static readonly DeviceCmykColorSpaceDetails Instance = new DeviceCmykColorSpaceDetails();
|
||||
|
||||
private DeviceCmykColorSpaceDetails() : base(ColorSpace.DeviceCMYK)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// A PDF consumer treats each sample value as an index into the color table and uses the color value it finds there.
|
||||
/// </summary>
|
||||
public class IndexedColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public ColorSpaceDetails BaseColorSpaceDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An integer that specifies the maximum valid index value. Can be no greater than 255.
|
||||
/// </summary>
|
||||
public byte HiVal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides the mapping between index values and the corresponding colors in the base color space.
|
||||
/// </summary>
|
||||
public IReadOnlyList<byte> ColorTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="IndexedColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public IndexedColorSpaceDetails(ColorSpaceDetails baseColorSpaceDetails, byte hiVal, IReadOnlyList<byte> colorTable)
|
||||
: base(ColorSpace.Indexed)
|
||||
{
|
||||
BaseColorSpaceDetails = baseColorSpaceDetails ?? throw new ArgumentNullException(nameof(baseColorSpaceDetails));
|
||||
HiVal = hiVal;
|
||||
ColorTable = colorTable;
|
||||
BaseType = baseColorSpaceDetails.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ColorSpace which the PdfPig library does not currently support. Please raise a PR if you need support for this ColorSpace.
|
||||
/// </summary>
|
||||
public class UnsupportedColorSpaceDetails : ColorSpaceDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// The single instance of the <see cref="UnsupportedColorSpaceDetails"/>.
|
||||
/// </summary>
|
||||
public static readonly UnsupportedColorSpaceDetails Instance = new UnsupportedColorSpaceDetails();
|
||||
|
||||
private UnsupportedColorSpaceDetails() : base(ColorSpace.DeviceGray)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@
|
||||
using PdfPig.Core;
|
||||
using Tokenization.Scanner;
|
||||
using Tokens;
|
||||
using Util;
|
||||
|
||||
internal class InlineImageBuilder
|
||||
{
|
||||
@@ -27,35 +28,7 @@
|
||||
throw new InvalidOperationException($"Inline image builder not completely defined before calling {nameof(CreateInlineImage)}.");
|
||||
}
|
||||
|
||||
bool TryMapColorSpace(NameToken name, out ColorSpace colorSpaceResult)
|
||||
{
|
||||
if (name.TryMapToColorSpace(out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryExtendedColorSpaceNameMapping(name, out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!resourceStore.TryGetNamedColorSpace(name, out var colorSpaceNamedToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (colorSpaceNamedToken.Name.TryMapToColorSpace(out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryExtendedColorSpaceNameMapping(colorSpaceNamedToken.Name, out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var bounds = transformationMatrix.Transform(new PdfRectangle(new PdfPoint(1, 1),
|
||||
new PdfPoint(0, 0)));
|
||||
@@ -90,7 +63,7 @@
|
||||
throw new PdfDocumentFormatException($"Invalid ColorSpace array defined for inline image: {colorSpaceArray}.");
|
||||
}
|
||||
|
||||
if (!TryMapColorSpace(firstColorSpaceName, out var colorSpaceMapped))
|
||||
if (!ColorSpaceMapper.TryMap(firstColorSpaceName, resourceStore, out var colorSpaceMapped))
|
||||
{
|
||||
throw new PdfDocumentFormatException($"Invalid ColorSpace defined for inline image: {firstColorSpaceName}.");
|
||||
}
|
||||
@@ -99,7 +72,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryMapColorSpace(colorSpaceName, out var colorSpaceMapped))
|
||||
if (!ColorSpaceMapper.TryMap(colorSpaceName, resourceStore, out var colorSpaceMapped))
|
||||
{
|
||||
throw new PdfDocumentFormatException($"Invalid ColorSpace defined for inline image: {colorSpaceName}.");
|
||||
}
|
||||
@@ -108,6 +81,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
var imgDic = new DictionaryToken(Properties ?? new Dictionary<NameToken, IToken>());
|
||||
|
||||
var details = ColorSpaceDetailsParser.GetColorSpaceDetails(
|
||||
colorSpace,
|
||||
imgDic,
|
||||
tokenScanner,
|
||||
resourceStore,
|
||||
filterProvider);
|
||||
|
||||
var renderingIntent = GetByKeys<NameToken>(NameToken.Intent, null, false)?.Data?.ToRenderingIntent() ?? defaultRenderingIntent;
|
||||
|
||||
var filterNames = new List<NameToken>();
|
||||
@@ -157,30 +139,8 @@
|
||||
|
||||
return new InlineImage(bounds, width, height, bitsPerComponent, isMask, renderingIntent, interpolate, colorSpace, decode, Bytes,
|
||||
filters,
|
||||
streamDictionary);
|
||||
}
|
||||
|
||||
private static bool TryExtendedColorSpaceNameMapping(NameToken name, out ColorSpace result)
|
||||
{
|
||||
result = ColorSpace.DeviceGray;
|
||||
|
||||
switch (name.Data)
|
||||
{
|
||||
case "G":
|
||||
result = ColorSpace.DeviceGray;
|
||||
return true;
|
||||
case "RGB":
|
||||
result = ColorSpace.DeviceRGB;
|
||||
return true;
|
||||
case "CMYK":
|
||||
result = ColorSpace.DeviceCMYK;
|
||||
return true;
|
||||
case "I":
|
||||
result = ColorSpace.Indexed;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
streamDictionary,
|
||||
details);
|
||||
}
|
||||
|
||||
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
|
||||
|
78
src/UglyToad.PdfPig/Images/ColorSpaceDetailsByteConverter.cs
Normal file
78
src/UglyToad.PdfPig/Images/ColorSpaceDetailsByteConverter.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
namespace UglyToad.PdfPig.Images
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Graphics.Colors;
|
||||
|
||||
internal static class ColorSpaceDetailsByteConverter
|
||||
{
|
||||
public static byte[] Convert(ColorSpaceDetails details, IReadOnlyList<byte> decoded)
|
||||
{
|
||||
switch (details)
|
||||
{
|
||||
case IndexedColorSpaceDetails indexed:
|
||||
return UnwrapIndexedColorSpaceBytes(indexed, decoded);
|
||||
}
|
||||
|
||||
return decoded.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] UnwrapIndexedColorSpaceBytes(IndexedColorSpaceDetails indexed, IReadOnlyList<byte> input)
|
||||
{
|
||||
var multiplier = 1;
|
||||
Func<byte, IEnumerable<byte>> transformer = null;
|
||||
switch (indexed.BaseColorSpaceDetails.Type)
|
||||
{
|
||||
case ColorSpace.DeviceRGB:
|
||||
transformer = x =>
|
||||
{
|
||||
var r = new byte[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
r[i] = indexed.ColorTable[x + i];
|
||||
}
|
||||
|
||||
return r;
|
||||
};
|
||||
multiplier = 3;
|
||||
break;
|
||||
case ColorSpace.DeviceCMYK:
|
||||
transformer = x =>
|
||||
{
|
||||
var r = new byte[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
r[i] = indexed.ColorTable[x + i];
|
||||
}
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
multiplier = 4;
|
||||
break;
|
||||
case ColorSpace.DeviceGray:
|
||||
transformer = x => new[] {indexed.ColorTable[x]};
|
||||
multiplier = 1;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,15 +9,23 @@
|
||||
{
|
||||
bytes = null;
|
||||
|
||||
var isColorSpaceSupported = image.ColorSpace == ColorSpace.DeviceGray || image.ColorSpace == ColorSpace.DeviceRGB;
|
||||
var hasValidDetails = image.ColorSpaceDetails != null &&
|
||||
!(image.ColorSpaceDetails is UnsupportedColorSpaceDetails);
|
||||
var actualColorSpace = hasValidDetails ? image.ColorSpaceDetails.BaseType : image.ColorSpace;
|
||||
|
||||
var isColorSpaceSupported =
|
||||
actualColorSpace == ColorSpace.DeviceGray || actualColorSpace == ColorSpace.DeviceRGB;
|
||||
|
||||
if (!isColorSpaceSupported || !image.TryGetBytes(out var bytesPure))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesPure = ColorSpaceDetailsByteConverter.Convert(image.ColorSpaceDetails, bytesPure);
|
||||
|
||||
try
|
||||
{
|
||||
var is3Byte = image.ColorSpace == ColorSpace.DeviceRGB;
|
||||
var is3Byte = actualColorSpace == ColorSpace.DeviceRGB;
|
||||
var multiplier = is3Byte ? 3 : 1;
|
||||
|
||||
var builder = PngBuilder.Create(image.WidthInSamples, image.HeightInSamples, false);
|
||||
|
200
src/UglyToad.PdfPig/Util/ColorSpaceDetailsParser.cs
Normal file
200
src/UglyToad.PdfPig/Util/ColorSpaceDetailsParser.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
namespace UglyToad.PdfPig.Util
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Content;
|
||||
using Filters;
|
||||
using Graphics.Colors;
|
||||
using Parser.Parts;
|
||||
using Tokenization.Scanner;
|
||||
using Tokens;
|
||||
|
||||
internal static class ColorSpaceMapper
|
||||
{
|
||||
private static bool TryExtendedColorSpaceNameMapping(NameToken name, out ColorSpace result)
|
||||
{
|
||||
result = ColorSpace.DeviceGray;
|
||||
|
||||
switch (name.Data)
|
||||
{
|
||||
case "G":
|
||||
result = ColorSpace.DeviceGray;
|
||||
return true;
|
||||
case "RGB":
|
||||
result = ColorSpace.DeviceRGB;
|
||||
return true;
|
||||
case "CMYK":
|
||||
result = ColorSpace.DeviceCMYK;
|
||||
return true;
|
||||
case "I":
|
||||
result = ColorSpace.Indexed;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryMap(NameToken name, IResourceStore resourceStore, out ColorSpace colorSpaceResult)
|
||||
{
|
||||
if (name.TryMapToColorSpace(out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryExtendedColorSpaceNameMapping(name, out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!resourceStore.TryGetNamedColorSpace(name, out var colorSpaceNamedToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (colorSpaceNamedToken.Name.TryMapToColorSpace(out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryExtendedColorSpaceNameMapping(colorSpaceNamedToken.Name, out colorSpaceResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ColorSpaceDetailsParser
|
||||
{
|
||||
public static ColorSpaceDetails GetColorSpaceDetails(ColorSpace? colorSpace,
|
||||
DictionaryToken imageDictionary,
|
||||
IPdfTokenScanner scanner,
|
||||
IResourceStore resourceStore,
|
||||
IFilterProvider filterProvider,
|
||||
bool cannotRecurse = false)
|
||||
{
|
||||
if (!colorSpace.HasValue)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
switch (colorSpace.Value)
|
||||
{
|
||||
case ColorSpace.DeviceGray:
|
||||
return DeviceGrayColorSpaceDetails.Instance;
|
||||
case ColorSpace.DeviceRGB:
|
||||
return DeviceRgbColorSpaceDetails.Instance;
|
||||
case ColorSpace.DeviceCMYK:
|
||||
return DeviceCmykColorSpaceDetails.Instance;
|
||||
case ColorSpace.CalGray:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.CalRGB:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.Lab:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.ICCBased:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.Indexed:
|
||||
{
|
||||
if (cannotRecurse)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
if (!imageDictionary.TryGet(NameToken.ColorSpace, scanner, out ArrayToken colorSpaceArray)
|
||||
|| colorSpaceArray.Length != 4)
|
||||
{
|
||||
// Error instead?
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var first = colorSpaceArray[0] as NameToken;
|
||||
|
||||
if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace)
|
||||
|| innerColorSpace != ColorSpace.Indexed)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var second = colorSpaceArray[1];
|
||||
|
||||
ColorSpaceDetails baseDetails;
|
||||
|
||||
if (DirectObjectFinder.TryGet(second, scanner, out NameToken baseColorSpaceNameToken)
|
||||
&& ColorSpaceMapper.TryMap(baseColorSpaceNameToken, resourceStore, out var baseColorSpaceName))
|
||||
{
|
||||
baseDetails = GetColorSpaceDetails(
|
||||
baseColorSpaceName,
|
||||
imageDictionary,
|
||||
scanner,
|
||||
resourceStore,
|
||||
filterProvider,
|
||||
true);
|
||||
}
|
||||
else if (DirectObjectFinder.TryGet(second, scanner, out ArrayToken baseColorSpaceArrayToken)
|
||||
&& 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}
|
||||
});
|
||||
|
||||
baseDetails = GetColorSpaceDetails(
|
||||
baseColorSpaceArrayColorSpace,
|
||||
pseudoImageDictionary,
|
||||
scanner,
|
||||
resourceStore,
|
||||
filterProvider,
|
||||
true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
if (baseDetails is UnsupportedColorSpaceDetails)
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var third = colorSpaceArray[2];
|
||||
|
||||
if (!DirectObjectFinder.TryGet(third, scanner, out NumericToken hiValNumericToken))
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
var hival = hiValNumericToken.Int;
|
||||
|
||||
var fourth = colorSpaceArray[3];
|
||||
|
||||
IReadOnlyList<byte> tableBytes;
|
||||
|
||||
if (DirectObjectFinder.TryGet(fourth, scanner, out HexToken tableHexToken))
|
||||
{
|
||||
tableBytes = tableHexToken.Bytes;
|
||||
}
|
||||
else if (DirectObjectFinder.TryGet(fourth, scanner, out StreamToken tableStreamToken))
|
||||
{
|
||||
tableBytes = tableStreamToken.Decode(filterProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
|
||||
return new IndexedColorSpaceDetails(baseDetails, (byte)hival, tableBytes);
|
||||
}
|
||||
case ColorSpace.Pattern:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.Separation:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
case ColorSpace.DeviceN:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
default:
|
||||
return UnsupportedColorSpaceDetails.Instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,4 @@
|
||||
using UglyToad.PdfPig.Parser.Parts;
|
||||
|
||||
namespace UglyToad.PdfPig.XObjects
|
||||
namespace UglyToad.PdfPig.XObjects
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -11,8 +9,10 @@ namespace UglyToad.PdfPig.XObjects
|
||||
using Graphics;
|
||||
using Graphics.Colors;
|
||||
using Graphics.Core;
|
||||
using Parser.Parts;
|
||||
using Tokenization.Scanner;
|
||||
using Tokens;
|
||||
using Util;
|
||||
|
||||
internal static class XObjectFactory
|
||||
{
|
||||
@@ -137,10 +137,27 @@ namespace UglyToad.PdfPig.XObjects
|
||||
}
|
||||
}
|
||||
|
||||
return new XObjectImage(bounds, width, height, bitsPerComponent, colorSpace, isJpxDecode, isImageMask, intent, interpolate, decode,
|
||||
dictionary, xObject.Stream.Data, decodedBytes);
|
||||
var details = ColorSpaceDetailsParser.GetColorSpaceDetails(colorSpace, dictionary, pdfScanner, resourceStore, filterProvider);
|
||||
|
||||
return new XObjectImage(
|
||||
bounds,
|
||||
width,
|
||||
height,
|
||||
bitsPerComponent,
|
||||
colorSpace,
|
||||
isJpxDecode,
|
||||
isImageMask,
|
||||
intent,
|
||||
interpolate,
|
||||
decode,
|
||||
dictionary,
|
||||
xObject.Stream.Data,
|
||||
decodedBytes,
|
||||
details);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static bool TryMapColorSpace(NameToken name, IResourceStore resourceStore, out ColorSpace colorSpaceResult)
|
||||
{
|
||||
if (name.TryMapToColorSpace(out colorSpaceResult))
|
||||
|
@@ -6,6 +6,7 @@
|
||||
using Core;
|
||||
using Graphics.Colors;
|
||||
using Graphics.Core;
|
||||
using Images;
|
||||
using Images.Png;
|
||||
using Tokens;
|
||||
using Util.JetBrains.Annotations;
|
||||
@@ -64,11 +65,17 @@
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<byte> RawBytes { get; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorSpaceDetails ColorSpaceDetails { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="XObjectImage"/>.
|
||||
/// </summary>
|
||||
internal XObjectImage(PdfRectangle bounds, int widthInSamples, int heightInSamples, int bitsPerComponent,
|
||||
internal XObjectImage(PdfRectangle bounds,
|
||||
int widthInSamples,
|
||||
int heightInSamples,
|
||||
int bitsPerComponent,
|
||||
ColorSpace? colorSpace,
|
||||
bool isJpxEncoded,
|
||||
bool isImageMask,
|
||||
@@ -76,8 +83,9 @@
|
||||
bool interpolate,
|
||||
IReadOnlyList<decimal> decode,
|
||||
DictionaryToken imageDictionary,
|
||||
IReadOnlyList<byte> rawBytes,
|
||||
Lazy<IReadOnlyList<byte>> bytes)
|
||||
IReadOnlyList<byte> rawBytes,
|
||||
Lazy<IReadOnlyList<byte>> bytes,
|
||||
ColorSpaceDetails colorSpaceDetails)
|
||||
{
|
||||
Bounds = bounds;
|
||||
WidthInSamples = widthInSamples;
|
||||
@@ -91,6 +99,7 @@
|
||||
Decode = decode;
|
||||
ImageDictionary = imageDictionary ?? throw new ArgumentNullException(nameof(imageDictionary));
|
||||
RawBytes = rawBytes;
|
||||
ColorSpaceDetails = colorSpaceDetails;
|
||||
bytesFactory = bytes;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user