Refactor PdfFunctionParser to account for indirect reference tokens

This commit is contained in:
BobLd
2023-05-21 11:11:21 +01:00
parent 32a562f02a
commit 903218854c
10 changed files with 227 additions and 287 deletions

View File

@@ -4,11 +4,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UglyToad.PdfPig.Functions; using UglyToad.PdfPig.Functions;
using UglyToad.PdfPig.Tests.Tokens;
using UglyToad.PdfPig.Tokens; using UglyToad.PdfPig.Tokens;
using UglyToad.PdfPig.Util;
using Xunit; using Xunit;
public class PdfFunctionType0Tests public class PdfFunctionType0Tests
{ {
private readonly TestPdfTokenScanner testPdfTokenScanner = new TestPdfTokenScanner();
private readonly TestFilterProvider testFilterProvider = new TestFilterProvider();
private static ArrayToken GetArrayToken(params double[] data) private static ArrayToken GetArrayToken(params double[] data)
{ {
return new ArrayToken(data.Select(v => new NumericToken((decimal)v)).ToArray()); return new ArrayToken(data.Select(v => new NumericToken((decimal)v)).ToArray());
@@ -33,7 +38,10 @@
StreamToken function = new StreamToken(dictionaryToken, data); StreamToken function = new StreamToken(dictionaryToken, data);
var function0 = new PdfFunctionType0(function); var func = PdfFunctionParser.Create(function, testPdfTokenScanner, testFilterProvider);
Assert.Equal(FunctionTypes.Sampled, func.FunctionType);
var function0 = func as PdfFunctionType0;
var result = function0.Eval(new double[] { 0 }); var result = function0.Eval(new double[] { 0 });
Assert.Equal(4, result.Length); Assert.Equal(4, result.Length);
result = function0.Eval(new double[] { 0.5 }); result = function0.Eval(new double[] { 0.5 });
@@ -61,7 +69,10 @@
StreamToken function = new StreamToken(dictionaryToken, data); StreamToken function = new StreamToken(dictionaryToken, data);
var function0 = new PdfFunctionType0(function); var func = PdfFunctionParser.Create(function, testPdfTokenScanner, testFilterProvider);
Assert.Equal(FunctionTypes.Sampled, func.FunctionType);
var function0 = func as PdfFunctionType0;
var result = function0.Eval(new double[] { 0.00 }); var result = function0.Eval(new double[] { 0.00 });
Assert.Single(result); Assert.Single(result);
Assert.Equal(0.0, result[0], 3); Assert.Equal(0.0, result[0], 3);
@@ -100,7 +111,10 @@
StreamToken function = new StreamToken(dictionaryToken, data); StreamToken function = new StreamToken(dictionaryToken, data);
var function0 = new PdfFunctionType0(function); var func = PdfFunctionParser.Create(function, testPdfTokenScanner, testFilterProvider);
Assert.Equal(FunctionTypes.Sampled, func.FunctionType);
var function0 = func as PdfFunctionType0;
var result = function0.Eval(new double[] { 0.00 }); var result = function0.Eval(new double[] { 0.00 });
Assert.Single(result); Assert.Single(result);
Assert.Equal(0.0, result[0], 3); Assert.Equal(0.0, result[0], 3);
@@ -139,7 +153,10 @@
StreamToken function = new StreamToken(dictionaryToken, data); StreamToken function = new StreamToken(dictionaryToken, data);
var function0 = new PdfFunctionType0(function); var func = PdfFunctionParser.Create(function, testPdfTokenScanner, testFilterProvider);
Assert.Equal(FunctionTypes.Sampled, func.FunctionType);
var function0 = func as PdfFunctionType0;
var result = function0.Eval(new double[] { 0, 0 }); var result = function0.Eval(new double[] { 0, 0 });
Assert.Equal(3, result.Length); Assert.Equal(3, result.Length);
Assert.Equal(new double[] { 1, 1, 0 }, result); // yellow Assert.Equal(new double[] { 1, 1, 0 }, result); // yellow
@@ -178,7 +195,9 @@
StreamToken function = new StreamToken(dictionaryToken, data); StreamToken function = new StreamToken(dictionaryToken, data);
var function0 = new PdfFunctionType0(function); var func = PdfFunctionParser.Create(function, testPdfTokenScanner, testFilterProvider);
Assert.Equal(FunctionTypes.Sampled, func.FunctionType);
var function0 = func as PdfFunctionType0;
var result = function0.Eval(new double[] { 0 }); var result = function0.Eval(new double[] { 0 });
Assert.Equal(3, result.Length); Assert.Equal(3, result.Length);

View File

@@ -3,16 +3,18 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UglyToad.PdfPig.Functions; using UglyToad.PdfPig.Functions;
using UglyToad.PdfPig.Tests.Tokens;
using UglyToad.PdfPig.Tokens; using UglyToad.PdfPig.Tokens;
using UglyToad.PdfPig.Util;
using Xunit; using Xunit;
public class PdfFunctionType2Tests public class PdfFunctionType2Tests
{ {
private PdfFunctionType2 CreateFunction(double[] domain, double[] range, double[] c0, double[] c1, double n) private static PdfFunctionType2 CreateFunction(double[] domain, double[] range, double[] c0, double[] c1, double n)
{ {
DictionaryToken dictionaryToken = new DictionaryToken(new Dictionary<NameToken, IToken>() DictionaryToken dictionaryToken = new DictionaryToken(new Dictionary<NameToken, IToken>()
{ {
{ NameToken.FunctionType, new NumericToken(4) }, { NameToken.FunctionType, new NumericToken(2) },
{ NameToken.Domain, new ArrayToken(domain.Select(v => new NumericToken((decimal)v)).ToArray()) }, { NameToken.Domain, new ArrayToken(domain.Select(v => new NumericToken((decimal)v)).ToArray()) },
{ NameToken.Range, new ArrayToken(range.Select(v => new NumericToken((decimal)v)).ToArray()) }, { NameToken.Range, new ArrayToken(range.Select(v => new NumericToken((decimal)v)).ToArray()) },
@@ -21,7 +23,9 @@
{ NameToken.N, new NumericToken((decimal)n) }, { NameToken.N, new NumericToken((decimal)n) },
}); });
return new PdfFunctionType2(dictionaryToken); var func = PdfFunctionParser.Create(dictionaryToken, new TestPdfTokenScanner(), new TestFilterProvider());
Assert.Equal(FunctionTypes.Exponential, func.FunctionType);
return func as PdfFunctionType2;
} }
[Fact] [Fact]

View File

@@ -4,12 +4,14 @@
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UglyToad.PdfPig.Functions; using UglyToad.PdfPig.Functions;
using UglyToad.PdfPig.Tests.Tokens;
using UglyToad.PdfPig.Tokens; using UglyToad.PdfPig.Tokens;
using UglyToad.PdfPig.Util;
using Xunit; using Xunit;
public class PdfFunctionType4Tests public class PdfFunctionType4Tests
{ {
private PdfFunctionType4 CreateFunction(string function, double[] domain, double[] range) private static PdfFunctionType4 CreateFunction(string function, double[] domain, double[] range)
{ {
DictionaryToken dictionaryToken = new DictionaryToken(new Dictionary<NameToken, IToken>() DictionaryToken dictionaryToken = new DictionaryToken(new Dictionary<NameToken, IToken>()
{ {
@@ -21,7 +23,10 @@
var data = Encoding.ASCII.GetBytes(function); // OtherEncodings.Iso88591.GetBytes(function); var data = Encoding.ASCII.GetBytes(function); // OtherEncodings.Iso88591.GetBytes(function);
StreamToken stream = new StreamToken(dictionaryToken, data); StreamToken stream = new StreamToken(dictionaryToken, data);
return new PdfFunctionType4(stream); var func = PdfFunctionParser.Create(stream, new TestPdfTokenScanner(), new TestFilterProvider());
Assert.Equal(FunctionTypes.PostScript, func.FunctionType);
return func as PdfFunctionType4;
} }
/// <summary> /// <summary>

View File

@@ -20,6 +20,7 @@
var appearance = annotationStamp.normalAppearanceStream; var appearance = annotationStamp.normalAppearanceStream;
// TODO - load color space in annotation appearance // TODO - load color space in annotation appearance
// TODO - contains function with indirect reference
} }
} }

View File

@@ -1,6 +1,5 @@
namespace UglyToad.PdfPig.Functions namespace UglyToad.PdfPig.Functions
{ {
using System;
using System.Linq; using System.Linq;
using UglyToad.PdfPig.Core; using UglyToad.PdfPig.Core;
using UglyToad.PdfPig.Tokens; using UglyToad.PdfPig.Tokens;
@@ -20,25 +19,27 @@
/// </summary> /// </summary>
public StreamToken FunctionStream { get; } public StreamToken FunctionStream { get; }
private ArrayToken domain;
private ArrayToken range;
private int numberOfInputValues = -1; private int numberOfInputValues = -1;
private int numberOfOutputValues = -1; private int numberOfOutputValues = -1;
/// <summary> /// <summary>
/// This class represents a function in a PDF document. /// This class represents a function in a PDF document.
/// </summary> /// </summary>
public PdfFunction(DictionaryToken function) public PdfFunction(DictionaryToken function, ArrayToken domain, ArrayToken range)
{ {
FunctionDictionary = function; FunctionDictionary = function;
DomainValues = domain;
RangeValues = range;
} }
/// <summary> /// <summary>
/// This class represents a function in a PDF document. /// This class represents a function in a PDF document.
/// </summary> /// </summary>
public PdfFunction(StreamToken function) public PdfFunction(StreamToken function, ArrayToken domain, ArrayToken range)
{ {
FunctionStream = function; FunctionStream = function;
DomainValues = domain;
RangeValues = range;
} }
/// <summary> /// <summary>
@@ -119,7 +120,7 @@
{ {
if (numberOfInputValues == -1) if (numberOfInputValues == -1)
{ {
ArrayToken array = GetDomainValues(); ArrayToken array = DomainValues;
numberOfInputValues = array.Length / 2; numberOfInputValues = array.Length / 2;
} }
return numberOfInputValues; return numberOfInputValues;
@@ -135,7 +136,7 @@
/// <returns>The domain range for this component.</returns> /// <returns>The domain range for this component.</returns>
public PdfRange GetDomainForInput(int n) public PdfRange GetDomainForInput(int n)
{ {
ArrayToken domainValues = GetDomainValues(); ArrayToken domainValues = DomainValues;
return new PdfRange(domainValues.Data.OfType<NumericToken>().Select(t => t.Double), n); return new PdfRange(domainValues.Data.OfType<NumericToken>().Select(t => t.Double), n);
} }
@@ -153,34 +154,13 @@
/// Returns all ranges for the output values as <see cref="ArrayToken"/>. Required for type 0 and type 4 functions. /// Returns all ranges for the output values as <see cref="ArrayToken"/>. Required for type 0 and type 4 functions.
/// </summary> /// </summary>
/// <returns>the ranges array.</returns> /// <returns>the ranges array.</returns>
protected virtual ArrayToken RangeValues protected ArrayToken RangeValues { get; }
{
get
{
if (range == null)
{
GetDictionary().TryGet(NameToken.Range, out range); // Optionnal
}
return range;
}
}
/// <summary> /// <summary>
/// Returns all domains for the input values as <see cref="ArrayToken"/>. Required for all function types. /// Returns all domains for the input values as <see cref="ArrayToken"/>. Required for all function types.
/// </summary> /// </summary>
/// <returns>the domains array.</returns> /// <returns>the domains array.</returns>
private ArrayToken GetDomainValues() private ArrayToken DomainValues { get; }
{
if (domain == null)
{
if (!GetDictionary().TryGet(NameToken.Domain, out ArrayToken domainToken))
{
throw new ArgumentException("Could not retrieve Domain.");
}
domain = domainToken;
}
return domain;
}
/// <summary> /// <summary>
/// Clip the given input values to the ranges. /// Clip the given input values to the ranges.

View File

@@ -2,7 +2,6 @@
{ {
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using UglyToad.PdfPig.Core; using UglyToad.PdfPig.Core;
@@ -10,26 +9,6 @@
internal sealed class PdfFunctionType0 : PdfFunction internal sealed class PdfFunctionType0 : PdfFunction
{ {
/// <summary>
/// An array of 2 x m numbers specifying the linear mapping of input values
/// into the domain of the function's sample table. Default value: [ 0 (Size0
/// - 1) 0 (Size1 - 1) ...].
/// </summary>
private ArrayToken encode;
/// <summary>
/// An array of 2 x n numbers specifying the linear mapping of sample values
/// into the range appropriate for the function's output values. Default
/// value: same as the value of Range.
/// </summary>
private ArrayToken decode;
/// <summary>
/// An array of m positive integers specifying the number of samples in each
/// input dimension of the sample table.
/// </summary>
private ArrayToken size;
/// <summary> /// <summary>
/// The samples of the function. /// The samples of the function.
/// </summary> /// </summary>
@@ -38,15 +17,27 @@
/// <summary> /// <summary>
/// Stitching function /// Stitching function
/// </summary> /// </summary>
internal PdfFunctionType0(DictionaryToken function) : base(function) internal PdfFunctionType0(DictionaryToken function, ArrayToken domain, ArrayToken range, ArrayToken size, int bitsPerSample, int order, ArrayToken encode, ArrayToken decode)
: base(function, domain, range)
{ {
Size = size;
BitsPerSample = bitsPerSample;
Order = order;
EncodeValues = encode;
DecodeValues = decode;
} }
/// <summary> /// <summary>
/// Stitching function /// Stitching function
/// </summary> /// </summary>
internal PdfFunctionType0(StreamToken function) : base(function) internal PdfFunctionType0(StreamToken function, ArrayToken domain, ArrayToken range, ArrayToken size, int bitsPerSample, int order, ArrayToken encode, ArrayToken decode)
: base(function, domain, range)
{ {
Size = size;
BitsPerSample = bitsPerSample;
Order = order;
EncodeValues = encode;
DecodeValues = decode;
} }
public override FunctionTypes FunctionType public override FunctionTypes FunctionType
@@ -59,35 +50,16 @@
/// <summary> /// <summary>
/// The "Size" entry, which is the number of samples in each input dimension of the sample table. /// The "Size" entry, which is the number of samples in each input dimension of the sample table.
/// <para>An array of m positive integers specifying the number of samples in each input dimension of the sample table.</para>
/// </summary> /// </summary>
public ArrayToken Size public ArrayToken Size { get; }
{
get
{
if (size == null && !GetDictionary().TryGet(NameToken.Size, out size))
{
throw new ArgumentNullException(NameToken.Size);
}
return size;
}
}
/// <summary> /// <summary>
/// Get the number of bits that the output value will take up. /// Get the number of bits that the output value will take up.
/// <para>Valid values are 1,2,4,8,12,16,24,32.</para> /// <para>Valid values are 1,2,4,8,12,16,24,32.</para>
/// </summary> /// </summary>
/// <returns>Number of bits for each output value.</returns> /// <returns>Number of bits for each output value.</returns>
public int BitsPerSample public int BitsPerSample { get; }
{
get
{
if (!GetDictionary().TryGet<NumericToken>(NameToken.BitsPerSample, out var bps))
{
throw new ArgumentNullException(NameToken.BitsPerSample);
}
return bps.Int;
}
}
/// <summary> /// <summary>
/// Get the order of interpolation between samples. Valid values are 1 and 3, /// Get the order of interpolation between samples. Valid values are 1 and 3,
@@ -95,69 +67,21 @@
/// is 1. See p.170 in PDF spec 1.7. /// is 1. See p.170 in PDF spec 1.7.
/// </summary> /// </summary>
/// <returns>order of interpolation.</returns> /// <returns>order of interpolation.</returns>
public int Order public int Order { get; }
{
get
{
if (!GetDictionary().TryGet<NumericToken>(NameToken.Order, out var order))
{
return 1;
}
return order.Int;
}
}
/// <summary> /// <summary>
/// Returns all encode values as <see cref="ArrayToken"/>. /// An array of 2 x m numbers specifying the linear mapping of input values
/// into the domain of the function's sample table. Default value: [ 0 (Size0
/// - 1) 0 (Size1 - 1) ...].
/// </summary> /// </summary>
/// <returns>the encode array. </returns> private ArrayToken EncodeValues { get; }
private ArrayToken EncodeValues
{
get
{
if (encode == null)
{
GetDictionary().TryGet<ArrayToken>(NameToken.Encode, out encode);
// the default value is [0 (size[0]-1) 0 (size[1]-1) ...]
if (encode == null)
{
var values = new List<NumericToken>();
ArrayToken sizeValues = Size;
int sizeValuesSize = sizeValues.Length;
for (int i = 0; i < sizeValuesSize; i++)
{
values.Add(new NumericToken(0));
values.Add(new NumericToken((sizeValues[i] as NumericToken).Int - 1L));
}
encode = new ArrayToken(values);
}
}
return encode;
}
}
/// <summary> /// <summary>
/// Returns all decode values as <see cref="ArrayToken"/>. /// An array of 2 x n numbers specifying the linear mapping of sample values
/// into the range appropriate for the function's output values. Default
/// value: same as the value of Range.
/// </summary> /// </summary>
/// <returns>the decode array.</returns> private ArrayToken DecodeValues { get; }
private ArrayToken DecodeValues
{
get
{
if (decode == null)
{
GetDictionary().TryGet<ArrayToken>(NameToken.Decode, out decode);
// if decode is null, the default values are the range values
if (decode == null)
{
decode = RangeValues;
}
}
return decode;
}
}
/// <summary> /// <summary>
/// Get the encode for the input parameter. /// Get the encode for the input parameter.

View File

@@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.Functions namespace UglyToad.PdfPig.Functions
{ {
using System; using System;
using System.Collections.Generic;
using UglyToad.PdfPig.Tokens; using UglyToad.PdfPig.Tokens;
/// <summary> /// <summary>
@@ -12,80 +11,20 @@
/// <summary> /// <summary>
/// Exponential interpolation function /// Exponential interpolation function
/// </summary> /// </summary>
internal PdfFunctionType2(DictionaryToken function) : base(function) internal PdfFunctionType2(DictionaryToken function, ArrayToken domain, ArrayToken range, ArrayToken c0, ArrayToken c1, double n)
: base(function, domain, range)
{ {
if (GetDictionary().TryGet(NameToken.C0, out ArrayToken array0)) C0 = c0;
{ C1 = c1;
C0 = array0; N = n;
}
else
{
C0 = new ArrayToken(new List<IToken>());
}
if (C0.Length == 0)
{
C0 = new ArrayToken(new List<NumericToken>() { new NumericToken(0) });
} }
if (GetDictionary().TryGet(NameToken.C1, out ArrayToken array1)) internal PdfFunctionType2(StreamToken function, ArrayToken domain, ArrayToken range, ArrayToken c0, ArrayToken c1, double n)
: base(function, domain, range)
{ {
C1 = array1; C0 = c0;
} C1 = c1;
else N = n;
{
C1 = new ArrayToken(new List<IToken>());
}
if (C0.Length == 0)
{
C1 = new ArrayToken(new List<NumericToken>() { new NumericToken(1) });
}
if (GetDictionary().TryGet(NameToken.N, out NumericToken exp))
{
N = exp.Double;
}
else
{
throw new NotImplementedException();
}
}
internal PdfFunctionType2(StreamToken function) : base(function)
{
if (GetDictionary().TryGet(NameToken.C0, out ArrayToken array0))
{
C0 = array0;
}
else
{
C0 = new ArrayToken(new List<IToken>());
}
if (C0.Length == 0)
{
C0 = new ArrayToken(new List<NumericToken>() { new NumericToken(0) });
}
if (GetDictionary().TryGet(NameToken.C1, out ArrayToken array1))
{
C1 = array1;
}
else
{
C1 = new ArrayToken(new List<IToken>());
}
if (C0.Length == 0)
{
C1 = new ArrayToken(new List<NumericToken>() { new NumericToken(1) });
}
if (GetDictionary().TryGet(NameToken.N, out NumericToken exp))
{
N = exp.Double;
}
else
{
throw new NotImplementedException();
}
} }
public override FunctionTypes FunctionType public override FunctionTypes FunctionType

View File

@@ -12,35 +12,38 @@
/// </summary> /// </summary>
internal sealed class PdfFunctionType3 : PdfFunction internal sealed class PdfFunctionType3 : PdfFunction
{ {
private ArrayToken functions; private readonly double[] boundsValues;
private ArrayToken encode;
private ArrayToken bounds;
private double[] boundsValues;
/// <summary> /// <summary>
/// Stitching function /// Stitching function
/// </summary> /// </summary>
internal PdfFunctionType3(DictionaryToken function, IReadOnlyList<PdfFunction> functionsArray) internal PdfFunctionType3(DictionaryToken function, ArrayToken domain, ArrayToken range, IReadOnlyList<PdfFunction> functionsArray, ArrayToken bounds, ArrayToken encode)
: base(function) : base(function, domain, range)
{ {
if (functionsArray == null || functionsArray.Count == 0) if (functionsArray == null || functionsArray.Count == 0)
{ {
throw new ArgumentNullException(nameof(functionsArray)); throw new ArgumentNullException(nameof(functionsArray));
} }
this.FunctionsArray = functionsArray; this.FunctionsArray = functionsArray;
Bounds = bounds;
Encode = encode;
boundsValues = Bounds.Data.OfType<NumericToken>().Select(t => t.Double).ToArray();
} }
/// <summary> /// <summary>
/// Stitching function /// Stitching function
/// </summary> /// </summary>
internal PdfFunctionType3(StreamToken function, IReadOnlyList<PdfFunction> functionsArray) internal PdfFunctionType3(StreamToken function, ArrayToken domain, ArrayToken range, IReadOnlyList<PdfFunction> functionsArray, ArrayToken bounds, ArrayToken encode)
: base(function) : base(function, domain, range)
{ {
if (functionsArray == null || functionsArray.Count == 0) if (functionsArray == null || functionsArray.Count == 0)
{ {
throw new ArgumentNullException(nameof(functionsArray)); throw new ArgumentNullException(nameof(functionsArray));
} }
this.FunctionsArray = functionsArray; this.FunctionsArray = functionsArray;
Bounds = bounds;
Encode = encode;
boundsValues = Bounds.Data.OfType<NumericToken>().Select(t => t.Double).ToArray();
} }
public override FunctionTypes FunctionType public override FunctionTypes FunctionType
@@ -71,11 +74,6 @@
} }
else else
{ {
if (boundsValues == null)
{
boundsValues = Bounds.Data.OfType<NumericToken>().Select(t => t.Double).ToArray();
}
int boundsSize = boundsValues.Length; int boundsSize = boundsValues.Length;
// create a combined array containing the domain and the bounds values // create a combined array containing the domain and the bounds values
// domain.min, bounds[0], bounds[1], ...., bounds[boundsSize-1], domain.max // domain.min, bounds[0], bounds[1], ...., bounds[boundsSize-1], domain.max
@@ -108,55 +106,22 @@
return ClipToRange(functionResult); return ClipToRange(functionResult);
} }
public IReadOnlyList<PdfFunction> FunctionsArray { get; }
/// <summary> /// <summary>
/// Returns all functions values as <see cref="ArrayToken"/>. /// Returns all functions values.
/// </summary> /// </summary>
/// <returns>the functions array. </returns> public IReadOnlyList<PdfFunction> FunctionsArray { get; }
public ArrayToken Functions
{
get
{
if (functions == null && !GetDictionary().TryGet<ArrayToken>(NameToken.Functions, out functions))
{
throw new ArgumentNullException(NameToken.Functions);
}
return functions;
}
}
/// <summary> /// <summary>
/// Returns all bounds values as <see cref="ArrayToken"/>. /// Returns all bounds values as <see cref="ArrayToken"/>.
/// </summary> /// </summary>
/// <returns>the bounds array.</returns> /// <returns>the bounds array.</returns>
public ArrayToken Bounds public ArrayToken Bounds { get; }
{
get
{
if (bounds == null && !GetDictionary().TryGet<ArrayToken>(NameToken.Bounds, out bounds))
{
throw new ArgumentNullException(NameToken.Bounds);
}
return bounds;
}
}
/// <summary> /// <summary>
/// Returns all encode values as <see cref="ArrayToken"/>. /// Returns all encode values as <see cref="ArrayToken"/>.
/// </summary> /// </summary>
/// <returns>the encode array.</returns> /// <returns>the encode array.</returns>
public ArrayToken Encode public ArrayToken Encode { get; }
{
get
{
if (encode == null && !GetDictionary().TryGet<ArrayToken>(NameToken.Encode, out encode))
{
throw new ArgumentNullException(NameToken.Encode);
}
return encode;
}
}
/// <summary> /// <summary>
/// Get the encode for the input parameter. /// Get the encode for the input parameter.

View File

@@ -17,7 +17,8 @@
/// <summary> /// <summary>
/// PostScript calculator function /// PostScript calculator function
/// </summary> /// </summary>
internal PdfFunctionType4(StreamToken function) : base(function) internal PdfFunctionType4(StreamToken function, ArrayToken domain, ArrayToken range)
: base(function, domain, range)
{ {
byte[] bytes = FunctionStream.Data.ToArray(); byte[] bytes = FunctionStream.Data.ToArray();
string str = OtherEncodings.Iso88591.GetString(bytes); string str = OtherEncodings.Iso88591.GetString(bytes);

View File

@@ -30,6 +30,13 @@
throw new ArgumentException(nameof(function)); throw new ArgumentException(nameof(function));
} }
if (!functionDictionary.TryGet(NameToken.Domain, scanner, out ArrayToken domain))
{
throw new ArgumentNullException(NameToken.Domain);
}
functionDictionary.TryGet(NameToken.Range, scanner, out ArrayToken range);
int functionType = (functionDictionary.Data[NameToken.FunctionType] as NumericToken).Int; int functionType = (functionDictionary.Data[NameToken.FunctionType] as NumericToken).Int;
switch (functionType) switch (functionType)
@@ -39,12 +46,93 @@
{ {
throw new NotImplementedException("PdfFunctionType0 not stream"); throw new NotImplementedException("PdfFunctionType0 not stream");
} }
return new PdfFunctionType0(functionStream); return CreatePdfFunctionType0(functionStream, domain, range, scanner);
case 2: case 2:
return new PdfFunctionType2(functionDictionary); return CreatePdfFunctionType2(functionDictionary, domain, range, scanner);
case 3: case 3:
return CreatePdfFunctionType3(functionDictionary, domain, range, scanner, filterProvider);
case 4:
if (functionStream == null)
{
throw new NotImplementedException("PdfFunctionType4 not stream");
}
return CreatePdfFunctionType4(functionStream, domain, range, scanner);
default:
throw new IOException("Error: Unknown function type " + functionType);
}
}
private static PdfFunctionType0 CreatePdfFunctionType0(StreamToken functionStream, ArrayToken domain, ArrayToken range, IPdfTokenScanner scanner)
{
if (range == null)
{
throw new ArgumentException("Could not retrieve Range in type 0 function.");
}
if (!functionStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Size, scanner, out var size))
{
throw new ArgumentNullException(NameToken.Size);
}
if (!functionStream.StreamDictionary.TryGet<NumericToken>(NameToken.BitsPerSample, scanner, out var bps))
{
throw new ArgumentNullException(NameToken.BitsPerSample);
}
int order = 1; // Default value
if (functionStream.StreamDictionary.TryGet<NumericToken>(NameToken.Order, scanner, out var orderToken))
{
order = orderToken.Int;
}
if (!functionStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Encode, scanner, out var encode) || encode == null)
{
// The default value is [0 (size[0]-1) 0 (size[1]-1) ...]
var values = new List<NumericToken>();
int sizeValuesSize = size.Length;
for (int i = 0; i < sizeValuesSize; i++)
{
values.Add(new NumericToken(0));
values.Add(new NumericToken((size[i] as NumericToken).Int - 1L));
}
encode = new ArrayToken(values);
}
if (!functionStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Decode, scanner, out var decode) || decode == null)
{
// if decode is null, the default values are the range values
decode = range;
}
return new PdfFunctionType0(functionStream, domain, range, size, bps.Int, order, encode, decode);
}
private static PdfFunctionType2 CreatePdfFunctionType2(DictionaryToken functionDictionary, ArrayToken domain, ArrayToken range, IPdfTokenScanner scanner)
{
if (!functionDictionary.TryGet(NameToken.C0, scanner, out ArrayToken array0) || array0.Length == 0)
{
array0 = new ArrayToken(new List<NumericToken>() { new NumericToken(0) }); // Default value: [0.0].
}
if (!functionDictionary.TryGet(NameToken.C1, scanner, out ArrayToken array1) || array1.Length == 0)
{
array1 = new ArrayToken(new List<NumericToken>() { new NumericToken(1) }); // Default value: [1.0].
}
if (!functionDictionary.TryGet(NameToken.N, scanner, out NumericToken exp))
{
throw new ArgumentNullException(NameToken.N);
}
return new PdfFunctionType2(functionDictionary, domain, range, array0, array1, exp.Double);
}
private static PdfFunctionType3 CreatePdfFunctionType3(DictionaryToken functionDictionary, ArrayToken domain, ArrayToken range, IPdfTokenScanner scanner, ILookupFilterProvider filterProvider)
{
var functions = new List<PdfFunction>(); var functions = new List<PdfFunction>();
if (functionDictionary.TryGet<ArrayToken>(NameToken.Functions, scanner, out var functionsToken)) if (functionDictionary.TryGet<ArrayToken>(NameToken.Functions, scanner, out var functionsToken))
{ {
@@ -64,18 +152,32 @@
} }
} }
} }
return new PdfFunctionType3(functionDictionary, functions); else
case 4:
if (functionStream == null)
{ {
throw new NotImplementedException("PdfFunctionType4 not stream"); throw new ArgumentNullException(NameToken.Functions);
} }
return new PdfFunctionType4(functionStream);
default: if (!functionDictionary.TryGet<ArrayToken>(NameToken.Bounds, out var bounds))
throw new IOException("Error: Unknown function type " + functionType); {
} throw new ArgumentNullException(NameToken.Bounds);
}
if (!functionDictionary.TryGet<ArrayToken>(NameToken.Encode, out var encode))
{
throw new ArgumentNullException(NameToken.Encode);
}
return new PdfFunctionType3(functionDictionary, domain, range, functions, bounds, encode);
}
private static PdfFunctionType4 CreatePdfFunctionType4(StreamToken functionStream, ArrayToken domain, ArrayToken range, IPdfTokenScanner scanner)
{
if (range == null)
{
throw new ArgumentException("Could not retrieve Range in type 4 function.");
}
return new PdfFunctionType4(functionStream, domain, range);
} }
} }
} }