mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-06-28 15:30:17 +08:00

* Enable nullable annotations * Remove unused Jetbrain annotations * Ensure system using statements are first * Improve nullability annotations * Annotate encryptionDictionary is non-null when IsEncrypted is true * Disable nullable for PdfTokenScanner.Get * Improve nullability annotations for ObjectLocationProvider.TryGetCached * Revert changes to RGBWorkingSpace * Update UglyToad.PdfPig.Package with new framework targets (fixes nightly builds)
255 lines
9.2 KiB
C#
255 lines
9.2 KiB
C#
namespace UglyToad.PdfPig.Functions
|
|
{
|
|
using System.Linq;
|
|
using UglyToad.PdfPig.Core;
|
|
using UglyToad.PdfPig.Tokens;
|
|
|
|
/// <summary>
|
|
/// This class represents a function in a PDF document.
|
|
/// </summary>
|
|
public abstract class PdfFunction
|
|
{
|
|
/// <summary>
|
|
/// The function dictionary.
|
|
/// </summary>
|
|
public DictionaryToken? FunctionDictionary { get; }
|
|
|
|
/// <summary>
|
|
/// The function stream.
|
|
/// </summary>
|
|
public StreamToken? FunctionStream { get; }
|
|
|
|
private int numberOfInputValues = -1;
|
|
private int numberOfOutputValues = -1;
|
|
|
|
/// <summary>
|
|
/// This class represents a function in a PDF document.
|
|
/// </summary>
|
|
public PdfFunction(DictionaryToken function, ArrayToken domain, ArrayToken? range)
|
|
{
|
|
FunctionDictionary = function;
|
|
DomainValues = domain;
|
|
RangeValues = range;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class represents a function in a PDF document.
|
|
/// </summary>
|
|
public PdfFunction(StreamToken function, ArrayToken domain, ArrayToken? range)
|
|
{
|
|
FunctionStream = function;
|
|
DomainValues = domain;
|
|
RangeValues = range;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the function type. Possible values are:
|
|
/// <list type="bullet">
|
|
/// <item><term>0</term><description>Sampled function</description></item>
|
|
/// <item><term>2</term><description>Exponential interpolation function</description></item>
|
|
/// <item><term>3</term><description>Stitching function</description></item>
|
|
/// <item><term>4</term><description>PostScript calculator function</description></item>
|
|
/// </list>
|
|
/// </summary>
|
|
/// <returns>the function type.</returns>
|
|
public abstract FunctionTypes FunctionType { get; }
|
|
|
|
/// <summary>
|
|
/// Returns the function's dictionary. If <see cref="FunctionDictionary"/> is defined, it will be returned.
|
|
/// If not, the <see cref="FunctionStream"/>'s StreamDictionary will be returned.
|
|
/// </summary>
|
|
public DictionaryToken? GetDictionary()
|
|
{
|
|
if (FunctionStream != null)
|
|
{
|
|
return FunctionStream.StreamDictionary;
|
|
}
|
|
else
|
|
{
|
|
return FunctionDictionary;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will get the number of output parameters that
|
|
/// have a range specified. A range for output parameters
|
|
/// is optional so this may return zero for a function
|
|
/// that does have output parameters, this will simply return the
|
|
/// number that have the range specified.
|
|
/// </summary>
|
|
/// <returns>The number of output parameters that have a range specified.</returns>
|
|
public int NumberOfOutputParameters
|
|
{
|
|
get
|
|
{
|
|
if (numberOfOutputValues == -1)
|
|
{
|
|
if (RangeValues is null)
|
|
{
|
|
numberOfOutputValues = 0;
|
|
}
|
|
else
|
|
{
|
|
numberOfOutputValues = RangeValues.Length / 2;
|
|
}
|
|
}
|
|
return numberOfOutputValues;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will get the range for a certain output parameters. This is will never
|
|
/// return null. If it is not present then the range 0 to 0 will
|
|
/// be returned.
|
|
/// </summary>
|
|
/// <param name="n">The output parameter number to get the range for.</param>
|
|
/// <returns>The range for this component.</returns>
|
|
public PdfRange GetRangeForOutput(int n)
|
|
{
|
|
return new PdfRange(RangeValues!.Data.OfType<NumericToken>().Select(t => t.Double), n);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will get the number of input parameters that
|
|
/// have a domain specified.
|
|
/// </summary>
|
|
/// <returns>The number of input parameters that have a domain specified.</returns>
|
|
public int NumberOfInputParameters
|
|
{
|
|
get
|
|
{
|
|
if (numberOfInputValues == -1)
|
|
{
|
|
ArrayToken array = DomainValues;
|
|
numberOfInputValues = array.Length / 2;
|
|
}
|
|
return numberOfInputValues;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will get the range for a certain input parameter. This is will never
|
|
/// return null. If it is not present then the range 0 to 0 will
|
|
/// be returned.
|
|
/// </summary>
|
|
/// <param name="n">The parameter number to get the domain for.</param>
|
|
/// <returns>The domain range for this component.</returns>
|
|
public PdfRange GetDomainForInput(int n)
|
|
{
|
|
ArrayToken domainValues = DomainValues;
|
|
return new PdfRange(domainValues.Data.OfType<NumericToken>().Select(t => t.Double), n);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Evaluates the function at the given input.
|
|
/// ReturnValue = f(input)
|
|
/// </summary>
|
|
/// <param name="input">The array of input values for the function.
|
|
/// In many cases will be an array of a single value, but not always.</param>
|
|
/// <returns>The of outputs the function returns based on those inputs.
|
|
/// In many cases will be an array of a single value, but not always.</returns>
|
|
public abstract double[] Eval(params double[] input);
|
|
|
|
/// <summary>
|
|
/// Returns all ranges for the output values as <see cref="ArrayToken"/>. Required for type 0 and type 4 functions.
|
|
/// </summary>
|
|
/// <returns>the ranges array.</returns>
|
|
protected ArrayToken? RangeValues { get; }
|
|
|
|
/// <summary>
|
|
/// Returns all domains for the input values as <see cref="ArrayToken"/>. Required for all function types.
|
|
/// </summary>
|
|
/// <returns>the domains array.</returns>
|
|
private ArrayToken DomainValues { get; }
|
|
|
|
/// <summary>
|
|
/// Clip the given input values to the ranges.
|
|
/// </summary>
|
|
/// <param name="inputValues">inputValues the input values</param>
|
|
/// <returns>the clipped values</returns>
|
|
protected double[] ClipToRange(double[] inputValues)
|
|
{
|
|
ArrayToken rangesArray = RangeValues!;
|
|
double[] result;
|
|
if (rangesArray != null && rangesArray.Length > 0)
|
|
{
|
|
double[] rangeValues = rangesArray.Data.OfType<NumericToken>().Select(t => t.Double).ToArray();
|
|
int numberOfRanges = rangeValues.Length / 2;
|
|
result = new double[numberOfRanges];
|
|
for (int i = 0; i < numberOfRanges; i++)
|
|
{
|
|
int index = i << 1;
|
|
result[i] = ClipToRange(inputValues[i], rangeValues[index], rangeValues[index + 1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = inputValues;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clip the given input value to the given range.
|
|
/// </summary>
|
|
/// <param name="x">x the input value</param>
|
|
/// <param name="rangeMin">the min value of the range</param>
|
|
/// <param name="rangeMax">the max value of the range</param>
|
|
/// <returns>the clipped value</returns>
|
|
public static double ClipToRange(double x, double rangeMin, double rangeMax)
|
|
{
|
|
if (x < rangeMin)
|
|
{
|
|
return rangeMin;
|
|
}
|
|
else if (x > rangeMax)
|
|
{
|
|
return rangeMax;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
/// <summary>
|
|
/// For a given value of x, interpolate calculates the y value
|
|
/// on the line defined by the two points (xRangeMin, xRangeMax)
|
|
/// and (yRangeMin, yRangeMax).
|
|
/// </summary>
|
|
/// <param name="x">the value to be interpolated value.</param>
|
|
/// <param name="xRangeMin">the min value of the x range</param>
|
|
/// <param name="xRangeMax">the max value of the x range</param>
|
|
/// <param name="yRangeMin">the min value of the y range</param>
|
|
/// <param name="yRangeMax">the max value of the y range</param>
|
|
/// <returns>the interpolated y value</returns>
|
|
protected static double Interpolate(double x, double xRangeMin, double xRangeMax, double yRangeMin, double yRangeMax)
|
|
{
|
|
return yRangeMin + ((x - xRangeMin) * (yRangeMax - yRangeMin) / (xRangeMax - xRangeMin));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pdf function types.
|
|
/// </summary>
|
|
public enum FunctionTypes : byte
|
|
{
|
|
/// <summary>
|
|
/// Sampled function.
|
|
/// </summary>
|
|
Sampled = 0,
|
|
|
|
/// <summary>
|
|
/// Exponential interpolation function.
|
|
/// </summary>
|
|
Exponential = 2,
|
|
|
|
/// <summary>
|
|
/// Stitching function.
|
|
/// </summary>
|
|
Stitching = 3,
|
|
|
|
/// <summary>
|
|
/// PostScript calculator function.
|
|
/// </summary>
|
|
PostScript = 4
|
|
}
|
|
}
|